The following changes since commit 7351f402b131fc4ad4e25bd2609a255a1ab4e97c: Merge branch 'next' (2013-04-08 09:46:54 +0200) are available in the git repository at: git://git.kernel.dk/fio.git master Jens Axboe (3): server: bump protocol version parse: add posval support to FIO_OPT_INT options: make unit_base be posval[] based Steven Noonan (4): num2str: add arguments to represent values in terms of bytes/bits implement 'unit_base' option to select between KB and Kbit et. al. stats: show summary bandwidth in terms of kb_base stat.c: make 'bw' summary line respect 'unit_base' option client.c | 3 ++ engines/net.c | 2 +- eta.c | 11 +++++---- fio.h | 3 +- init.c | 7 ++++++ ioengine.h | 1 + lib/num2str.c | 25 +++++++++++++++++----- options.c | 21 +++++++++++++++++++ parse.c | 18 ++++++++++++++++ server.c | 2 + server.h | 2 +- stat.c | 62 ++++++++++++++++++++++++++++++++++---------------------- stat.h | 3 ++ 13 files changed, 122 insertions(+), 38 deletions(-) --- Diff of recent changes: diff --git a/client.c b/client.c index 0dc620d..7915268 100644 --- a/client.c +++ b/client.c @@ -651,6 +651,7 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src) dst->total_err_count = le64_to_cpu(src->total_err_count); dst->first_error = le32_to_cpu(src->first_error); dst->kb_base = le32_to_cpu(src->kb_base); + dst->unit_base = le32_to_cpu(src->unit_base); } static void convert_gs(struct group_run_stats *dst, struct group_run_stats *src) @@ -667,6 +668,7 @@ static void convert_gs(struct group_run_stats *dst, struct group_run_stats *src) } dst->kb_base = le32_to_cpu(src->kb_base); + dst->unit_base = le32_to_cpu(src->unit_base); dst->groupid = le32_to_cpu(src->groupid); dst->unified_rw_rep = le32_to_cpu(src->unified_rw_rep); } @@ -774,6 +776,7 @@ static void convert_jobs_eta(struct jobs_eta *je) je->elapsed_sec = le64_to_cpu(je->elapsed_sec); je->eta_sec = le64_to_cpu(je->eta_sec); je->is_pow2 = le32_to_cpu(je->is_pow2); + je->unit_base = le32_to_cpu(je->unit_base); } static void sum_jobs_eta(struct jobs_eta *dst, struct jobs_eta *je) diff --git a/engines/net.c b/engines/net.c index 624ff15..31f7151 100644 --- a/engines/net.c +++ b/engines/net.c @@ -970,7 +970,7 @@ static struct ioengine_ops ioengine_rw = { .options = options, .option_struct_size = sizeof(struct netio_options), .flags = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR | - FIO_PIPEIO, + FIO_PIPEIO | FIO_BIT_BASED, }; static int str_hostname_cb(void *data, const char *input) diff --git a/eta.c b/eta.c index f90d428..50d229c 100644 --- a/eta.c +++ b/eta.c @@ -319,6 +319,7 @@ int calc_thread_status(struct jobs_eta *je, int force) unified_rw_rep += td->o.unified_rw_rep; if (is_power_of_2(td->o.kb_base)) je->is_pow2 = 1; + je->unit_base = td->o.unit_base; if (td->o.bw_avg_time < bw_avg_time) bw_avg_time = td->o.bw_avg_time; if (td->runstate == TD_RUNNING || td->runstate == TD_VERIFYING @@ -449,9 +450,9 @@ void display_thread_status(struct jobs_eta *je) if (je->m_rate || je->t_rate) { char *tr, *mr; - mr = num2str(je->m_rate, 4, 0, je->is_pow2); - tr = num2str(je->t_rate, 4, 0, je->is_pow2); - p += sprintf(p, ", CR=%s/%s KB/s", tr, mr); + mr = num2str(je->m_rate, 4, 0, je->is_pow2, 8); + tr = num2str(je->t_rate, 4, 0, je->is_pow2, 8); + p += sprintf(p, ", CR=%s/%s /s", tr, mr); free(tr); free(mr); } else if (je->m_iops || je->t_iops) @@ -474,8 +475,8 @@ void display_thread_status(struct jobs_eta *je) for (ddir = DDIR_READ; ddir < DDIR_RWDIR_CNT; ddir++) { rate_str[ddir] = num2str(je->rate[ddir], 5, - 1024, je->is_pow2); - iops_str[ddir] = num2str(je->iops[ddir], 4, 1, 0); + 1024, je->is_pow2, je->unit_base); + iops_str[ddir] = num2str(je->iops[ddir], 4, 1, 0, 0); } left = sizeof(output) - (p - output) - 1; diff --git a/fio.h b/fio.h index db594ab..e74bdb3 100644 --- a/fio.h +++ b/fio.h @@ -108,6 +108,7 @@ struct thread_options { enum td_ddir td_ddir; unsigned int rw_seq; unsigned int kb_base; + unsigned int unit_base; unsigned int ddir_seq_nr; long ddir_seq_add; unsigned int iodepth; @@ -686,7 +687,7 @@ extern void fio_options_mem_dupe(struct thread_data *); extern void options_mem_dupe(void *data, struct fio_option *options); extern void td_fill_rand_seeds(struct thread_data *); extern void add_job_opts(const char **); -extern char *num2str(unsigned long, int, int, int); +extern char *num2str(unsigned long, int, int, int, int); extern int ioengine_load(struct thread_data *); #define FIO_GETOPT_JOB 0x89000000 diff --git a/init.c b/init.c index 92b3e5b..44c74e3 100644 --- a/init.c +++ b/init.c @@ -560,6 +560,13 @@ static int fixup_options(struct thread_data *td) } } + if (!o->unit_base) { + if (td->io_ops->flags & FIO_BIT_BASED) + o->unit_base = 1; + else + o->unit_base = 8; + } + #ifndef CONFIG_FDATASYNC if (o->fdatasync_blocks) { log_info("fio: this platform does not support fdatasync()" diff --git a/ioengine.h b/ioengine.h index 7299636..d15d15e 100644 --- a/ioengine.h +++ b/ioengine.h @@ -153,6 +153,7 @@ enum fio_ioengine_flags { FIO_PIPEIO = 1 << 7, /* input/output no seekable */ FIO_BARRIER = 1 << 8, /* engine supports barriers */ FIO_MEMALIGN = 1 << 9, /* engine wants aligned memory */ + FIO_BIT_BASED = 1 << 10, /* engine uses a bit base (e.g. uses Kbit as opposed to KB) */ }; /* diff --git a/lib/num2str.c b/lib/num2str.c index 559cbeb..a104192 100644 --- a/lib/num2str.c +++ b/lib/num2str.c @@ -5,12 +5,13 @@ /* * Cheesy number->string conversion, complete with carry rounding error. */ -char *num2str(unsigned long num, int maxlen, int base, int pow2) +char *num2str(unsigned long num, int maxlen, int base, int pow2, int unit_base) { - char postfix[] = { ' ', 'K', 'M', 'G', 'P', 'E' }; - unsigned int thousand[] = { 1000, 1024 }; + const char *postfix[] = { "", "K", "M", "G", "P", "E" }; + const char *byte_postfix[] = { "", "B", "bit" }; + const unsigned int thousand[] = { 1000, 1024 }; unsigned int modulo, decimals; - int post_index, carry = 0; + int byte_post_index = 0, post_index, carry = 0; char tmp[32]; char *buf; @@ -19,6 +20,16 @@ char *num2str(unsigned long num, int maxlen, int base, int pow2) for (post_index = 0; base > 1; post_index++) base /= thousand[!!pow2]; + switch (unit_base) { + case 1: + byte_post_index = 2; + num *= 8; + break; + case 8: + byte_post_index = 1; + break; + } + modulo = -1U; while (post_index < sizeof(postfix)) { sprintf(tmp, "%lu", num); @@ -33,7 +44,8 @@ char *num2str(unsigned long num, int maxlen, int base, int pow2) if (modulo == -1U) { done: - sprintf(buf, "%lu%c", num, postfix[post_index]); + sprintf(buf, "%lu%s%s", num, postfix[post_index], + byte_postfix[byte_post_index]); return buf; } @@ -53,6 +65,7 @@ done: modulo = (modulo + 9) / 10; } while (1); - sprintf(buf, "%lu.%u%c", num, modulo, postfix[post_index]); + sprintf(buf, "%lu.%u%s%s", num, modulo, postfix[post_index], + byte_postfix[byte_post_index]); return buf; } diff --git a/options.c b/options.c index bca217f..6cd1e92 100644 --- a/options.c +++ b/options.c @@ -1149,6 +1149,27 @@ static struct fio_option options[FIO_MAX_OPTS] = { .help = "How many bytes per KB for reporting (1000 or 1024)", }, { + .name = "unit_base", + .type = FIO_OPT_INT, + .off1 = td_var_offset(unit_base), + .prio = 1, + .posval = { + { .ival = "0", + .oval = 0, + .help = "Auto-detect", + }, + { .ival = "8", + .oval = 8, + .help = "Normal (byte based)", + }, + { .ival = "1", + .oval = 1, + .help = "Bit based", + }, + }, + .help = "Bit multiple of result summary data (8 for byte, 1 for bit)", + }, + { .name = "lockfile", .type = FIO_OPT_STR, .off1 = td_var_offset(file_lock_mode), diff --git a/parse.c b/parse.c index 5b8e10f..dddcb8e 100644 --- a/parse.c +++ b/parse.c @@ -465,6 +465,24 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, " (%u min)\n", ull, o->minval); return 1; } + if (o->posval[0].ival) { + posval_sort(o, posval); + + ret = 1; + for (i = 0; i < PARSE_MAX_VP; i++) { + vp = &posval[i]; + if (!vp->ival || vp->ival[0] == '\0') + continue; + if (vp->oval == ull) { + ret = 0; + break; + } + } + if (ret) { + log_err("value %d not in allowed range\n",ull); + return 1; + } + } if (fn) ret = fn(data, &ull); diff --git a/server.c b/server.c index d4676dd..f239d43 100644 --- a/server.c +++ b/server.c @@ -648,6 +648,7 @@ static void convert_gs(struct group_run_stats *dst, struct group_run_stats *src) } dst->kb_base = cpu_to_le32(src->kb_base); + dst->unit_base = cpu_to_le32(src->unit_base); dst->groupid = cpu_to_le32(src->groupid); dst->unified_rw_rep = cpu_to_le32(src->unified_rw_rep); } @@ -730,6 +731,7 @@ void fio_server_send_ts(struct thread_stat *ts, struct group_run_stats *rs) p.ts.total_err_count = cpu_to_le64(ts->total_err_count); p.ts.first_error = cpu_to_le32(ts->first_error); p.ts.kb_base = cpu_to_le32(ts->kb_base); + p.ts.unit_base = cpu_to_le32(ts->unit_base); convert_gs(&p.rs, rs); diff --git a/server.h b/server.h index 15b802b..da11671 100644 --- a/server.h +++ b/server.h @@ -36,7 +36,7 @@ struct fio_net_int_cmd { }; enum { - FIO_SERVER_VER = 10, + FIO_SERVER_VER = 11, FIO_SERVER_MAX_PDU = 1024, diff --git a/stat.c b/stat.c index 38c5d02..ab2f808 100644 --- a/stat.c +++ b/stat.c @@ -276,12 +276,12 @@ void show_group_stats(struct group_run_stats *rs) if (!rs->max_run[i]) continue; - p1 = num2str(rs->io_kb[i], 6, rs->kb_base, i2p); - p2 = num2str(rs->agg[i], 6, rs->kb_base, i2p); - p3 = num2str(rs->min_bw[i], 6, rs->kb_base, i2p); - p4 = num2str(rs->max_bw[i], 6, rs->kb_base, i2p); + p1 = num2str(rs->io_kb[i], 6, rs->kb_base, i2p, 8); + p2 = num2str(rs->agg[i], 6, rs->kb_base, i2p, rs->unit_base); + p3 = num2str(rs->min_bw[i], 6, rs->kb_base, i2p, rs->unit_base); + p4 = num2str(rs->max_bw[i], 6, rs->kb_base, i2p, rs->unit_base); - log_info("%s: io=%sB, aggrb=%sB/s, minb=%sB/s, maxb=%sB/s," + log_info("%s: io=%s, aggrb=%s/s, minb=%s/s, maxb=%s/s," " mint=%llumsec, maxt=%llumsec\n", rs->unified_rw_rep ? " MIXED" : ddir_str[i], p1, p2, p3, p4, rs->min_run[i], rs->max_run[i]); @@ -379,13 +379,13 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts, runt = ts->runtime[ddir]; bw = (1000 * ts->io_bytes[ddir]) / runt; - io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p); - bw_p = num2str(bw, 6, 1, i2p); + io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p, 8); + bw_p = num2str(bw, 6, 1, i2p, ts->unit_base); iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt; - iops_p = num2str(iops, 6, 1, 0); + iops_p = num2str(iops, 6, 1, 0, 0); - log_info(" %s: io=%sB, bw=%sB/s, iops=%s, runt=%6llumsec\n", + log_info(" %s: io=%s, bw=%s/s, iops=%s, runt=%6llumsec\n", rs->unified_rw_rep ? "mixed" : ddir_str[ddir], io_p, bw_p, iops_p, ts->runtime[ddir]); @@ -400,8 +400,8 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts, if (!usec_to_msec(&min, &max, &mean, &dev)) base = "(msec)"; - minp = num2str(min, 6, 1, 0); - maxp = num2str(max, 6, 1, 0); + minp = num2str(min, 6, 1, 0, 0); + maxp = num2str(max, 6, 1, 0, 0); log_info(" slat %s: min=%s, max=%s, avg=%5.02f," " stdev=%5.02f\n", base, minp, maxp, mean, dev); @@ -416,8 +416,8 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts, if (!usec_to_msec(&min, &max, &mean, &dev)) base = "(msec)"; - minp = num2str(min, 6, 1, 0); - maxp = num2str(max, 6, 1, 0); + minp = num2str(min, 6, 1, 0, 0); + maxp = num2str(max, 6, 1, 0, 0); log_info(" clat %s: min=%s, max=%s, avg=%5.02f," " stdev=%5.02f\n", base, minp, maxp, mean, dev); @@ -432,8 +432,8 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts, if (!usec_to_msec(&min, &max, &mean, &dev)) base = "(msec)"; - minp = num2str(min, 6, 1, 0); - maxp = num2str(max, 6, 1, 0); + minp = num2str(min, 6, 1, 0, 0); + maxp = num2str(max, 6, 1, 0, 0); log_info(" lat %s: min=%s, max=%s, avg=%5.02f," " stdev=%5.02f\n", base, minp, maxp, mean, dev); @@ -448,8 +448,15 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts, ts->percentile_precision); } if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) { - double p_of_agg = 100.0; - const char *bw_str = "KB"; + double p_of_agg = 100.0, fkb_base = (double)rs->kb_base; + const char *bw_str = (rs->unit_base == 1 ? "Kbit" : "KB"); + + if (rs->unit_base == 1) { + min *= 8.0; + max *= 8.0; + mean *= 8.0; + dev *= 8.0; + } if (rs->agg[ddir]) { p_of_agg = mean * 100 / (double) rs->agg[ddir]; @@ -457,15 +464,15 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts, p_of_agg = 100.0; } - if (mean > 999999.9) { - min /= 1000.0; - max /= 1000.0; - mean /= 1000.0; - dev /= 1000.0; - bw_str = "MB"; + if (mean > fkb_base * fkb_base) { + min /= fkb_base; + max /= fkb_base; + mean /= fkb_base; + dev /= fkb_base; + bw_str = (rs->unit_base == 1 ? "Mbit" : "MB"); } - log_info(" bw (%s/s) : min=%5lu, max=%5lu, per=%3.2f%%," + log_info(" bw (%-4s/s): min=%5lu, max=%5lu, per=%3.2f%%," " avg=%5.02f, stdev=%5.02f\n", bw_str, min, max, p_of_agg, mean, dev); } @@ -1169,6 +1176,7 @@ void show_run_stats(void) struct thread_stat *threadstats, *ts; int i, j, nr_ts, last_ts, idx; int kb_base_warned = 0; + int unit_base_warned = 0; struct json_object *root = NULL; struct json_array *array = NULL; @@ -1240,11 +1248,16 @@ void show_run_stats(void) ts->pid = td->pid; ts->kb_base = td->o.kb_base; + ts->unit_base = td->o.unit_base; ts->unified_rw_rep = td->o.unified_rw_rep; } else if (ts->kb_base != td->o.kb_base && !kb_base_warned) { log_info("fio: kb_base differs for jobs in group, using" " %u as the base\n", ts->kb_base); kb_base_warned = 1; + } else if (ts->unit_base != td->o.unit_base && !unit_base_warned) { + log_info("fio: unit_base differs for jobs in group, using" + " %u as the base\n", ts->unit_base); + unit_base_warned = 1; } ts->continue_on_error = td->o.continue_on_error; @@ -1270,6 +1283,7 @@ void show_run_stats(void) ts = &threadstats[i]; rs = &runstats[ts->groupid]; rs->kb_base = ts->kb_base; + rs->unit_base = ts->unit_base; rs->unified_rw_rep += ts->unified_rw_rep; for (j = 0; j < DDIR_RWDIR_CNT; j++) { diff --git a/stat.h b/stat.h index 98ae4c8..f23abfa 100644 --- a/stat.h +++ b/stat.h @@ -7,6 +7,7 @@ struct group_run_stats { uint64_t io_kb[DDIR_RWDIR_CNT]; uint64_t agg[DDIR_RWDIR_CNT]; uint32_t kb_base; + uint32_t unit_base; uint32_t groupid; uint32_t unified_rw_rep; }; @@ -170,6 +171,7 @@ struct thread_stat { uint32_t first_error; uint32_t kb_base; + uint32_t unit_base; }; struct jobs_eta { @@ -184,6 +186,7 @@ struct jobs_eta { uint64_t elapsed_sec; uint64_t eta_sec; uint32_t is_pow2; + uint32_t unit_base; /* * Network 'copy' of run_str[] -- 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