Use kb_base=1000 to follow international standards for unit prefixes.
To specify power-of-10 decimal values defined in the International
System of Units (SI):
Ki means kilo (K) or 1000
Mi means mega (M) or 1000**2
Gi means giga (G) or 1000**3
Ti means tera (T) or 1000**4
Pi means peta (P) or 1000**5
To specify power-of-2 binary values defined in IEC 80000-13:
k means kibi (Ki) or 1024
M means mebi (Mi) or 1024**2
G means gibi (Gi) or 1024**3
T means tebi (Ti) or 1024**4
P means pebi (Pi) or 1024**5
For example, this specifies a blocksize of 4096 bytes:
kb_base=1000
bs=4KiB
With kb_base=1024 (the default), the unit prefixes are opposite from
those specified in the SI and IEC 80000-13 standards to provide
compatibility with old scripts. For example, this specifies a
blocksize of 4096 bytes:
kb_base=1024
bs=4K
For outputs printing quantities and bandwidths:
* eta stats only use the preferred prefix
* final stats include both (non-preferred prefix in parenthesis)
* in gfio, all windows include both
Text outputs are rearranged to try to obviously break any scripts
parsing the output rather than silently confuse them. The terse
and json outputs, which are intended for parsing, are unchanged.
Old:
Jobs: 576 (f=576), CR=86.4GB/576MB KB/s: [w(288),r(288)] [0.0% done] [33884MB/27114MB/0KB /s] [8471K/6778K/0 iops] [eta 06h:59m:57s]
read: io=363338MB, bw=34014MB/s, iops=8304.3K, runt= 10682msec
write: io=282447MB, bw=26225MB/s, iops=6402.7K, runt= 10770msec
READ: io=363338MB, aggrb=34014MB/s, minb=34014MB/s, maxb=34014MB/s, mint=10682msec, maxt=10682msec
WRITE: io=282447MB, aggrb=26225MB/s, minb=26225MB/s, maxb=26225MB/s, mint=10770msec, maxt=10770msec
New:
Jobs: 576 (f=576), 590MB/s-89.2GB/s: [w(288),r(288)][0.0%][r=34.2GB/s,w=26.3GB/s][r=8542k,w=6572k IOPS][eta 06h:59m:55s]
read: IOPS=8362k, BW=34.3GB/s (31.1GiB/s)(665GB/19417msec)
write: IOPS=6423k, BW=26.4GB/s (24.6GiB/s)(511GB/19431msec)
READ: bw=34.3GB/s (31.1GiB/s), 34.3GB/s-34.3GB/s (31.1GiB/s-31.1GiB/s), io=665GB (619GiB), run=19417-19417msec
WRITE: bw=26.4GB/s (24.6GiB/s), 26.4GB/s-26.4GB/s (24.6GiB/s-24.6GiB/s), io=511GB (476GiB), run=19431-19431msec
Documentation changes are in a subsequent patch.
Signed-off-by: Jens Axboe <axboe@fb.com>
}
p += sprintf(p, "Jobs: %d (f=%d)", je->nr_running, je->files_open);
}
p += sprintf(p, "Jobs: %d (f=%d)", je->nr_running, je->files_open);
- if (je->m_rate[0] || je->m_rate[1] || je->t_rate[0] || je->t_rate[1]) {
+
+ /* rate limits, if any */
+ if (je->m_rate[0] || je->m_rate[1] || je->m_rate[2] ||
+ je->t_rate[0] || je->t_rate[1] || je->t_rate[2]) {
- mr = num2str(je->m_rate[0] + je->m_rate[1], 4, 0, je->is_pow2, 8);
- tr = num2str(je->t_rate[0] + je->t_rate[1], 4, 0, je->is_pow2, 8);
- p += sprintf(p, ", CR=%s/%s KB/s", tr, mr);
+ mr = num2str(je->m_rate[0] + je->m_rate[1] + je->m_rate[2],
+ 4, 0, je->is_pow2, N2S_BYTEPERSEC);
+ tr = num2str(je->t_rate[0] + je->t_rate[1] + je->t_rate[2],
+ 4, 0, je->is_pow2, N2S_BYTEPERSEC);
+
+ p += sprintf(p, ", %s-%s", mr, tr);
- } else if (je->m_iops[0] || je->m_iops[1] || je->t_iops[0] || je->t_iops[1]) {
- p += sprintf(p, ", CR=%d/%d IOPS",
- je->t_iops[0] + je->t_iops[1],
- je->m_iops[0] + je->m_iops[1]);
+ } else if (je->m_iops[0] || je->m_iops[1] || je->m_iops[2] ||
+ je->t_iops[0] || je->t_iops[1] || je->t_iops[2]) {
+ p += sprintf(p, ", %d-%d IOPS",
+ je->m_iops[0] + je->m_iops[1] + je->m_iops[2],
+ je->t_iops[0] + je->t_iops[1] + je->t_iops[2]);
+
+ /* current run string, % done, bandwidth, iops, eta */
if (je->eta_sec != INT_MAX && je->nr_running) {
char perc_str[32];
char *iops_str[DDIR_RWDIR_CNT];
if (je->eta_sec != INT_MAX && je->nr_running) {
char perc_str[32];
char *iops_str[DDIR_RWDIR_CNT];
if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running ||
je->eta_sec == -1)
if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running ||
je->eta_sec == -1)
- strcpy(perc_str, "-.-% done");
+ strcpy(perc_str, "-.-%");
else {
double mult = 100.0;
else {
double mult = 100.0;
eta_good = 1;
perc *= mult;
eta_good = 1;
perc *= mult;
- sprintf(perc_str, "%3.1f%% done", perc);
+ sprintf(perc_str, "%3.1f%%", perc);
}
for (ddir = DDIR_READ; ddir < DDIR_RWDIR_CNT; ddir++) {
}
for (ddir = DDIR_READ; ddir < DDIR_RWDIR_CNT; ddir++) {
- rate_str[ddir] = num2str(je->rate[ddir], 5,
+ rate_str[ddir] = num2str(je->rate[ddir], 4,
1024, je->is_pow2, je->unit_base);
1024, je->is_pow2, je->unit_base);
- iops_str[ddir] = num2str(je->iops[ddir], 4, 1, 0, 0);
+ iops_str[ddir] = num2str(je->iops[ddir], 4, 1, 0, N2S_NONE);
}
left = sizeof(output) - (p - output) - 1;
}
left = sizeof(output) - (p - output) - 1;
- l = snprintf(p, left, ": [%s] [%s] [%s/%s/%s /s] [%s/%s/%s iops] [eta %s]",
+ if (je->rate[DDIR_TRIM] || je->iops[DDIR_TRIM])
+ l = snprintf(p, left,
+ ": [%s][%s][r=%s,w=%s,t=%s][r=%s,w=%s,t=%s IOPS][eta %s]",
je->run_str, perc_str, rate_str[DDIR_READ],
rate_str[DDIR_WRITE], rate_str[DDIR_TRIM],
iops_str[DDIR_READ], iops_str[DDIR_WRITE],
iops_str[DDIR_TRIM], eta_str);
je->run_str, perc_str, rate_str[DDIR_READ],
rate_str[DDIR_WRITE], rate_str[DDIR_TRIM],
iops_str[DDIR_READ], iops_str[DDIR_WRITE],
iops_str[DDIR_TRIM], eta_str);
+ else
+ l = snprintf(p, left,
+ ": [%s][%s][r=%s,w=%s][r=%s,w=%s IOPS][eta %s]",
+ je->run_str, perc_str,
+ rate_str[DDIR_READ], rate_str[DDIR_WRITE],
+ iops_str[DDIR_READ], iops_str[DDIR_WRITE],
+ eta_str);
p += l;
if (l >= 0 && l < linelen_last)
p += sprintf(p, "%*s", linelen_last - l, "");
p += l;
if (l >= 0 && l < linelen_last)
p += sprintf(p, "%*s", linelen_last - l, "");
extern int initialize_fio(char *envp[]);
extern void deinitialize_fio(void);
extern int initialize_fio(char *envp[]);
extern void deinitialize_fio(void);
+#define N2S_NONE 0
+#define N2S_BITPERSEC 1 /* match unit_base for bit rates */
+#define N2S_PERSEC 2
+#define N2S_BIT 3
+#define N2S_BYTE 4
+#define N2S_BYTEPERSEC 8 /* match unit_base for byte rates */
+
#define FIO_GETOPT_JOB 0x89000000
#define FIO_GETOPT_IOENGINE 0x98000000
#define FIO_NR_OPTIONS (FIO_MAX_OPTS + 128)
#define FIO_GETOPT_JOB 0x89000000
#define FIO_GETOPT_IOENGINE 0x98000000
#define FIO_NR_OPTIONS (FIO_MAX_OPTS + 128)
if (je->eta_sec != INT_MAX && je->nr_running) {
char *iops_str[DDIR_RWDIR_CNT];
char *rate_str[DDIR_RWDIR_CNT];
if (je->eta_sec != INT_MAX && je->nr_running) {
char *iops_str[DDIR_RWDIR_CNT];
char *rate_str[DDIR_RWDIR_CNT];
+ char *rate_alt[DDIR_RWDIR_CNT];
+ char tmp[128];
int i;
if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
int i;
if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
sprintf(output, "%3.1f%% done", perc);
}
sprintf(output, "%3.1f%% done", perc);
}
- rate_str[0] = num2str(je->rate[0], 5, 10, i2p, 0);
- rate_str[1] = num2str(je->rate[1], 5, 10, i2p, 0);
- rate_str[2] = num2str(je->rate[2], 5, 10, i2p, 0);
+ iops_str[0] = num2str(je->iops[0], 4, 1, 0, N2S_PERSEC);
+ iops_str[1] = num2str(je->iops[1], 4, 1, 0, N2S_PERSEC);
+ iops_str[2] = num2str(je->iops[2], 4, 1, 0, N2S_PERSEC);
- iops_str[0] = num2str(je->iops[0], 4, 1, 0, 0);
- iops_str[1] = num2str(je->iops[1], 4, 1, 0, 0);
- iops_str[2] = num2str(je->iops[2], 4, 1, 0, 0);
-
- gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), rate_str[0]);
+ rate_str[0] = num2str(je->rate[0], 4, 10, i2p, N2S_BYTEPERSEC);
+ rate_alt[0] = num2str(je->rate[0], 4, 10, !i2p, N2S_BYTEPERSEC);
+ snprintf(tmp, sizeof(tmp), "%s (%s)", rate_str[0], rate_alt[0]);
+ gtk_entry_set_text(GTK_ENTRY(ge->eta.read_bw), tmp);
gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), iops_str[0]);
gtk_entry_set_text(GTK_ENTRY(ge->eta.read_iops), iops_str[0]);
- gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), rate_str[1]);
+
+ rate_str[1] = num2str(je->rate[1], 4, 10, i2p, N2S_BYTEPERSEC);
+ rate_alt[1] = num2str(je->rate[1], 4, 10, !i2p, N2S_BYTEPERSEC);
+ snprintf(tmp, sizeof(tmp), "%s (%s)", rate_str[1], rate_alt[1]);
+ gtk_entry_set_text(GTK_ENTRY(ge->eta.write_bw), tmp);
gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), iops_str[1]);
gtk_entry_set_text(GTK_ENTRY(ge->eta.write_iops), iops_str[1]);
- gtk_entry_set_text(GTK_ENTRY(ge->eta.trim_bw), rate_str[2]);
+
+ rate_str[2] = num2str(je->rate[2], 4, 10, i2p, N2S_BYTEPERSEC);
+ rate_alt[2] = num2str(je->rate[2], 4, 10, !i2p, N2S_BYTEPERSEC);
+ snprintf(tmp, sizeof(tmp), "%s (%s)", rate_str[2], rate_alt[2]);
+ gtk_entry_set_text(GTK_ENTRY(ge->eta.trim_bw), tmp);
gtk_entry_set_text(GTK_ENTRY(ge->eta.trim_iops), iops_str[2]);
graph_add_xy_data(ge->graphs.iops_graph, ge->graphs.read_iops, je->elapsed_sec, je->iops[0], iops_str[0]);
gtk_entry_set_text(GTK_ENTRY(ge->eta.trim_iops), iops_str[2]);
graph_add_xy_data(ge->graphs.iops_graph, ge->graphs.read_iops, je->elapsed_sec, je->iops[0], iops_str[0]);
for (i = 0; i < DDIR_RWDIR_CNT; i++) {
free(rate_str[i]);
for (i = 0; i < DDIR_RWDIR_CNT; i++) {
free(rate_str[i]);
entry_set_int_value(ui->eta.jobs, je->nr_running);
if (je->eta_sec != INT_MAX && je->nr_running) {
entry_set_int_value(ui->eta.jobs, je->nr_running);
if (je->eta_sec != INT_MAX && je->nr_running) {
- char *iops_str[3];
- char *rate_str[3];
+ char *iops_str[DDIR_RWDIR_CNT];
+ char *rate_str[DDIR_RWDIR_CNT];
+ char *rate_alt[DDIR_RWDIR_CNT];
+ char tmp[128];
if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
strcpy(output, "-.-% done");
if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running)
strcpy(output, "-.-% done");
sprintf(output, "%3.1f%% done", perc);
}
sprintf(output, "%3.1f%% done", perc);
}
- rate_str[0] = num2str(je->rate[0], 5, 10, i2p, 0);
- rate_str[1] = num2str(je->rate[1], 5, 10, i2p, 0);
- rate_str[2] = num2str(je->rate[2], 5, 10, i2p, 0);
-
- iops_str[0] = num2str(je->iops[0], 4, 1, 0, 0);
- iops_str[1] = num2str(je->iops[1], 4, 1, 0, 0);
- iops_str[2] = num2str(je->iops[2], 4, 1, 0, 0);
+ iops_str[0] = num2str(je->iops[0], 4, 1, 0, N2S_PERSEC);
+ iops_str[1] = num2str(je->iops[1], 4, 1, 0, N2S_PERSEC);
+ iops_str[2] = num2str(je->iops[2], 4, 1, 0, N2S_PERSEC);
- gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), rate_str[0]);
+ rate_str[0] = num2str(je->rate[0], 4, 10, i2p, N2S_BYTEPERSEC);
+ rate_alt[0] = num2str(je->rate[0], 4, 10, !i2p, N2S_BYTEPERSEC);
+ snprintf(tmp, sizeof(tmp), "%s (%s)", rate_str[0], rate_alt[0]);
+ gtk_entry_set_text(GTK_ENTRY(ui->eta.read_bw), tmp);
gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), iops_str[0]);
gtk_entry_set_text(GTK_ENTRY(ui->eta.read_iops), iops_str[0]);
- gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), rate_str[1]);
+
+ rate_str[1] = num2str(je->rate[1], 4, 10, i2p, N2S_BYTEPERSEC);
+ rate_alt[1] = num2str(je->rate[1], 4, 10, !i2p, N2S_BYTEPERSEC);
+ snprintf(tmp, sizeof(tmp), "%s (%s)", rate_str[1], rate_alt[1]);
+ gtk_entry_set_text(GTK_ENTRY(ui->eta.write_bw), tmp);
gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), iops_str[1]);
gtk_entry_set_text(GTK_ENTRY(ui->eta.write_iops), iops_str[1]);
- gtk_entry_set_text(GTK_ENTRY(ui->eta.trim_bw), rate_str[2]);
+
+ rate_str[2] = num2str(je->rate[2], 4, 10, i2p, N2S_BYTEPERSEC);
+ rate_alt[2] = num2str(je->rate[2], 4, 10, !i2p, N2S_BYTEPERSEC);
+ snprintf(tmp, sizeof(tmp), "%s (%s)", rate_str[2], rate_alt[2]);
+ gtk_entry_set_text(GTK_ENTRY(ui->eta.trim_bw), tmp);
gtk_entry_set_text(GTK_ENTRY(ui->eta.trim_iops), iops_str[2]);
graph_add_xy_data(ui->graphs.iops_graph, ui->graphs.read_iops, je->elapsed_sec, je->iops[0], iops_str[0]);
gtk_entry_set_text(GTK_ENTRY(ui->eta.trim_iops), iops_str[2]);
graph_add_xy_data(ui->graphs.iops_graph, ui->graphs.read_iops, je->elapsed_sec, je->iops[0], iops_str[0]);
for (i = 0; i < DDIR_RWDIR_CNT; i++) {
free(rate_str[i]);
for (i = 0; i < DDIR_RWDIR_CNT; i++) {
free(rate_str[i]);
struct thread_options *o;
char *c1, *c2, *c3, *c4;
char tmp[80];
struct thread_options *o;
char *c1, *c2, *c3, *c4;
char tmp[80];
p->thread_number = le32_to_cpu(p->thread_number);
p->groupid = le32_to_cpu(p->groupid);
p->thread_number = le32_to_cpu(p->thread_number);
p->groupid = le32_to_cpu(p->groupid);
sprintf(tmp, "%s %s", o->odirect ? "direct" : "buffered", ddir_str(o->td_ddir));
multitext_add_entry(&ge->eta.iotype, tmp);
sprintf(tmp, "%s %s", o->odirect ? "direct" : "buffered", ddir_str(o->td_ddir));
multitext_add_entry(&ge->eta.iotype, tmp);
- c1 = fio_uint_to_kmg(o->min_bs[DDIR_READ]);
- c2 = fio_uint_to_kmg(o->max_bs[DDIR_WRITE]);
- c3 = fio_uint_to_kmg(o->min_bs[DDIR_READ]);
- c4 = fio_uint_to_kmg(o->max_bs[DDIR_WRITE]);
- sprintf(tmp, "%s-%s/%s-%s", c1, c2, c3, c4);
+ i2p = is_power_of_2(o->kb_base);
+ c1 = num2str(o->min_bs[DDIR_READ], 4, 1, i2p, N2S_BYTE);
+ c2 = num2str(o->max_bs[DDIR_READ], 4, 1, i2p, N2S_BYTE);
+ c3 = num2str(o->min_bs[DDIR_WRITE], 4, 1, i2p, N2S_BYTE);
+ c4 = num2str(o->max_bs[DDIR_WRITE], 4, 1, i2p, N2S_BYTE);
+
+ sprintf(tmp, "%s-%s,%s-%s", c1, c2, c3, c4);
free(c1);
free(c2);
free(c3);
free(c1);
free(c2);
free(c3);
if (usec_to_msec(&min, &max, &mean, &dev))
base = "(msec)";
if (usec_to_msec(&min, &max, &mean, &dev))
base = "(msec)";
- minp = num2str(min, 6, 1, 0, 0);
- maxp = num2str(max, 6, 1, 0, 0);
+ minp = num2str(min, 6, 1, 0, N2S_NONE);
+ maxp = num2str(max, 6, 1, 0, N2S_NONE);
sprintf(tmp, "%s %s", name, base);
frame = gtk_frame_new(tmp);
sprintf(tmp, "%s %s", name, base);
frame = gtk_frame_new(tmp);
unsigned long long bw, iops;
unsigned int flags = 0;
double mean[3], dev[3];
unsigned long long bw, iops;
unsigned int flags = 0;
double mean[3], dev[3];
- char *io_p, *bw_p, *iops_p;
+ char *io_p, *io_palt, *bw_p, *bw_palt, *iops_p;
+ char tmp[128];
int i2p;
if (!ts->runtime[ddir])
int i2p;
if (!ts->runtime[ddir])
runt = ts->runtime[ddir];
bw = (1000 * ts->io_bytes[ddir]) / runt;
runt = ts->runtime[ddir];
bw = (1000 * ts->io_bytes[ddir]) / runt;
- 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 = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
- iops_p = num2str(iops, 6, 1, 0, 0);
+ iops_p = num2str(iops, 4, 1, 0, N2S_PERSEC);
box = gtk_hbox_new(FALSE, 3);
gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
box = gtk_hbox_new(FALSE, 3);
gtk_box_pack_start(GTK_BOX(mbox), box, TRUE, FALSE, 3);
gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
label = new_info_label_in_frame(box, "IO");
gtk_box_pack_start(GTK_BOX(main_vbox), box, TRUE, FALSE, 3);
label = new_info_label_in_frame(box, "IO");
- gtk_label_set_text(GTK_LABEL(label), io_p);
+ io_p = num2str(ts->io_bytes[ddir], 4, 1, i2p, N2S_BYTE);
+ io_palt = num2str(ts->io_bytes[ddir], 4, 1, !i2p, N2S_BYTE);
+ snprintf(tmp, sizeof(tmp), "%s (%s)", io_p, io_palt);
+ gtk_label_set_text(GTK_LABEL(label), tmp);
+
label = new_info_label_in_frame(box, "Bandwidth");
label = new_info_label_in_frame(box, "Bandwidth");
- gtk_label_set_text(GTK_LABEL(label), bw_p);
+ bw_p = num2str(bw, 4, 1, i2p, ts->unit_base);
+ bw_palt = num2str(bw, 4, 1, !i2p, ts->unit_base);
+ snprintf(tmp, sizeof(tmp), "%s (%s)", bw_p, bw_palt);
+ gtk_label_set_text(GTK_LABEL(label), tmp);
+
label = new_info_label_in_frame(box, "IOPS");
gtk_label_set_text(GTK_LABEL(label), iops_p);
label = new_info_label_in_frame(box, "Runtime (msec)");
label = new_info_label_in_frame(box, "IOPS");
gtk_label_set_text(GTK_LABEL(label), iops_p);
label = new_info_label_in_frame(box, "Runtime (msec)");
if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
double p_of_agg = 100.0;
if (calc_lat(&ts->bw_stat[ddir], &min[0], &max[0], &mean[0], &dev[0])) {
double p_of_agg = 100.0;
- const char *bw_str = "KB";
+ const char *bw_str = "KiB/s";
char tmp[32];
if (rs->agg[ddir]) {
char tmp[32];
if (rs->agg[ddir]) {
- if (mean[0] > 999999.9) {
- min[0] /= 1000.0;
- max[0] /= 1000.0;
- mean[0] /= 1000.0;
- dev[0] /= 1000.0;
- bw_str = "MB";
+ if (mean[0] > 1073741824.9) {
+ min[0] /= 1048576.0;
+ max[0] /= 1048576.0;
+ mean[0] /= 1048576.0;
+ dev[0] /= 1048576.0;
+ bw_str = "GiB/s";
+ if (mean[0] > 1047575.9) {
+ min[0] /= 1024.0;
+ max[0] /= 1024.0;
+ mean[0] /= 1024.0;
+ dev[0] /= 1024.0;
+ bw_str = "MiB/s";
+ }
sprintf(tmp, "Bandwidth (%s)", bw_str);
frame = gtk_frame_new(tmp);
gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
sprintf(tmp, "Bandwidth (%s)", bw_str);
frame = gtk_frame_new(tmp);
gtk_box_pack_start(GTK_BOX(main_vbox), frame, FALSE, FALSE, 5);
+ free(io_palt);
+ free(bw_palt);
#include "oslib/strcasestr.h"
#include "crc/test.h"
#include "oslib/strcasestr.h"
#include "crc/test.h"
const char fio_version_string[] = FIO_VERSION;
const char fio_version_string[] = FIO_VERSION;
-/*
- * This function leaks the buffer
- */
-char *fio_uint_to_kmg(unsigned int val)
-{
- char *buf = malloc(32);
- char post[] = { 0, 'K', 'M', 'G', 'P', 'E', 0 };
- char *p = post;
-
- do {
- if (val & 1023)
- break;
-
- val >>= 10;
- p++;
- } while (*p);
-
- snprintf(buf, 32, "%u%c", val, *p);
- return buf;
-}
-
/* External engines are specified by "external:name.o") */
static const char *get_engine_name(const char *str)
{
/* External engines are specified by "external:name.o") */
static const char *get_engine_name(const char *str)
{
if (!td_ioengine_flagged(td, FIO_NOIO)) {
char *c1, *c2, *c3, *c4;
char *c5 = NULL, *c6 = NULL;
if (!td_ioengine_flagged(td, FIO_NOIO)) {
char *c1, *c2, *c3, *c4;
char *c5 = NULL, *c6 = NULL;
+ int i2p = is_power_of_2(o->kb_base);
- c1 = fio_uint_to_kmg(o->min_bs[DDIR_READ]);
- c2 = fio_uint_to_kmg(o->max_bs[DDIR_READ]);
- c3 = fio_uint_to_kmg(o->min_bs[DDIR_WRITE]);
- c4 = fio_uint_to_kmg(o->max_bs[DDIR_WRITE]);
+ c1 = num2str(o->min_bs[DDIR_READ], 4, 1, i2p, N2S_BYTE);
+ c2 = num2str(o->max_bs[DDIR_READ], 4, 1, i2p, N2S_BYTE);
+ c3 = num2str(o->min_bs[DDIR_WRITE], 4, 1, i2p, N2S_BYTE);
+ c4 = num2str(o->max_bs[DDIR_WRITE], 4, 1, i2p, N2S_BYTE);
if (!o->bs_is_seq_rand) {
if (!o->bs_is_seq_rand) {
- c5 = fio_uint_to_kmg(o->min_bs[DDIR_TRIM]);
- c6 = fio_uint_to_kmg(o->max_bs[DDIR_TRIM]);
+ c5 = num2str(o->min_bs[DDIR_TRIM], 4, 1, i2p, N2S_BYTE);
+ c6 = num2str(o->max_bs[DDIR_TRIM], 4, 1, i2p, N2S_BYTE);
}
log_info("%s: (g=%d): rw=%s, ", td->o.name,
}
log_info("%s: (g=%d): rw=%s, ", td->o.name,
ddir_str(o->td_ddir));
if (o->bs_is_seq_rand)
ddir_str(o->td_ddir));
if (o->bs_is_seq_rand)
- log_info("bs(seq/rand)=%s-%s/%s-%s, ",
+ log_info("bs=%s-%s,%s-%s, bs_is_seq_rand, ",
- log_info("bs=%s-%s/%s-%s/%s-%s, ",
+ log_info("bs=%s-%s,%s-%s,%s-%s, ",
c1, c2, c3, c4, c5, c6);
log_info("ioengine=%s, iodepth=%u\n",
c1, c2, c3, c4, c5, c6);
log_info("ioengine=%s, iodepth=%u\n",
#define ARRAY_LENGTH(arr) sizeof(arr) / sizeof((arr)[0])
#define ARRAY_LENGTH(arr) sizeof(arr) / sizeof((arr)[0])
-/*
- * Cheesy number->string conversion, complete with carry rounding error.
+/**
+ * num2str() - Cheesy number->string conversion, complete with carry rounding error.
+ * @num: quantity (e.g., number of blocks, bytes or bits)
+ * @maxlen: max number of digits in the output string (not counting prefix and units)
+ * @base: multiplier for num (e.g., if num represents Ki, use 1024)
+ * @pow2: select unit prefix - 0=power-of-10 decimal SI, nonzero=power-of-2 binary IEC
+ * @units: select units - N2S_* macros defined in fio.h
+ * @returns a malloc'd buffer containing "number[<unit prefix>][<units>]"
-char *num2str(uint64_t num, int maxlen, int base, int pow2, int unit_base)
+char *num2str(uint64_t num, int maxlen, int base, int pow2, int units)
- const char *postfix[] = { "", "K", "M", "G", "P", "E" };
- const char *byte_postfix[] = { "", "B", "bit" };
+ const char *sistr[] = { "", "k", "M", "G", "T", "P" };
+ const char *iecstr[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi" };
+ const char **unitprefix;
+ const char *unitstr[] = { "", "/s", "B", "bit", "B/s", "bit/s" };
const unsigned int thousand[] = { 1000, 1024 };
unsigned int modulo, decimals;
const unsigned int thousand[] = { 1000, 1024 };
unsigned int modulo, decimals;
- int byte_post_index = 0, post_index, carry = 0;
+ int unit_index = 0, post_index, carry = 0;
+ compiletime_assert(sizeof(sistr) == sizeof(iecstr), "unit prefix arrays must be identical sizes");
+
+ if (!buf)
+ return NULL;
+
+ if (pow2)
+ unitprefix = iecstr;
+ else
+ unitprefix = sistr;
for (post_index = 0; base > 1; post_index++)
base /= thousand[!!pow2];
for (post_index = 0; base > 1; post_index++)
base /= thousand[!!pow2];
- switch (unit_base) {
- case 1:
- byte_post_index = 2;
+ switch (units) {
+ case N2S_PERSEC:
+ unit_index = 1;
+ break;
+ case N2S_BYTE:
+ unit_index = 2;
+ break;
+ case N2S_BIT:
+ unit_index = 3;
- case 8:
- byte_post_index = 1;
+ case N2S_BYTEPERSEC:
+ unit_index = 4;
+ break;
+ case N2S_BITPERSEC:
+ unit_index = 5;
+ num *= 8;
- while (post_index < sizeof(postfix)) {
+ while (post_index < sizeof(sistr)) {
sprintf(tmp, "%llu", (unsigned long long) num);
if (strlen(tmp) <= maxlen)
break;
sprintf(tmp, "%llu", (unsigned long long) num);
if (strlen(tmp) <= maxlen)
break;
if (modulo == -1U) {
done:
if (modulo == -1U) {
done:
- if (post_index >= ARRAY_LENGTH(postfix))
+ if (post_index >= ARRAY_LENGTH(sistr))
post_index = 0;
sprintf(buf, "%llu%s%s", (unsigned long long) num,
post_index = 0;
sprintf(buf, "%llu%s%s", (unsigned long long) num,
- postfix[post_index], byte_postfix[byte_post_index]);
+ unitprefix[post_index], unitstr[unit_index]);
} while (1);
sprintf(buf, "%llu.%u%s%s", (unsigned long long) num, modulo,
} while (1);
sprintf(buf, "%llu.%u%s%s", (unsigned long long) num, modulo,
- postfix[post_index], byte_postfix[byte_post_index]);
+ unitprefix[post_index], unitstr[unit_index]);
.posval = {
{ .ival = "1024",
.oval = 1024,
.posval = {
{ .ival = "1024",
.oval = 1024,
- .help = "Use 1024 as the K base",
+ .help = "Inputs invert IEC and SI prefixes (for compatibility); outputs prefer binary",
},
{ .ival = "1000",
.oval = 1000,
},
{ .ival = "1000",
.oval = 1000,
- .help = "Use 1000 as the K base",
+ .help = "Inputs use IEC and SI prefixes; outputs prefer SI",
- .help = "How many bytes per KB for reporting (1000 or 1024)",
+ .help = "Unit prefix interpretation for quantities of data (IEC and SI)",
.category = FIO_OPT_C_GENERAL,
.group = FIO_OPT_G_INVALID,
},
{
.name = "unit_base",
.category = FIO_OPT_C_GENERAL,
.group = FIO_OPT_G_INVALID,
},
{
.name = "unit_base",
- .lname = "Base unit for reporting (Bits or Bytes)",
+ .lname = "Unit for quantities of data (Bits or Bytes)",
.type = FIO_OPT_INT,
.off1 = offsetof(struct thread_options, unit_base),
.prio = 1,
.type = FIO_OPT_INT,
.off1 = offsetof(struct thread_options, unit_base),
.prio = 1,
+ /* If kb_base is 1000, use true units.
+ * If kb_base is 1024, use opposite units.
+ */
if (!strncmp("pib", c, 3)) {
pow = 5;
if (!strncmp("pib", c, 3)) {
pow = 5;
+ if (kb_base == 1000)
+ mult = 1024;
+ else if (kb_base == 1024)
+ mult = 1000;
} else if (!strncmp("tib", c, 3)) {
pow = 4;
} else if (!strncmp("tib", c, 3)) {
pow = 4;
+ if (kb_base == 1000)
+ mult = 1024;
+ else if (kb_base == 1024)
+ mult = 1000;
} else if (!strncmp("gib", c, 3)) {
pow = 3;
} else if (!strncmp("gib", c, 3)) {
pow = 3;
+ if (kb_base == 1000)
+ mult = 1024;
+ else if (kb_base == 1024)
+ mult = 1000;
} else if (!strncmp("mib", c, 3)) {
pow = 2;
} else if (!strncmp("mib", c, 3)) {
pow = 2;
+ if (kb_base == 1000)
+ mult = 1024;
+ else if (kb_base == 1024)
+ mult = 1000;
} else if (!strncmp("kib", c, 3)) {
pow = 1;
} else if (!strncmp("kib", c, 3)) {
pow = 1;
- mult = 1000;
- } else if (!strncmp("p", c, 1) || !strncmp("pb", c, 2))
+ if (kb_base == 1000)
+ mult = 1024;
+ else if (kb_base == 1024)
+ mult = 1000;
+ } else if (!strncmp("p", c, 1) || !strncmp("pb", c, 2)) {
- else if (!strncmp("t", c, 1) || !strncmp("tb", c, 2))
+ } else if (!strncmp("t", c, 1) || !strncmp("tb", c, 2)) {
- else if (!strncmp("g", c, 1) || !strncmp("gb", c, 2))
+ } else if (!strncmp("g", c, 1) || !strncmp("gb", c, 2)) {
- else if (!strncmp("m", c, 1) || !strncmp("mb", c, 2))
+ } else if (!strncmp("m", c, 1) || !strncmp("mb", c, 2)) {
- else if (!strncmp("k", c, 1) || !strncmp("kb", c, 2))
+ } else if (!strncmp("k", c, 1) || !strncmp("kb", c, 2)) {
- else if (!strncmp("%", c, 1)) {
+ } else if (!strncmp("%", c, 1)) {
*percent = 1;
free(c);
return ret;
*percent = 1;
free(c);
return ret;
void show_group_stats(struct group_run_stats *rs, struct buf_output *out)
{
void show_group_stats(struct group_run_stats *rs, struct buf_output *out)
{
- char *p1, *p2, *p3, *p4;
+ char *io, *agg, *min, *max;
+ char *ioalt, *aggalt, *minalt, *maxalt;
const char *str[] = { " READ", " WRITE" , " TRIM"};
int i;
const char *str[] = { " READ", " WRITE" , " TRIM"};
int i;
if (!rs->max_run[i])
continue;
if (!rs->max_run[i])
continue;
- p1 = num2str(rs->iobytes[i], 6, 1, i2p, 8);
- p2 = num2str(rs->agg[i], 6, 1, i2p, rs->unit_base);
- p3 = num2str(rs->min_bw[i], 6, 1, i2p, rs->unit_base);
- p4 = num2str(rs->max_bw[i], 6, 1, i2p, rs->unit_base);
-
- log_buf(out, "%s: io=%s, aggrb=%s/s, minb=%s/s, maxb=%s/s,"
- " mint=%llumsec, maxt=%llumsec\n",
+ io = num2str(rs->iobytes[i], 4, 1, i2p, N2S_BYTE);
+ ioalt = num2str(rs->iobytes[i], 4, 1, !i2p, N2S_BYTE);
+ agg = num2str(rs->agg[i], 4, 1, i2p, rs->unit_base);
+ aggalt = num2str(rs->agg[i], 4, 1, !i2p, rs->unit_base);
+ min = num2str(rs->min_bw[i], 4, 1, i2p, rs->unit_base);
+ minalt = num2str(rs->min_bw[i], 4, 1, !i2p, rs->unit_base);
+ max = num2str(rs->max_bw[i], 4, 1, i2p, rs->unit_base);
+ maxalt = num2str(rs->max_bw[i], 4, 1, !i2p, rs->unit_base);
+ log_buf(out, "%s: bw=%s (%s), %s-%s (%s-%s), io=%s (%s), run=%llu-%llumsec\n",
rs->unified_rw_rep ? " MIXED" : str[i],
rs->unified_rw_rep ? " MIXED" : str[i],
+ agg, aggalt, min, max, minalt, maxalt, io, ioalt,
(unsigned long long) rs->min_run[i],
(unsigned long long) rs->max_run[i]);
(unsigned long long) rs->min_run[i],
(unsigned long long) rs->max_run[i]);
- free(p1);
- free(p2);
- free(p3);
- free(p4);
+ free(io);
+ free(agg);
+ free(min);
+ free(max);
+ free(ioalt);
+ free(aggalt);
+ free(minalt);
+ free(maxalt);
if (usec_to_msec(&min, &max, &mean, &dev))
base = "(msec)";
if (usec_to_msec(&min, &max, &mean, &dev))
base = "(msec)";
- minp = num2str(min, 6, 1, 0, 0);
- maxp = num2str(max, 6, 1, 0, 0);
+ minp = num2str(min, 6, 1, 0, N2S_NONE);
+ maxp = num2str(max, 6, 1, 0, N2S_NONE);
log_buf(out, " %s %s: min=%s, max=%s, avg=%5.02f,"
" stdev=%5.02f\n", name, base, minp, maxp, mean, dev);
log_buf(out, " %s %s: min=%s, max=%s, avg=%5.02f,"
" stdev=%5.02f\n", name, base, minp, maxp, mean, dev);
unsigned long min, max, runt;
unsigned long long bw, iops;
double mean, dev;
unsigned long min, max, runt;
unsigned long long bw, iops;
double mean, dev;
- char *io_p, *bw_p, *iops_p;
+ char *io_p, *bw_p, *bw_p_alt, *iops_p;
int i2p;
assert(ddir_rw(ddir));
int i2p;
assert(ddir_rw(ddir));
runt = ts->runtime[ddir];
bw = (1000 * ts->io_bytes[ddir]) / runt;
runt = ts->runtime[ddir];
bw = (1000 * ts->io_bytes[ddir]) / runt;
- io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p, 8);
- bw_p = num2str(bw, 6, 1, i2p, ts->unit_base);
+ io_p = num2str(ts->io_bytes[ddir], 4, 1, i2p, N2S_BYTE);
+ bw_p = num2str(bw, 4, 1, i2p, ts->unit_base);
+ bw_p_alt = num2str(bw, 4, 1, !i2p, ts->unit_base);
iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
- iops_p = num2str(iops, 6, 1, 0, 0);
+ iops_p = num2str(iops, 4, 1, 0, N2S_NONE);
- log_buf(out, " %s: io=%s, bw=%s/s, iops=%s, runt=%6llumsec\n",
- rs->unified_rw_rep ? "mixed" : str[ddir],
- io_p, bw_p, iops_p,
- (unsigned long long) ts->runtime[ddir]);
+ log_buf(out, " %s: IOPS=%s, BW=%s (%s)(%s/%llumsec)\n",
+ rs->unified_rw_rep ? "mixed" : str[ddir],
+ iops_p, bw_p, bw_p_alt, io_p,
+ (unsigned long long) ts->runtime[ddir]);
free(iops_p);
if (calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev))
free(iops_p);
if (calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev))
}
if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
double p_of_agg = 100.0, fkb_base = (double)rs->kb_base;
}
if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
double p_of_agg = 100.0, fkb_base = (double)rs->kb_base;
- const char *bw_str = (rs->unit_base == 1 ? "Kbit" : "KB");
+ const char *bw_str;
+
+ if ((rs->unit_base == 1) && i2p)
+ bw_str = "Kibit";
+ else if (rs->unit_base == 1)
+ bw_str = "kbit";
+ else if (i2p)
+ bw_str = "KiB";
+ else
+ bw_str = "kB";
if (rs->unit_base == 1) {
min *= 8.0;
if (rs->unit_base == 1) {
min *= 8.0;
max /= fkb_base;
mean /= fkb_base;
dev /= fkb_base;
max /= fkb_base;
mean /= fkb_base;
dev /= fkb_base;
- bw_str = (rs->unit_base == 1 ? "Mbit" : "MB");
+ bw_str = (rs->unit_base == 1 ? "Mibit" : "MiB");
- log_buf(out, " 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);
+ log_buf(out, " bw (%5s/s): min=%5lu, max=%5lu, per=%3.2f%%, avg=%5.02f, stdev=%5.02f\n",
+ bw_str, min, max, p_of_agg, mean, dev);
static void show_ss_normal(struct thread_stat *ts, struct buf_output *out)
{
static void show_ss_normal(struct thread_stat *ts, struct buf_output *out)
{
unsigned long long bw_mean, iops_mean;
const int i2p = is_power_of_2(ts->kb_base);
unsigned long long bw_mean, iops_mean;
const int i2p = is_power_of_2(ts->kb_base);
bw_mean = steadystate_bw_mean(ts);
iops_mean = steadystate_iops_mean(ts);
bw_mean = steadystate_bw_mean(ts);
iops_mean = steadystate_iops_mean(ts);
- p1 = num2str(bw_mean / ts->kb_base, 6, ts->kb_base, i2p, ts->unit_base);
- p2 = num2str(iops_mean, 6, 1, 0, 0);
+ p1 = num2str(bw_mean / ts->kb_base, 4, ts->kb_base, i2p, ts->unit_base);
+ p1alt = num2str(bw_mean / ts->kb_base, 4, ts->kb_base, !i2p, ts->unit_base);
+ p2 = num2str(iops_mean, 4, 1, 0, N2S_NONE);
- log_buf(out, " steadystate : attained=%s, bw=%s/s, iops=%s, %s%s=%.3f%s\n",
+ log_buf(out, " steadystate : attained=%s, bw=%s (%s), iops=%s, %s%s=%.3f%s\n",
ts->ss_state & __FIO_SS_ATTAINED ? "yes" : "no",
ts->ss_state & __FIO_SS_ATTAINED ? "yes" : "no",
ts->ss_state & __FIO_SS_IOPS ? "iops" : "bw",
ts->ss_state & __FIO_SS_SLOPE ? " slope": " mean dev",
ts->ss_criterion.u.f,
ts->ss_state & __FIO_SS_PCT ? "%" : "");
free(p1);
ts->ss_state & __FIO_SS_IOPS ? "iops" : "bw",
ts->ss_state & __FIO_SS_SLOPE ? " slope": " mean dev",
ts->ss_criterion.u.f,
ts->ss_state & __FIO_SS_PCT ? "%" : "");
free(p1);
io_u_dist[1], io_u_dist[2],
io_u_dist[3], io_u_dist[4],
io_u_dist[5], io_u_dist[6]);
io_u_dist[1], io_u_dist[2],
io_u_dist[3], io_u_dist[4],
io_u_dist[5], io_u_dist[6]);
- log_buf(out, " issued : total=r=%llu/w=%llu/d=%llu,"
- " short=r=%llu/w=%llu/d=%llu,"
- " drop=r=%llu/w=%llu/d=%llu\n",
+ log_buf(out, " issued rwt: total=%llu,%llu,%llu,"
+ " short=%llu,%llu,%llu,"
+ " dropped=%llu,%llu,%llu\n",
(unsigned long long) ts->total_io_u[0],
(unsigned long long) ts->total_io_u[1],
(unsigned long long) ts->total_io_u[2],
(unsigned long long) ts->total_io_u[0],
(unsigned long long) ts->total_io_u[1],
(unsigned long long) ts->total_io_u[2],