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