X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=stat.c;h=71eca48e9bf23a731bb9956e2af6cca0b3cf684e;hp=ee6ee51ec1553550322f0e8e9377b069127427ce;hb=5b9babb7fb9ac46c0e960ccd88c2d85ba3065c01;hpb=0a0b49007cbce8d16c9214e7ed47a2b7cc0cc7ed diff --git a/stat.c b/stat.c index ee6ee51e..71eca48e 100644 --- a/stat.c +++ b/stat.c @@ -9,23 +9,24 @@ #include "fio.h" #include "diskutil.h" +#include "ieee754.h" void update_rusage_stat(struct thread_data *td) { struct thread_stat *ts = &td->ts; - getrusage(RUSAGE_SELF, &ts->ru_end); + getrusage(RUSAGE_SELF, &td->ru_end); - ts->usr_time += mtime_since(&ts->ru_start.ru_utime, - &ts->ru_end.ru_utime); - ts->sys_time += mtime_since(&ts->ru_start.ru_stime, - &ts->ru_end.ru_stime); - ts->ctx += ts->ru_end.ru_nvcsw + ts->ru_end.ru_nivcsw - - (ts->ru_start.ru_nvcsw + ts->ru_start.ru_nivcsw); - ts->minf += ts->ru_end.ru_minflt - ts->ru_start.ru_minflt; - ts->majf += ts->ru_end.ru_majflt - ts->ru_start.ru_majflt; + ts->usr_time += mtime_since(&td->ru_start.ru_utime, + &td->ru_end.ru_utime); + ts->sys_time += mtime_since(&td->ru_start.ru_stime, + &td->ru_end.ru_stime); + ts->ctx += td->ru_end.ru_nvcsw + td->ru_end.ru_nivcsw + - (td->ru_start.ru_nvcsw + td->ru_start.ru_nivcsw); + ts->minf += td->ru_end.ru_minflt - td->ru_start.ru_minflt; + ts->majf += td->ru_end.ru_majflt - td->ru_start.ru_majflt; - memcpy(&ts->ru_start, &ts->ru_end, sizeof(ts->ru_end)); + memcpy(&td->ru_start, &td->ru_end, sizeof(td->ru_end)); } /* @@ -47,8 +48,10 @@ static unsigned int plat_val_to_idx(unsigned int val) else msb = (sizeof(val)*8) - __builtin_clz(val) - 1; - /* MSB <= (FIO_IO_U_PLAT_BITS-1), cannot be rounded off. Use - * all bits of the sample as index */ + /* + * MSB <= (FIO_IO_U_PLAT_BITS-1), cannot be rounded off. Use + * all bits of the sample as index + */ if (msb <= FIO_IO_U_PLAT_BITS) return val; @@ -58,8 +61,10 @@ static unsigned int plat_val_to_idx(unsigned int val) /* Compute the number of buckets before the group */ base = (error_bits + 1) << FIO_IO_U_PLAT_BITS; - /* Discard the error bits and apply the mask to find the - * index for the buckets in the group */ + /* + * Discard the error bits and apply the mask to find the + * index for the buckets in the group + */ offset = (FIO_IO_U_PLAT_VAL - 1) & (val >> error_bits); /* Make sure the index does not exceed (array size - 1) */ @@ -97,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; @@ -112,33 +117,34 @@ 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) +static void show_clat_percentiles(unsigned int *io_u_plat, unsigned long nr, + fio_fp64_t *plist) { unsigned long sum = 0; unsigned int len, i, j = 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}; + int is_last = 0; - const double* plist = user_list? user_list: def_list; - for (len = 0; len 1) - qsort((void*)user_list, len, sizeof(user_list[0]), double_cmp); + /* + * 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 (len > 1) + qsort((void*)plist, len, sizeof(plist[0]), double_cmp); - int is_last = 0; log_info(" clat percentiles (usec) :"); - for (i = 0; i = (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); - if (j!=0 && (j%4) == 0) /* for formatting */ + /* for formatting */ + if (j != 0 && (j % 4) == 0) log_info(" "); /* end of the list */ @@ -147,9 +153,10 @@ static void show_clat_percentiles(unsigned int* io_u_plat, unsigned long nr, log_info(" %2.2fth=%u%c", plist[j], plat_idx_to_val(i), (is_last? '\n' : ',')); - if (is_last) break; + if (is_last) + break; - if (j%4 == 3) /* for formatting */ + if (j % 4 == 3) /* for formatting */ log_info("\n"); j++; } @@ -168,23 +175,23 @@ 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; return 1; } -static void show_group_stats(struct group_run_stats *rs, int id) +void show_group_stats(struct group_run_stats *rs) { char *p1, *p2, *p3, *p4; const char *ddir_str[] = { " READ", " WRITE" }; int i; - log_info("\nRun status group %d (all jobs):\n", id); + log_info("\nRun status group %d (all jobs):\n", rs->groupid); for (i = 0; i <= DDIR_WRITE; i++) { const int i2p = is_power_of_2(rs->kb_base); @@ -365,7 +372,7 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts, double p_of_agg; p_of_agg = mean * 100 / (double) rs->agg[ddir]; - log_info(" bw (KB/s) : min=%5lu, max=%5lu, per=%3.2f%%," + log_info(" bw (KB/s) : min=%5lu, max=%5lu, per=%3.2f%%," " avg=%5.02f, stdev=%5.02f\n", min, max, p_of_agg, mean, dev); } @@ -420,8 +427,7 @@ static void show_latencies(double *io_u_lat_u, double *io_u_lat_m) log_info("\n"); } -static void show_thread_status(struct thread_stat *ts, - struct group_run_stats *rs) +void show_thread_status(struct thread_stat *ts, struct group_run_stats *rs) { double usr_cpu, sys_cpu; unsigned long runtime; @@ -605,6 +611,9 @@ static void sum_stat(struct io_stat *dst, struct io_stat *src, int nr) { double mean, S; + if (src->samples == 0) + return; + dst->min_val = min(dst->min_val, src->min_val); dst->max_val = max(dst->max_val, src->max_val); @@ -614,23 +623,72 @@ 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 sum_thread_stats(struct thread_stat *dst, struct thread_stat *src, int nr) +{ + int l, k; + + for (l = 0; l <= DDIR_WRITE; l++) { + 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); + + dst->io_bytes[l] += src->io_bytes[l]; + + if (dst->runtime[l] < src->runtime[l]) + dst->runtime[l] = src->runtime[l]; + } + + dst->usr_time += src->usr_time; + dst->sys_time += src->sys_time; + dst->ctx += src->ctx; + dst->majf += src->majf; + dst->minf += src->minf; + + for (k = 0; k < FIO_IO_U_MAP_NR; k++) + dst->io_u_map[k] += src->io_u_map[k]; + for (k = 0; k < FIO_IO_U_MAP_NR; k++) + dst->io_u_submit[k] += src->io_u_submit[k]; + for (k = 0; k < FIO_IO_U_MAP_NR; k++) + dst->io_u_complete[k] += src->io_u_complete[k]; + for (k = 0; k < FIO_IO_U_LAT_U_NR; k++) + dst->io_u_lat_u[k] += src->io_u_lat_u[k]; + for (k = 0; k < FIO_IO_U_LAT_M_NR; k++) + dst->io_u_lat_m[k] += src->io_u_lat_m[k]; + + for (k = 0; k <= 2; k++) { + dst->total_io_u[k] += src->total_io_u[k]; + dst->short_io_u[k] += src->short_io_u[k]; + } + + for (k = 0; k <= DDIR_WRITE; k++) { + int m; + for (m = 0; m < FIO_IO_U_PLAT_NR; m++) + dst->io_u_plat[k][m] += src->io_u_plat[k][m]; + } + + dst->total_run_time += src->total_run_time; + dst->total_submit += src->total_submit; + dst->total_complete += src->total_complete; } void show_run_stats(void) @@ -638,7 +696,7 @@ void show_run_stats(void) struct group_run_stats *runstats, *rs; struct thread_data *td; struct thread_stat *threadstats, *ts; - int i, j, k, l, nr_ts, last_ts, idx; + int i, j, nr_ts, last_ts, idx; int kb_base_warned = 0; runstats = malloc(sizeof(struct group_run_stats) * (groupid + 1)); @@ -700,9 +758,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++; @@ -711,8 +769,13 @@ void show_run_stats(void) /* * These are per-group shared already */ - ts->name = td->o.name; - ts->description = td->o.description; + strncpy(ts->name, td->o.name, FIO_JOBNAME_SIZE); + if (td->o.description) + strncpy(ts->description, td->o.description, + FIO_JOBNAME_SIZE); + else + memset(ts->description, 0, FIO_JOBNAME_SIZE); + ts->groupid = td->groupid; /* @@ -734,57 +797,14 @@ void show_run_stats(void) if (!td->error && td->o.continue_on_error && td->first_error) { ts->error = td->first_error; - ts->verror = td->verror; + strcpy(ts->verror, td->verror); } else if (td->error) { ts->error = td->error; - ts->verror = td->verror; + strcpy(ts->verror, td->verror); } } - for (l = 0; l <= DDIR_WRITE; l++) { - sum_stat(&ts->clat_stat[l], &td->ts.clat_stat[l], idx); - sum_stat(&ts->slat_stat[l], &td->ts.slat_stat[l], idx); - sum_stat(&ts->lat_stat[l], &td->ts.lat_stat[l], idx); - sum_stat(&ts->bw_stat[l], &td->ts.bw_stat[l], idx); - - ts->stat_io_bytes[l] += td->ts.stat_io_bytes[l]; - ts->io_bytes[l] += td->ts.io_bytes[l]; - - if (ts->runtime[l] < td->ts.runtime[l]) - ts->runtime[l] = td->ts.runtime[l]; - } - - ts->usr_time += td->ts.usr_time; - ts->sys_time += td->ts.sys_time; - ts->ctx += td->ts.ctx; - ts->majf += td->ts.majf; - ts->minf += td->ts.minf; - - for (k = 0; k < FIO_IO_U_MAP_NR; k++) - ts->io_u_map[k] += td->ts.io_u_map[k]; - for (k = 0; k < FIO_IO_U_MAP_NR; k++) - ts->io_u_submit[k] += td->ts.io_u_submit[k]; - for (k = 0; k < FIO_IO_U_MAP_NR; k++) - ts->io_u_complete[k] += td->ts.io_u_complete[k]; - for (k = 0; k < FIO_IO_U_LAT_U_NR; k++) - ts->io_u_lat_u[k] += td->ts.io_u_lat_u[k]; - for (k = 0; k < FIO_IO_U_LAT_M_NR; k++) - ts->io_u_lat_m[k] += td->ts.io_u_lat_m[k]; - - - for (k = 0; k <= 2; k++) { - int m; - - ts->total_io_u[k] += td->ts.total_io_u[k]; - ts->short_io_u[k] += td->ts.short_io_u[k]; - - for (m = 0; m < FIO_IO_U_PLAT_NR; m++) - ts->io_u_plat[k][m] += td->ts.io_u_plat[k][m]; - } - - ts->total_run_time += td->ts.total_run_time; - ts->total_submit += td->ts.total_submit; - ts->total_complete += td->ts.total_complete; + sum_thread_stats(ts, &td->ts, idx); } for (i = 0; i < nr_ts; i++) { @@ -841,15 +861,24 @@ void show_run_stats(void) ts = &threadstats[i]; rs = &runstats[ts->groupid]; - if (terse_output) + if (is_backend) + fio_server_send_ts(ts, rs); + else if (terse_output) show_thread_status_terse(ts, rs); else show_thread_status(ts, rs); } if (!terse_output) { - for (i = 0; i < groupid + 1; i++) - show_group_stats(&runstats[i], i); + for (i = 0; i < groupid + 1; i++) { + rs = &runstats[i]; + + rs->groupid = i; + if (is_backend) + fio_server_send_gs(rs); + else + show_group_stats(rs); + } show_disk_util(); } @@ -868,10 +897,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++; @@ -937,8 +966,8 @@ void add_clat_sample(struct thread_data *td, enum fio_ddir ddir, add_stat_sample(&ts->clat_stat[ddir], usec); - if (ts->clat_log) - add_log_sample(td, ts->clat_log, usec, ddir, bs); + if (td->clat_log) + add_log_sample(td, td->clat_log, usec, ddir, bs); if (ts->clat_percentiles) add_clat_percentile_sample(ts, usec, ddir); @@ -954,8 +983,8 @@ void add_slat_sample(struct thread_data *td, enum fio_ddir ddir, add_stat_sample(&ts->slat_stat[ddir], usec); - if (ts->slat_log) - add_log_sample(td, ts->slat_log, usec, ddir, bs); + if (td->slat_log) + add_log_sample(td, td->slat_log, usec, ddir, bs); } void add_lat_sample(struct thread_data *td, enum fio_ddir ddir, @@ -968,8 +997,8 @@ void add_lat_sample(struct thread_data *td, enum fio_ddir ddir, add_stat_sample(&ts->lat_stat[ddir], usec); - if (ts->lat_log) - add_log_sample(td, ts->lat_log, usec, ddir, bs); + if (td->lat_log) + add_log_sample(td, td->lat_log, usec, ddir, bs); } void add_bw_sample(struct thread_data *td, enum fio_ddir ddir, unsigned int bs, @@ -981,17 +1010,43 @@ void add_bw_sample(struct thread_data *td, enum fio_ddir ddir, unsigned int bs, if (!ddir_rw(ddir)) return; - spent = mtime_since(&ts->stat_sample_time[ddir], t); + spent = mtime_since(&td->bw_sample_time, t); if (spent < td->o.bw_avg_time) return; - rate = (td->this_io_bytes[ddir] - ts->stat_io_bytes[ddir]) * + rate = (td->this_io_bytes[ddir] - td->stat_io_bytes[ddir]) * 1000 / spent / 1024; add_stat_sample(&ts->bw_stat[ddir], rate); - if (ts->bw_log) - add_log_sample(td, ts->bw_log, rate, ddir, bs); + if (td->bw_log) + add_log_sample(td, td->bw_log, rate, ddir, bs); + + fio_gettime(&td->bw_sample_time, NULL); + td->stat_io_bytes[ddir] = td->this_io_bytes[ddir]; +} + +void add_iops_sample(struct thread_data *td, enum fio_ddir ddir, + struct timeval *t) +{ + struct thread_stat *ts = &td->ts; + unsigned long spent, iops; + + if (!ddir_rw(ddir)) + return; + + spent = mtime_since(&td->iops_sample_time, t); + if (spent < td->o.iops_avg_time) + return; + + iops = ((td->this_io_blocks[ddir] - td->stat_io_blocks[ddir]) * 1000) / spent; + + add_stat_sample(&ts->iops_stat[ddir], iops); + + if (td->iops_log) { + assert(iops); + add_log_sample(td, td->iops_log, iops, ddir, 0); + } - fio_gettime(&ts->stat_sample_time[ddir], NULL); - ts->stat_io_bytes[ddir] = td->this_io_bytes[ddir]; + fio_gettime(&td->iops_sample_time, NULL); + td->stat_io_blocks[ddir] = td->this_io_blocks[ddir]; }