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