log-writes: Add support to output human readable flags
[xfstests-dev.git] / src / metaperf.c
1 /*
2  * Copyright (c) 2000-2003 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include <sys/param.h>
20 #include <sys/stat.h>
21 #include <sys/time.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <dirent.h>
28 #include <linux/param.h>
29
30 typedef void    *(*fpi_t)(void);
31 typedef void    (*fpt_t)(int, void *);
32 typedef void    (*fpd_t)(void *);
33 typedef struct  tdesc
34 {
35         char    *name;
36         fpi_t   init;
37         fpt_t   test;
38         fpd_t   done;
39 } tdesc_t;
40
41 static void     d_readdir(void *);
42 static void     *i_readdir(void);
43 static void     t_readdir(int, void *);
44 static void     crfiles(char **, int, char *);
45 static void     d_chown(void *);
46 static void     d_create(void *);
47 static void     d_linkun(void *);
48 static void     d_open(void *);
49 static void     d_rename(void *);
50 static void     d_stat(void *);
51 static void     delflist(char **);
52 static void     dotest(tdesc_t *);
53 static void     *i_chown(void);
54 static void     *i_create(void);
55 static void     *i_linkun(void);
56 static void     *i_open(void);
57 static void     *i_rename(void);
58 static void     *i_stat(void);
59 static char     **mkflist(int, int, char);
60 static double   now(void);
61 static void     prtime(char *, int, double);
62 static void     rmfiles(char **);
63 static void     t_chown(int, void *);
64 static void     t_create(int, void *);
65 static void     t_crunlink(int, void *);
66 static void     t_linkun(int, void *);
67 static void     t_open(int, void *);
68 static void     t_rename(int, void *);
69 static void     t_stat(int, void *);
70 static void     usage(void);
71
72 tdesc_t tests[] = {
73         { "chown",      i_chown, t_chown, d_chown },
74         { "create",     i_create, t_create, d_create },
75         { "crunlink",   (fpi_t)0, t_crunlink, (fpd_t)0 },
76         { "readdir",    i_readdir, t_readdir, d_readdir },
77         { "linkun",     i_linkun, t_linkun, d_linkun },
78         { "open",       i_open, t_open, d_open },
79         { "rename",     i_rename, t_rename, d_rename },
80         { "stat",       i_stat, t_stat, d_stat },
81         { NULL }
82 };
83
84 char            *buffer;
85 int             compact = 0;
86 int             files_bg = 0;
87 int             files_op = 1;
88 char            **flist_bg;
89 char            **flist_op;
90 int             fnlen_bg = 5;
91 int             fnlen_op = 5;
92 int             fsize = 0;
93 int             iters = 0;
94 double          time_end;
95 double          time_start;
96 int             totsec = 0;
97 int             verbose = 0;
98
99 int
100 main(int argc, char **argv)
101 {
102         int             c;
103         char            *testdir;
104         tdesc_t         *tp;
105
106         testdir = getenv("TMPDIR");
107         if (testdir == NULL)
108                 testdir = ".";
109         while ((c = getopt(argc, argv, "cd:i:l:L:n:N:s:t:v")) != -1) {
110                 switch (c) {
111                 case 'c':
112                         compact = 1;
113                         break;
114                 case 'd':
115                         testdir = optarg;
116                         break;
117                 case 'i':
118                         iters = atoi(optarg);   
119                         break;
120                 case 'l':
121                         fnlen_op = atoi(optarg);
122                         break;
123                 case 'L':
124                         fnlen_bg = atoi(optarg);
125                         break;
126                 case 'n':
127                         files_op = atoi(optarg);
128                         break;
129                 case 'N':
130                         files_bg = atoi(optarg);
131                         break;
132                 case 's':
133                         fsize = atoi(optarg);
134                         break;
135                 case 't':
136                         totsec = atoi(optarg);
137                         break;
138                 case 'v':
139                         verbose = 1;
140                         break;
141                 case '?':
142                         fprintf(stderr, "bad option\n");
143                         usage();
144                 }
145         }
146         if (!iters && !totsec)
147                 iters = 1;
148         if (chdir(testdir) < 0) {
149                 perror(testdir);
150                 return 1;
151         }
152         if (mkdir("metaperf", 0777) < 0 || chdir("metaperf") < 0) {
153                 perror("metaperf");
154                 return 1;
155         }
156         for (; optind < argc; optind++) {
157                 for (tp = tests; tp->name; tp++) {
158                         if (strcmp(argv[optind], tp->name) == 0) {
159                                 dotest(tp);
160                                 break;
161                         }
162                 }
163         }
164         chdir("..");
165         rmdir("metaperf");
166         return 0;
167 }
168
169 static void
170 crfiles(char **flist, int fsize, char *buf)
171 {
172         int     fd;
173         char    **fnp;
174
175         for (fnp = flist; *fnp; fnp++) {
176                 fd = creat(*fnp, 0666);
177                 if (fsize)
178                         write(fd, buf, fsize);
179                 close(fd);
180         }
181 }
182
183 /* ARGSUSED */
184 static void
185 d_chown(void *v)
186 {
187         rmfiles(flist_op);
188 }
189
190 /* ARGSUSED */
191 static void
192 d_create(void *v)
193 {
194         rmfiles(flist_op);
195 }
196
197 static void
198 d_readdir(void *v)
199 {
200         rmfiles(flist_op);
201         closedir((DIR *)v);
202 }
203
204 /* ARGSUSED */
205 static void
206 d_linkun(void *v)
207 {
208         unlink("a");
209 }
210
211 /* ARGSUSED */
212 static void
213 d_open(void *v)
214 {
215         rmfiles(flist_op);
216 }
217
218 static void
219 d_rename(void *v)
220 {
221         rmfiles(flist_op);
222         rmfiles((char **)v);
223         delflist((char **)v);
224 }
225
226 /* ARGSUSED */
227 static void
228 d_stat(void *v)
229 {
230         rmfiles(flist_op);
231 }
232
233 static void
234 delflist(char **flist)
235 {
236         char    **fnp;
237
238         for (fnp = flist; *fnp; fnp++)
239                 free(*fnp);
240         free(flist);
241 }
242
243 static void
244 dotest(tdesc_t *tp)
245 {
246         double  dn;
247         double  gotsec;
248         int     n;
249         void    *v;
250
251         flist_bg = mkflist(files_bg, fnlen_bg, 'b');
252         flist_op = mkflist(files_op, fnlen_op, 'o');
253         if (fsize)
254                 buffer = calloc(fsize, 1);
255         else
256                 buffer = NULL;
257         crfiles(flist_bg, 0, (char *)0);
258         n = iters ? iters : 1;
259         v = (void *)0;
260         for (;;) {
261                 if (tp->init)
262                         v = (tp->init)();
263                 sync();
264                 sleep(1);
265                 time_start = now();
266                 (tp->test)(n, v);
267                 time_end = now();
268                 if (tp->done)
269                         (tp->done)(v);
270                 gotsec = time_end - time_start;
271                 if (!totsec || gotsec >= 0.9 * totsec)
272                         break;
273                 if (verbose)
274                         prtime(tp->name, n, gotsec);
275                 if (!gotsec)
276                         gotsec = 1.0 / (2 * HZ);
277                 if (gotsec < 0.001 * totsec)
278                         dn = n * (0.01 * totsec / gotsec);
279                 else if (gotsec < 0.01 * totsec)
280                         dn = n * (0.1 * totsec / gotsec);
281                 else
282                         dn = n * (totsec / gotsec);
283                 if ((int)dn <= n)
284                         n++;
285                 else
286                         n = (int)dn;
287         }
288         prtime(tp->name, n, gotsec);
289         rmfiles(flist_bg);
290         delflist(flist_bg);
291         delflist(flist_op);
292         if (fsize)
293                 free(buffer);
294 }
295
296 static void *
297 i_chown(void)
298 {
299         char    **fnp;
300
301         crfiles(flist_op, 0, (char *)0);
302         for (fnp = flist_op; *fnp; fnp++)
303                 chown(*fnp, 1, -1);
304         return (void *)0;
305 }
306
307 static void *
308 i_create(void)
309 {
310         crfiles(flist_op, fsize, buffer);
311         return (void *)0;
312 }
313
314 static void *
315 i_readdir(void)
316 {
317         crfiles(flist_op, 0, (char *)0);
318         return opendir(".");
319 }
320
321 static void *
322 i_linkun(void)
323 {
324         close(creat("a", 0666));
325         return (void *)0;
326 }
327
328 static void *
329 i_open(void)
330 {
331         crfiles(flist_op, 0, (char *)0);
332         return (void *)0;
333 }
334
335 static void *
336 i_rename(void)
337 {
338         crfiles(flist_op, 0, (char *)0);
339         return (void *)mkflist(files_op, fnlen_op, 'r');
340 }
341
342 static void *
343 i_stat(void)
344 {
345         crfiles(flist_op, 0, (char *)0);
346         return (void *)0;
347 }
348
349 static char **
350 mkflist(int files, int fnlen, char start)
351 {
352         int     i;
353         char    **rval;
354
355         rval = calloc(files + 1, sizeof(char *));
356         for (i = 0; i < files; i++) {
357                 rval[i] = malloc(fnlen + 1);
358                 sprintf(rval[i], "%0*d%c", fnlen - 1, i, start);
359         }
360         return rval;
361 }
362
363 static double
364 now(void)
365 {
366         struct timeval  t;
367
368         gettimeofday(&t, (void *)0);
369         return (double)t.tv_sec + 1.0e-6 * (double)t.tv_usec;
370 }
371
372 static void
373 prtime(char *name, int n, double t)
374 {
375         double  ops_per_sec;
376         double  usec_per_op;
377
378         ops_per_sec = (double)n * (double)files_op / t;
379         usec_per_op = t * 1.0e6 / ((double)n * (double)files_op);
380         if (compact)
381                 printf("%s %d %d %d %d %d %d %f %f %f\n",
382                         name, n, files_op, fnlen_op, fsize, files_bg, fnlen_bg,
383                         t, ops_per_sec, usec_per_op);
384         else {
385                 printf("%s: %d times, %d file(s) namelen %d",
386                         name, n, files_op, fnlen_op);
387                 if (fsize)
388                         printf(" size %d", fsize);
389                 if (files_bg)
390                         printf(", bg %d file(s) namelen %d",
391                                 files_bg, fnlen_bg);
392                 printf(", time = %f sec, ops/sec=%f, usec/op = %f\n",
393                         t, ops_per_sec, usec_per_op);
394         }
395 }
396
397 static void
398 rmfiles(char **flist)
399 {
400         char    **fnp;
401
402         for (fnp = flist; *fnp; fnp++)
403                 unlink(*fnp);
404 }
405
406 /* ARGSUSED */
407 static void
408 t_chown(int n, void *v)
409 {
410         char    **fnp;
411         int     i;
412
413         for (i = 0; i < n; i++) {
414                 for (fnp = flist_op; *fnp; fnp++) {
415                         if ((i & 1) == 0)
416                                 chown(*fnp, 2, -1);
417                         else
418                                 chown(*fnp, 1, -1);
419                 }
420         }
421 }
422
423 /* ARGSUSED */
424 static void
425 t_create(int n, void *v)
426 {
427         int     i;
428
429         for (i = 0; i < n; i++)
430                 crfiles(flist_op, fsize, buffer);
431 }
432
433 /* ARGSUSED */
434 static void
435 t_crunlink(int n, void *v)
436 {
437         int     i;
438
439         for (i = 0; i < n; i++) {
440                 crfiles(flist_op, fsize, buffer);
441                 rmfiles(flist_op);
442         }
443 }
444
445 static void
446 t_readdir(int n, void *v)
447 {
448         DIR     *dir;
449         int     i;
450
451         for (dir = (DIR *)v, i = 0; i < n; i++) {
452                 rewinddir(dir);
453                 while ((readdir(dir)) != NULL);
454         }
455 }
456
457 /* ARGSUSED */
458 static void
459 t_linkun(int n, void *v)
460 {
461         char    **fnp;
462         int     i;
463
464         for (i = 0; i < n; i++) {
465                 for (fnp = flist_op; *fnp; fnp++)
466                         link("a", *fnp);
467                 rmfiles(flist_op);
468         }
469 }
470
471 /* ARGSUSED */
472 static void
473 t_open(int n, void *v)
474 {
475         char            **fnp;
476         int             i;
477
478         for (i = 0; i < n; i++) {
479                 for (fnp = flist_op; *fnp; fnp++)
480                         close(open(*fnp, O_RDWR));
481         }
482 }
483
484 static void
485 t_rename(int n, void *v)
486 {
487         char    **fnp;
488         int     i;
489         char    **rflist;
490         char    **rfp;
491
492         for (rflist = (char **)v, i = 0; i < n; i++) {
493                 for (fnp = flist_op, rfp = rflist; *fnp; fnp++, rfp++) {
494                         if ((i & 1) == 0)
495                                 rename(*fnp, *rfp);
496                         else
497                                 rename(*rfp, *fnp);
498                 }
499         }
500 }
501
502 /* ARGSUSED */
503 static void
504 t_stat(int n, void *v)
505 {
506         char            **fnp;
507         int             i;
508         struct stat     stb;
509
510         for (i = 0; i < n; i++) {
511                 for (fnp = flist_op; *fnp; fnp++)
512                         stat(*fnp, &stb);
513         }
514 }
515
516 static void
517 usage(void)
518 {
519         fprintf(stderr,
520                 "Usage: metaperf [-d dname] [-i iters|-t seconds] [-s fsize]\n"
521                 "\t[-l opfnamelen] [-L bgfnamelen]\n"
522                 "\t[-n opfcount] [-N bgfcount] test...\n");
523         fprintf(stderr,
524                 "Tests: chown create crunlink linkun open rename stat readdir\n");
525         exit(1);
526 }