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