/* $Id: fsperf2.c,v 1.5 2003/11/26 19:01:52 ca Exp $ */
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include "sm/queue.h"
/*
test program to re-use existing files
*/
#define MAXFN 16
struct freef_S
{
char fn[MAXFN];
SLIST_ENTRY(freef) next;
};
typedef struct freef_S freef_T, *freef_P;
SLIST_HEAD(hdname, freef) fhd;
static int reallyrm = 0;
#define PERLEVEL 100
#define FNAMEFMT0 "%06d"
#define FNAMEFMT1 "%02d/%06d"
#define FNAMEFMT2 "%02d/%02d/%06d"
#define DNAMEFMT1 "%02d"
#define DNAMEFMT2 "%02d/%02d"
static void
fatal(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
exit(1);
}
static void
filename(char *fn, int n, int level)
{
switch(level)
{
case 0:
sprintf(fn, FNAMEFMT0, n);
break;
case 1:
sprintf(fn, FNAMEFMT1, n % PERLEVEL, n);
break;
case 2:
sprintf(fn, FNAMEFMT2, (n / PERLEVEL) % PERLEVEL, n % PERLEVEL,
n);
break;
default:
fatal("filename: wrong level %d", level);
/* NOTREACHED */
}
}
/* make_file - create a little file and use it */
static void
make_file(int seqno, int size, int level)
{
char path[MAXFN];
char buf[1024];
FILE *fp;
int i;
filename(path, seqno, level);
/* printf("+: %s\n", path); */
if ((fp = fopen(path, "w")) == 0)
fatal("open(%s): %d", path, errno);
memset(buf, 'x', sizeof(buf));
for (i = 0; i < size; i++)
if (fwrite(buf, sizeof(buf), 1, fp) != 1)
fatal("fwrite: %d", errno);
if (fsync(fileno(fp)))
fatal("fsync(%s): %d", path, errno);
if (fclose(fp))
fatal("fclose(%s): %d", path, errno);
if ((fp = fopen(path, "r")) == 0)
fatal("open(%s): %d", path, errno);
while (fgets(path, sizeof(path), fp))
/* void */ ;
if (fclose(fp))
fatal("fclose(%s): %d", path, errno);
}
/* use_file - use existing file */
static void
use_file(int seqno, int size, int level)
{
char path[MAXFN];
FILE *fp;
int i;
filename(path, seqno, level);
if ((fp = fopen(path, "w")) == NULL)
fatal("open %s: %d", path, errno);
for (i = 0; i < size; i++)
fprintf(fp, "hello");
if (fsync(fileno(fp)))
fatal("fsync: %d", errno);
if (fclose(fp))
fatal("fclose: %d", errno);
if ((fp = fopen(path, "r+")) == NULL)
fatal("open %s: %d", path, errno);
while (fgets(path, sizeof(path), fp) != NULL)
/* void */ ;
if (ftruncate(fileno(fp), (off_t) 0))
fatal("ftruncate: %d", errno);
if (fclose(fp))
fatal("fclose: %d", errno);
}
/* remove_file - delete specified file */
static void
remove_file(int n, int level)
{
char path[MAXFN];
filename(path, n, level);
/* printf("-: %s\n", path); */
if (reallyrm)
{
if (remove(path))
fatal("remove %s: %d", path, errno);
}
else
{
if (truncate(path, 0))
fatal("truncate %s: %d", path, errno);
}
}
/* remove_silent - delete specified file, silently */
static void
remove_silent(int n, int level)
{
char path[MAXFN];
filename(path, n, level);
(void) remove(path);
}
/* usage - explain */
static void usage(char *myname)
{
fprintf(stderr, "usage: %s [-cr] [-C concurrency] [-h hash] [-l lines] [-s size] messages directory_entries\n",
myname);
fprintf(stderr, "\t-C n\tkeep n messages open concurrently\n");
fprintf(stderr, "\t-c\tcreate/delete file\n");
fprintf(stderr, "\t-h hashlevel\t0, 1, 2: number of directory levels\n");
fprintf(stderr, "\t-l lines\tlines for file to use\n");
fprintf(stderr, "\t-p\tpopulate directory with files before start\n");
fprintf(stderr, "\t-r\tremove files\n");
fprintf(stderr, "\t-s size\tsize of file\n");
exit(1);
}
int
main(int argc, char **argv)
{
int op_count;
int max_file;
time_t start;
int do_create = 0;
int populate = 0;
int seq, h;
int o;
int ch;
int size = 2;
int lines = 400;
int level = 0;
int concurrent = 0;
char path[MAXFN];
while ((ch = getopt(argc, argv, "C:ch:l:prs:")) != EOF)
{
switch (ch)
{
case 'C':
if ((concurrent = atoi(optarg)) < 0)
usage(argv[0]);
break;
case 'c':
do_create = 1;
break;
case 'h':
if ((level = atoi(optarg)) < 0)
usage(argv[0]);
break;
case 'l':
if ((lines = atoi(optarg)) <= 0)
usage(argv[0]);
break;
case 'p':
populate = 1;
break;
case 'r':
reallyrm = 1;
break;
case 's':
if ((size = atoi(optarg)) <= 0)
usage(argv[0]);
break;
default:
usage(argv[0]);
}
}
if (argc != optind + 2 || !do_create)
usage(argv[0]);
if ((op_count = atoi(argv[optind])) <= 0)
usage(argv[0]);
if ((max_file = atoi(argv[optind + 1])) <= 0)
usage(argv[0]);
if (concurrent >= max_file)
usage(argv[0]);
if (op_count < max_file)
usage(argv[0]);
if (level > 0)
{
for (seq = 0; seq < PERLEVEL; seq++)
{
sprintf(path, DNAMEFMT1, seq);
if (mkdir(path, 0750) && errno != EEXIST)
fatal("mkdir(%s): %d", path, errno);
}
}
if (level > 1)
{
for (h = 0; h < PERLEVEL; h++)
{
for (seq = 0; seq < PERLEVEL; seq++)
{
sprintf(path, DNAMEFMT2, h, seq);
if (mkdir(path, 0750))
fatal("mkdir(%s): %d", path, errno);
}
}
}
SLIST_INIT(&fhd);
/* Populate the directory with little files. */
if (populate)
for (seq = 0; seq < max_file; seq++)
make_file(seq, size, level);
/* Simulate arrival and delivery of mail messages. */
seq = 0;
start = time((time_t *) 0);
if (concurrent > 0 && do_create)
{
for (h = 0; h < concurrent; h++)
{
seq %= max_file;
make_file(seq, size, level);
seq++;
}
}
while (op_count > 0)
{
seq %= max_file;
if (do_create)
{
make_file(seq, size, level);
o = seq - concurrent;
if (o < 0)
o += max_file;
remove_file(o, level);
}
else
{
use_file(seq, lines, level);
}
seq++;
op_count--;
}
if (concurrent > 0 && do_create)
{
for (h = 0; h < concurrent; h++)
{
o = seq - concurrent;
if (o < 0)
o += max_file;
remove_file(o, level);
seq++;
}
}
printf("elapsed time: %ld\n", (long) time((time_t *) 0) - start);
/* Clean up directory fillers. */
if (populate || !do_create)
for (seq = 0; seq < max_file; seq++)
remove_silent(seq, level);
if (level > 1)
{
for (h = 0; h < PERLEVEL; h++)
{
for (seq = 0; seq < PERLEVEL; seq++)
{
sprintf(path, DNAMEFMT2, h, seq);
(void) rmdir(path);
}
}
}
if (level > 0)
{
for (seq = 0; seq < PERLEVEL; seq++)
{
sprintf(path, DNAMEFMT1, seq);
(void) rmdir(path);
}
}
return (0);
}
syntax highlighted by Code2HTML, v. 0.9.1