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