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