stat: log out both average and max over the window
authorAnkit Kumar <ankit.kumar@samsung.com>
Thu, 25 Jan 2024 11:01:23 +0000 (16:31 +0530)
committerVincent Fu <vincent.fu@samsung.com>
Thu, 25 Jan 2024 13:46:15 +0000 (08:46 -0500)
Add option log_window_value alias of log_max_value which reports
average, max or both the values. Retain backward compatibility by
allowing =0 and =1 values to specify avg and max values respectively.

There is no change to existing log formats while reporting only average
or max values.

Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com>
Link: https://lore.kernel.org/r/20240125110124.55137-2-ankit.kumar@samsung.com
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
client.c
iolog.c
iolog.h
options.c
server.c
stat.c

index 699a2e5b981e4dd7532f48d56c861273eb9cb6c3..4cb7dffede753d52f641afd1d4f1a448588a8509 100644 (file)
--- a/client.c
+++ b/client.c
@@ -1718,8 +1718,10 @@ static struct cmd_iolog_pdu *convert_iolog(struct fio_net_cmd *cmd,
                        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);
diff --git a/iolog.c b/iolog.c
index 5213c60f1a984570a5ee2fe2eceda1f605ed6853..b4c7a8f13157531be4f4d426ebc9e8a32bf50bcc 100644 (file)
--- a/iolog.c
+++ b/iolog.c
@@ -862,6 +862,8 @@ void setup_log(struct io_log **log, struct log_params *p,
                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);
 
@@ -988,7 +990,7 @@ static void flush_hist_samples(FILE *f, int hist_coarseness, void *samples,
 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;
@@ -999,17 +1001,32 @@ void flush_samples(FILE *f, void *samples, uint64_t sample_size)
        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);
@@ -1023,20 +1040,37 @@ void flush_samples(FILE *f, void *samples, uint64_t sample_size)
                        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);
                }
        }
 }
diff --git a/iolog.h b/iolog.h
index 62cbd1b02fe78cd8fed2fbe827ba779c446ece19..26dd5cca81f388e194199caf4197dcf9368592b7 100644 (file)
--- a/iolog.h
+++ b/iolog.h
@@ -26,13 +26,23 @@ struct io_hist {
        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 })
 
 /*
@@ -154,8 +164,13 @@ struct io_log {
  * 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,
index 53df03de9eb5e51d21afffa5e0d4be4ee982918b..1da4de78151054237ff2a0f3a3ad5026cca5b70c 100644 (file)
--- a/options.c
+++ b/options.c
@@ -4540,14 +4540,38 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .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",
index b9f0e2ac3c4652652b300a1bcca7e9716acfe41e..afaeb3482b0fd0072c123bf78b925b5a35176bf1 100644 (file)
--- a/server.c
+++ b/server.c
@@ -2288,8 +2288,10 @@ int fio_send_iolog(struct thread_data *td, struct io_log *log, const char *name)
                        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);
 
diff --git a/stat.c b/stat.c
index 7cf6bee1945aabea351f13853f5b32ba386881a9..11b586268b188f25eec77317e2983568699cb91f 100644 (file)
--- a/stat.c
+++ b/stat.c
@@ -3149,7 +3149,7 @@ void reset_io_stats(struct thread_data *td)
 }
 
 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,
@@ -3159,10 +3159,16 @@ static void __add_stat_to_log(struct io_log *iolog, enum fio_ddir ddir,
        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);
        }
@@ -3171,7 +3177,7 @@ static void __add_stat_to_log(struct io_log *iolog, enum fio_ddir ddir,
 }
 
 static void _add_stat_to_log(struct io_log *iolog, unsigned long elapsed,
-                            bool log_max)
+                            int log_max)
 {
        enum fio_ddir ddir;
 
@@ -3205,7 +3211,7 @@ static unsigned long add_log_sample(struct thread_data *td,
         * 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
@@ -3221,7 +3227,7 @@ static unsigned long add_log_sample(struct thread_data *td,
                        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);
 
@@ -3235,15 +3241,15 @@ void finalize_logs(struct thread_data *td, bool unit_logs)
        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,