* Status and ETA code
*/
#include <unistd.h>
-#include <fcntl.h>
#include <string.h>
+#include <stdlib.h>
+#ifdef CONFIG_VALGRIND_DEV
+#include <valgrind/drd.h>
+#else
+#define DRD_IGNORE_VAR(x) do { } while (0)
+#endif
#include "fio.h"
#include "lib/pow2.h"
static char __run_str[REAL_MAX_JOBS + 1];
-static char run_str[__THREAD_RUNSTR_SZ(REAL_MAX_JOBS)];
+static char run_str[__THREAD_RUNSTR_SZ(REAL_MAX_JOBS) + 1];
static void update_condensed_str(char *rstr, char *run_str_condensed)
{
str += sprintf(str, "%02uh:", h);
str += sprintf(str, "%02um:", m);
- str += sprintf(str, "%02us", s);
+ sprintf(str, "%02us", s);
}
/*
bytes_total = td->fill_device_size;
}
- if (td->o.zone_size && td->o.zone_skip && bytes_total) {
+ /*
+ * If io_size is set, bytes_total is an exact value that does not need
+ * adjustment.
+ */
+ if (td->o.zone_size && td->o.zone_skip && bytes_total &&
+ !fio_option_is_set(&td->o, io_size)) {
unsigned int nr_zones;
uint64_t zone_bytes;
- zone_bytes = bytes_total + td->o.zone_size + td->o.zone_skip;
- nr_zones = (zone_bytes - 1) / (td->o.zone_size + td->o.zone_skip);
+ /*
+ * Calculate the upper bound of the number of zones that will
+ * be processed, including skipped bytes between zones. If this
+ * is larger than total_io_size (e.g. when --io_size or --size
+ * specify a small value), use the lower bound to avoid
+ * adjustments to a negative value that would result in a very
+ * large bytes_total and an incorrect eta.
+ */
+ zone_bytes = td->o.zone_size + td->o.zone_skip;
+ nr_zones = (bytes_total + zone_bytes - 1) / zone_bytes;
+ if (bytes_total < nr_zones * td->o.zone_skip)
+ nr_zones = bytes_total / zone_bytes;
bytes_total -= nr_zones * td->o.zone_skip;
}
else
this_rate = 0;
- if (unified_rw_rep) {
+ if (unified_rw_rep == UNIFIED_MIXED) {
rate[i] = 0;
rate[0] += this_rate;
} else
else
this_iops = 0;
- if (unified_rw_rep) {
+ if (unified_rw_rep == UNIFIED_MIXED) {
iops[i] = 0;
iops[0] += this_iops;
} else
struct thread_data *td;
int i, unified_rw_rep;
uint64_t rate_time, disp_time, bw_avg_time, *eta_secs;
- unsigned long long io_bytes[DDIR_RWDIR_CNT];
- unsigned long long io_iops[DDIR_RWDIR_CNT];
+ unsigned long long io_bytes[DDIR_RWDIR_CNT] = {};
+ unsigned long long io_iops[DDIR_RWDIR_CNT] = {};
struct timespec now;
static unsigned long long rate_io_bytes[DDIR_RWDIR_CNT];
je->elapsed_sec = (mtime_since_genesis() + 999) / 1000;
- io_bytes[DDIR_READ] = io_bytes[DDIR_WRITE] = io_bytes[DDIR_TRIM] = 0;
- io_iops[DDIR_READ] = io_iops[DDIR_WRITE] = io_iops[DDIR_TRIM] = 0;
bw_avg_time = ULONG_MAX;
unified_rw_rep = 0;
for_each_td(td, i) {
if (is_power_of_2(td->o.kb_base))
je->is_pow2 = 1;
je->unit_base = td->o.unit_base;
+ je->sig_figs = td->o.sig_figs;
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
calc_rate(unified_rw_rep, rate_time, io_bytes, rate_io_bytes,
je->rate);
memcpy(&rate_prev_time, &now, sizeof(now));
- add_agg_sample(sample_val(je->rate[DDIR_READ]), DDIR_READ, 0);
- add_agg_sample(sample_val(je->rate[DDIR_WRITE]), DDIR_WRITE, 0);
- add_agg_sample(sample_val(je->rate[DDIR_TRIM]), DDIR_TRIM, 0);
+ regrow_agg_logs();
+ for_each_rw_ddir(ddir) {
+ add_agg_sample(sample_val(je->rate[ddir]), ddir, 0);
+ }
}
disp_time = mtime_since(&disp_prev_time, &now);
return true;
}
+static int gen_eta_str(struct jobs_eta *je, char *p, size_t left,
+ char **rate_str, char **iops_str)
+{
+ static const char c[DDIR_RWDIR_CNT] = {'r', 'w', 't'};
+ bool has[DDIR_RWDIR_CNT];
+ bool has_any = false;
+ const char *sep;
+ int l = 0;
+
+ for_each_rw_ddir(ddir) {
+ has[ddir] = (je->rate[ddir] || je->iops[ddir]);
+ has_any |= has[ddir];
+ }
+ if (!has_any)
+ return 0;
+
+ l += snprintf(p + l, left - l, "[");
+ sep = "";
+ for_each_rw_ddir(ddir) {
+ if (has[ddir]) {
+ l += snprintf(p + l, left - l, "%s%c=%s",
+ sep, c[ddir], rate_str[ddir]);
+ sep = ",";
+ }
+ }
+ l += snprintf(p + l, left - l, "][");
+ sep = "";
+ for_each_rw_ddir(ddir) {
+ if (has[ddir]) {
+ l += snprintf(p + l, left - l, "%s%c=%s",
+ sep, c[ddir], iops_str[ddir]);
+ sep = ",";
+ }
+ }
+ l += snprintf(p + l, left - l, " IOPS]");
+
+ return l;
+}
+
void display_thread_status(struct jobs_eta *je)
{
static struct timespec disp_eta_new_line;
static int eta_new_line_init, eta_new_line_pending;
static int linelen_last;
static int eta_good;
- char output[REAL_MAX_JOBS + 512], *p = output;
+ char output[__THREAD_RUNSTR_SZ(REAL_MAX_JOBS) + 512], *p = output;
char eta_str[128];
double perc = 0.0;
if (eta_new_line_pending) {
eta_new_line_pending = 0;
+ linelen_last = 0;
p += sprintf(p, "\n");
}
char *tr, *mr;
mr = num2str(je->m_rate[0] + je->m_rate[1] + je->m_rate[2],
- je->sig_figs, 0, je->is_pow2, N2S_BYTEPERSEC);
+ je->sig_figs, 1, je->is_pow2, N2S_BYTEPERSEC);
tr = num2str(je->t_rate[0] + je->t_rate[1] + je->t_rate[2],
- je->sig_figs, 0, je->is_pow2, N2S_BYTEPERSEC);
+ je->sig_figs, 1, je->is_pow2, N2S_BYTEPERSEC);
p += sprintf(p, ", %s-%s", mr, tr);
free(tr);
size_t left;
int l;
int ddir;
+ int linelen;
if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running ||
je->eta_sec == -1)
}
left = sizeof(output) - (p - output) - 1;
+ l = snprintf(p, left, ": [%s][%s]", je->run_str, perc_str);
+ l += gen_eta_str(je, p + l, left - l, rate_str, iops_str);
+ l += snprintf(p + l, left - l, "[eta %s]", eta_str);
- 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);
- 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);
+ /* If truncation occurred adjust l so p is on the null */
+ if (l >= left)
+ l = left - 1;
p += l;
- if (l >= 0 && l < linelen_last)
- p += sprintf(p, "%*s", linelen_last - l, "");
- linelen_last = l;
+ linelen = p - output;
+ if (l >= 0 && linelen < linelen_last)
+ p += sprintf(p, "%*s", linelen_last - linelen, "");
+ linelen_last = linelen;
for (ddir = 0; ddir < DDIR_RWDIR_CNT; ddir++) {
free(rate_str[ddir]);
free(iops_str[ddir]);
}
}
- p += sprintf(p, "\r");
+ sprintf(p, "\r");
printf("%s", output);
size_t size;
je = get_jobs_eta(false, &size);
- if (je)
+ if (je) {
display_thread_status(je);
-
- free(je);
+ free(je);
+ }
}
void print_status_init(int thr_number)
{
+ struct jobs_eta_packed jep;
+
+ compiletime_assert(sizeof(struct jobs_eta) == sizeof(jep), "jobs_eta");
+
+ DRD_IGNORE_VAR(__run_str);
__run_str[thr_number] = 'P';
update_condensed_str(__run_str, run_str);
}