The following changes since commit 78a6aad70b54fbf6eb63f14c60b292bcf6a5605e: act: fixes (2013-05-23 00:29:38 +0200) are available in the git repository at: git://git.kernel.dk/fio.git master Jens Axboe (7): act: bring closer to real ACT act: basic reporting Fix segfault is bool option is used on command line and fails parsing Better catch arguments with required options and none passed Make group_reporting be a string-set option again parse: if profile is set, only show options relevant to the profile Always exit if do_exit is set after parse backend.c | 1 + init.c | 21 ++++-- options.c | 2 +- parse.c | 2 + profiles/act.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 251 insertions(+), 31 deletions(-) --- Diff of recent changes: diff --git a/backend.c b/backend.c index 6b6da67..8787cce 100644 --- a/backend.c +++ b/backend.c @@ -1554,6 +1554,7 @@ reaped: exit_value++; done_secs += mtime_since_now(&td->epoch) / 1000; + profile_td_exit(td); } if (*nr_running == cputhreads && !pending && realthreads) diff --git a/init.c b/init.c index 7246bd8..c44fa67 100644 --- a/init.c +++ b/init.c @@ -1725,9 +1725,20 @@ int parse_cmd_line(int argc, char *argv[], int client_type) fio_options_set_ioengine_opts(l_opts, td); } - ret = fio_cmd_option_parse(td, opt, val); - if (ret) + if ((!val || !strlen(val)) && + l_opts[lidx].has_arg == required_argument) { + log_err("fio: option %s requires an argument\n", opt); + ret = 1; + } else + ret = fio_cmd_option_parse(td, opt, val); + + if (ret) { + if (td) { + put_job(td); + td = NULL; + } do_exit++; + } if (!ret && !strcmp(opt, "ioengine")) { free_ioengine(td); @@ -1833,10 +1844,8 @@ int parse_cmd_line(int argc, char *argv[], int client_type) break; } - if (do_exit) { - if (exit_val && !(is_backend || nr_clients)) - exit(exit_val); - } + if (do_exit && !(is_backend || nr_clients)) + exit(exit_val); if (nr_clients && fio_clients_connect()) { do_exit++; diff --git a/options.c b/options.c index e9df6a8..d0c53b6 100644 --- a/options.c +++ b/options.c @@ -2824,7 +2824,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { { .name = "group_reporting", .lname = "Group reporting", - .type = FIO_OPT_BOOL, + .type = FIO_OPT_STR_SET, .off1 = td_var_offset(group_reporting), .help = "Do reporting on a per-group basis", .category = FIO_OPT_C_STAT, diff --git a/parse.c b/parse.c index b8ec3aa..f54dae6 100644 --- a/parse.c +++ b/parse.c @@ -1086,6 +1086,8 @@ int show_cmd_help(struct fio_option *options, const char *name) continue; if (!exec_profile && o->prof_name) continue; + if (exec_profile && !(o->prof_name && !strcmp(exec_profile, o->prof_name))) + continue; if (name) { if (!strcmp(name, o->name) || diff --git a/profiles/act.c b/profiles/act.c index e5b31d7..2080602 100644 --- a/profiles/act.c +++ b/profiles/act.c @@ -2,9 +2,9 @@ #include "../profile.h" #include "../parse.h" -#define OBJ_SIZE 1536 /* each object */ -#define W_BUF_SIZE 128 * 1024 /* write coalescing */ - +/* + * 1x loads + */ #define R_LOAD 2000 #define W_LOAD 1000 @@ -31,28 +31,43 @@ static struct act_pass_criteria act_pass[ACT_MAX_CRIT] = { }, }; +struct act_run_data { + struct fio_mutex *mutex; + unsigned int pending; + + uint64_t lat_buckets[ACT_MAX_CRIT]; + uint64_t total_ios; +}; +static struct act_run_data *act_run_data; + struct act_prof_data { struct timeval sample_tv; uint64_t lat_buckets[ACT_MAX_CRIT]; uint64_t total_ios; + uint64_t cum_lat_buckets[ACT_MAX_CRIT]; + uint64_t cum_total_ios; }; static char *device_names; static unsigned int load = 1; +static unsigned int prep; +static unsigned int threads_per_queue; +static unsigned int num_read_blocks; +static unsigned int write_size; -static const char *act_opts[128] = { +#define ACT_MAX_OPTS 128 +static const char *act_opts[ACT_MAX_OPTS] = { "direct=1", - "ioengine=libaio", - "iodepth=32", + "ioengine=sync", "random_generator=lfsr", - "runtime=24h", - "time_based=1", + "group_reporting=1", + "thread", NULL, }; -static unsigned int opt_idx = 6; +static unsigned int opt_idx = 5; static unsigned int org_idx; -static void act_add_opt(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +static int act_add_opt(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2))); static struct fio_option options[] = { { @@ -70,6 +85,46 @@ static struct fio_option options[] = { .type = FIO_OPT_INT, .roff1 = &load, .help = "ACT load multipler (default 1x)", + .def = "1", + .category = FIO_OPT_C_PROFILE, + .group = FIO_OPT_G_ACT, + }, + { + .name = "threads-per-queue", + .lname = "Number of read IO threads per device", + .type = FIO_OPT_INT, + .roff1 = &threads_per_queue, + .help = "Number of read IO threads per device", + .def = "8", + .category = FIO_OPT_C_PROFILE, + .group = FIO_OPT_G_ACT, + }, + { + .name = "read-req-num-512-blocks", + .lname = "Number of 512b blocks to read", + .type = FIO_OPT_INT, + .roff1 = &num_read_blocks, + .help = "Number of 512b blocks to read at the time", + .def = "3", + .category = FIO_OPT_C_PROFILE, + .group = FIO_OPT_G_ACT, + }, + { + .name = "large-block-op-kbytes", + .lname = "Size of large block ops (writes)", + .type = FIO_OPT_INT, + .roff1 = &write_size, + .help = "Size of large block ops (writes)", + .def = "128k", + .category = FIO_OPT_C_PROFILE, + .group = FIO_OPT_G_ACT, + }, + { + .name = "prep", + .lname = "Run ACT prep phase", + .type = FIO_OPT_STR_SET, + .roff1 = &prep, + .help = "Set to run ACT prep phase", .category = FIO_OPT_C_PROFILE, .group = FIO_OPT_G_ACT, }, @@ -78,31 +133,106 @@ static struct fio_option options[] = { }, }; -static void act_add_opt(const char *str, ...) +static int act_add_opt(const char *str, ...) { char buffer[512]; va_list args; size_t len; + if (opt_idx == ACT_MAX_OPTS) { + log_err("act: ACT_MAX_OPTS is too small\n"); + return 1; + } + va_start(args, str); len = vsnprintf(buffer, sizeof(buffer), str, args); va_end(args); if (len) act_opts[opt_idx++] = strdup(buffer); + + return 0; +} + +static int act_add_rw(const char *dev, int reads) +{ + if (act_add_opt("name=act-%s-%s", reads ? "read" : "write", dev)) + return 1; + if (act_add_opt("filename=%s", dev)) + return 1; + if (act_add_opt("rw=%s", reads ? "randread" : "randwrite")) + return 1; + if (reads) { + int rload = load * R_LOAD / threads_per_queue; + + if (act_add_opt("numjobs=%u", threads_per_queue)) + return 1; + if (act_add_opt("rate_iops=%u", rload)) + return 1; + if (act_add_opt("bs=%u", num_read_blocks * 512)) + return 1; + } else { + const int rsize = write_size / (num_read_blocks * 512); + int wload = (load * W_LOAD + rsize - 1) / rsize; + + if (act_add_opt("rate_iops=%u", wload)) + return 1; + if (act_add_opt("bs=%u", write_size)) + return 1; + } + + return 0; +} + +static int act_add_dev_prep(const char *dev) +{ + /* Add sequential zero phase */ + if (act_add_opt("name=act-prep-zeroes-%s", dev)) + return 1; + if (act_add_opt("filename=%s", dev)) + return 1; + if (act_add_opt("bs=1M")) + return 1; + if (act_add_opt("zero_buffers")) + return 1; + if (act_add_opt("rw=write")) + return 1; + + /* Randomly overwrite device */ + if (act_add_opt("name=act-prep-salt-%s", dev)) + return 1; + if (act_add_opt("stonewall")) + return 1; + if (act_add_opt("filename=%s", dev)) + return 1; + if (act_add_opt("bs=4k")) + return 1; + if (act_add_opt("ioengine=libaio")) + return 1; + if (act_add_opt("iodepth=64")) + return 1; + if (act_add_opt("rw=randwrite")) + return 1; + + return 0; } -static void act_add_dev(const char *dev) +static int act_add_dev(const char *dev) { - act_add_opt("name=act-read-%s", dev); - act_add_opt("filename=%s", dev); - act_add_opt("rw=randread"); - act_add_opt("rate_iops=%u", load * R_LOAD); - - act_add_opt("name=act-write-%s", dev); - act_add_opt("filename=%s", dev); - act_add_opt("rw=randwrite"); - act_add_opt("rate_iops=%u", load * W_LOAD); + if (prep) + return act_add_dev_prep(dev); + + if (act_add_opt("runtime=24h")) + return 1; + if (act_add_opt("time_based=1")) + return 1; + + if (act_add_rw(dev, 1)) + return 1; + if (act_add_rw(dev, 0)) + return 1; + + return 0; } /* @@ -116,7 +246,6 @@ static int act_prep_cmdline(void) } org_idx = opt_idx; - act_add_opt("bs=%u", OBJ_SIZE); do { char *dev; @@ -125,7 +254,10 @@ static int act_prep_cmdline(void) if (!dev) break; - act_add_dev(dev); + if (act_add_dev(dev)) { + log_err("act: failed adding device to the mix\n"); + break; + } } while (1); return 0; @@ -137,6 +269,9 @@ static int act_io_u_lat(struct thread_data *td, uint64_t usec) int i, ret = 0; double perm; + if (prep) + return 0; + apd->total_ios++; for (i = ACT_MAX_CRIT - 1; i >= 0; i--) { @@ -160,17 +295,83 @@ static int act_io_u_lat(struct thread_data *td, uint64_t usec) break; } - memset(apd->lat_buckets, 0, sizeof(apd->lat_buckets)); + for (i = 0; i < ACT_MAX_CRIT; i++) { + apd->cum_lat_buckets[i] += apd->lat_buckets[i]; + apd->lat_buckets[i] = 0; + } + + apd->cum_total_ios += apd->total_ios; apd->total_ios = 0; fio_gettime(&apd->sample_tv, NULL); return ret; } +static void get_act_ref(void) +{ + fio_mutex_down(act_run_data->mutex); + act_run_data->pending++; + fio_mutex_up(act_run_data->mutex); +} + +static void act_show_all_stats(void) +{ + unsigned int i; + + log_info(" trans device\n"); + log_info(" %%>(ms) %%>(ms)\n"); + log_info(" slice"); + + for (i = 0; i < ACT_MAX_CRIT; i++) + log_info("\t%2u", act_pass[i].max_usec / 1000); + for (i = 0; i < ACT_MAX_CRIT; i++) + log_info("\t%2u", act_pass[i].max_usec / 1000); + + log_info("\n"); + log_info(" ----- ------ ------ ------ ------ ------ ------\n"); + log_info(" 1"); + + for (i = 0; i < ACT_MAX_CRIT; i++) { + double perc; + + perc = 100.0 * (double) act_run_data->lat_buckets[i] / (double) act_run_data->total_ios; + log_info("\t%2.2f", perc); + } + for (i = 0; i < ACT_MAX_CRIT; i++) { + double perc; + + perc = 100.0 * (double) act_run_data->lat_buckets[i] / (double) act_run_data->total_ios; + log_info("\t%2.2f", perc); + } + +} + +static void put_act_ref(struct thread_data *td) +{ + struct act_prof_data *apd = td->prof_data; + unsigned int i; + + fio_mutex_down(act_run_data->mutex); + + for (i = 0; i < ACT_MAX_CRIT; i++) { + act_run_data->lat_buckets[i] += apd->cum_lat_buckets[i]; + act_run_data->lat_buckets[i] += apd->lat_buckets[i]; + } + + act_run_data->total_ios += apd->cum_total_ios + apd->total_ios; + + if (!--act_run_data->pending) + act_show_all_stats(); + + fio_mutex_up(act_run_data->mutex); +} + static int act_td_init(struct thread_data *td) { struct act_prof_data *apd; + get_act_ref(); + apd = calloc(sizeof(*apd), 1); fio_gettime(&apd->sample_tv, NULL); td->prof_data = apd; @@ -179,6 +380,7 @@ static int act_td_init(struct thread_data *td) static void act_td_exit(struct thread_data *td) { + put_act_ref(td); free(td->prof_data); td->prof_data = NULL; } @@ -200,6 +402,9 @@ static struct profile_ops act_profile = { static void fio_init act_register(void) { + act_run_data = calloc(sizeof(*act_run_data), 1); + act_run_data->mutex = fio_mutex_init(FIO_MUTEX_UNLOCKED); + if (register_profile(&act_profile)) log_err("fio: failed to register profile 'act'\n"); } @@ -210,4 +415,7 @@ static void fio_exit act_unregister(void) free((void *) act_opts[++org_idx]); unregister_profile(&act_profile); + fio_mutex_remove(act_run_data->mutex); + free(act_run_data); + act_run_data = NULL; } -- To unsubscribe from this list: send the line "unsubscribe fio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html