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