s = (struct io_sample *)((char *)s + sizeof(struct io_u_plat_entry) * i);
s->time = le64_to_cpu(s->time);
- if (ret->log_type != IO_LOG_TYPE_HIST)
- s->data.val = le64_to_cpu(s->data.val);
+ if (ret->log_type != IO_LOG_TYPE_HIST) {
+ s->data.val.val0 = le64_to_cpu(s->data.val.val0);
+ s->data.val.val1 = le64_to_cpu(s->data.val.val1);
+ }
s->__ddir = __le32_to_cpu(s->__ddir);
s->bs = le64_to_cpu(s->bs);
s->priority = le16_to_cpu(s->priority);
l->log_ddir_mask = LOG_OFFSET_SAMPLE_BIT;
if (l->log_prio)
l->log_ddir_mask |= LOG_PRIO_SAMPLE_BIT;
+ if (l->td->o.log_max == IO_LOG_SAMPLE_BOTH)
+ l->log_ddir_mask |= LOG_AVG_MAX_SAMPLE_BIT;
INIT_FLIST_HEAD(&l->chunk_list);
void flush_samples(FILE *f, void *samples, uint64_t sample_size)
{
struct io_sample *s;
- int log_offset, log_prio;
+ int log_offset, log_prio, log_avg_max;
uint64_t i, nr_samples;
unsigned int prio_val;
const char *fmt;
s = __get_sample(samples, 0, 0);
log_offset = (s->__ddir & LOG_OFFSET_SAMPLE_BIT) != 0;
log_prio = (s->__ddir & LOG_PRIO_SAMPLE_BIT) != 0;
+ log_avg_max = (s->__ddir & LOG_AVG_MAX_SAMPLE_BIT) != 0;
if (log_offset) {
- if (log_prio)
- fmt = "%" PRIu64 ", %" PRId64 ", %u, %llu, %llu, 0x%04x\n";
- else
- fmt = "%" PRIu64 ", %" PRId64 ", %u, %llu, %llu, %u\n";
+ if (log_prio) {
+ if (log_avg_max)
+ fmt = "%" PRIu64 ", %" PRId64 ", %" PRId64 ", %u, %llu, %llu, 0x%04x\n";
+ else
+ fmt = "%" PRIu64 ", %" PRId64 ", %u, %llu, %llu, 0x%04x\n";
+ } else {
+ if (log_avg_max)
+ fmt = "%" PRIu64 ", %" PRId64 ", %" PRId64 ", %u, %llu, %llu, %u\n";
+ else
+ fmt = "%" PRIu64 ", %" PRId64 ", %u, %llu, %llu, %u\n";
+ }
} else {
- if (log_prio)
- fmt = "%" PRIu64 ", %" PRId64 ", %u, %llu, 0x%04x\n";
- else
- fmt = "%" PRIu64 ", %" PRId64 ", %u, %llu, %u\n";
+ if (log_prio) {
+ if (log_avg_max)
+ fmt = "%" PRIu64 ", %" PRId64 ", %" PRId64 ", %u, %llu, 0x%04x\n";
+ else
+ fmt = "%" PRIu64 ", %" PRId64 ", %u, %llu, 0x%04x\n";
+ } else {
+ if (log_avg_max)
+ fmt = "%" PRIu64 ", %" PRId64 ", %" PRId64 ", %u, %llu, %u\n";
+ else
+ fmt = "%" PRIu64 ", %" PRId64 ", %u, %llu, %u\n";
+ }
}
nr_samples = sample_size / __log_entry_sz(log_offset);
prio_val = ioprio_value_is_class_rt(s->priority);
if (!log_offset) {
- fprintf(f, fmt,
- s->time,
- s->data.val,
- io_sample_ddir(s), (unsigned long long) s->bs,
- prio_val);
+ if (log_avg_max)
+ fprintf(f, fmt,
+ s->time,
+ s->data.val.val0,
+ s->data.val.val1,
+ io_sample_ddir(s), (unsigned long long) s->bs,
+ prio_val);
+ else
+ fprintf(f, fmt,
+ s->time,
+ s->data.val.val0,
+ io_sample_ddir(s), (unsigned long long) s->bs,
+ prio_val);
} else {
struct io_sample_offset *so = (void *) s;
- fprintf(f, fmt,
- s->time,
- s->data.val,
- io_sample_ddir(s), (unsigned long long) s->bs,
- (unsigned long long) so->offset,
- prio_val);
+ if (log_avg_max)
+ fprintf(f, fmt,
+ s->time,
+ s->data.val.val0,
+ s->data.val.val1,
+ io_sample_ddir(s), (unsigned long long) s->bs,
+ (unsigned long long) so->offset,
+ prio_val);
+ else
+ fprintf(f, fmt,
+ s->time,
+ s->data.val.val0,
+ io_sample_ddir(s), (unsigned long long) s->bs,
+ (unsigned long long) so->offset,
+ prio_val);
}
}
}
struct flist_head list;
};
+enum {
+ IO_LOG_SAMPLE_AVG = 0,
+ IO_LOG_SAMPLE_MAX,
+ IO_LOG_SAMPLE_BOTH,
+};
+
+struct io_sample_value {
+ uint64_t val0;
+ uint64_t val1;
+};
union io_sample_data {
- uint64_t val;
+ struct io_sample_value val;
struct io_u_plat_entry *plat_entry;
};
-#define sample_val(value) ((union io_sample_data) { .val = value })
+#define sample_val(value) ((union io_sample_data) { .val.val0 = value })
#define sample_plat(plat) ((union io_sample_data) { .plat_entry = plat })
/*
* If the bit following the upper bit is set, then we have the priority
*/
#define LOG_PRIO_SAMPLE_BIT 0x40000000U
+/*
+ * If the bit following prioity sample vit is set, we report both avg and max
+ */
+#define LOG_AVG_MAX_SAMPLE_BIT 0x20000000U
-#define LOG_SAMPLE_BITS (LOG_OFFSET_SAMPLE_BIT | LOG_PRIO_SAMPLE_BIT)
+#define LOG_SAMPLE_BITS (LOG_OFFSET_SAMPLE_BIT | LOG_PRIO_SAMPLE_BIT |\
+ LOG_AVG_MAX_SAMPLE_BIT)
#define io_sample_ddir(io) ((io)->__ddir & ~LOG_SAMPLE_BITS)
static inline void io_sample_set_ddir(struct io_log *log,
.group = FIO_OPT_G_INVALID,
},
{
- .name = "log_max_value",
- .lname = "Log maximum instead of average",
- .type = FIO_OPT_BOOL,
+ .name = "log_window_value",
+ .alias = "log_max_value",
+ .lname = "Log maximum, average or both values",
+ .type = FIO_OPT_STR,
.off1 = offsetof(struct thread_options, log_max),
- .help = "Log max sample in a window instead of average",
- .def = "0",
+ .help = "Log max, average or both sample in a window",
+ .def = "avg",
.category = FIO_OPT_C_LOG,
.group = FIO_OPT_G_INVALID,
+ .posval = {
+ { .ival = "avg",
+ .oval = IO_LOG_SAMPLE_AVG,
+ .help = "Log average value over the window",
+ },
+ { .ival = "max",
+ .oval = IO_LOG_SAMPLE_MAX,
+ .help = "Log maximum value in the window",
+ },
+ { .ival = "both",
+ .oval = IO_LOG_SAMPLE_BOTH,
+ .help = "Log both average and maximum values over the window"
+ },
+ /* Compatibility with former boolean values */
+ { .ival = "0",
+ .oval = IO_LOG_SAMPLE_AVG,
+ .help = "Alias for 'avg'",
+ },
+ { .ival = "1",
+ .oval = IO_LOG_SAMPLE_MAX,
+ .help = "Alias for 'max'",
+ },
+ },
},
{
.name = "log_offset",
struct io_sample *s = get_sample(log, cur_log, i);
s->time = cpu_to_le64(s->time);
- if (log->log_type != IO_LOG_TYPE_HIST)
- s->data.val = cpu_to_le64(s->data.val);
+ if (log->log_type != IO_LOG_TYPE_HIST) {
+ s->data.val.val0 = cpu_to_le64(s->data.val.val0);
+ s->data.val.val1 = cpu_to_le64(s->data.val.val1);
+ }
s->__ddir = __cpu_to_le32(s->__ddir);
s->bs = cpu_to_le64(s->bs);
}
static void __add_stat_to_log(struct io_log *iolog, enum fio_ddir ddir,
- unsigned long elapsed, bool log_max)
+ unsigned long elapsed, int log_max)
{
/*
* Note an entry in the log. Use the mean from the logged samples,
if (iolog->avg_window[ddir].samples) {
union io_sample_data data;
- if (log_max)
- data.val = iolog->avg_window[ddir].max_val;
- else
- data.val = iolog->avg_window[ddir].mean.u.f + 0.50;
+ if (log_max == IO_LOG_SAMPLE_AVG) {
+ data.val.val0 = iolog->avg_window[ddir].mean.u.f + 0.50;
+ data.val.val1 = 0;
+ } else if (log_max == IO_LOG_SAMPLE_MAX) {
+ data.val.val0 = iolog->avg_window[ddir].max_val;
+ data.val.val1 = 0;
+ } else {
+ data.val.val0 = iolog->avg_window[ddir].mean.u.f + 0.50;
+ data.val.val1 = iolog->avg_window[ddir].max_val;
+ }
__add_log_sample(iolog, data, ddir, 0, elapsed, 0, 0);
}
}
static void _add_stat_to_log(struct io_log *iolog, unsigned long elapsed,
- bool log_max)
+ int log_max)
{
enum fio_ddir ddir;
* Add the sample. If the time period has passed, then
* add that entry to the log and clear.
*/
- add_stat_sample(&iolog->avg_window[ddir], data.val);
+ add_stat_sample(&iolog->avg_window[ddir], data.val.val0);
/*
* If period hasn't passed, adding the above sample is all we
return diff;
}
- __add_stat_to_log(iolog, ddir, elapsed, td->o.log_max != 0);
+ __add_stat_to_log(iolog, ddir, elapsed, td->o.log_max);
iolog->avg_last[ddir] = elapsed - (elapsed % iolog->avg_msec);
elapsed = mtime_since_now(&td->epoch);
if (td->clat_log && unit_logs)
- _add_stat_to_log(td->clat_log, elapsed, td->o.log_max != 0);
+ _add_stat_to_log(td->clat_log, elapsed, td->o.log_max);
if (td->slat_log && unit_logs)
- _add_stat_to_log(td->slat_log, elapsed, td->o.log_max != 0);
+ _add_stat_to_log(td->slat_log, elapsed, td->o.log_max);
if (td->lat_log && unit_logs)
- _add_stat_to_log(td->lat_log, elapsed, td->o.log_max != 0);
+ _add_stat_to_log(td->lat_log, elapsed, td->o.log_max);
if (td->bw_log && (unit_logs == per_unit_log(td->bw_log)))
- _add_stat_to_log(td->bw_log, elapsed, td->o.log_max != 0);
+ _add_stat_to_log(td->bw_log, elapsed, td->o.log_max);
if (td->iops_log && (unit_logs == per_unit_log(td->iops_log)))
- _add_stat_to_log(td->iops_log, elapsed, td->o.log_max != 0);
+ _add_stat_to_log(td->iops_log, elapsed, td->o.log_max);
}
void add_agg_sample(union io_sample_data data, enum fio_ddir ddir,