client/server: pass back job options to client
[fio.git] / stat.c
diff --git a/stat.c b/stat.c
index 091d6fb1dd1e6a66daa7c0c306737fa2f8312e64..a3bfe632454e4b0a2a2d5c5dcde5a4b429f4e6f5 100644 (file)
--- a/stat.c
+++ b/stat.c
 
 struct fio_mutex *stat_mutex;
 
+void clear_rusage_stat(struct thread_data *td)
+{
+       struct thread_stat *ts = &td->ts;
+
+       fio_getrusage(&td->ru_start);
+       ts->usr_time = ts->sys_time = 0;
+       ts->ctx = 0;
+       ts->minf = ts->majf = 0;
+}
+
 void update_rusage_stat(struct thread_data *td)
 {
        struct thread_stat *ts = &td->ts;
@@ -832,7 +842,7 @@ static void add_ddir_status_json(struct thread_stat *ts,
        unsigned int len, minv, maxv;
        int i;
        const char *ddirname[] = {"read", "write", "trim"};
-       struct json_object *dir_object, *tmp_object, *percentile_object;
+       struct json_object *dir_object, *tmp_object, *percentile_object, *clat_bins_object;
        char buf[120];
        double p_of_agg = 100.0;
 
@@ -903,6 +913,18 @@ static void add_ddir_status_json(struct thread_stat *ts,
                json_object_add_value_int(percentile_object, (const char *)buf, ovals[i]);
        }
 
+       if (output_format & FIO_OUTPUT_JSON_PLUS) {
+               clat_bins_object = json_create_object();
+               json_object_add_value_object(tmp_object, "bins", clat_bins_object);
+               for(i = 0; i < FIO_IO_U_PLAT_NR; i++) {
+                       snprintf(buf, sizeof(buf), "%d", i);
+                       json_object_add_value_int(clat_bins_object, (const char *)buf, ts->io_u_plat[ddir][i]);
+               }
+               json_object_add_value_int(clat_bins_object, "FIO_IO_U_PLAT_BITS", FIO_IO_U_PLAT_BITS);
+               json_object_add_value_int(clat_bins_object, "FIO_IO_U_PLAT_VAL", FIO_IO_U_PLAT_VAL);
+               json_object_add_value_int(clat_bins_object, "FIO_IO_U_PLAT_NR", FIO_IO_U_PLAT_NR);
+       }
+
        if (!calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev)) {
                min = max = 0;
                mean = dev = 0.0;
@@ -1064,8 +1086,34 @@ static void show_thread_status_terse_v3_v4(struct thread_stat *ts,
        log_buf(out, "\n");
 }
 
+void json_add_job_opts(struct json_object *root, const char *name,
+                      struct flist_head *opt_list, bool num_jobs)
+{
+       struct json_object *dir_object;
+       struct flist_head *entry;
+       struct print_option *p;
+
+       if (flist_empty(opt_list))
+               return;
+
+       dir_object = json_create_object();
+       json_object_add_value_object(root, name, dir_object);
+
+       flist_for_each(entry, opt_list) {
+               const char *pos = "";
+
+               p = flist_entry(entry, struct print_option, list);
+               if (!num_jobs && !strcmp(p->name, "numjobs"))
+                       continue;
+               if (p->value)
+                       pos = p->value;
+               json_object_add_value_string(dir_object, p->name, pos);
+       }
+}
+
 static struct json_object *show_thread_status_json(struct thread_stat *ts,
-                                   struct group_run_stats *rs)
+                                                  struct group_run_stats *rs,
+                                                  struct flist_head *opt_list)
 {
        struct json_object *root, *tmp;
        struct jobs_eta *je;
@@ -1082,12 +1130,15 @@ static struct json_object *show_thread_status_json(struct thread_stat *ts,
        json_object_add_value_int(root, "error", ts->error);
 
        /* ETA Info */
-       je = get_jobs_eta(1, &size);
+       je = get_jobs_eta(true, &size);
        if (je) {
                json_object_add_value_int(root, "eta", je->eta_sec);
                json_object_add_value_int(root, "elapsed", je->elapsed_sec);
        }
 
+       if (opt_list)
+               json_add_job_opts(root, "job options", opt_list, true);
+
        add_ddir_status_json(ts, rs, DDIR_READ, root);
        add_ddir_status_json(ts, rs, DDIR_WRITE, root);
        add_ddir_status_json(ts, rs, DDIR_TRIM, root);
@@ -1217,6 +1268,7 @@ static void show_thread_status_terse(struct thread_stat *ts,
 
 struct json_object *show_thread_status(struct thread_stat *ts,
                                       struct group_run_stats *rs,
+                                      struct flist_head *opt_list,
                                       struct buf_output *out)
 {
        struct json_object *ret = NULL;
@@ -1224,14 +1276,14 @@ struct json_object *show_thread_status(struct thread_stat *ts,
        if (output_format & FIO_OUTPUT_TERSE)
                show_thread_status_terse(ts, rs,  out);
        if (output_format & FIO_OUTPUT_JSON)
-               ret = show_thread_status_json(ts, rs);
+               ret = show_thread_status_json(ts, rs, opt_list);
        if (output_format & FIO_OUTPUT_NORMAL)
                show_thread_status_normal(ts, rs,  out);
 
        return ret;
 }
 
-static void sum_stat(struct io_stat *dst, struct io_stat *src, int nr)
+static void sum_stat(struct io_stat *dst, struct io_stat *src, bool first)
 {
        double mean, S;
 
@@ -1246,7 +1298,7 @@ static void sum_stat(struct io_stat *dst, struct io_stat *src, int nr)
         * <http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
         *  #Parallel_algorithm>
         */
-       if (nr == 1) {
+       if (first) {
                mean = src->mean.u.f;
                S = src->S.u.f;
        } else {
@@ -1290,31 +1342,38 @@ void sum_group_stats(struct group_run_stats *dst, struct group_run_stats *src)
                dst->unit_base = src->unit_base;
 }
 
-void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src, int nr)
+void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src,
+                     bool first)
 {
        int l, k;
 
        for (l = 0; l < DDIR_RWDIR_CNT; l++) {
                if (!dst->unified_rw_rep) {
-                       sum_stat(&dst->clat_stat[l], &src->clat_stat[l], nr);
-                       sum_stat(&dst->slat_stat[l], &src->slat_stat[l], nr);
-                       sum_stat(&dst->lat_stat[l], &src->lat_stat[l], nr);
-                       sum_stat(&dst->bw_stat[l], &src->bw_stat[l], nr);
+                       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);
 
                        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], nr);
-                       sum_stat(&dst->slat_stat[0], &src->slat_stat[l], nr);
-                       sum_stat(&dst->lat_stat[0], &src->lat_stat[l], nr);
-                       sum_stat(&dst->bw_stat[0], &src->bw_stat[l], nr);
+                       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);
 
                        dst->io_bytes[0] += src->io_bytes[l];
 
                        if (dst->runtime[0] < src->runtime[l])
                                dst->runtime[0] = src->runtime[l];
+
+                       /*
+                        * We're summing to the same destination, so override
+                        * 'first' after the first iteration of the loop
+                        */
+                       first = false;
                }
        }
 
@@ -1398,6 +1457,7 @@ void __show_run_stats(void)
        struct json_object *root = NULL;
        struct json_array *array = NULL;
        struct buf_output output[FIO_OUTPUT_NR];
+       struct flist_head **opt_lists;
 
        runstats = malloc(sizeof(struct group_run_stats) * (groupid + 1));
 
@@ -1423,9 +1483,12 @@ void __show_run_stats(void)
        }
 
        threadstats = malloc(nr_ts * sizeof(struct thread_stat));
+       opt_lists = malloc(nr_ts * sizeof(struct flist_head *));
 
-       for (i = 0; i < nr_ts; i++)
+       for (i = 0; i < nr_ts; i++) {
                init_thread_stat(&threadstats[i]);
+               opt_lists[i] = NULL;
+       }
 
        j = 0;
        last_ts = -1;
@@ -1444,6 +1507,7 @@ void __show_run_stats(void)
                ts->clat_percentiles = td->o.clat_percentiles;
                ts->percentile_precision = td->o.percentile_precision;
                memcpy(ts->percentile_list, td->o.percentile_list, sizeof(td->o.percentile_list));
+               opt_lists[j] = &td->opt_list;
 
                idx++;
                ts->members++;
@@ -1509,7 +1573,7 @@ void __show_run_stats(void)
                for (k = 0; k < ts->nr_block_infos; k++)
                        ts->block_infos[k] = td->ts.block_infos[k];
 
-               sum_thread_stats(ts, &td->ts, idx);
+               sum_thread_stats(ts, &td->ts, idx == 1);
        }
 
        for (i = 0; i < nr_ts; i++) {
@@ -1567,6 +1631,7 @@ void __show_run_stats(void)
        if (output_format & FIO_OUTPUT_NORMAL)
                log_buf(&output[__FIO_OUTPUT_NORMAL], "\n");
        if (output_format & FIO_OUTPUT_JSON) {
+               struct thread_data *global;
                char time_buf[32];
                time_t time_p;
 
@@ -1579,28 +1644,34 @@ void __show_run_stats(void)
                json_object_add_value_string(root, "fio version", fio_version_string);
                json_object_add_value_int(root, "timestamp", time_p);
                json_object_add_value_string(root, "time", time_buf);
+               global = get_global_options();
+               json_add_job_opts(root, "global options", &global->opt_list, false);
                array = json_create_array();
                json_object_add_value_array(root, "jobs", array);
        }
 
+       if (is_backend)
+               fio_server_send_job_options(&get_global_options()->opt_list, -1U);
+
        for (i = 0; i < nr_ts; i++) {
                ts = &threadstats[i];
                rs = &runstats[ts->groupid];
 
-               if (is_backend)
+               if (is_backend) {
+                       fio_server_send_job_options(opt_lists[i], i);
                        fio_server_send_ts(ts, rs);
-               else {
+               else {
                        if (output_format & FIO_OUTPUT_TERSE)
                                show_thread_status_terse(ts, rs, &output[__FIO_OUTPUT_TERSE]);
                        if (output_format & FIO_OUTPUT_JSON) {
-                               struct json_object *tmp = show_thread_status_json(ts, rs);
+                               struct json_object *tmp = show_thread_status_json(ts, rs, opt_lists[i]);
                                json_array_add_value_object(array, tmp);
                        }
                        if (output_format & FIO_OUTPUT_NORMAL)
                                show_thread_status_normal(ts, rs, &output[__FIO_OUTPUT_NORMAL]);
                }
        }
-       if (output_format & FIO_OUTPUT_JSON) {
+       if (!is_backend && (output_format & FIO_OUTPUT_JSON)) {
                /* disk util stats, if any */
                show_disk_util(1, root, &output[__FIO_OUTPUT_JSON]);
 
@@ -1636,6 +1707,7 @@ void __show_run_stats(void)
        log_info_flush();
        free(runstats);
        free(threadstats);
+       free(opt_lists);
 }
 
 void show_run_stats(void)