1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2000-2004 Silicon Graphics, Inc.
19 typedef unsigned int uint_t;
22 * Loop over directory sizes:
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)
34 static uint_t dirchars;
35 static char *directory;
36 static uint_t firstsize;
37 static uint_t lastsize;
38 static uint_t minchars;
42 static uint_t pfxchars;
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);
52 * Maximum size allowed, this is pretty nuts.
53 * The largest one we've ever built has been about 2 million.
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
62 main(int argc, char **argv)
69 char name[NAME_MAX + 1];
73 while ((c = getopt(argc, argv, "a:c:d:f:l:m:n:s:")) != -1) {
76 addval = (uint_t)atoi(optarg);
79 nchars = (uint_t)atoi(optarg);
85 firstsize = (uint_t)atoi(optarg);
88 lastsize = (uint_t)atoi(optarg);
91 mulval = atof(optarg);
94 ndirs = (uint_t)atoi(optarg);
97 stats = (uint_t)atoi(optarg);
105 if (!addval && !mulval)
107 else if ((addval && mulval) || mulval < 0.0) {
116 if (mkdir(directory, 0777) < 0 && errno != EEXIST) {
120 if (chdir(directory) < 0) {
126 firstsize = DFL_FIRST_SIZE;
127 else if (firstsize > MAX_DIR_SIZE)
128 firstsize = MAX_DIR_SIZE;
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)
138 else if (nchars >= NAME_MAX + 1)
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;
147 memset(&name[dirchars + 1], 'a', pfxchars);
148 for (j = 0; j < ndirs; j++) {
149 filename(0, j, name);
150 name[dirchars] = '\0';
153 for (cursize = firstsize;
155 cursize = nextsize(cursize)) {
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));
163 for (i = 0; i < cursize * stats; i++) {
164 for (j = 0; j < ndirs; j++) {
165 filename((i + j) % cursize, j, name);
169 for (j = 0; j < ndirs; j++) {
170 filename(0, j, name);
171 name[dirchars] = '\0';
172 dirp = opendir(name);
173 while (readdir(dirp))
177 for (i = 0; i < cursize; i++) {
178 for (j = 0; j < ndirs; j++) {
179 filename((i + j) % cursize, j, name);
183 printf("%d %.3f\n", cursize,
184 (now() - stime) * 1.0e3 / (cursize * ndirs));
186 for (j = 0; j < ndirs; j++) {
187 filename(0, j, name);
188 name[dirchars] = '\0';
195 filename(int idx, int dir, char *name)
197 static char hexc[16] = "0123456789abcdef";
200 for (i = dirchars - 1; i >= 0; i--)
201 *name++ = hexc[(dir >> (4 * i)) & 0xf];
203 name += pfxchars; /* skip pfx a's */
204 for (i = minchars - 1; i >= 0; i--)
205 *name++ = hexc[(idx >> (4 * i)) & 0xf];
210 hexchars(uint_t maxval)
214 if (maxval < 16 * 16)
216 if (maxval < 16 * 16 * 16)
218 if (maxval < 16 * 16 * 16 * 16)
220 if (maxval < 16 * 16 * 16 * 16 * 16)
222 if (maxval < 16 * 16 * 16 * 16 * 16 * 16)
224 if (maxval < 16 * 16 * 16 * 16 * 16 * 16 * 16)
230 nextsize(uint_t cursize)
239 if (n > (double)lastsize + 0.5)
240 return lastsize + 1; /* i.e. out of bounds */
241 else if ((uint_t)n == cursize)
252 gettimeofday(&tv, NULL);
253 return (double)tv.tv_sec + 1.0e-6 * (double)tv.tv_usec;
260 "usage: dirperf [-d dir] [-a addstep | -m mulstep] [-f first] "
261 "[-l last] [-c nchars] [-n ndirs] [-s nstats]\n");