1 /*
2 * Benchmark creates & deletes.
3 */
4
5 char *id = "$Id$\n";
6
7 #include "bench.h"
8
9
10 struct _state {
11 char *tmpdir;
12 long max;
13 long n;
14 char** names;
15 long ndirs;
16 char** dirs;
17 size_t size;
18 };
19 void measure(size_t size,
20 int parallel, int warmup, int repetitions, void* cookie);
21 void mkfile(char* s, size_t size);
22 void setup_names(iter_t iterations, void* cookie);
23 void cleanup_names(iter_t iterations, void* cookie);
24 void setup_rm(iter_t iterations, void* cookie);
25 void cleanup_mk(iter_t iterations, void* cookie);
26 void benchmark_mk(iter_t iterations, void* cookie);
27 void benchmark_rm(iter_t iterations, void* cookie);
28
29 int
main(int ac,char ** av)30 main(int ac, char **av)
31 {
32 int i;
33 int parallel = 1;
34 int warmup = 0;
35 int repetitions = -1;
36 static int sizes[] = { 0, 1024, 4096, 10*1024 };
37 struct _state state;
38 int c;
39 char* usage = "[-s <file size>] [-n <max files per dir>] [-P <parallelism>] [-W <warmup>] [-N <repetitions>] [<dir>]\n";
40
41 state.size = 0;
42 state.max = 100;
43 state.tmpdir = NULL;
44
45 while (( c = getopt(ac, av, "s:n:P:W:N:")) != EOF) {
46 switch(c) {
47 case 's':
48 state.size = bytes(optarg);
49 break;
50 case 'n':
51 state.max = bytes(optarg);
52 break;
53 case 'P':
54 parallel = atoi(optarg);
55 if (parallel <= 0) lmbench_usage(ac, av, usage);
56 break;
57 case 'W':
58 warmup = atoi(optarg);
59 break;
60 case 'N':
61 repetitions = atoi(optarg);
62 break;
63 default:
64 lmbench_usage(ac, av, usage);
65 break;
66 }
67 }
68 if (optind < ac - 1) {
69 lmbench_usage(ac, av, usage);
70 }
71 if (optind == ac - 1) {
72 state.tmpdir = av[1];
73 }
74
75 if (state.size) {
76 measure(state.size, parallel, warmup, repetitions, &state);
77 } else {
78 for (i = 0; i < sizeof(sizes)/sizeof(int); ++i) {
79 state.size = sizes[i];
80 measure(state.size,
81 parallel, warmup, repetitions, &state);
82 }
83 }
84 return(0);
85 }
86
87 void
measure(size_t size,int parallel,int warmup,int repetitions,void * cookie)88 measure(size_t size, int parallel, int warmup, int repetitions, void* cookie)
89 {
90 fprintf(stderr, "%luk", size>>10);
91 benchmp(setup_names, benchmark_mk, cleanup_mk, 0, parallel,
92 warmup, repetitions, cookie);
93 if (gettime()) {
94 fprintf(stderr, "\t%lu\t%.0f", (unsigned long)get_n(),
95 (double)(1000000. * get_n() / (double)gettime()));
96 } else {
97 fprintf(stderr, "\t-1\t-1");
98 }
99
100 benchmp(setup_rm, benchmark_rm, cleanup_names, 0, parallel,
101 warmup, repetitions, cookie);
102 if (gettime()) {
103 fprintf(stderr, "\t%.0f",
104 (double)(1000000. * get_n() / (double)gettime()));
105 } else {
106 fprintf(stderr, "\t-1");
107 }
108 fprintf(stderr, "\n");
109 }
110
111 void
mkfile(char * name,size_t size)112 mkfile(char *name, size_t size)
113 {
114 size_t chunk;
115 int fd = creat(name, 0666);
116 char buf[128*1024]; /* XXX - track sizes */
117
118 while (size > 0) {
119 chunk = ((size > (128*1024)) ? (128*1024) : size);
120 write(fd, buf, chunk);
121 size -= chunk;
122 }
123 close(fd);
124 }
125
126 void
setup_names_recurse(iter_t * foff,iter_t * doff,int depth,struct _state * state)127 setup_names_recurse(iter_t* foff, iter_t* doff, int depth, struct _state* state)
128 {
129 long i, ndirs, count;
130 char* basename = state->dirs[*doff];
131 char name[L_tmpnam + 8192];
132
133 if (depth > 0) {
134 for (count = state->max, i = 1; i < depth; ++i) {
135 count *= state->max;
136 }
137 ndirs = (state->n - *foff) / count + 1;
138 for (i = 0; i < state->max && i < ndirs && *foff < state->n; ++i) {
139 sprintf(name, "%s/%ld", basename, i);
140 state->dirs[++(*doff)] = strdup(name);
141 mkdir(name, 0777);
142 setup_names_recurse(foff, doff, depth-1, state);
143 }
144 } else {
145 for (i = 0; i < state->max && *foff < state->n; ++i) {
146 sprintf(name, "%s/%ld", basename, i);
147 state->names[(*foff)++] = strdup(name);
148 }
149 }
150 }
151
152 void
setup_names(iter_t iterations,void * cookie)153 setup_names(iter_t iterations, void* cookie)
154 {
155 long i, ndirs, depth;
156 iter_t foff;
157 iter_t doff;
158 char dirname_tmpl[L_tmpnam + 256];
159 char* dirname;
160 struct _state* state = (struct _state*)cookie;
161
162 if (!iterations) return;
163
164 depth = 0;
165 state->n = iterations;
166 state->ndirs = iterations / state->max;
167 if (iterations % state->max) state->ndirs++;
168 for (ndirs = state->ndirs; ndirs > 1; ) {
169 ndirs = ndirs / state->max + ((ndirs % state->max) ? 1 : 0);
170 state->ndirs += ndirs;
171 depth++;
172 }
173
174 state->names = (char**)malloc(iterations * sizeof(char*));
175 state->dirs = (char**)malloc(state->ndirs * sizeof(char*));
176 if (iterations && !state->names || state->ndirs && !state->dirs) {
177 perror("malloc");
178 exit(1);
179 }
180 for (i = 0; i < iterations; ++i) {
181 state->names[i] = NULL;
182 }
183
184 for (i = 0; i < state->ndirs; ++i) {
185 state->dirs[i] = NULL;
186 }
187
188 sprintf(dirname_tmpl, "lat_fs_%d_XXXXXX", getpid());
189 dirname = tempnam(state->tmpdir, dirname_tmpl);
190 if (!dirname) {
191 perror("tempnam failed");
192 exit(1);
193 }
194 if (mkdir(dirname, S_IRUSR|S_IWUSR|S_IXUSR)) {
195 perror("mkdir failed");
196 exit(1);
197 }
198 state->dirs[0] = dirname;
199 foff = 0;
200 doff = 0;
201 setup_names_recurse(&foff, &doff, depth, state);
202 if (foff != iterations || doff != state->ndirs - 1) {
203 fprintf(stderr, "setup_names: ERROR: foff=%lu, iterations=%lu, doff=%lu, ndirs=%lu, depth=%ld\n", (unsigned long)foff, (unsigned long)iterations, (unsigned long)doff, (unsigned long)state->ndirs, depth);
204 }
205 }
206
207 void
cleanup_names(iter_t iterations,void * cookie)208 cleanup_names(iter_t iterations, void* cookie)
209 {
210 long i;
211 struct _state* state = (struct _state*)cookie;
212
213 if (!iterations) return;
214
215 for (i = 0; i < state->n; ++i) {
216 if (state->names[i]) free(state->names[i]);
217 }
218 free(state->names);
219 state->n = 0;
220
221 for (i = state->ndirs - 1; i >= 0; --i) {
222 if (state->dirs[i]) {
223 rmdir(state->dirs[i]);
224 free(state->dirs[i]);
225 }
226 }
227 free(state->dirs);
228 state->ndirs = 0;
229 }
230
231 void
setup_rm(iter_t iterations,void * cookie)232 setup_rm(iter_t iterations, void* cookie)
233 {
234 if (!iterations) return;
235
236 setup_names(iterations, cookie);
237 benchmark_mk(iterations, cookie);
238 }
239
240 void
cleanup_mk(iter_t iterations,void * cookie)241 cleanup_mk(iter_t iterations, void* cookie)
242 {
243 if (!iterations) return;
244
245 benchmark_rm(iterations, cookie);
246 cleanup_names(iterations, cookie);
247 }
248
249 void
benchmark_mk(iter_t iterations,void * cookie)250 benchmark_mk(iter_t iterations, void* cookie)
251 {
252 struct _state* state = (struct _state*)cookie;
253
254 while (iterations-- > 0) {
255 if (!state->names[iterations]) {
256 fprintf(stderr, "benchmark_mk: null filename at %lu of %lu\n", iterations, state->n);
257 continue;
258 }
259 mkfile(state->names[iterations], state->size);
260 }
261 }
262
263 void
benchmark_rm(iter_t iterations,void * cookie)264 benchmark_rm(iter_t iterations, void* cookie)
265 {
266 struct _state* state = (struct _state*)cookie;
267
268 while (iterations-- > 0) {
269 if (!state->names[iterations]) {
270 fprintf(stderr, "benchmark_rm: null filename at %lu of %lu\n", iterations, state->n);
271 continue;
272 }
273 unlink(state->names[iterations]);
274 }
275 }
276
277