X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=stat.c;h=f9c6985338d998095fd35a229d8b0be5ed533760;hp=a84f28a58edf4069091bccf25ffc9801426ce3fb;hb=429ca0735f71961ffe52c5ac102b0a14ee1b2c4c;hpb=1188caf84ba7fb6c2b3955ad67f4bf087ede13fd diff --git a/stat.c b/stat.c index a84f28a5..f9c69853 100644 --- a/stat.c +++ b/stat.c @@ -12,6 +12,46 @@ static struct itimerval itimer; static struct list_head disk_list = LIST_HEAD_INIT(disk_list); +/* + * Cheasy number->string conversion, complete with carry rounding error. + */ +static char *num2str(unsigned long num, int maxlen, int base) +{ + /* + * could be passed in for 10^3 base, but every caller expects + * 2^10 base right now. + */ + const unsigned int thousand = 1024; + char postfix[] = { 'K', 'M', 'G', 'P', 'E' }; + char *buf; + int i; + + buf = malloc(128); + + for (i = 0; base > 1; i++) + base /= thousand; + + do { + int len, carry = 0; + + len = sprintf(buf, "%'lu", num); + if (len <= maxlen) { + buf[len] = postfix[i]; + buf[len + 1] = '\0'; + return buf; + } + + if ((num % thousand) >= (thousand / 2)) + carry = 1; + + num /= thousand; + num += carry; + i++; + } while (i <= 5); + + return buf; +} + static int get_io_ticks(struct disk_util *du, struct disk_util_stat *dus) { unsigned in_flight; @@ -205,7 +245,7 @@ void init_disk_util(struct thread_data *td) dev_t dev; char *p; - if (!td->do_disk_util) + if (!td->do_disk_util || (td->io_ops->flags & (FIO_NETIO | FIO_NULLIO))) return; /* @@ -275,7 +315,6 @@ void update_rusage_stat(struct thread_data *td) td->usr_time += mtime_since(&td->ru_start.ru_utime, &td->ru_end.ru_utime); td->sys_time += mtime_since(&td->ru_start.ru_stime, &td->ru_end.ru_stime); td->ctx += td->ru_end.ru_nvcsw + td->ru_end.ru_nivcsw - (td->ru_start.ru_nvcsw + td->ru_start.ru_nivcsw); - memcpy(&td->ru_start, &td->ru_end, sizeof(td->ru_end)); } @@ -283,7 +322,7 @@ void update_rusage_stat(struct thread_data *td) static int calc_lat(struct io_stat *is, unsigned long *min, unsigned long *max, double *mean, double *dev) { - double n, o; + double n = is->samples; if (is->samples == 0) return 0; @@ -292,29 +331,40 @@ static int calc_lat(struct io_stat *is, unsigned long *min, unsigned long *max, *max = is->max_val; n = (double) is->samples; - *mean = (double) is->val / n; - *dev = 0.01; - - if (n <= 1.0) - return 1; + *mean = is->mean; - o = (double) is->val_sq - ((*mean * *mean) / n); - if (o < 0.0) - *dev = -1.0; + if (n > 1.0) + *dev = sqrt(is->S / (n - 1.0)); else - *dev = sqrt(o / (n - 1.0)); + *dev = -1.0; return 1; } static void show_group_stats(struct group_run_stats *rs, int id) { + char *p1, *p2, *p3, *p4; + const char *ddir_str[] = { " READ", " WRITE" }; + int i; + fprintf(f_out, "\nRun status group %d (all jobs):\n", id); - if (rs->max_run[DDIR_READ]) - fprintf(f_out, " READ: io=%lluMiB, aggrb=%llu, minb=%llu, maxb=%llu, mint=%llumsec, maxt=%llumsec\n", rs->io_kb[0] >> 10, rs->agg[0], rs->min_bw[0], rs->max_bw[0], rs->min_run[0], rs->max_run[0]); - if (rs->max_run[DDIR_WRITE]) - fprintf(f_out, " WRITE: io=%lluMiB, aggrb=%llu, minb=%llu, maxb=%llu, mint=%llumsec, maxt=%llumsec\n", rs->io_kb[1] >> 10, rs->agg[1], rs->min_bw[1], rs->max_bw[1], rs->min_run[1], rs->max_run[1]); + for (i = 0; i <= DDIR_WRITE; i++) { + if (!rs->max_run[i]) + continue; + + p1 = num2str(rs->io_kb[i], 6, 1); + p2 = num2str(rs->agg[i], 6, 1); + p3 = num2str(rs->min_bw[i], 6, 1); + p4 = num2str(rs->max_bw[i], 6, 1); + + fprintf(f_out, "%s: io=%siB, aggrb=%siB/s, minb=%siB/s, maxb=%siB/s, mint=%llumsec, maxt=%llumsec\n", ddir_str[i], p1, p2, p3, p4, rs->min_run[0], rs->max_run[0]); + + free(p1); + free(p2); + free(p3); + free(p4); + } } static void show_disk_util(void) @@ -355,24 +405,31 @@ static void show_ddir_status(struct thread_data *td, struct group_run_stats *rs, unsigned long min, max; unsigned long long bw; double mean, dev; + char *io_p, *bw_p; if (!td->runtime[ddir]) return; bw = td->io_bytes[ddir] / td->runtime[ddir]; - fprintf(f_out, " %s: io=%6lluMiB, bw=%6lluKiB/s, runt=%6lumsec\n", ddir_str[ddir], td->io_bytes[ddir] >> 20, bw, td->runtime[ddir]); + io_p = num2str(td->io_bytes[ddir] >> 10, 6, 1); + bw_p = num2str(bw, 6, 1); + + fprintf(f_out, " %s: io=%siB, bw=%siB/s, runt=%6lumsec\n", ddir_str[ddir], io_p, bw_p, td->runtime[ddir]); + + free(io_p); + free(bw_p); if (calc_lat(&td->slat_stat[ddir], &min, &max, &mean, &dev)) - fprintf(f_out, " slat (msec): min=%5lu, max=%5lu, avg=%5.02f, dev=%5.02f\n", min, max, mean, dev); + fprintf(f_out, " slat (msec): min=%5lu, max=%5lu, avg=%5.02f, stdev=%5.02f\n", min, max, mean, dev); if (calc_lat(&td->clat_stat[ddir], &min, &max, &mean, &dev)) - fprintf(f_out, " clat (msec): min=%5lu, max=%5lu, avg=%5.02f, dev=%5.02f\n", min, max, mean, dev); + fprintf(f_out, " clat (msec): min=%5lu, max=%5lu, avg=%5.02f, stdev=%5.02f\n", min, max, mean, dev); if (calc_lat(&td->bw_stat[ddir], &min, &max, &mean, &dev)) { double p_of_agg; p_of_agg = mean * 100 / (double) rs->agg[ddir]; - fprintf(f_out, " bw (KiB/s) : min=%5lu, max=%5lu, per=%3.2f%%, avg=%5.02f, dev=%5.02f\n", min, max, p_of_agg, mean, dev); + fprintf(f_out, " bw (KiB/s) : min=%5lu, max=%5lu, per=%3.2f%%, avg=%5.02f, stdev=%5.02f\n", min, max, p_of_agg, mean, dev); } } @@ -381,11 +438,16 @@ static void show_thread_status(struct thread_data *td, { double usr_cpu, sys_cpu; unsigned long runtime; + double io_u_dist[FIO_IO_U_MAP_NR]; + int i; - if (!(td->io_bytes[0] + td->io_bytes[1]) && !td->error) + if (!(td->io_bytes[0] + td->io_bytes[1])) return; - fprintf(f_out, "%s: (groupid=%d): err=%2d:\n",td->name, td->groupid, td->error); + if (!td->error) + fprintf(f_out, "%s: (groupid=%d): err=%2d: pid=%d\n",td->name, td->groupid, td->error, td->pid); + else + fprintf(f_out, "%s: (groupid=%d): err=%2d (%s): pid=%d\n",td->name, td->groupid, td->error, td->verror, td->pid); show_ddir_status(td, rs, td->ddir); if (td->io_bytes[td->ddir ^ 1]) @@ -403,6 +465,19 @@ static void show_thread_status(struct thread_data *td, } fprintf(f_out, " cpu : usr=%3.2f%%, sys=%3.2f%%, ctx=%lu\n", usr_cpu, sys_cpu, td->ctx); + + /* + * Do depth distribution calculations + */ + for (i = 0; i < FIO_IO_U_MAP_NR; i++) { + io_u_dist[i] = (double) td->io_u_map[i] / (double) td->total_io_u; + io_u_dist[i] *= 100.0; + } + + fprintf(f_out, " IO depths : 1=%3.1f%%, 2=%3.1f%%, 4=%3.1f%%, 8=%3.1f%%, 16=%3.1f%%, 32=%3.1f%%, >=64=%3.1f%%\n", io_u_dist[0], io_u_dist[1], io_u_dist[2], io_u_dist[3], io_u_dist[4], io_u_dist[5], io_u_dist[6]); + + if (td->description) + fprintf(f_out, "%s\n", td->description); } static void show_ddir_status_terse(struct thread_data *td, @@ -481,11 +556,6 @@ void show_run_stats(void) for_each_td(td, i) { unsigned long long rbw, wbw; - if (td->error) { - fprintf(f_out, "%s: %s\n", td->name, td->verror); - continue; - } - rs = &runstats[td->groupid]; if (td->runtime[0] < rs->min_run[0] || !rs->min_run[0]) @@ -550,20 +620,26 @@ void show_run_stats(void) free(runstats); } -static inline void add_stat_sample(struct io_stat *is, unsigned long val) +static inline void add_stat_sample(struct io_stat *is, unsigned long data) { - if (val > is->max_val) - is->max_val = val; - if (val < is->min_val) - is->min_val = val; + double val = data; + double delta, n; + + if (data > is->max_val) + is->max_val = data; + if (data < is->min_val) + is->min_val = data; + + delta = val - is->mean; + n = is->samples + 1.0; + is->mean += delta / n; + is->S += delta * (val - is->mean); - is->val += val; - is->val_sq += val * val; is->samples++; } -static void add_log_sample(struct thread_data *td, struct io_log *iolog, - unsigned long val, enum fio_ddir ddir) +static void __add_log_sample(struct io_log *iolog, unsigned long val, + enum fio_ddir ddir, unsigned long time) { if (iolog->nr_samples == iolog->max_samples) { int new_size = sizeof(struct io_sample) * iolog->max_samples*2; @@ -573,11 +649,24 @@ static void add_log_sample(struct thread_data *td, struct io_log *iolog, } iolog->log[iolog->nr_samples].val = val; - iolog->log[iolog->nr_samples].time = mtime_since_now(&td->epoch); + iolog->log[iolog->nr_samples].time = time; iolog->log[iolog->nr_samples].ddir = ddir; iolog->nr_samples++; } +static void add_log_sample(struct thread_data *td, struct io_log *iolog, + unsigned long val, enum fio_ddir ddir) +{ + __add_log_sample(iolog, val, ddir, mtime_since_now(&td->epoch)); +} + +void add_agg_sample(unsigned long val, enum fio_ddir ddir) +{ + struct io_log *iolog = agg_io_log[ddir]; + + __add_log_sample(iolog, val, ddir, mtime_since_genesis()); +} + void add_clat_sample(struct thread_data *td, enum fio_ddir ddir, unsigned long msec) {