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