Add support for latency probing over an interval of load
[fio.git] / stat.c
diff --git a/stat.c b/stat.c
index ef9c4af2d81878a1ec6ec427cc804c18f7b07752..26125fad6908b5d5291c239a6daed84d3ae9bbf6 100644 (file)
--- a/stat.c
+++ b/stat.c
@@ -15,6 +15,7 @@
 #include "helper_thread.h"
 #include "smalloc.h"
 #include "zbd.h"
+#include "target.h"
 
 #define LOG_MSEC_SLACK 1
 
@@ -391,7 +392,7 @@ void stat_calc_lat_m(struct thread_stat *ts, double *io_u_lat)
        stat_calc_lat(ts, io_u_lat, ts->io_u_lat_m, FIO_IO_U_LAT_M_NR);
 }
 
-static void display_lat(const char *name, unsigned long long min,
+void display_lat(const char *name, unsigned long long min,
                        unsigned long long max, double mean, double dev,
                        struct buf_output *out)
 {
@@ -416,7 +417,6 @@ static void display_lat(const char *name, unsigned long long min,
 static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts,
                             int ddir, struct buf_output *out)
 {
-       const char *str[] = { " read", "write", " trim", "sync" };
        unsigned long runt;
        unsigned long long min, max, bw, iops;
        double mean, dev;
@@ -426,12 +426,12 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts,
        if (ddir_sync(ddir)) {
                if (calc_lat(&ts->sync_stat, &min, &max, &mean, &dev)) {
                        log_buf(out, "  %s:\n", "fsync/fdatasync/sync_file_range");
-                       display_lat(str[ddir], min, max, mean, dev, out);
+                       display_lat(io_ddir_name(ddir), min, max, mean, dev, out);
                        show_clat_percentiles(ts->io_u_sync_plat,
                                                ts->sync_stat.samples,
                                                ts->percentile_list,
                                                ts->percentile_precision,
-                                               str[ddir], out);
+                                               io_ddir_name(ddir), out);
                }
                return;
        }
@@ -455,7 +455,7 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts,
                zbd_w_st = zbd_write_status(ts);
 
        log_buf(out, "  %s: IOPS=%s, BW=%s (%s)(%s/%llumsec)%s\n",
-                       rs->unified_rw_rep ? "mixed" : str[ddir],
+                       rs->unified_rw_rep ? "mixed" : io_ddir_name(ddir),
                        iops_p, bw_p, bw_p_alt, io_p,
                        (unsigned long long) ts->runtime[ddir],
                        zbd_w_st ? : "");
@@ -888,6 +888,11 @@ static void show_thread_status_normal(struct thread_stat *ts,
 
        if (ts->ss_dur)
                show_ss_normal(ts, out);
+
+       if (lat_ts_has_stats(ts)) {
+               log_buf(out, "  Stepped latency report\n");
+               lat_step_report(ts, out);
+       }
 }
 
 static void show_ddir_status_terse(struct thread_stat *ts,
@@ -985,7 +990,6 @@ static void add_ddir_status_json(struct thread_stat *ts,
        double mean, dev, iops;
        unsigned int len;
        int i;
-       const char *ddirname[] = { "read", "write", "trim", "sync" };
        struct json_object *dir_object, *tmp_object, *percentile_object, *clat_bins_object = NULL;
        char buf[120];
        double p_of_agg = 100.0;
@@ -997,7 +1001,7 @@ static void add_ddir_status_json(struct thread_stat *ts,
 
        dir_object = json_create_object();
        json_object_add_value_object(parent,
-               ts->unified_rw_rep ? "mixed" : ddirname[ddir], dir_object);
+               ts->unified_rw_rep ? "mixed" : io_ddir_name(ddir), dir_object);
 
        if (ddir_rw(ddir)) {
                bw_bytes = 0;
@@ -1266,7 +1270,7 @@ static struct json_object *show_thread_status_json(struct thread_stat *ts,
        double io_u_lat_u[FIO_IO_U_LAT_U_NR];
        double io_u_lat_m[FIO_IO_U_LAT_M_NR];
        double usr_cpu, sys_cpu;
-       int i;
+       int i, j;
        size_t size;
 
        root = json_create_object();
@@ -1490,6 +1494,32 @@ static struct json_object *show_thread_status_json(struct thread_stat *ts,
                json_object_add_value_array(data, "bw", bw);
        }
 
+       if (lat_ts_has_stats(ts)) {
+               tmp = json_create_object();
+               json_object_add_value_object(root, "lat_step", tmp);
+       }
+
+       for (i = 0; i < DDIR_RWDIR_CNT; i++) {
+               struct json_object *val;
+
+               if (!__lat_ts_has_stats(ts, i))
+                       continue;
+
+               val = json_create_object();
+               json_object_add_value_object(tmp, io_ddir_name(i), val);
+
+               for (j = 0; j < ARRAY_SIZE(ts->step_stats); j++) {
+                       struct lat_step_stats *ls = &ts->step_stats[j];
+                       char name[32];
+
+                       if (!ls->iops[i])
+                               continue;
+
+                       sprintf(name, "%llu", (unsigned long long) ls->iops[i]);
+                       json_object_add_value_float(val, name, ls->avg[i].u.f);
+               }
+       }
+
        return root;
 }
 
@@ -1555,6 +1585,25 @@ static void sum_stat(struct io_stat *dst, struct io_stat *src, bool first)
        dst->S.u.f = S;
 }
 
+static void sum_lat_step_stats(struct lat_step_stats *dst,
+                              struct lat_step_stats *src, bool first)
+{
+       int i;
+
+       for (i = 0; i < DDIR_RWDIR_CNT; i++) {
+               if (!dst->iops[i] && !src->iops[i])
+                       continue;
+               if (first)
+                       dst->avg[i].u.f = src->avg[i].u.f;
+               else {
+                       dst->avg[i].u.f = ((src->avg[i].u.f * src->iops[i]) +
+                               (dst->avg[i].u.f * dst->iops[i])) /
+                               (dst->iops[i] + src->iops[i]);
+               }
+               dst->iops[i] += src->iops[i];
+       }
+}
+
 void sum_group_stats(struct group_run_stats *dst, struct group_run_stats *src)
 {
        int i;
@@ -1667,6 +1716,9 @@ void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src,
        dst->total_submit += src->total_submit;
        dst->total_complete += src->total_complete;
        dst->nr_zone_resets += src->nr_zone_resets;
+
+       for (l = 0; l < ARRAY_SIZE(dst->step_stats); l++)
+               sum_lat_step_stats(&dst->step_stats[l], &src->step_stats[l], first);
 }
 
 void init_group_run_stat(struct group_run_stats *gs)
@@ -1713,6 +1765,9 @@ void __show_run_stats(void)
        for (i = 0; i < groupid + 1; i++)
                init_group_run_stat(&runstats[i]);
 
+       for (i = 0; i < FIO_OUTPUT_NR; i++)
+               buf_output_init(&output[i]);
+
        /*
         * find out how many threads stats we need. if group reporting isn't
         * enabled, it's one-per-td.
@@ -1889,9 +1944,6 @@ void __show_run_stats(void)
                }
        }
 
-       for (i = 0; i < FIO_OUTPUT_NR; i++)
-               buf_output_init(&output[i]);
-
        /*
         * don't overwrite last signal output
         */