/*++
/* NAME
/* fsstone 1
/* SUMMARY
/* measure directory operation overhead
/* SYNOPSIS
/* .fi
/* \fBfsstone\fR [\fB-cr\fR] [\fB-s \fIsize\fR]
/* \fImsg_count files_per_dir\fR
/* DESCRIPTION
/* The \fBfsstone\fR command measures the cost of creating, renaming
/* and deleting queue files versus appending messages to existing
/* files and truncating them after use.
/*
/* The program simulates the arrival of \fImsg_count\fR short messages,
/* and arranges for at most \fIfiles_per_dir\fR simultaneous files
/* in the same directory.
/*
/* Options:
/* .IP \fB-c\fR
/* Create and delete files.
/* .IP \fB-r\fR
/* Rename files twice (requires \fB-c\fR).
/* .IP \fB-s \fIsize\fR
/* Specify the file size in kbytes.
/* DIAGNOSTICS
/* Problems are reported to the standard error stream.
/* BUGS
/* The \fB-r\fR option renames files within the same directory.
/* For a more realistic simulation, the program should rename files
/* between directories, and should also have an option to use
/* hashed directories as implemented with, for example, the
/* \fBdir_forest\fR(3) module.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include
#include
#include
#include
#include
#include
/* Utility library. */
#include
#include
/* Global directory. */
#include
/* rename_file - rename a file */
static void rename_file(int old, int new)
{
char new_path[BUFSIZ];
char old_path[BUFSIZ];
sprintf(new_path, "%06d", new);
sprintf(old_path, "%06d", old);
if (rename(old_path, new_path))
msg_fatal("rename %s to %s: %m", old_path, new_path);
}
/* make_file - create a little file and use it */
static void make_file(int seqno, int size)
{
char path[BUFSIZ];
char buf[1024];
FILE *fp;
int i;
sprintf(path, "%06d", seqno);
if ((fp = fopen(path, "w")) == 0)
msg_fatal("open %s: %m", path);
memset(buf, 'x', sizeof(buf));
for (i = 0; i < size; i++)
if (fwrite(buf, 1, sizeof(buf), fp) != sizeof(buf))
msg_fatal("fwrite: %m");
if (fsync(fileno(fp)))
msg_fatal("fsync: %m");
if (fclose(fp))
msg_fatal("fclose: %m");
if ((fp = fopen(path, "r")) == 0)
msg_fatal("open %s: %m", path);
while (fgets(path, sizeof(path), fp))
/* void */ ;
if (fclose(fp))
msg_fatal("fclose: %m");
}
/* use_file - use existing file */
static void use_file(int seqno)
{
char path[BUFSIZ];
FILE *fp;
int i;
sprintf(path, "%06d", seqno);
if ((fp = fopen(path, "w")) == 0)
msg_fatal("open %s: %m", path);
for (i = 0; i < 400; i++)
fprintf(fp, "hello");
if (fsync(fileno(fp)))
msg_fatal("fsync: %m");
if (fclose(fp))
msg_fatal("fclose: %m");
if ((fp = fopen(path, "r+")) == 0)
msg_fatal("open %s: %m", path);
while (fgets(path, sizeof(path), fp))
/* void */ ;
if (ftruncate(fileno(fp), (off_t) 0))
msg_fatal("ftruncate: %m");;
if (fclose(fp))
msg_fatal("fclose: %m");
}
/* remove_file - delete specified file */
static void remove_file(int seq)
{
char path[BUFSIZ];
sprintf(path, "%06d", seq);
if (remove(path))
msg_fatal("remove %s: %m", path);
}
/* remove_silent - delete specified file, silently */
static void remove_silent(int seq)
{
char path[BUFSIZ];
sprintf(path, "%06d", seq);
(void) remove(path);
}
/* usage - explain */
static void usage(char *myname)
{
msg_fatal("usage: %s [-cr] [-s size] messages directory_entries", myname);
}
MAIL_VERSION_STAMP_DECLARE;
int main(int argc, char **argv)
{
int op_count;
int max_file;
struct timeval start, end;
int do_rename = 0;
int do_create = 0;
int seq;
int ch;
int size = 2;
/*
* Fingerprint executables and core dumps.
*/
MAIL_VERSION_STAMP_ALLOCATE;
msg_vstream_init(argv[0], VSTREAM_ERR);
while ((ch = GETOPT(argc, argv, "crs:")) != EOF) {
switch (ch) {
case 'c':
do_create++;
break;
case 'r':
do_rename++;
break;
case 's':
if ((size = atoi(optarg)) <= 0)
usage(argv[0]);
break;
default:
usage(argv[0]);
}
}
if (argc - optind != 2 || (do_rename && !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]);
/*
* Populate the directory with little files.
*/
for (seq = 0; seq < max_file; seq++)
make_file(seq, size);
/*
* Simulate arrival and delivery of mail messages.
*/
GETTIMEOFDAY(&start);
while (op_count > 0) {
seq %= max_file;
if (do_create) {
remove_file(seq);
make_file(seq, size);
if (do_rename) {
rename_file(seq, seq + max_file);
rename_file(seq + max_file, seq);
}
} else {
use_file(seq);
}
seq++;
op_count--;
}
GETTIMEOFDAY(&end);
if (end.tv_usec < start.tv_usec) {
end.tv_sec--;
end.tv_usec += 1000000;
}
printf("elapsed time: %ld.%06ld\n",
(long) (end.tv_sec - start.tv_sec),
(long) (end.tv_usec - start.tv_usec));
/*
* Clean up directory fillers.
*/
for (seq = 0; seq < max_file; seq++)
remove_silent(seq);
return (0);
}