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