Handle percentile lists with higher precision that 2 digits
authorVincent Kang Fu <VFu@fusionio.com>
Wed, 6 Feb 2013 07:43:40 +0000 (08:43 +0100)
committerJens Axboe <axboe@kernel.dk>
Wed, 6 Feb 2013 07:43:40 +0000 (08:43 +0100)
We cap the output at %2.2f right now, that's not always enough.
Make the parser check and store the precision required to
output the list correctly.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
fio.h
init.c
options.c
parse.c
stat.c
stat.h

diff --git a/fio.h b/fio.h
index 370ddaa..43f4854 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -248,6 +248,7 @@ struct thread_options {
        unsigned int trim_zero;
        unsigned long long trim_backlog;
        unsigned int clat_percentiles;
+       unsigned int percentile_precision;      /* digits after decimal for percentiles */
        fio_fp64_t percentile_list[FIO_IO_U_LIST_MAX_LEN];
 
        char *read_iolog_file;
diff --git a/init.c b/init.c
index 52665f0..60ba299 100644 (file)
--- a/init.c
+++ b/init.c
@@ -867,6 +867,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
        td->mutex = fio_mutex_init(FIO_MUTEX_LOCKED);
 
        td->ts.clat_percentiles = td->o.clat_percentiles;
+       td->ts.percentile_precision = td->o.percentile_precision;
        memcpy(td->ts.percentile_list, td->o.percentile_list, sizeof(td->o.percentile_list));
 
        for (i = 0; i < DDIR_RWDIR_CNT; i++) {
index 4522fe4..42a2ea0 100644 (file)
--- a/options.c
+++ b/options.c
@@ -2434,6 +2434,7 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .name   = "percentile_list",
                .type   = FIO_OPT_FLOAT_LIST,
                .off1   = td_var_offset(percentile_list),
+               .off2   = td_var_offset(percentile_precision),
                .help   = "Specify a custom list of percentiles to report",
                .def    = "1:5:10:20:30:40:50:60:70:80:90:95:99:99.5:99.9:99.95:99.99",
                .maxlen = FIO_IO_U_LIST_MAX_LEN,
diff --git a/parse.c b/parse.c
index 4ce29c1..15aeb0a 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -369,10 +369,11 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data,
        long ul1, ul2;
        double uf;
        char **cp = NULL;
+       char *cp2;
        int ret = 0, is_time = 0;
        const struct value_pair *vp;
        struct value_pair posval[PARSE_MAX_VP];
-       int i, all_skipped = 1;
+       int i, len, all_skipped = 1;
 
        dprint(FD_PARSE, "__handle_option=%s, type=%d, ptr=%s\n", o->name,
                                                        o->type, ptr);
@@ -502,6 +503,19 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data,
                break;
        }
        case FIO_OPT_FLOAT_LIST: {
+               if (first) {
+                       /*
+                       ** Initialize precision to 0 and zero out list
+                       ** in case specified list is shorter than default
+                       */
+                       ul2 = 0;
+                       ilp = td_var(data, o->off2);
+                       *ilp = ul2;
+
+                       flp = td_var(data, o->off1);
+                       for(i = 0; i < o->maxlen; i++)
+                               flp[i].u.f = 0.0;
+               }
                if (curr >= o->maxlen) {
                        log_err("the list exceeding max length %d\n",
                                        o->maxlen);
@@ -525,6 +539,23 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data,
                flp = td_var(data, o->off1);
                flp[curr].u.f = uf;
 
+               /*
+               ** Calculate precision for output by counting
+               ** number of digits after period. Find first
+               ** period in entire remaining list each time
+               */
+               cp2 = strchr(ptr, '.');
+               if (cp2 != NULL) {
+                       len = 0;
+
+                       while (*++cp2 != '\0' && *cp2 >= '0' && *cp2 <= '9')
+                               len++;
+
+                       ilp = td_var(data, o->off2);
+                       if (len > *ilp)
+                               *ilp = len;
+               }
+
                break;
        }
        case FIO_OPT_STR_STORE: {
diff --git a/stat.c b/stat.c
index fb5ff64..c523f5c 100644 (file)
--- a/stat.c
+++ b/stat.c
@@ -182,11 +182,12 @@ static unsigned int calc_clat_percentiles(unsigned int *io_u_plat,
  * Find and display the p-th percentile of clat
  */
 static void show_clat_percentiles(unsigned int *io_u_plat, unsigned long nr,
-                                 fio_fp64_t *plist)
+                                 fio_fp64_t *plist, uint64_t precision)
 {
        unsigned int len, j = 0, minv, maxv;
        unsigned int *ovals;
        int is_last, scale_down;
+       char buf1[32], buf2[32];
 
        len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
        if (!len)
@@ -204,8 +205,10 @@ static void show_clat_percentiles(unsigned int *io_u_plat, unsigned long nr,
                log_info("    clat percentiles (usec):\n     |");
        }
 
+       snprintf(buf1, sizeof(buf1), " %%1.%luf", precision);
+       snprintf(buf2, sizeof(buf1), "%%1.%luf", precision);
        for (j = 0; j < len; j++) {
-               char fbuf[8];
+               char fbuf[16];
 
                /* for formatting */
                if (j != 0 && (j % 4) == 0)
@@ -215,9 +218,9 @@ static void show_clat_percentiles(unsigned int *io_u_plat, unsigned long nr,
                is_last = (j == len - 1);
 
                if (plist[j].u.f < 10.0)
-                       sprintf(fbuf, " %2.2f", plist[j].u.f);
+                       snprintf(fbuf, sizeof(fbuf), buf1, plist[j].u.f);
                else
-                       sprintf(fbuf, "%2.2f", plist[j].u.f);
+                       snprintf(fbuf, sizeof(fbuf), buf2, plist[j].u.f);
 
                if (scale_down)
                        ovals[j] = (ovals[j] + 999) / 1000;
@@ -440,7 +443,8 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts,
        if (ts->clat_percentiles) {
                show_clat_percentiles(ts->io_u_plat[ddir],
                                        ts->clat_stat[ddir].samples,
-                                       ts->percentile_list);
+                                       ts->percentile_list,
+                                       ts->percentile_precision);
        }
        if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
                double p_of_agg = 100.0;
@@ -655,7 +659,7 @@ static void show_ddir_status_terse(struct thread_stat *ts,
                        log_info(";0%%=0");
                        continue;
                }
-               log_info(";%2.2f%%=%u", ts->percentile_list[i].u.f, ovals[i]);
+               log_info(";%f%%=%u", ts->percentile_list[i].u.f, ovals[i]);
        }
 
        if (calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev))
@@ -753,7 +757,7 @@ static void add_ddir_status_json(struct thread_stat *ts,
                        json_object_add_value_int(percentile_object, "0.00", 0);
                        continue;
                }
-               snprintf(buf, sizeof(buf), "%2.2f", ts->percentile_list[i].u.f);
+               snprintf(buf, sizeof(buf), "%f", ts->percentile_list[i].u.f);
                json_object_add_value_int(percentile_object, (const char *)buf, ovals[i]);
        }
 
@@ -1210,6 +1214,7 @@ void show_run_stats(void)
                ts = &threadstats[j];
 
                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));
 
                idx++;
diff --git a/stat.h b/stat.h
index 97186c1..98ae4c8 100644 (file)
--- a/stat.h
+++ b/stat.h
@@ -144,6 +144,7 @@ struct thread_stat {
         * IO depth and latency stats
         */
        uint64_t clat_percentiles;
+       uint64_t percentile_precision;
        fio_fp64_t percentile_list[FIO_IO_U_LIST_MAX_LEN];
 
        uint32_t io_u_map[FIO_IO_U_MAP_NR];