fstests: add missing remove of the $seqres.full file for some tests
[xfstests-dev.git] / src / dirperf.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2000-2004 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 <dirent.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <math.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18
19 typedef unsigned int uint_t;
20
21 /*
22  * Loop over directory sizes:
23  *      make m directories
24  *      touch n files in each directory
25  *      stat the files round-robin
26  *      readdir/unlink the files 
27  * Change directory sizes by multiplication or addition.
28  * Allow control of starting & stopping sizes, name length, target directory.
29  * Print size and wallclock time (ms per file).
30  * Output can be used to make graphs (gnuplot)
31  */
32
33 static uint_t   addval;
34 static uint_t   dirchars;
35 static char     *directory;
36 static uint_t   firstsize;
37 static uint_t   lastsize;
38 static uint_t   minchars;
39 static double   mulval;
40 static uint_t   nchars;
41 static uint_t   ndirs;
42 static uint_t   pfxchars;
43 static uint_t   stats;
44
45 static void     filename(int, int, char *);
46 static int      hexchars(uint_t);
47 static uint_t   nextsize(uint_t);
48 static double   now(void);
49 static void     usage(void);
50
51 /*
52  * Maximum size allowed, this is pretty nuts.
53  * The largest one we've ever built has been about 2 million.
54  */
55 #define MAX_DIR_SIZE    (16 * 1024 * 1024)
56 #define DFL_FIRST_SIZE  1
57 #define DFL_LAST_SIZE   (1024 * 1024)
58 #define MAX_DIR_COUNT   1024
59 #define MIN_DIR_COUNT   1
60
61 int
62 main(int argc, char **argv)
63 {
64         int             c;
65         uint_t          cursize;
66         DIR             *dirp;
67         int             i;
68         int             j;
69         char            name[NAME_MAX + 1];
70         struct stat     stb;
71         double          stime;
72
73         while ((c = getopt(argc, argv, "a:c:d:f:l:m:n:s:")) != -1) {
74                 switch (c) {
75                 case 'a':
76                         addval = (uint_t)atoi(optarg);
77                         break;
78                 case 'c':
79                         nchars = (uint_t)atoi(optarg);
80                         break;
81                 case 'd':
82                         directory = optarg;
83                         break;
84                 case 'f':
85                         firstsize = (uint_t)atoi(optarg);
86                         break;
87                 case 'l':
88                         lastsize = (uint_t)atoi(optarg);
89                         break;
90                 case 'm':
91                         mulval = atof(optarg);
92                         break;
93                 case 'n':
94                         ndirs = (uint_t)atoi(optarg);
95                         break;
96                 case 's':
97                         stats = (uint_t)atoi(optarg);
98                         break;
99                 case '?':
100                 default:
101                         usage();
102                         exit(1);
103                 }
104         }
105         if (!addval && !mulval)
106                 mulval = 2.0;
107         else if ((addval && mulval) || mulval < 0.0) {
108                 usage();
109                 exit(1);
110         }
111         if (stats == 0)
112                 stats = 1;
113         if (!directory)
114                 directory = ".";
115         else {
116                 if (mkdir(directory, 0777) < 0 && errno != EEXIST) {
117                         perror(directory);
118                         exit(1);
119                 }
120                 if (chdir(directory) < 0) {
121                         perror(directory);
122                         exit(1);
123                 }
124         }
125         if (firstsize == 0)
126                 firstsize = DFL_FIRST_SIZE;
127         else if (firstsize > MAX_DIR_SIZE)
128                 firstsize = MAX_DIR_SIZE;
129         if (lastsize == 0)
130                 lastsize = DFL_LAST_SIZE;
131         else if (lastsize > MAX_DIR_SIZE)
132                 lastsize = MAX_DIR_SIZE;
133         if (lastsize < firstsize)
134                 lastsize = firstsize;
135         minchars = hexchars(lastsize - 1);
136         if (nchars < minchars)
137                 nchars = minchars;
138         else if (nchars >= NAME_MAX + 1)
139                 nchars = NAME_MAX;
140         if (ndirs > MAX_DIR_COUNT)
141                 ndirs = MAX_DIR_COUNT;
142         if (ndirs < MIN_DIR_COUNT)
143                 ndirs = MIN_DIR_COUNT;
144         dirchars = hexchars(ndirs);
145         pfxchars = nchars - minchars;
146         if (pfxchars)
147                 memset(&name[dirchars + 1], 'a', pfxchars);
148         for (j = 0; j < ndirs; j++) {
149                 filename(0, j, name);
150                 name[dirchars] = '\0';
151                 mkdir(name, 0777);
152         }
153         for (cursize = firstsize;
154              cursize <= lastsize;
155              cursize = nextsize(cursize)) {
156                 stime = now();
157                 for (i = 0; i < cursize; i++) {
158                         for (j = 0; j < ndirs; j++) {
159                                 filename((i + j) % cursize, j, name);
160                                 close(creat(name, 0666));
161                         }
162                 }
163                 for (i = 0; i < cursize * stats; i++) {
164                         for (j = 0; j < ndirs; j++) {
165                                 filename((i + j) % cursize, j, name);
166                                 stat(name, &stb);
167                         }
168                 }
169                 for (j = 0; j < ndirs; j++) {
170                         filename(0, j, name);
171                         name[dirchars] = '\0';
172                         dirp = opendir(name);
173                         while (readdir(dirp))
174                                 continue;
175                         closedir(dirp);
176                 }
177                 for (i = 0; i < cursize; i++) {
178                         for (j = 0; j < ndirs; j++) {
179                                 filename((i + j) % cursize, j, name);
180                                 unlink(name);
181                         }
182                 }
183                 printf("%d %.3f\n", cursize,
184                         (now() - stime) * 1.0e3 / (cursize * ndirs));
185         }
186         for (j = 0; j < ndirs; j++) {
187                 filename(0, j, name);
188                 name[dirchars] = '\0';
189                 rmdir(name);
190         }
191         return 0;
192 }
193
194 static void
195 filename(int idx, int dir, char *name)
196 {
197         static char     hexc[16] = "0123456789abcdef";
198         int             i;
199
200         for (i = dirchars - 1; i >= 0; i--)
201                 *name++ = hexc[(dir >> (4 * i)) & 0xf];
202         *name++ = '/';
203         name += pfxchars;               /* skip pfx a's */
204         for (i = minchars - 1; i >= 0; i--)
205                 *name++ = hexc[(idx >> (4 * i)) & 0xf];
206         *name = '\0';
207 }
208
209 static int
210 hexchars(uint_t maxval)
211 {
212         if (maxval < 16)
213                 return 1;
214         if (maxval < 16 * 16)
215                 return 2;
216         if (maxval < 16 * 16 * 16)
217                 return 3;
218         if (maxval < 16 * 16 * 16 * 16)
219                 return 4;
220         if (maxval < 16 * 16 * 16 * 16 * 16)
221                 return 5;
222         if (maxval < 16 * 16 * 16 * 16 * 16 * 16)
223                 return 6;
224         if (maxval < 16 * 16 * 16 * 16 * 16 * 16 * 16)
225                 return 7;
226         return 8;
227 }
228
229 static uint_t
230 nextsize(uint_t cursize)
231 {
232         double  n;
233
234         n = cursize;
235         if (addval)
236                 n += addval;
237         else
238                 n *= mulval;
239         if (n > (double)lastsize + 0.5)
240                 return lastsize + 1;    /* i.e. out of bounds */
241         else if ((uint_t)n == cursize)
242                 return cursize + 1;
243         else
244                 return (uint_t)n;
245 }
246
247 static double
248 now(void)
249 {
250         struct timeval  tv;
251
252         gettimeofday(&tv, NULL);
253         return (double)tv.tv_sec + 1.0e-6 * (double)tv.tv_usec;
254 }
255
256 static void
257 usage(void)
258 {
259         fprintf(stderr,
260                 "usage: dirperf [-d dir] [-a addstep | -m mulstep] [-f first] "
261                 "[-l last] [-c nchars] [-n ndirs] [-s nstats]\n");
262 }