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 /* APPLE */ 71 snprintf(new_path, sizeof new_path, "%06d", new); 72 snprintf(old_path, sizeof old_path, "%06d", old); 73 if (rename(old_path, new_path)) 74 msg_fatal("rename %s to %s: %m", old_path, new_path); 75} 76 77/* make_file - create a little file and use it */ 78 79static void make_file(int seqno, int size) 80{ 81 char path[BUFSIZ]; 82 char buf[1024]; 83 FILE *fp; 84 int i; 85 86 /* APPLE */ 87 snprintf(path, sizeof path, "%06d", seqno); 88 if ((fp = fopen(path, "w")) == 0) 89 msg_fatal("open %s: %m", path); 90 memset(buf, 'x', sizeof(buf)); 91 for (i = 0; i < size; i++) 92 if (fwrite(buf, 1, sizeof(buf), fp) != sizeof(buf)) 93 msg_fatal("fwrite: %m"); 94 if (fsync(fileno(fp))) 95 msg_fatal("fsync: %m"); 96 if (fclose(fp)) 97 msg_fatal("fclose: %m"); 98 if ((fp = fopen(path, "r")) == 0) 99 msg_fatal("open %s: %m", path); 100 while (fgets(path, sizeof(path), fp)) 101 /* void */ ; 102 if (fclose(fp)) 103 msg_fatal("fclose: %m"); 104} 105 106/* use_file - use existing file */ 107 108static void use_file(int seqno) 109{ 110 char path[BUFSIZ]; 111 FILE *fp; 112 int i; 113 114 /* APPLE */ 115 snprintf(path, sizeof path, "%06d", seqno); 116 if ((fp = fopen(path, "w")) == 0) 117 msg_fatal("open %s: %m", path); 118 for (i = 0; i < 400; i++) 119 fprintf(fp, "hello"); 120 if (fsync(fileno(fp))) 121 msg_fatal("fsync: %m"); 122 if (fclose(fp)) 123 msg_fatal("fclose: %m"); 124 if ((fp = fopen(path, "r+")) == 0) 125 msg_fatal("open %s: %m", path); 126 while (fgets(path, sizeof(path), fp)) 127 /* void */ ; 128 if (ftruncate(fileno(fp), (off_t) 0)) 129 msg_fatal("ftruncate: %m");; 130 if (fclose(fp)) 131 msg_fatal("fclose: %m"); 132} 133 134/* remove_file - delete specified file */ 135 136static void remove_file(int seq) 137{ 138 char path[BUFSIZ]; 139 140 /* APPLE */ 141 snprintf(path, sizeof path, "%06d", seq); 142 if (remove(path)) 143 msg_fatal("remove %s: %m", path); 144} 145 146/* remove_silent - delete specified file, silently */ 147 148static void remove_silent(int seq) 149{ 150 char path[BUFSIZ]; 151 152 /* APPLE */ 153 snprintf(path, sizeof path, "%06d", seq); 154 (void) remove(path); 155} 156 157/* usage - explain */ 158 159static void usage(char *myname) 160{ 161 msg_fatal("usage: %s [-cr] [-s size] messages directory_entries", myname); 162} 163 164MAIL_VERSION_STAMP_DECLARE; 165 166int main(int argc, char **argv) 167{ 168 int op_count; 169 int max_file; 170 struct timeval start, end; 171 int do_rename = 0; 172 int do_create = 0; 173 int seq; 174 int ch; 175 int size = 2; 176 177 /* 178 * Fingerprint executables and core dumps. 179 */ 180 MAIL_VERSION_STAMP_ALLOCATE; 181 182 msg_vstream_init(argv[0], VSTREAM_ERR); 183 while ((ch = GETOPT(argc, argv, "crs:")) != EOF) { 184 switch (ch) { 185 case 'c': 186 do_create++; 187 break; 188 case 'r': 189 do_rename++; 190 break; 191 case 's': 192 if ((size = atoi(optarg)) <= 0) 193 usage(argv[0]); 194 break; 195 default: 196 usage(argv[0]); 197 } 198 } 199 200 if (argc - optind != 2 || (do_rename && !do_create)) 201 usage(argv[0]); 202 if ((op_count = atoi(argv[optind])) <= 0) 203 usage(argv[0]); 204 if ((max_file = atoi(argv[optind + 1])) <= 0) 205 usage(argv[0]); 206 207 /* 208 * Populate the directory with little files. 209 */ 210 for (seq = 0; seq < max_file; seq++) 211 make_file(seq, size); 212 213 /* 214 * Simulate arrival and delivery of mail messages. 215 */ 216 GETTIMEOFDAY(&start); 217 while (op_count > 0) { 218 seq %= max_file; 219 if (do_create) { 220 remove_file(seq); 221 make_file(seq, size); 222 if (do_rename) { 223 rename_file(seq, seq + max_file); 224 rename_file(seq + max_file, seq); 225 } 226 } else { 227 use_file(seq); 228 } 229 seq++; 230 op_count--; 231 } 232 GETTIMEOFDAY(&end); 233 if (end.tv_usec < start.tv_usec) { 234 end.tv_sec--; 235 end.tv_usec += 1000000; 236 } 237 printf("elapsed time: %ld.%06ld\n", 238 (long) (end.tv_sec - start.tv_sec), 239 (long) (end.tv_usec - start.tv_usec)); 240 241 /* 242 * Clean up directory fillers. 243 */ 244 for (seq = 0; seq < max_file; seq++) 245 remove_silent(seq); 246 return (0); 247} 248