Change network transmitted doubles to fio_fp64_t IEEE 754 type
Encode and decode when transferring over the network.
Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/client.c b/client.c
index 97bfc89..d538e8a 100644
--- a/client.c
+++ b/client.c
@@ -330,9 +330,12 @@
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 @@
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
--- a/fio.h
+++ b/fio.h
@@ -197,7 +197,7 @@
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 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;
diff --git a/ieee754.c b/ieee754.c
index 0fbc7f0..c7742a2 100644
--- 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)
{
diff --git a/ieee754.h b/ieee754.h
index 2087da5..5af9518 100644
--- 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
--- a/init.c
+++ b/init.c
@@ -69,6 +69,24 @@
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 @@
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
--- 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 @@
uint64_t min_val;
uint64_t samples;
- double mean;
- double S;
+ fio_fp64_t mean;
+ fio_fp64_t S;
};
/*
diff --git a/server.c b/server.c
index 29e2387..0f64c23 100644
--- 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 @@
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 @@
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
--- 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 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 @@
* 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 @@
*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 @@
* #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 @@
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 @@
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
--- a/stat.h
+++ b/stat.h
@@ -141,7 +141,7 @@
* 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];