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