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