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 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 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 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 */ 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 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 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 138 void tg_set_bindfs(ffsb_tg_t * tg, int fsnum) 139 { 140 tg->bindfs = fsnum; 141 } 142 143 int tg_get_bindfs(ffsb_tg_t * tg) 144 { 145 return tg->bindfs; 146 } 147 148 unsigned tg_get_numthreads(ffsb_tg_t * tg) 149 { 150 return tg->num_threads; 151 } 152 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 163 void tg_set_read_random(ffsb_tg_t * tg, int rr) 164 { 165 tg->read_random = rr; 166 } 167 168 void tg_set_write_random(ffsb_tg_t * tg, int wr) 169 { 170 tg->write_random = wr; 171 } 172 173 void tg_set_fsync_file(ffsb_tg_t * tg, int fsync) 174 { 175 tg->fsync_file = fsync; 176 } 177 178 void tg_set_read_size(ffsb_tg_t * tg, uint64_t rs) 179 { 180 tg->read_size = rs; 181 } 182 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 189 void tg_set_read_skip(ffsb_tg_t * tg, int rs) 190 { 191 tg->read_skip = rs; 192 } 193 194 void tg_set_read_skipsize(ffsb_tg_t * tg, uint32_t rs) 195 { 196 tg->read_skipsize = rs; 197 } 198 199 void tg_set_write_size(ffsb_tg_t * tg, uint64_t ws) 200 { 201 tg->write_size = ws; 202 } 203 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 210 int tg_get_read_random(ffsb_tg_t * tg) 211 { 212 return tg->read_random; 213 } 214 215 int tg_get_write_random(ffsb_tg_t * tg) 216 { 217 return tg->write_random; 218 } 219 220 int tg_get_fsync_file(ffsb_tg_t * tg) 221 { 222 return tg->fsync_file; 223 } 224 225 uint64_t tg_get_read_size(ffsb_tg_t * tg) 226 { 227 return tg->read_size; 228 } 229 230 uint32_t tg_get_read_blocksize(ffsb_tg_t * tg) 231 { 232 return tg->read_blocksize; 233 } 234 235 int tg_get_read_skip(ffsb_tg_t * tg) 236 { 237 return tg->read_skip; 238 } 239 240 uint32_t tg_get_read_skipsize(ffsb_tg_t * tg) 241 { 242 return tg->read_skipsize; 243 } 244 245 uint64_t tg_get_write_size(ffsb_tg_t * tg) 246 { 247 return tg->write_size; 248 } 249 250 uint32_t tg_get_write_blocksize(ffsb_tg_t * tg) 251 { 252 return tg->write_blocksize; 253 } 254 255 int tg_get_stopval(ffsb_tg_t * tg) 256 { 257 return tg->stopval; 258 } 259 260 ffsb_barrier_t *tg_get_start_barrier(ffsb_tg_t * tg) 261 { 262 return tg->start_barrier; 263 } 264 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 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 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 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 327 void tg_set_waittime(ffsb_tg_t * tg, unsigned time) 328 { 329 tg->wait_time = time; 330 } 331 332 unsigned tg_get_waittime(ffsb_tg_t * tg) 333 { 334 return tg->wait_time; 335 } 336 337 int tg_get_flagval(ffsb_tg_t * tg) 338 { 339 return tg->flagval; 340 } 341 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 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 366 int tg_needs_stats(ffsb_tg_t * tg) 367 { 368 return tg->need_stats; 369 } 370