[PATCH] Add option for terse parseable output
diff --git a/README b/README
index c951504..d6ff109 100644
--- a/README
+++ b/README
@@ -48,6 +48,7 @@
-w Generate per-job bandwidth logs
-f <file> Read <file> for job descriptions
-o <file> Log output to file
+ -m Minimal (terse) output
-h Print help info
-v Print version information and exit
@@ -303,6 +304,31 @@
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 b53a58e..445600f 100644
--- a/fio.c
+++ b/fio.c
@@ -1576,7 +1576,7 @@
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 @@
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 cc68603..39d9587 100644
--- a/fio.h
+++ b/fio.h
@@ -324,6 +324,7 @@
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 bbc9aad..40fcf1c 100644
--- a/init.c
+++ b/init.c
@@ -54,6 +54,7 @@
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 @@
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 @@
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 @@
{
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 @@
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 f3aa232..4cc3b7e 100644
--- a/stat.c
+++ b/stat.c
@@ -369,6 +369,63 @@
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 @@
/*
* 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)