fio: fix aio trim completion latencies
[fio.git] / stat.c
diff --git a/stat.c b/stat.c
index 331abf676c7bfae00c349208e894f7049f5f6ad5..bf87917c2956eb60729fa9ea95ac93b1cbe1ed50 100644 (file)
--- a/stat.c
+++ b/stat.c
@@ -139,7 +139,6 @@ unsigned int calc_clat_percentiles(uint64_t *io_u_plat, unsigned long long nr,
 {
        unsigned long long sum = 0;
        unsigned int len, i, j = 0;
-       unsigned int oval_len = 0;
        unsigned long long *ovals = NULL;
        bool is_last;
 
@@ -161,20 +160,19 @@ unsigned int calc_clat_percentiles(uint64_t *io_u_plat, unsigned long long nr,
        if (len > 1)
                qsort((void *)plist, len, sizeof(plist[0]), double_cmp);
 
+       ovals = malloc(len * sizeof(*ovals));
+       if (!ovals)
+               return 0;
+
        /*
         * Calculate bucket values, note down max and min values
         */
        is_last = false;
        for (i = 0; i < FIO_IO_U_PLAT_NR && !is_last; i++) {
                sum += io_u_plat[i];
-               while (sum >= (plist[j].u.f / 100.0 * nr)) {
+               while (sum >= ((long double) plist[j].u.f / 100.0 * nr)) {
                        assert(plist[j].u.f <= 100.0);
 
-                       if (j == oval_len) {
-                               oval_len += 100;
-                               ovals = realloc(ovals, oval_len * sizeof(*ovals));
-                       }
-
                        ovals[j] = plat_idx_to_val(i);
                        if (ovals[j] < *minv)
                                *minv = ovals[j];
@@ -189,6 +187,9 @@ unsigned int calc_clat_percentiles(uint64_t *io_u_plat, unsigned long long nr,
                }
        }
 
+       if (!is_last)
+               log_err("fio: error calculating latency percentiles\n");
+
        *output = ovals;
        return len;
 }
@@ -419,7 +420,7 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts,
        unsigned long runt;
        unsigned long long min, max, bw, iops;
        double mean, dev;
-       char *io_p, *bw_p, *bw_p_alt, *iops_p, *zbd_w_st = NULL;
+       char *io_p, *bw_p, *bw_p_alt, *iops_p, *post_st = NULL;
        int i2p;
 
        if (ddir_sync(ddir)) {
@@ -451,15 +452,25 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts,
        iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
        iops_p = num2str(iops, ts->sig_figs, 1, 0, N2S_NONE);
        if (ddir == DDIR_WRITE)
-               zbd_w_st = zbd_write_status(ts);
+               post_st = zbd_write_status(ts);
+       else if (ddir == DDIR_READ && ts->cachehit && ts->cachemiss) {
+               uint64_t total;
+               double hit;
+
+               total = ts->cachehit + ts->cachemiss;
+               hit = (double) ts->cachehit / (double) total;
+               hit *= 100.0;
+               if (asprintf(&post_st, "; Cachehit=%0.2f%%", hit) < 0)
+                       post_st = NULL;
+       }
 
        log_buf(out, "  %s: IOPS=%s, BW=%s (%s)(%s/%llumsec)%s\n",
                        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 ? : "");
+                       post_st ? : "");
 
-       free(zbd_w_st);
+       free(post_st);
        free(io_p);
        free(bw_p);
        free(bw_p_alt);
@@ -1080,7 +1091,8 @@ static void add_ddir_status_json(struct thread_stat *ts,
                len = 0;
 
        percentile_object = json_create_object();
-       json_object_add_value_object(tmp_object, "percentile", percentile_object);
+       if (ts->clat_percentiles)
+               json_object_add_value_object(tmp_object, "percentile", percentile_object);
        for (i = 0; i < len; i++) {
                snprintf(buf, sizeof(buf), "%f", ts->percentile_list[i].u.f);
                json_object_add_value_int(percentile_object, (const char *)buf, ovals[i]);
@@ -1119,6 +1131,8 @@ static void add_ddir_status_json(struct thread_stat *ts,
        json_object_add_value_int(tmp_object, "max", max);
        json_object_add_value_float(tmp_object, "mean", mean);
        json_object_add_value_float(tmp_object, "stddev", dev);
+       if (ts->lat_percentiles)
+               json_object_add_value_object(tmp_object, "percentile", percentile_object);
        if (output_format & FIO_OUTPUT_JSON_PLUS && ts->lat_percentiles)
                json_object_add_value_object(tmp_object, "bins", clat_bins_object);
 
@@ -1153,6 +1167,16 @@ static void add_ddir_status_json(struct thread_stat *ts,
        json_object_add_value_float(dir_object, "iops_stddev", dev);
        json_object_add_value_int(dir_object, "iops_samples",
                                (&ts->iops_stat[ddir])->samples);
+
+       if (ts->cachehit + ts->cachemiss) {
+               uint64_t total;
+               double hit;
+
+               total = ts->cachehit + ts->cachemiss;
+               hit = (double) ts->cachehit / (double) total;
+               hit *= 100.0;
+               json_object_add_value_float(dir_object, "cachehit", hit);
+       }
 }
 
 static void show_thread_status_terse_all(struct thread_stat *ts,
@@ -1220,12 +1244,13 @@ static void show_thread_status_terse_all(struct thread_stat *ts,
        /* Additional output if continue_on_error set - default off*/
        if (ts->continue_on_error)
                log_buf(out, ";%llu;%d", (unsigned long long) ts->total_err_count, ts->first_error);
-       if (ver == 2)
-               log_buf(out, "\n");
 
        /* Additional output if description is set */
-       if (strlen(ts->description))
+       if (strlen(ts->description)) {
+               if (ver == 2)
+                       log_buf(out, "\n");
                log_buf(out, ";%s", ts->description);
+       }
 
        log_buf(out, "\n");
 }
@@ -1518,13 +1543,10 @@ struct json_object *show_thread_status(struct thread_stat *ts,
        return ret;
 }
 
-static void sum_stat(struct io_stat *dst, struct io_stat *src, bool first)
+static void __sum_stat(struct io_stat *dst, struct io_stat *src, bool first)
 {
        double mean, S;
 
-       if (src->samples == 0)
-               return;
-
        dst->min_val = min(dst->min_val, src->min_val);
        dst->max_val = max(dst->max_val, src->max_val);
 
@@ -1551,6 +1573,39 @@ static void sum_stat(struct io_stat *dst, struct io_stat *src, bool first)
        dst->samples += src->samples;
        dst->mean.u.f = mean;
        dst->S.u.f = S;
+
+}
+
+/*
+ * We sum two kinds of stats - one that is time based, in which case we
+ * apply the proper summing technique, and then one that is iops/bw
+ * numbers. For group_reporting, we should just add those up, not make
+ * them the mean of everything.
+ */
+static void sum_stat(struct io_stat *dst, struct io_stat *src, bool first,
+                    bool pure_sum)
+{
+       if (src->samples == 0)
+               return;
+
+       if (!pure_sum) {
+               __sum_stat(dst, src, first);
+               return;
+       }
+
+       if (first) {
+               dst->min_val = src->min_val;
+               dst->max_val = src->max_val;
+               dst->samples = src->samples;
+               dst->mean.u.f = src->mean.u.f;
+               dst->S.u.f = src->S.u.f;
+       } else {
+               dst->min_val += src->min_val;
+               dst->max_val += src->max_val;
+               dst->samples += src->samples;
+               dst->mean.u.f += src->mean.u.f;
+               dst->S.u.f += src->S.u.f;
+       }
 }
 
 void sum_group_stats(struct group_run_stats *dst, struct group_run_stats *src)
@@ -1586,22 +1641,22 @@ void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src,
 
        for (l = 0; l < DDIR_RWDIR_CNT; l++) {
                if (!dst->unified_rw_rep) {
-                       sum_stat(&dst->clat_stat[l], &src->clat_stat[l], first);
-                       sum_stat(&dst->slat_stat[l], &src->slat_stat[l], first);
-                       sum_stat(&dst->lat_stat[l], &src->lat_stat[l], first);
-                       sum_stat(&dst->bw_stat[l], &src->bw_stat[l], first);
-                       sum_stat(&dst->iops_stat[l], &src->iops_stat[l], first);
+                       sum_stat(&dst->clat_stat[l], &src->clat_stat[l], first, false);
+                       sum_stat(&dst->slat_stat[l], &src->slat_stat[l], first, false);
+                       sum_stat(&dst->lat_stat[l], &src->lat_stat[l], first, false);
+                       sum_stat(&dst->bw_stat[l], &src->bw_stat[l], first, true);
+                       sum_stat(&dst->iops_stat[l], &src->iops_stat[l], first, true);
 
                        dst->io_bytes[l] += src->io_bytes[l];
 
                        if (dst->runtime[l] < src->runtime[l])
                                dst->runtime[l] = src->runtime[l];
                } else {
-                       sum_stat(&dst->clat_stat[0], &src->clat_stat[l], first);
-                       sum_stat(&dst->slat_stat[0], &src->slat_stat[l], first);
-                       sum_stat(&dst->lat_stat[0], &src->lat_stat[l], first);
-                       sum_stat(&dst->bw_stat[0], &src->bw_stat[l], first);
-                       sum_stat(&dst->iops_stat[0], &src->iops_stat[l], first);
+                       sum_stat(&dst->clat_stat[0], &src->clat_stat[l], first, false);
+                       sum_stat(&dst->slat_stat[0], &src->slat_stat[l], first, false);
+                       sum_stat(&dst->lat_stat[0], &src->lat_stat[l], first, false);
+                       sum_stat(&dst->bw_stat[0], &src->bw_stat[l], first, true);
+                       sum_stat(&dst->iops_stat[0], &src->iops_stat[l], first, true);
 
                        dst->io_bytes[0] += src->io_bytes[l];
 
@@ -1616,7 +1671,7 @@ void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src,
                }
        }
 
-       sum_stat(&dst->sync_stat, &src->sync_stat, first);
+       sum_stat(&dst->sync_stat, &src->sync_stat, first, false);
        dst->usr_time += src->usr_time;
        dst->sys_time += src->sys_time;
        dst->ctx += src->ctx;
@@ -1628,11 +1683,14 @@ void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src,
                dst->io_u_submit[k] += src->io_u_submit[k];
                dst->io_u_complete[k] += src->io_u_complete[k];
        }
-       for (k = 0; k < FIO_IO_U_LAT_N_NR; k++) {
+
+       for (k = 0; k < FIO_IO_U_LAT_N_NR; k++)
                dst->io_u_lat_n[k] += src->io_u_lat_n[k];
+       for (k = 0; k < FIO_IO_U_LAT_U_NR; k++)
                dst->io_u_lat_u[k] += src->io_u_lat_u[k];
+       for (k = 0; k < FIO_IO_U_LAT_M_NR; k++)
                dst->io_u_lat_m[k] += src->io_u_lat_m[k];
-       }
+
        for (k = 0; k < FIO_IO_U_PLAT_NR; k++)
                dst->io_u_sync_plat[k] += src->io_u_sync_plat[k];
 
@@ -1665,6 +1723,8 @@ 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;
+       dst->cachehit += src->cachehit;
+       dst->cachemiss += src->cachemiss;
 }
 
 void init_group_run_stat(struct group_run_stats *gs)
@@ -2299,7 +2359,8 @@ static void __add_log_sample(struct io_log *iolog, union io_sample_data data,
 
 static inline void reset_io_stat(struct io_stat *ios)
 {
-       ios->max_val = ios->min_val = ios->samples = 0;
+       ios->min_val = -1ULL;
+       ios->max_val = ios->samples = 0;
        ios->mean.u.f = ios->S.u.f = 0;
 }
 
@@ -2346,6 +2407,7 @@ void reset_io_stats(struct thread_data *td)
        ts->total_submit = 0;
        ts->total_complete = 0;
        ts->nr_zone_resets = 0;
+       ts->cachehit = ts->cachemiss = 0;
 }
 
 static void __add_stat_to_log(struct io_log *iolog, enum fio_ddir ddir,