Change network transmitted doubles to fio_fp64_t IEEE 754 type
authorJens Axboe <axboe@kernel.dk>
Wed, 5 Oct 2011 07:51:58 +0000 (09:51 +0200)
committerJens Axboe <axboe@kernel.dk>
Wed, 5 Oct 2011 07:51:58 +0000 (09:51 +0200)
Encode and decode when transferring over the network.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
client.c
fio.h
ieee754.c
ieee754.h
init.c
iolog.h
server.c
stat.c
stat.h

index 97bfc89..d538e8a 100644 (file)
--- a/client.c
+++ b/client.c
@@ -330,9 +330,12 @@ static void convert_io_stat(struct io_stat *dst, struct io_stat *src)
        dst->max_val    = le64_to_cpu(src->max_val);
        dst->min_val    = le64_to_cpu(src->min_val);
        dst->samples    = le64_to_cpu(src->samples);
-       /* FIXME */
-       dst->mean       = __le64_to_cpu(src->mean);
-       dst->S          = __le64_to_cpu(src->S);
+
+       /*
+        * Floats arrive as IEEE 754 encoded uint64_t, convert back to double
+        */
+       dst->mean.u.f   = fio_uint64_to_double(le64_to_cpu(dst->mean.u.i));
+       dst->S.u.f      = fio_uint64_to_double(le64_to_cpu(dst->S.u.i));
 }
 
 static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
@@ -357,7 +360,13 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
        dst->minf               = le64_to_cpu(src->minf);
        dst->majf               = le64_to_cpu(src->majf);
        dst->clat_percentiles   = le64_to_cpu(src->clat_percentiles);
-       dst->percentile_list    = NULL;
+
+       for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
+               fio_fp64_t *fps = &src->percentile_list[i];
+               fio_fp64_t *fpd = &dst->percentile_list[i];
+
+               fpd->u.f = fio_uint64_to_double(le64_to_cpu(fps->u.i));
+       }
 
        for (i = 0; i < FIO_IO_U_MAP_NR; i++) {
                dst->io_u_map[i]        = le32_to_cpu(src->io_u_map[i]);
diff --git a/fio.h b/fio.h
index dce4d8d..1fb2118 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -197,7 +197,7 @@ struct thread_options {
        unsigned long long trim_backlog;
        unsigned int clat_percentiles;
        unsigned int overwrite_plist;
-       double percentile_list[FIO_IO_U_LIST_MAX_LEN];
+       fio_fp64_t percentile_list[FIO_IO_U_LIST_MAX_LEN];
 
        char *read_iolog_file;
        char *write_iolog_file;
@@ -498,6 +498,7 @@ extern int terse_version;
 extern int is_backend;
 extern int nr_clients;
 extern int log_syslog;
+extern const fio_fp64_t def_percentile_list[FIO_IO_U_LIST_MAX_LEN];
 
 extern struct thread_data *threads;
 
index 0fbc7f0..c7742a2 100644 (file)
--- a/ieee754.c
+++ b/ieee754.c
@@ -6,6 +6,7 @@
  * Below code was granted to the public domain.
  */
 #include <inttypes.h>
+#include "ieee754.h"
 
 uint64_t pack754(long double f, unsigned bits, unsigned expbits)
 {
index 2087da5..5af9518 100644 (file)
--- a/ieee754.h
+++ b/ieee754.h
@@ -1,10 +1,20 @@
 #ifndef FIO_IEEE754_H
 #define FIO_IEEE754_H
 
+#include <inttypes.h>
+
 extern uint64_t pack754(long double f, unsigned bits, unsigned expbits);
 extern long double unpack754(uint64_t i, unsigned bits, unsigned expbits);
 
 #define fio_double_to_uint64(val)      pack754((val), 64, 11)
 #define fio_uint64_to_double(val)      unpack754((val), 64, 11)
 
+typedef struct fio_fp64 {
+       union {
+               uint64_t i;
+               double f;
+               uint8_t filler[16];
+       } u;
+} fio_fp64_t;
+
 #endif
diff --git a/init.c b/init.c
index 2341915..6066fc5 100644 (file)
--- a/init.c
+++ b/init.c
@@ -69,6 +69,24 @@ unsigned int *fio_debug_jobp = NULL;
 
 static char cmd_optstr[256];
 
+const fio_fp64_t def_percentile_list[FIO_IO_U_LIST_MAX_LEN] = {
+       { .u.f  =  1.0 },
+       { .u.f  =  5.0 },
+       { .u.f  = 10.0 },
+       { .u.f  = 20.0 },
+       { .u.f  = 30.0 },
+       { .u.f  = 40.0 },
+       { .u.f  = 50.0 },
+       { .u.f  = 60.0 },
+       { .u.f  = 70.0 },
+       { .u.f  = 80.0 },
+       { .u.f  = 90.0 },
+       { .u.f  = 95.0 },
+       { .u.f  = 99.0 },
+       { .u.f  = 99.5 },
+       { .u.f  = 99.9 },
+};
+
 /*
  * Command line options. These will contain the above, plus a few
  * extra that only pertain to fio itself and not jobs.
@@ -718,9 +736,9 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
 
        td->ts.clat_percentiles = td->o.clat_percentiles;
        if (td->o.overwrite_plist)
-               td->ts.percentile_list = td->o.percentile_list;
+               memcpy(td->ts.percentile_list, td->o.percentile_list, sizeof(td->o.percentile_list));
        else
-               td->ts.percentile_list = NULL;
+               memcpy(td->ts.percentile_list, def_percentile_list, sizeof(def_percentile_list));
 
        td->ts.clat_stat[0].min_val = td->ts.clat_stat[1].min_val = ULONG_MAX;
        td->ts.slat_stat[0].min_val = td->ts.slat_stat[1].min_val = ULONG_MAX;
diff --git a/iolog.h b/iolog.h
index fa0a218..dd4d647 100644 (file)
--- a/iolog.h
+++ b/iolog.h
@@ -1,6 +1,8 @@
 #ifndef FIO_IOLOG_H
 #define FIO_IOLOG_H
 
+#include "ieee754.h"
+
 /*
  * Use for maintaining statistics
  */
@@ -9,8 +11,8 @@ struct io_stat {
        uint64_t min_val;
        uint64_t samples;
 
-       double mean;
-       double S;
+       fio_fp64_t mean;
+       fio_fp64_t S;
 };
 
 /*
index 29e2387..0f64c23 100644 (file)
--- a/server.c
+++ b/server.c
@@ -18,6 +18,7 @@
 #include "fio.h"
 #include "server.h"
 #include "crc/crc16.h"
+#include "ieee754.h"
 
 int fio_net_port = 8765;
 
@@ -464,9 +465,12 @@ static void convert_io_stat(struct io_stat *dst, struct io_stat *src)
        dst->max_val    = cpu_to_le64(src->max_val);
        dst->min_val    = cpu_to_le64(src->min_val);
        dst->samples    = cpu_to_le64(src->samples);
-       /* FIXME */
-       dst->mean       = __cpu_to_le64(src->mean);
-       dst->S          = __cpu_to_le64(src->S);
+
+       /*
+        * Encode to IEEE 754 for network transfer
+        */
+       dst->mean.u.i   = __cpu_to_le64(fio_double_to_uint64(src->mean.u.f));
+       dst->S.u.i      = __cpu_to_le64(fio_double_to_uint64(src->S.u.f));
 }
 
 static void convert_gs(struct group_run_stats *dst, struct group_run_stats *src)
@@ -521,7 +525,12 @@ void fio_server_send_ts(struct thread_stat *ts, struct group_run_stats *rs)
        p.ts.minf               = cpu_to_le64(ts->minf);
        p.ts.majf               = cpu_to_le64(ts->majf);
        p.ts.clat_percentiles   = cpu_to_le64(ts->clat_percentiles);
-       p.ts.percentile_list    = NULL;
+
+       for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
+               fio_fp64_t *fp = &p.ts.percentile_list[i];
+
+               fp->u.i = __cpu_to_le64(fio_double_to_uint64(fp->u.f));
+       }
 
        for (i = 0; i < FIO_IO_U_MAP_NR; i++) {
                p.ts.io_u_map[i]        = cpu_to_le32(ts->io_u_map[i]);
diff --git a/stat.c b/stat.c
index cfb2978..7bcae31 100644 (file)
--- a/stat.c
+++ b/stat.c
@@ -9,6 +9,7 @@
 
 #include "fio.h"
 #include "diskutil.h"
+#include "ieee754.h"
 
 void update_rusage_stat(struct thread_data *td)
 {
@@ -101,13 +102,13 @@ static unsigned int plat_idx_to_val(unsigned int idx)
 
 static int double_cmp(const void *a, const void *b)
 {
-       const double fa = *(const double *)a;
-       const double fb = *(const double *)b;
+       const fio_fp64_t fa = *(const fio_fp64_t *) a;
+       const fio_fp64_t fb = *(const fio_fp64_t *) b;
        int cmp = 0;
 
-       if (fa > fb)
+       if (fa.u.f > fb.u.f)
                cmp = 1;
-       else if (fa < fb)
+       else if (fa.u.f < fb.u.f)
                cmp = -1;
 
        return cmp;
@@ -117,37 +118,30 @@ static int double_cmp(const void *a, const void *b)
  * Find and display the p-th percentile of clat
  */
 static void show_clat_percentiles(unsigned int *io_u_plat, unsigned long nr,
-                                double *user_list)
+                                 fio_fp64_t *plist)
 {
        unsigned long sum = 0;
        unsigned int len, i, j = 0;
-       const double *plist;
        int is_last = 0;
-       static const double def_list[FIO_IO_U_LIST_MAX_LEN] = {
-                       1.0, 5.0, 10.0, 20.0, 30.0,
-                       40.0, 50.0, 60.0, 70.0, 80.0,
-                       90.0, 95.0, 99.0, 99.5, 99.9};
 
-       plist = user_list;
-       if (!plist)
-               plist = def_list;
-
-       for (len = 0; len <FIO_IO_U_LIST_MAX_LEN && plist[len] != 0; len++)
-               ;
+       len = 0;
+       while (len < FIO_IO_U_LIST_MAX_LEN && plist[len].u.f != 0.0)
+               len++;
 
        /*
-        * Sort the user-specified list. Note that this does not work
-        * for NaN values
+        * Sort the percentile list. Note that it may already be sorted if
+        * we are using the default values, but since it's a short list this
+        * isn't a worry. Also note that this does not work for NaN values.
         */
-       if (user_list && len > 1)
-               qsort((void*)user_list, len, sizeof(user_list[0]), double_cmp);
+       if (len > 1)
+               qsort((void*)plist, len, sizeof(plist[0]), double_cmp);
 
        log_info("    clat percentiles (usec) :");
 
        for (i = 0; i < FIO_IO_U_PLAT_NR && !is_last; i++) {
                sum += io_u_plat[i];
-               while (sum >= (plist[j] / 100 * nr)) {
-                       assert(plist[j] <= 100.0);
+               while (sum >= (plist[j].u.f / 100.0 * nr)) {
+                       assert(plist[j].u.f <= 100.0);
 
                        /* for formatting */
                        if (j != 0 && (j % 4) == 0)
@@ -181,10 +175,10 @@ static int calc_lat(struct io_stat *is, unsigned long *min, unsigned long *max,
        *max = is->max_val;
 
        n = (double) is->samples;
-       *mean = is->mean;
+       *mean = is->mean.u.f;
 
        if (n > 1.0)
-               *dev = sqrt(is->S / (n - 1.0));
+               *dev = sqrt(is->S.u.f / (n - 1.0));
        else
                *dev = 0;
 
@@ -629,23 +623,23 @@ static void sum_stat(struct io_stat *dst, struct io_stat *src, int nr)
         *  #Parallel_algorithm>
         */
        if (nr == 1) {
-               mean = src->mean;
-               S = src->S;
+               mean = src->mean.u.f;
+               S = src->S.u.f;
        } else {
-               double delta = src->mean - dst->mean;
+               double delta = src->mean.u.f - dst->mean.u.f;
 
-               mean = ((src->mean * src->samples) +
-                       (dst->mean * dst->samples)) /
+               mean = ((src->mean.u.f * src->samples) +
+                       (dst->mean.u.f * dst->samples)) /
                        (dst->samples + src->samples);
 
-               S =  src->S + dst->S + pow(delta, 2.0) *
+               S =  src->S.u.f + dst->S.u.f + pow(delta, 2.0) *
                        (dst->samples * src->samples) /
                        (dst->samples + src->samples);
        }
 
        dst->samples += src->samples;
-       dst->mean = mean;
-       dst->S = S;
+       dst->mean.u.f = mean;
+       dst->S.u.f = S;
 }
 
 void show_run_stats(void)
@@ -715,9 +709,9 @@ void show_run_stats(void)
 
                ts->clat_percentiles = td->o.clat_percentiles;
                if (td->o.overwrite_plist)
-                       ts->percentile_list = td->o.percentile_list;
+                       memcpy(ts->percentile_list, td->o.percentile_list, sizeof(td->o.percentile_list));
                else
-                       ts->percentile_list = NULL;
+                       memcpy(ts->percentile_list, def_percentile_list, sizeof(def_percentile_list));
 
                idx++;
                ts->members++;
@@ -897,10 +891,10 @@ static inline void add_stat_sample(struct io_stat *is, unsigned long data)
        if (data < is->min_val)
                is->min_val = data;
 
-       delta = val - is->mean;
+       delta = val - is->mean.u.f;
        if (delta) {
-               is->mean += delta / (is->samples + 1.0);
-               is->S += delta * (val - is->mean);
+               is->mean.u.f += delta / (is->samples + 1.0);
+               is->S.u.f += delta * (val - is->mean.u.f);
        }
 
        is->samples++;
diff --git a/stat.h b/stat.h
index 72cbe16..89766fc 100644 (file)
--- a/stat.h
+++ b/stat.h
@@ -141,7 +141,7 @@ struct thread_stat {
         * IO depth and latency stats
         */
        uint64_t clat_percentiles;
-       double *percentile_list;
+       fio_fp64_t percentile_list[FIO_IO_U_LIST_MAX_LEN];
 
        uint32_t io_u_map[FIO_IO_U_MAP_NR];
        uint32_t io_u_submit[FIO_IO_U_MAP_NR];