From 802ad4a83e92a30b5fdccf117d59fbb69068c054 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 5 Oct 2011 09:51:58 +0200 Subject: [PATCH] Change network transmitted doubles to fio_fp64_t IEEE 754 type Encode and decode when transferring over the network. Signed-off-by: Jens Axboe --- client.c | 17 ++++++++++---- fio.h | 3 ++- ieee754.c | 1 + ieee754.h | 10 ++++++++ init.c | 22 ++++++++++++++++-- iolog.h | 6 +++-- server.c | 17 ++++++++++---- stat.c | 68 +++++++++++++++++++++++++------------------------------ stat.h | 2 +- 9 files changed, 95 insertions(+), 51 deletions(-) diff --git a/client.c b/client.c index 97bfc898..d538e8ab 100644 --- 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 dce4d8d4..1fb21180 100644 --- 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; diff --git a/ieee754.c b/ieee754.c index 0fbc7f0e..c7742a2d 100644 --- a/ieee754.c +++ b/ieee754.c @@ -6,6 +6,7 @@ * Below code was granted to the public domain. */ #include +#include "ieee754.h" uint64_t pack754(long double f, unsigned bits, unsigned expbits) { diff --git a/ieee754.h b/ieee754.h index 2087da5e..5af9518e 100644 --- a/ieee754.h +++ b/ieee754.h @@ -1,10 +1,20 @@ #ifndef FIO_IEEE754_H #define FIO_IEEE754_H +#include + 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 23419158..6066fc59 100644 --- 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 fa0a218b..dd4d6470 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 @@ struct io_stat { 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 29e23873..0f64c235 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 @@ 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 cfb29788..7bcae310 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 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 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 72cbe168..89766fc0 100644 --- 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]; -- 2.25.1