1 /* $NetBSD: fsstone.c,v 1.1.1.1 2009/06/23 10:08:44 tron Exp $ */ 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 67 static 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 80 static 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 108 static 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 135 static 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 146 static 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 156 static void usage(char *myname) 157 { 158 msg_fatal("usage: %s [-cr] [-s size] messages directory_entries", myname); 159 } 160 161 MAIL_VERSION_STAMP_DECLARE; 162 163 int 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