/* * Copyright (c) International Business Machines Corp., 2001-2004 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include "ffsb_tg.h" #include "util.h" void init_ffsb_tg(ffsb_tg_t * tg, unsigned num_threads, unsigned tg_num) { int i; memset(tg, 0, sizeof(ffsb_tg_t)); tg->threads = ffsb_malloc(sizeof(ffsb_thread_t) * num_threads); tg->tg_num = tg_num; tg->num_threads = num_threads; tg->bindfs = -1; /* default is not bound */ tg->thread_bufsize = 0; for (i = 0; i < num_threads; i++) init_ffsb_thread(tg->threads + i, tg, 0, tg_num, i); } void destroy_ffsb_tg(ffsb_tg_t * tg) { int i; for (i = 0; i < tg->num_threads; i++) destroy_ffsb_thread(tg->threads + i); free(tg->threads); if (tg_needs_stats(tg)) ffsb_statsc_destroy(&tg->fsc); } void *tg_run(void *data) { tg_run_params_t *params = (tg_run_params_t *) data; ffsb_tg_t *tg = params->tg; int i; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); tg->start_barrier = params->thread_barrier; /* Sum up the weights for use later by tg_get_op() */ tg->sum_weights = 0; for (i = 0; i < FFSB_NUMOPS; i++) tg->sum_weights += tg->op_weights[i]; tg->fc = params->fc; tg->flagval = -1; tg->stopval = 1; /* spawn threads */ for (i = 0; i < tg->num_threads; i++) { ffsb_thread_t *ft = &tg->threads[i]; pthread_create(&ft->ptid, &attr, ft_run, ft); } if (params->tg_barrier) ffsb_barrier_wait(params->tg_barrier); /* wait for termination condition to be true */ do { ffsb_sleep(params->wait_time); } while (params->poll_fn(params->poll_data) == 0); /* set flag value */ tg->flagval = tg->stopval; /* wait on theads to finish */ for (i = 0; i < tg->num_threads; i++) pthread_join(tg->threads[i].ptid, NULL); return NULL; } /* Needs to set params->opnum and params->fs */ void tg_get_op(ffsb_tg_t * tg, randdata_t * rd, tg_op_params_t * params) { unsigned curop; int num; int fsnum; num = 1 + getrandom(rd, tg->sum_weights); curop = 0; while (tg->op_weights[curop] < num) { num -= tg->op_weights[curop]; curop++; } params->opnum = curop; /* If we're bound to a particular filesystem, use that, * otherwise, pick one at random. */ fsnum = tg->bindfs; if (fsnum < 0) fsnum = getrandom(rd, tg->fc->num_filesys); params->fs = fc_get_fs(tg->fc, fsnum); } void tg_set_op_weight(ffsb_tg_t * tg, char *opname, unsigned weight) { int opnum = ops_find_op(opname); assert(opnum >= 0); tg->op_weights[opnum] = weight; } unsigned tg_get_op_weight(ffsb_tg_t * tg, char *opname) { int opnum = ops_find_op(opname); assert(opnum >= 0); return tg->op_weights[opnum]; } void tg_set_bindfs(ffsb_tg_t * tg, int fsnum) { tg->bindfs = fsnum; } int tg_get_bindfs(ffsb_tg_t * tg) { return tg->bindfs; } unsigned tg_get_numthreads(ffsb_tg_t * tg) { return tg->num_threads; } static void update_bufsize(ffsb_tg_t * tg) { int i; uint32_t newmax = max(tg->read_blocksize, tg->write_blocksize); if (newmax == max(newmax, tg->thread_bufsize)) for (i = 0; i < tg->num_threads; i++) ft_alter_bufsize(tg->threads + i, newmax); } void tg_set_read_random(ffsb_tg_t * tg, int rr) { tg->read_random = rr; } void tg_set_write_random(ffsb_tg_t * tg, int wr) { tg->write_random = wr; } void tg_set_fsync_file(ffsb_tg_t * tg, int fsync) { tg->fsync_file = fsync; } void tg_set_read_size(ffsb_tg_t * tg, uint64_t rs) { tg->read_size = rs; } void tg_set_read_blocksize(ffsb_tg_t * tg, uint32_t rs) { tg->read_blocksize = rs; update_bufsize(tg); } void tg_set_read_skip(ffsb_tg_t * tg, int rs) { tg->read_skip = rs; } void tg_set_read_skipsize(ffsb_tg_t * tg, uint32_t rs) { tg->read_skipsize = rs; } void tg_set_write_size(ffsb_tg_t * tg, uint64_t ws) { tg->write_size = ws; } void tg_set_write_blocksize(ffsb_tg_t * tg, uint32_t ws) { tg->write_blocksize = ws; update_bufsize(tg); } int tg_get_read_random(ffsb_tg_t * tg) { return tg->read_random; } int tg_get_write_random(ffsb_tg_t * tg) { return tg->write_random; } int tg_get_fsync_file(ffsb_tg_t * tg) { return tg->fsync_file; } uint64_t tg_get_read_size(ffsb_tg_t * tg) { return tg->read_size; } uint32_t tg_get_read_blocksize(ffsb_tg_t * tg) { return tg->read_blocksize; } int tg_get_read_skip(ffsb_tg_t * tg) { return tg->read_skip; } uint32_t tg_get_read_skipsize(ffsb_tg_t * tg) { return tg->read_skipsize; } uint64_t tg_get_write_size(ffsb_tg_t * tg) { return tg->write_size; } uint32_t tg_get_write_blocksize(ffsb_tg_t * tg) { return tg->write_blocksize; } int tg_get_stopval(ffsb_tg_t * tg) { return tg->stopval; } ffsb_barrier_t *tg_get_start_barrier(ffsb_tg_t * tg) { return tg->start_barrier; } static void tg_print_config_helper(ffsb_tg_t * tg) { int i; int sumweights = 0; char buf[256]; printf("\t num_threads = %d\n", tg->num_threads); printf("\t\n"); printf("\t read_random = %s\n", (tg->read_random) ? "on" : "off"); printf("\t read_size = %llu\t(%s)\n", tg->read_size, ffsb_printsize(buf, tg->read_size, 256)); printf("\t read_blocksize = %u\t(%s)\n", tg->read_blocksize, ffsb_printsize(buf, tg->read_blocksize, 256)); printf("\t read_skip = %s\n", (tg->read_skip) ? "on" : "off"); printf("\t read_skipsize = %u\t(%s)\n", tg->read_skipsize, ffsb_printsize(buf, tg->read_skipsize, 256)); printf("\t\n"); printf("\t write_random = %s\n", (tg->write_random) ? "on" : "off"); printf("\t write_size = %llu\t(%s)\n", tg->write_size, ffsb_printsize(buf, tg->write_size, 256)); printf("\t fsync_file = %d\n", tg->fsync_file); printf("\t write_blocksize = %u\t(%s)\n", tg->write_blocksize, ffsb_printsize(buf, tg->write_blocksize, 256)); printf("\t wait time = %u\n", tg->wait_time); if (tg->bindfs >= 0) { printf("\t\n"); printf("\t bound to fs %d\n", tg->bindfs); } printf("\t\n"); printf("\t op weights\n"); for (i = 0; i < FFSB_NUMOPS; i++) sumweights += tg->op_weights[i]; for (i = 0; i < FFSB_NUMOPS; i++) printf("\t %20s = %d (%.2f%%)\n", op_get_name(i), tg->op_weights[i], 100 * (float)tg->op_weights[i] / (float)sumweights); printf("\t\n"); } void tg_print_config(ffsb_tg_t * tg) { printf("ThreadGroup %d\n", tg->tg_num); printf("================\n"); tg_print_config_helper(tg); } void tg_print_config_aging(ffsb_tg_t * tg, char *fsname) { printf("\t Aging ThreadGroup for fs %s\n", fsname); printf("\t ================\n"); tg_print_config_helper(tg); } void tg_collect_results(ffsb_tg_t * tg, ffsb_op_results_t * r) { int i; for (i = 0; i < tg_get_numthreads(tg); i++) add_results(r, ft_get_results(tg->threads + i)); } void tg_set_waittime(ffsb_tg_t * tg, unsigned time) { tg->wait_time = time; } unsigned tg_get_waittime(ffsb_tg_t * tg) { return tg->wait_time; } int tg_get_flagval(ffsb_tg_t * tg) { return tg->flagval; } void tg_set_statsc(ffsb_tg_t * tg, ffsb_statsc_t * fsc) { if (fsc) { int i; tg->need_stats = 1; ffsb_statsc_copy(&tg->fsc, fsc); for (i = 0; i < tg->num_threads; i++) ft_set_statsc(tg->threads + i, &tg->fsc); } } void tg_collect_stats(ffsb_tg_t * tg, ffsb_statsd_t * fsd) { int i; assert(tg->need_stats); ffsb_statsd_init(fsd, &tg->fsc); for (i = 0; i < tg_get_numthreads(tg); i++) ffsb_statsd_add(fsd, ft_get_stats_data(tg->threads + i)); } int tg_needs_stats(ffsb_tg_t * tg) { return tg->need_stats; }