1/*++ 2/* NAME 3/* fsstone 1 4/* SUMMARY 5/* measure directory operation overhead 6/* SYNOPSIS 7/* .fi 8/* \fBfsstone\fR [\fB-cr\fR] [\fB-s \fIsize\fR] 9/* \fImsg_count files_per_dir\fR 10/* DESCRIPTION 11/* The \fBfsstone\fR command measures the cost of creating, renaming 12/* and deleting queue files versus appending messages to existing 13/* files and truncating them after use. 14/* 15/* The program simulates the arrival of \fImsg_count\fR short messages, 16/* and arranges for at most \fIfiles_per_dir\fR simultaneous files 17/* in the same directory. 18/* 19/* Options: 20/* .IP \fB-c\fR 21/* Create and delete files. 22/* .IP \fB-r\fR 23/* Rename files twice (requires \fB-c\fR). 24/* .IP \fB-s \fIsize\fR 25/* Specify the file size in kbytes. 26/* DIAGNOSTICS 27/* Problems are reported to the standard error stream. 28/* BUGS 29/* The \fB-r\fR option renames files within the same directory. 30/* For a more realistic simulation, the program should rename files 31/* <i>between</i> directories, and should also have an option to use 32/* <i>hashed</i> directories as implemented with, for example, the 33/* \fBdir_forest\fR(3) module. 34/* LICENSE 35/* .ad 36/* .fi 37/* The Secure Mailer license must be distributed with this software. 38/* AUTHOR(S) 39/* Wietse Venema 40/* IBM T.J. Watson Research 41/* P.O. Box 704 42/* Yorktown Heights, NY 10598, USA 43/*--*/ 44 45/* System library. */ 46 47#include <sys_defs.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <unistd.h> 51#include <string.h> 52#include <sys/time.h> 53 54/* Utility library. */ 55 56#include <msg.h> 57#include <msg_vstream.h> 58 59/* Global directory. */ 60 61#include <mail_version.h> 62 63/* rename_file - rename a file */ 64 65static void rename_file(int old, int new) 66{ 67 char new_path[BUFSIZ]; 68 char old_path[BUFSIZ]; 69 70 sprintf(new_path, "%06d", new); 71 sprintf(old_path, "%06d", old); 72 if (rename(old_path, new_path)) 73 msg_fatal("rename %s to %s: %m", old_path, new_path); 74} 75 76/* make_file - create a little file and use it */ 77 78static void make_file(int seqno, int size) 79{ 80 char path[BUFSIZ]; 81 char buf[1024]; 82 FILE *fp; 83 int i; 84 85 sprintf(path, "%06d", seqno); 86 if ((fp = fopen(path, "w")) == 0) 87 msg_fatal("open %s: %m", path); 88 memset(buf, 'x', sizeof(buf)); 89 for (i = 0; i < size; i++) 90 if (fwrite(buf, 1, sizeof(buf), fp) != sizeof(buf)) 91 msg_fatal("fwrite: %m"); 92 if (fsync(fileno(fp))) 93 msg_fatal("fsync: %m"); 94 if (fclose(fp)) 95 msg_fatal("fclose: %m"); 96 if ((fp = fopen(path, "r")) == 0) 97 msg_fatal("open %s: %m", path); 98 while (fgets(path, sizeof(path), fp)) 99 /* void */ ; 100 if (fclose(fp)) 101 msg_fatal("fclose: %m"); 102} 103 104/* use_file - use existing file */ 105 106static void use_file(int seqno) 107{ 108 char path[BUFSIZ]; 109 FILE *fp; 110 int i; 111 112 sprintf(path, "%06d", seqno); 113 if ((fp = fopen(path, "w")) == 0) 114 msg_fatal("open %s: %m", path); 115 for (i = 0; i < 400; i++) 116 fprintf(fp, "hello"); 117 if (fsync(fileno(fp))) 118 msg_fatal("fsync: %m"); 119 if (fclose(fp)) 120 msg_fatal("fclose: %m"); 121 if ((fp = fopen(path, "r+")) == 0) 122 msg_fatal("open %s: %m", path); 123 while (fgets(path, sizeof(path), fp)) 124 /* void */ ; 125 if (ftruncate(fileno(fp), (off_t) 0)) 126 msg_fatal("ftruncate: %m");; 127 if (fclose(fp)) 128 msg_fatal("fclose: %m"); 129} 130 131/* remove_file - delete specified file */ 132 133static void remove_file(int seq) 134{ 135 char path[BUFSIZ]; 136 137 sprintf(path, "%06d", seq); 138 if (remove(path)) 139 msg_fatal("remove %s: %m", path); 140} 141 142/* remove_silent - delete specified file, silently */ 143 144static void remove_silent(int seq) 145{ 146 char path[BUFSIZ]; 147 148 sprintf(path, "%06d", seq); 149 (void) remove(path); 150} 151 152/* usage - explain */ 153 154static void usage(char *myname) 155{ 156 msg_fatal("usage: %s [-cr] [-s size] messages directory_entries", myname); 157} 158 159MAIL_VERSION_STAMP_DECLARE; 160 161int main(int argc, char **argv) 162{ 163 int op_count; 164 int max_file; 165 struct timeval start, end; 166 int do_rename = 0; 167 int do_create = 0; 168 int seq; 169 int ch; 170 int size = 2; 171 172 /* 173 * Fingerprint executables and core dumps. 174 */ 175 MAIL_VERSION_STAMP_ALLOCATE; 176 177 msg_vstream_init(argv[0], VSTREAM_ERR); 178 while ((ch = GETOPT(argc, argv, "crs:")) != EOF) { 179 switch (ch) { 180 case 'c': 181 do_create++; 182 break; 183 case 'r': 184 do_rename++; 185 break; 186 case 's': 187 if ((size = atoi(optarg)) <= 0) 188 usage(argv[0]); 189 break; 190 default: 191 usage(argv[0]); 192 } 193 } 194 195 if (argc - optind != 2 || (do_rename && !do_create)) 196 usage(argv[0]); 197 if ((op_count = atoi(argv[optind])) <= 0) 198 usage(argv[0]); 199 if ((max_file = atoi(argv[optind + 1])) <= 0) 200 usage(argv[0]); 201 202 /* 203 * Populate the directory with little files. 204 */ 205 for (seq = 0; seq < max_file; seq++) 206 make_file(seq, size); 207 208 /* 209 * Simulate arrival and delivery of mail messages. 210 */ 211 GETTIMEOFDAY(&start); 212 while (op_count > 0) { 213 seq %= max_file; 214 if (do_create) { 215 remove_file(seq); 216 make_file(seq, size); 217 if (do_rename) { 218 rename_file(seq, seq + max_file); 219 rename_file(seq + max_file, seq); 220 } 221 } else { 222 use_file(seq); 223 } 224 seq++; 225 op_count--; 226 } 227 GETTIMEOFDAY(&end); 228 if (end.tv_usec < start.tv_usec) { 229 end.tv_sec--; 230 end.tv_usec += 1000000; 231 } 232 printf("elapsed time: %ld.%06ld\n", 233 (long) (end.tv_sec - start.tv_sec), 234 (long) (end.tv_usec - start.tv_usec)); 235 236 /* 237 * Clean up directory fillers. 238 */ 239 for (seq = 0; seq < max_file; seq++) 240 remove_silent(seq); 241 return (0); 242} 243