From c6ae0a5b8123ea9af2ce70319081fbd5d65c8093 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 12 Jun 2006 11:04:44 +0200 Subject: [PATCH 1/1] [PATCH] Add option for terse parseable output --- README | 26 +++++++++++++++++++++ fio.c | 8 ++++--- fio.h | 1 + init.c | 18 +++++++++++---- stat.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 113 insertions(+), 13 deletions(-) diff --git a/README b/README index c951504e..d6ff1096 100644 --- a/README +++ b/README @@ -48,6 +48,7 @@ $ fio -w Generate per-job bandwidth logs -f Read for job descriptions -o Log output to file + -m Minimal (terse) output -h Print help info -v Print version information and exit @@ -303,6 +304,31 @@ util= The disk utilization. A value of 100% means we kept the disk busy constantly, 50% would be a disk idling half of the time. +Terse output +------------ + +For scripted usage where you typically want to generate tables or graphs +of the results, fio can output the results in a comma seperated format. +The format is one long line of values, such as: + +client1,0,0,936,331,2894,0,0,0.000000,0.000000,1,170,22.115385,34.290410,16,714,84.252874%,366.500000,566.417819,3496,1237,2894,0,0,0.000000,0.000000,0,246,6.671625,21.436952,0,2534,55.465300%,1406.600000,2008.044216,0.000000%,0.431928%,1109 + +Split up, the format is as follows: + + jobname, groupid, error + READ status: + KiB IO, bandwidth (KiB/sec), runtime (msec) + Submission latency: min, max, mean, deviation + Completion latency: min, max, mean, deviation + Bw: min, max, aggreate percentage of total, mean, deviation + WRITE status: + KiB IO, bandwidth (KiB/sec), runtime (msec) + Submission latency: min, max, mean, deviation + Completion latency: min, max, mean, deviation + Bw: min, max, aggreate percentage of total, mean, deviation + CPU usage: user, system, context switches + + Author ------ diff --git a/fio.c b/fio.c index b53a58eb..445600f2 100644 --- a/fio.c +++ b/fio.c @@ -1576,7 +1576,7 @@ static void print_thread_status(void) char eta_str[32]; double perc = 0.0; - if (temp_stall_ts) + if (temp_stall_ts || terse_output) return; eta_secs = malloc(thread_number * sizeof(int)); @@ -1717,8 +1717,10 @@ static void run_threads(void) mlocked_mem = fio_pin_memory(); - printf("Starting %d thread%s\n", thread_number, thread_number > 1 ? "s" : ""); - fflush(stdout); + if (!terse_output) { + printf("Starting %d thread%s\n", thread_number, thread_number > 1 ? "s" : ""); + fflush(stdout); + } signal(SIGINT, sig_handler); signal(SIGALRM, sig_handler); diff --git a/fio.h b/fio.h index cc686034..39d95874 100644 --- a/fio.h +++ b/fio.h @@ -324,6 +324,7 @@ extern int exitall_on_terminate; extern int thread_number; extern int shm_id; extern int groupid; +extern int terse_output; extern FILE *f_out; extern FILE *f_err; diff --git a/init.c b/init.c index bbc9aadf..40fcf1c3 100644 --- a/init.c +++ b/init.c @@ -54,6 +54,7 @@ int rate_quit = 0; int write_lat_log = 0; int write_bw_log = 0; int exitall_on_terminate = 0; +int terse_output = 0; unsigned long long mlock_size = 0; FILE *f_out = NULL; FILE *f_err = NULL; @@ -173,10 +174,12 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num) ddir = td->ddir + (!td->sequential << 1) + (td->iomix << 2); - if (!job_add_num) - fprintf(f_out, "%s: (g=%d): rw=%s, odir=%d, bs=%d-%d, rate=%d, ioengine=%s, iodepth=%d\n", td->name, td->groupid, ddir_str[ddir], td->odirect, td->min_bs, td->max_bs, td->rate, td->io_engine_name, td->iodepth); - else if (job_add_num == 1) - fprintf(f_out, "...\n"); + if (!terse_output) { + if (!job_add_num) + fprintf(f_out, "%s: (g=%d): rw=%s, odir=%d, bs=%d-%d, rate=%d, ioengine=%s, iodepth=%d\n", td->name, td->groupid, ddir_str[ddir], td->odirect, td->min_bs, td->max_bs, td->rate, td->io_engine_name, td->iodepth); + else if (job_add_num == 1) + fprintf(f_out, "...\n"); + } /* * recurse add identical jobs, clear numjobs and stonewall options @@ -965,6 +968,7 @@ static void usage(char *name) printf("\t-t Runtime in seconds\n"); printf("\t-l Generate per-job latency logs\n"); printf("\t-w Generate per-job bandwidth logs\n"); + printf("\t-m Minimal (terse) output\n"); printf("\t-f Job file (Required)\n"); printf("\t-v Print version info and exit\n"); } @@ -973,7 +977,7 @@ static int parse_cmd_line(int argc, char *argv[]) { int c, idx = 1, ini_idx = 0; - while ((c = getopt(argc, argv, "t:o:f:lwvh")) != EOF) { + while ((c = getopt(argc, argv, "t:o:f:lwvhm")) != EOF) { switch (c) { case 't': def_timeout = atoi(optarg); @@ -1002,6 +1006,10 @@ static int parse_cmd_line(int argc, char *argv[]) f_err = f_out; idx++; break; + case 'm': + terse_output = 1; + idx++; + break; case 'h': usage(argv[0]); exit(0); diff --git a/stat.c b/stat.c index f3aa2320..4cc3b7e9 100644 --- a/stat.c +++ b/stat.c @@ -369,6 +369,63 @@ 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); } +static void show_ddir_status_terse(struct thread_data *td, + struct group_run_stats *rs, int ddir) +{ + unsigned long min, max; + unsigned long long bw; + double mean, dev; + + bw = 0; + if (td->runtime[ddir]) + bw = td->io_bytes[ddir] / td->runtime[ddir]; + + fprintf(f_out, ",%llu,%llu,%lu", td->io_bytes[ddir] >> 10, bw, td->runtime[ddir]); + + if (calc_lat(&td->slat_stat[ddir], &min, &max, &mean, &dev)) + fprintf(f_out, ",%lu,%lu,%f,%f", min, max, mean, dev); + else + fprintf(f_out, ",%lu,%lu,%f,%f", 0UL, 0UL, 0.0, 0.0); + + if (calc_lat(&td->clat_stat[ddir], &min, &max, &mean, &dev)) + fprintf(f_out, ",%lu,%lu,%f,%f", min, max, mean, dev); + else + fprintf(f_out, ",%lu,%lu,%f,%f", 0UL, 0UL, 0.0, 0.0); + + 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, ",%lu,%lu,%f%%,%f,%f", min, max, p_of_agg, mean, dev); + } else + fprintf(f_out, ",%lu,%lu,%f%%,%f,%f", 0UL, 0UL, 0.0, 0.0, 0.0); + +} + + +static void show_thread_status_terse(struct thread_data *td, + struct group_run_stats *rs) +{ + double usr_cpu, sys_cpu; + + fprintf(f_out, "%s,%d,%d",td->name, td->groupid, td->error); + + show_ddir_status_terse(td, rs, 0); + show_ddir_status_terse(td, rs, 1); + + if (td->runtime[0] + td->runtime[1]) { + double runt = td->runtime[0] + td->runtime[1]; + + usr_cpu = (double) td->usr_time * 100 / runt; + sys_cpu = (double) td->sys_time * 100 / runt; + } else { + usr_cpu = 0; + sys_cpu = 0; + } + + fprintf(f_out, ",%f%%,%f%%,%lu\n", usr_cpu, sys_cpu, td->ctx); +} + void show_run_stats(void) { struct group_run_stats *runstats, *rs; @@ -437,19 +494,25 @@ void show_run_stats(void) /* * don't overwrite last signal output */ - printf("\n"); + if (!terse_output) + printf("\n"); for (i = 0; i < thread_number; i++) { td = &threads[i]; rs = &runstats[td->groupid]; - show_thread_status(td, rs); + if (terse_output) + show_thread_status_terse(td, rs); + else + show_thread_status(td, rs); } - for (i = 0; i < groupid + 1; i++) - show_group_stats(&runstats[i], i); + if (!terse_output) { + for (i = 0; i < groupid + 1; i++) + show_group_stats(&runstats[i], i); - show_disk_util(); + show_disk_util(); + } } static inline void add_stat_sample(struct io_stat *is, unsigned long val) -- 2.25.1