1 /*
2 * Copyright (c) International Business Machines Corp., 2001-2004
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
12 * the 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 to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 #include <string.h>
19 #include <stdio.h>
20 #include <assert.h>
21 #include <pthread.h>
22
23 #include "ffsb_tg.h"
24 #include "util.h"
25
init_ffsb_tg(ffsb_tg_t * tg,unsigned num_threads,unsigned tg_num)26 void init_ffsb_tg(ffsb_tg_t * tg, unsigned num_threads, unsigned tg_num)
27 {
28 int i;
29 memset(tg, 0, sizeof(ffsb_tg_t));
30
31 tg->threads = ffsb_malloc(sizeof(ffsb_thread_t) * num_threads);
32 tg->tg_num = tg_num;
33 tg->num_threads = num_threads;
34
35 tg->bindfs = -1; /* default is not bound */
36
37 tg->thread_bufsize = 0;
38 for (i = 0; i < num_threads; i++)
39 init_ffsb_thread(tg->threads + i, tg, 0, tg_num, i);
40 }
41
destroy_ffsb_tg(ffsb_tg_t * tg)42 void destroy_ffsb_tg(ffsb_tg_t * tg)
43 {
44 int i;
45 for (i = 0; i < tg->num_threads; i++)
46 destroy_ffsb_thread(tg->threads + i);
47 free(tg->threads);
48 if (tg_needs_stats(tg))
49 ffsb_statsc_destroy(&tg->fsc);
50 }
51
tg_run(void * data)52 void *tg_run(void *data)
53 {
54 tg_run_params_t *params = (tg_run_params_t *) data;
55 ffsb_tg_t *tg = params->tg;
56 int i;
57 pthread_attr_t attr;
58
59 pthread_attr_init(&attr);
60 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
61
62 tg->start_barrier = params->thread_barrier;
63
64 /* Sum up the weights for use later by tg_get_op() */
65 tg->sum_weights = 0;
66 for (i = 0; i < FFSB_NUMOPS; i++)
67 tg->sum_weights += tg->op_weights[i];
68
69 tg->fc = params->fc;
70 tg->flagval = -1;
71 tg->stopval = 1;
72
73 /* spawn threads */
74 for (i = 0; i < tg->num_threads; i++) {
75 ffsb_thread_t *ft = &tg->threads[i];
76 pthread_create(&ft->ptid, &attr, ft_run, ft);
77 }
78
79 if (params->tg_barrier)
80 ffsb_barrier_wait(params->tg_barrier);
81
82 /* wait for termination condition to be true */
83 do {
84 ffsb_sleep(params->wait_time);
85 } while (params->poll_fn(params->poll_data) == 0);
86
87 /* set flag value */
88 tg->flagval = tg->stopval;
89
90 /* wait on theads to finish */
91 for (i = 0; i < tg->num_threads; i++)
92 pthread_join(tg->threads[i].ptid, NULL);
93
94 return NULL;
95 }
96
97 /* Needs to set params->opnum and params->fs */
tg_get_op(ffsb_tg_t * tg,randdata_t * rd,tg_op_params_t * params)98 void tg_get_op(ffsb_tg_t * tg, randdata_t * rd, tg_op_params_t * params)
99 {
100 unsigned curop;
101 int num;
102 int fsnum;
103
104 num = 1 + getrandom(rd, tg->sum_weights);
105 curop = 0;
106
107 while (tg->op_weights[curop] < num) {
108 num -= tg->op_weights[curop];
109 curop++;
110 }
111
112 params->opnum = curop;
113
114 /* If we're bound to a particular filesystem, use that,
115 * otherwise, pick one at random.
116 */
117 fsnum = tg->bindfs;
118 if (fsnum < 0)
119 fsnum = getrandom(rd, tg->fc->num_filesys);
120
121 params->fs = fc_get_fs(tg->fc, fsnum);
122 }
123
tg_set_op_weight(ffsb_tg_t * tg,char * opname,unsigned weight)124 void tg_set_op_weight(ffsb_tg_t * tg, char *opname, unsigned weight)
125 {
126 int opnum = ops_find_op(opname);
127 assert(opnum >= 0);
128 tg->op_weights[opnum] = weight;
129 }
130
tg_get_op_weight(ffsb_tg_t * tg,char * opname)131 unsigned tg_get_op_weight(ffsb_tg_t * tg, char *opname)
132 {
133 int opnum = ops_find_op(opname);
134 assert(opnum >= 0);
135 return tg->op_weights[opnum];
136 }
137
tg_set_bindfs(ffsb_tg_t * tg,int fsnum)138 void tg_set_bindfs(ffsb_tg_t * tg, int fsnum)
139 {
140 tg->bindfs = fsnum;
141 }
142
tg_get_bindfs(ffsb_tg_t * tg)143 int tg_get_bindfs(ffsb_tg_t * tg)
144 {
145 return tg->bindfs;
146 }
147
tg_get_numthreads(ffsb_tg_t * tg)148 unsigned tg_get_numthreads(ffsb_tg_t * tg)
149 {
150 return tg->num_threads;
151 }
152
update_bufsize(ffsb_tg_t * tg)153 static void update_bufsize(ffsb_tg_t * tg)
154 {
155 int i;
156 uint32_t newmax = max(tg->read_blocksize, tg->write_blocksize);
157
158 if (newmax == max(newmax, tg->thread_bufsize))
159 for (i = 0; i < tg->num_threads; i++)
160 ft_alter_bufsize(tg->threads + i, newmax);
161 }
162
tg_set_read_random(ffsb_tg_t * tg,int rr)163 void tg_set_read_random(ffsb_tg_t * tg, int rr)
164 {
165 tg->read_random = rr;
166 }
167
tg_set_write_random(ffsb_tg_t * tg,int wr)168 void tg_set_write_random(ffsb_tg_t * tg, int wr)
169 {
170 tg->write_random = wr;
171 }
172
tg_set_fsync_file(ffsb_tg_t * tg,int fsync)173 void tg_set_fsync_file(ffsb_tg_t * tg, int fsync)
174 {
175 tg->fsync_file = fsync;
176 }
177
tg_set_read_size(ffsb_tg_t * tg,uint64_t rs)178 void tg_set_read_size(ffsb_tg_t * tg, uint64_t rs)
179 {
180 tg->read_size = rs;
181 }
182
tg_set_read_blocksize(ffsb_tg_t * tg,uint32_t rs)183 void tg_set_read_blocksize(ffsb_tg_t * tg, uint32_t rs)
184 {
185 tg->read_blocksize = rs;
186 update_bufsize(tg);
187 }
188
tg_set_read_skip(ffsb_tg_t * tg,int rs)189 void tg_set_read_skip(ffsb_tg_t * tg, int rs)
190 {
191 tg->read_skip = rs;
192 }
193
tg_set_read_skipsize(ffsb_tg_t * tg,uint32_t rs)194 void tg_set_read_skipsize(ffsb_tg_t * tg, uint32_t rs)
195 {
196 tg->read_skipsize = rs;
197 }
198
tg_set_write_size(ffsb_tg_t * tg,uint64_t ws)199 void tg_set_write_size(ffsb_tg_t * tg, uint64_t ws)
200 {
201 tg->write_size = ws;
202 }
203
tg_set_write_blocksize(ffsb_tg_t * tg,uint32_t ws)204 void tg_set_write_blocksize(ffsb_tg_t * tg, uint32_t ws)
205 {
206 tg->write_blocksize = ws;
207 update_bufsize(tg);
208 }
209
tg_get_read_random(ffsb_tg_t * tg)210 int tg_get_read_random(ffsb_tg_t * tg)
211 {
212 return tg->read_random;
213 }
214
tg_get_write_random(ffsb_tg_t * tg)215 int tg_get_write_random(ffsb_tg_t * tg)
216 {
217 return tg->write_random;
218 }
219
tg_get_fsync_file(ffsb_tg_t * tg)220 int tg_get_fsync_file(ffsb_tg_t * tg)
221 {
222 return tg->fsync_file;
223 }
224
tg_get_read_size(ffsb_tg_t * tg)225 uint64_t tg_get_read_size(ffsb_tg_t * tg)
226 {
227 return tg->read_size;
228 }
229
tg_get_read_blocksize(ffsb_tg_t * tg)230 uint32_t tg_get_read_blocksize(ffsb_tg_t * tg)
231 {
232 return tg->read_blocksize;
233 }
234
tg_get_read_skip(ffsb_tg_t * tg)235 int tg_get_read_skip(ffsb_tg_t * tg)
236 {
237 return tg->read_skip;
238 }
239
tg_get_read_skipsize(ffsb_tg_t * tg)240 uint32_t tg_get_read_skipsize(ffsb_tg_t * tg)
241 {
242 return tg->read_skipsize;
243 }
244
tg_get_write_size(ffsb_tg_t * tg)245 uint64_t tg_get_write_size(ffsb_tg_t * tg)
246 {
247 return tg->write_size;
248 }
249
tg_get_write_blocksize(ffsb_tg_t * tg)250 uint32_t tg_get_write_blocksize(ffsb_tg_t * tg)
251 {
252 return tg->write_blocksize;
253 }
254
tg_get_stopval(ffsb_tg_t * tg)255 int tg_get_stopval(ffsb_tg_t * tg)
256 {
257 return tg->stopval;
258 }
259
tg_get_start_barrier(ffsb_tg_t * tg)260 ffsb_barrier_t *tg_get_start_barrier(ffsb_tg_t * tg)
261 {
262 return tg->start_barrier;
263 }
264
tg_print_config_helper(ffsb_tg_t * tg)265 static void tg_print_config_helper(ffsb_tg_t * tg)
266 {
267 int i;
268 int sumweights = 0;
269 char buf[256];
270
271 printf("\t num_threads = %d\n", tg->num_threads);
272 printf("\t\n");
273 printf("\t read_random = %s\n", (tg->read_random) ? "on" : "off");
274 printf("\t read_size = %llu\t(%s)\n", tg->read_size,
275 ffsb_printsize(buf, tg->read_size, 256));
276 printf("\t read_blocksize = %u\t(%s)\n", tg->read_blocksize,
277 ffsb_printsize(buf, tg->read_blocksize, 256));
278 printf("\t read_skip = %s\n", (tg->read_skip) ? "on" : "off");
279 printf("\t read_skipsize = %u\t(%s)\n", tg->read_skipsize,
280 ffsb_printsize(buf, tg->read_skipsize, 256));
281 printf("\t\n");
282 printf("\t write_random = %s\n", (tg->write_random) ? "on" : "off");
283 printf("\t write_size = %llu\t(%s)\n", tg->write_size,
284 ffsb_printsize(buf, tg->write_size, 256));
285 printf("\t fsync_file = %d\n", tg->fsync_file);
286 printf("\t write_blocksize = %u\t(%s)\n", tg->write_blocksize,
287 ffsb_printsize(buf, tg->write_blocksize, 256));
288 printf("\t wait time = %u\n", tg->wait_time);
289 if (tg->bindfs >= 0) {
290 printf("\t\n");
291 printf("\t bound to fs %d\n", tg->bindfs);
292 }
293 printf("\t\n");
294 printf("\t op weights\n");
295
296 for (i = 0; i < FFSB_NUMOPS; i++)
297 sumweights += tg->op_weights[i];
298
299 for (i = 0; i < FFSB_NUMOPS; i++)
300 printf("\t %20s = %d (%.2f%%)\n", op_get_name(i),
301 tg->op_weights[i], 100 * (float)tg->op_weights[i] /
302 (float)sumweights);
303 printf("\t\n");
304 }
305
tg_print_config(ffsb_tg_t * tg)306 void tg_print_config(ffsb_tg_t * tg)
307 {
308 printf("ThreadGroup %d\n", tg->tg_num);
309 printf("================\n");
310 tg_print_config_helper(tg);
311 }
312
tg_print_config_aging(ffsb_tg_t * tg,char * fsname)313 void tg_print_config_aging(ffsb_tg_t * tg, char *fsname)
314 {
315 printf("\t Aging ThreadGroup for fs %s\n", fsname);
316 printf("\t ================\n");
317 tg_print_config_helper(tg);
318 }
319
tg_collect_results(ffsb_tg_t * tg,ffsb_op_results_t * r)320 void tg_collect_results(ffsb_tg_t * tg, ffsb_op_results_t * r)
321 {
322 int i;
323 for (i = 0; i < tg_get_numthreads(tg); i++)
324 add_results(r, ft_get_results(tg->threads + i));
325 }
326
tg_set_waittime(ffsb_tg_t * tg,unsigned time)327 void tg_set_waittime(ffsb_tg_t * tg, unsigned time)
328 {
329 tg->wait_time = time;
330 }
331
tg_get_waittime(ffsb_tg_t * tg)332 unsigned tg_get_waittime(ffsb_tg_t * tg)
333 {
334 return tg->wait_time;
335 }
336
tg_get_flagval(ffsb_tg_t * tg)337 int tg_get_flagval(ffsb_tg_t * tg)
338 {
339 return tg->flagval;
340 }
341
tg_set_statsc(ffsb_tg_t * tg,ffsb_statsc_t * fsc)342 void tg_set_statsc(ffsb_tg_t * tg, ffsb_statsc_t * fsc)
343 {
344 if (fsc) {
345 int i;
346
347 tg->need_stats = 1;
348 ffsb_statsc_copy(&tg->fsc, fsc);
349
350 for (i = 0; i < tg->num_threads; i++)
351 ft_set_statsc(tg->threads + i, &tg->fsc);
352 }
353 }
354
tg_collect_stats(ffsb_tg_t * tg,ffsb_statsd_t * fsd)355 void tg_collect_stats(ffsb_tg_t * tg, ffsb_statsd_t * fsd)
356 {
357 int i;
358
359 assert(tg->need_stats);
360 ffsb_statsd_init(fsd, &tg->fsc);
361
362 for (i = 0; i < tg_get_numthreads(tg); i++)
363 ffsb_statsd_add(fsd, ft_get_stats_data(tg->threads + i));
364 }
365
tg_needs_stats(ffsb_tg_t * tg)366 int tg_needs_stats(ffsb_tg_t * tg)
367 {
368 return tg->need_stats;
369 }
370