static struct itimerval itimer;
static struct list_head disk_list = LIST_HEAD_INIT(disk_list);
+/*
+ * Cheasy number->string conversion, complete with carry rounding error.
+ */
+static char *num2str(unsigned long num, int maxlen, int base)
+{
+ /*
+ * could be passed in for 10^3 base, but every caller expects
+ * 2^10 base right now.
+ */
+ const unsigned int thousand = 1024;
+ char postfix[] = { 'K', 'M', 'G', 'P' };
+ char *buf;
+ int i;
+
+ buf = malloc(128);
+
+ for (i = 0; base > 1; i++)
+ base /= thousand;
+
+ do {
+ int len, carry = 0;
+
+ len = sprintf(buf, "%'lu", num);
+ if (len <= maxlen) {
+ buf[len] = postfix[i];
+ buf[len + 1] = '\0';
+ return buf;
+ }
+
+ if ((num % thousand) >= (thousand / 2))
+ carry = 1;
+
+ num /= thousand;
+ num += carry;
+ i++;
+ } while (i <= 4);
+
+ return buf;
+}
+
static int get_io_ticks(struct disk_util *du, struct disk_util_stat *dus)
{
unsigned in_flight;
dev_t dev;
char *p;
- if (!td->do_disk_util)
+ if (!td->do_disk_util || (td->io_ops->flags & (FIO_NETIO | FIO_NULLIO)))
return;
/*
td->usr_time += mtime_since(&td->ru_start.ru_utime, &td->ru_end.ru_utime);
td->sys_time += mtime_since(&td->ru_start.ru_stime, &td->ru_end.ru_stime);
td->ctx += td->ru_end.ru_nvcsw + td->ru_end.ru_nivcsw - (td->ru_start.ru_nvcsw + td->ru_start.ru_nivcsw);
-
memcpy(&td->ru_start, &td->ru_end, sizeof(td->ru_end));
}
static int calc_lat(struct io_stat *is, unsigned long *min, unsigned long *max,
double *mean, double *dev)
{
- double n, o;
+ double n = is->samples;
if (is->samples == 0)
return 0;
*max = is->max_val;
n = (double) is->samples;
- *mean = (double) is->val / n;
- *dev = 0.01;
-
- if (n <= 1.0)
- return 1;
+ *mean = is->mean;
- o = ((double) is->val_sq - (*mean * is->val)) / n;
- if (o < 0.0)
- *dev = -1.0;
+ if (n > 1.0)
+ *dev = sqrt(is->S / (n - 1.0));
else
- *dev = sqrt(o);
+ *dev = -1.0;
return 1;
}
static void show_group_stats(struct group_run_stats *rs, int id)
{
+ char *p1, *p2, *p3, *p4;
+ const char *ddir_str[] = { " READ", " WRITE" };
+ int i;
+
fprintf(f_out, "\nRun status group %d (all jobs):\n", id);
- if (rs->max_run[DDIR_READ])
- fprintf(f_out, " READ: io=%lluMiB, aggrb=%llu, minb=%llu, maxb=%llu, mint=%llumsec, maxt=%llumsec\n", rs->io_kb[0] >> 10, rs->agg[0], rs->min_bw[0], rs->max_bw[0], rs->min_run[0], rs->max_run[0]);
- if (rs->max_run[DDIR_WRITE])
- fprintf(f_out, " WRITE: io=%lluMiB, aggrb=%llu, minb=%llu, maxb=%llu, mint=%llumsec, maxt=%llumsec\n", rs->io_kb[1] >> 10, rs->agg[1], rs->min_bw[1], rs->max_bw[1], rs->min_run[1], rs->max_run[1]);
+ for (i = 0; i <= DDIR_WRITE; i++) {
+ if (!rs->max_run[i])
+ continue;
+
+ p1 = num2str(rs->io_kb[i], 6, 1);
+ p2 = num2str(rs->agg[i], 6, 1);
+ p3 = num2str(rs->min_bw[i], 6, 1);
+ p4 = num2str(rs->max_bw[i], 6, 1);
+
+ fprintf(f_out, "%s: io=%siB, aggrb=%siB/s, minb=%siB/s, maxb=%siB/s, mint=%llumsec, maxt=%llumsec\n", ddir_str[i], p1, p2, p3, p4, rs->min_run[0], rs->max_run[0]);
+
+ free(p1);
+ free(p2);
+ free(p3);
+ free(p4);
+ }
}
static void show_disk_util(void)
unsigned long min, max;
unsigned long long bw;
double mean, dev;
+ char *io_p, *bw_p;
if (!td->runtime[ddir])
return;
bw = td->io_bytes[ddir] / td->runtime[ddir];
- fprintf(f_out, " %s: io=%6lluMiB, bw=%6lluKiB/s, runt=%6lumsec\n", ddir_str[ddir], td->io_bytes[ddir] >> 20, bw, td->runtime[ddir]);
+ io_p = num2str(td->io_bytes[ddir] >> 10, 6, 1);
+ bw_p = num2str(bw, 6, 1);
+
+ fprintf(f_out, " %s: io=%siB, bw=%siB/s, runt=%6lumsec\n", ddir_str[ddir], io_p, bw_p, td->runtime[ddir]);
+
+ free(io_p);
+ free(bw_p);
if (calc_lat(&td->slat_stat[ddir], &min, &max, &mean, &dev))
- fprintf(f_out, " slat (msec): min=%5lu, max=%5lu, avg=%5.02f, dev=%5.02f\n", min, max, mean, dev);
+ fprintf(f_out, " slat (msec): min=%5lu, max=%5lu, avg=%5.02f, stdev=%5.02f\n", min, max, mean, dev);
if (calc_lat(&td->clat_stat[ddir], &min, &max, &mean, &dev))
- fprintf(f_out, " clat (msec): min=%5lu, max=%5lu, avg=%5.02f, dev=%5.02f\n", min, max, mean, dev);
+ fprintf(f_out, " clat (msec): min=%5lu, max=%5lu, avg=%5.02f, stdev=%5.02f\n", min, max, mean, dev);
if (calc_lat(&td->bw_stat[ddir], &min, &max, &mean, &dev)) {
double p_of_agg;
p_of_agg = mean * 100 / (double) rs->agg[ddir];
- fprintf(f_out, " bw (KiB/s) : min=%5lu, max=%5lu, per=%3.2f%%, avg=%5.02f, dev=%5.02f\n", min, max, p_of_agg, mean, dev);
+ fprintf(f_out, " bw (KiB/s) : min=%5lu, max=%5lu, per=%3.2f%%, avg=%5.02f, stdev=%5.02f\n", min, max, p_of_agg, mean, dev);
}
}
{
double usr_cpu, sys_cpu;
unsigned long runtime;
+ double io_u_dist[FIO_IO_U_MAP_NR];
+ int i;
- if (!(td->io_bytes[0] + td->io_bytes[1]) && !td->error)
+ if (!(td->io_bytes[0] + td->io_bytes[1]))
return;
- fprintf(f_out, "%s: (groupid=%d): err=%2d:\n",td->name, td->groupid, td->error);
+ if (!td->error)
+ fprintf(f_out, "%s: (groupid=%d): err=%2d: pid=%d\n",td->name, td->groupid, td->error, td->pid);
+ else
+ fprintf(f_out, "%s: (groupid=%d): err=%2d (%s): pid=%d\n",td->name, td->groupid, td->error, td->verror, td->pid);
show_ddir_status(td, rs, td->ddir);
if (td->io_bytes[td->ddir ^ 1])
}
fprintf(f_out, " cpu : usr=%3.2f%%, sys=%3.2f%%, ctx=%lu\n", usr_cpu, sys_cpu, td->ctx);
+
+ /*
+ * Do depth distribution calculations
+ */
+ for (i = 0; i < FIO_IO_U_MAP_NR; i++) {
+ io_u_dist[i] = (double) td->io_u_map[i] / (double) td->total_io_u;
+ io_u_dist[i] *= 100.0;
+ }
+
+ fprintf(f_out, " IO depths : 1=%3.1f%%, 2=%3.1f%%, 4=%3.1f%%, 8=%3.1f%%, 16=%3.1f%%, 32=%3.1f%%, >=64=%3.1f%%\n", io_u_dist[0], io_u_dist[1], io_u_dist[2], io_u_dist[3], io_u_dist[4], io_u_dist[5], io_u_dist[6]);
+
+ if (td->description)
+ fprintf(f_out, "%s\n", td->description);
}
static void show_ddir_status_terse(struct thread_data *td,
for_each_td(td, i) {
unsigned long long rbw, wbw;
- if (td->error) {
- fprintf(f_out, "%s: %s\n", td->name, td->verror);
- continue;
- }
-
rs = &runstats[td->groupid];
if (td->runtime[0] < rs->min_run[0] || !rs->min_run[0])
free(runstats);
}
-static inline void add_stat_sample(struct io_stat *is, unsigned long val)
+static inline void add_stat_sample(struct io_stat *is, unsigned long data)
{
- if (val > is->max_val)
- is->max_val = val;
- if (val < is->min_val)
- is->min_val = val;
+ double val = data;
+ double delta, n;
+
+ if (data > is->max_val)
+ is->max_val = data;
+ if (data < is->min_val)
+ is->min_val = data;
+
+ delta = val - is->mean;
+ n = is->samples + 1.0;
+ is->mean += delta / n;
+ is->S += delta * (val - is->mean);
- is->val += val;
- is->val_sq += val * val;
is->samples++;
}
-static void add_log_sample(struct thread_data *td, struct io_log *iolog,
- unsigned long val, enum fio_ddir ddir)
+static void __add_log_sample(struct io_log *iolog, unsigned long val,
+ enum fio_ddir ddir, unsigned long time)
{
if (iolog->nr_samples == iolog->max_samples) {
int new_size = sizeof(struct io_sample) * iolog->max_samples*2;
}
iolog->log[iolog->nr_samples].val = val;
- iolog->log[iolog->nr_samples].time = mtime_since_now(&td->epoch);
+ iolog->log[iolog->nr_samples].time = time;
iolog->log[iolog->nr_samples].ddir = ddir;
iolog->nr_samples++;
}
+static void add_log_sample(struct thread_data *td, struct io_log *iolog,
+ unsigned long val, enum fio_ddir ddir)
+{
+ __add_log_sample(iolog, val, ddir, mtime_since_now(&td->epoch));
+}
+
+void add_agg_sample(unsigned long val, enum fio_ddir ddir)
+{
+ struct io_log *iolog = agg_io_log[ddir];
+
+ __add_log_sample(iolog, val, ddir, mtime_since_genesis());
+}
+
void add_clat_sample(struct thread_data *td, enum fio_ddir ddir,
unsigned long msec)
{