diff options
-rw-r--r-- | tools/testing/selftests/bpf/veristat.c | 111 |
1 files changed, 75 insertions, 36 deletions
diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c index c0c8a65cda52..0472bfae3c9d 100644 --- a/tools/testing/selftests/bpf/veristat.c +++ b/tools/testing/selftests/bpf/veristat.c @@ -46,10 +46,17 @@ struct stat_specs { int lens[ALL_STATS_CNT]; }; +enum resfmt { + RESFMT_TABLE, + RESFMT_TABLE_CALCLEN, /* fake format to pre-calculate table's column widths */ + RESFMT_CSV, +}; + static struct env { char **filenames; int filename_cnt; bool verbose; + enum resfmt out_fmt; struct verif_stats *prog_stats; int prog_stat_cnt; @@ -78,8 +85,9 @@ const char argp_program_doc[] = static const struct argp_option opts[] = { { NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" }, { "verbose", 'v', NULL, 0, "Verbose mode" }, - { "output", 'o', "SPEC", 0, "Specify output stats" }, + { "emit", 'e', "SPEC", 0, "Specify stats to be emitted" }, { "sort", 's', "SPEC", 0, "Specify sort order" }, + { "output-format", 'o', "FMT", 0, "Result output format (table, csv), default is table." }, {}, }; @@ -97,7 +105,7 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) case 'v': env.verbose = true; break; - case 'o': + case 'e': err = parse_stats(arg, &env.output_spec); if (err) return err; @@ -107,6 +115,16 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) if (err) return err; break; + case 'o': + if (strcmp(arg, "table") == 0) { + env.out_fmt = RESFMT_TABLE; + } else if (strcmp(arg, "csv") == 0) { + env.out_fmt = RESFMT_CSV; + } else { + fprintf(stderr, "Unrecognized output format '%s'\n", arg); + return -EINVAL; + } + break; case ARGP_KEY_ARG: tmp = realloc(env.filenames, (env.filename_cnt + 1) * sizeof(*env.filenames)); if (!tmp) @@ -147,7 +165,7 @@ static struct stat_def { [FILE_NAME] = { "File", {"file_name", "filename", "file"}, true /* asc */ }, [PROG_NAME] = { "Program", {"prog_name", "progname", "prog"}, true /* asc */ }, [VERDICT] = { "Verdict", {"verdict"}, true /* asc: failure, success */ }, - [DURATION] = { "Duration, us", {"duration", "dur"}, }, + [DURATION] = { "Duration (us)", {"duration", "dur"}, }, [TOTAL_INSNS] = { "Total insns", {"total_insns", "insns"}, }, [TOTAL_STATES] = { "Total states", {"total_states", "states"}, }, [PEAK_STATES] = { "Peak states", {"peak_states"}, }, @@ -385,7 +403,21 @@ static int cmp_prog_stats(const void *v1, const void *v2) #define HEADER_CHAR '-' #define COLUMN_SEP " " -static void output_headers(bool calc_len) +static void output_header_underlines(void) +{ + int i, j, len; + + for (i = 0; i < env.output_spec.spec_cnt; i++) { + len = env.output_spec.lens[i]; + + printf("%s", i == 0 ? "" : COLUMN_SEP); + for (j = 0; j < len; j++) + printf("%c", HEADER_CHAR); + } + printf("\n"); +} + +static void output_headers(enum resfmt fmt) { int i, len; @@ -393,34 +425,30 @@ static void output_headers(bool calc_len) int id = env.output_spec.ids[i]; int *max_len = &env.output_spec.lens[i]; - if (calc_len) { + switch (fmt) { + case RESFMT_TABLE_CALCLEN: len = snprintf(NULL, 0, "%s", stat_defs[id].header); if (len > *max_len) *max_len = len; - } else { + break; + case RESFMT_TABLE: printf("%s%-*s", i == 0 ? "" : COLUMN_SEP, *max_len, stat_defs[id].header); + if (i == env.output_spec.spec_cnt - 1) + printf("\n"); + break; + case RESFMT_CSV: + printf("%s%s", i == 0 ? "" : ",", stat_defs[id].names[0]); + if (i == env.output_spec.spec_cnt - 1) + printf("\n"); + break; } } - if (!calc_len) - printf("\n"); + if (fmt == RESFMT_TABLE) + output_header_underlines(); } -static void output_header_underlines(void) -{ - int i, j, len; - - for (i = 0; i < env.output_spec.spec_cnt; i++) { - len = env.output_spec.lens[i]; - - printf("%s", i == 0 ? "" : COLUMN_SEP); - for (j = 0; j < len; j++) - printf("%c", HEADER_CHAR); - } - printf("\n"); -} - -static void output_stats(const struct verif_stats *s, bool calc_len) +static void output_stats(const struct verif_stats *s, enum resfmt fmt, bool last) { int i; @@ -453,23 +481,36 @@ static void output_stats(const struct verif_stats *s, bool calc_len) exit(1); } - if (calc_len) { + switch (fmt) { + case RESFMT_TABLE_CALCLEN: if (str) len = snprintf(NULL, 0, "%s", str); else len = snprintf(NULL, 0, "%ld", val); if (len > *max_len) *max_len = len; - } else { + break; + case RESFMT_TABLE: if (str) printf("%s%-*s", i == 0 ? "" : COLUMN_SEP, *max_len, str); else printf("%s%*ld", i == 0 ? "" : COLUMN_SEP, *max_len, val); + if (i == env.output_spec.spec_cnt - 1) + printf("\n"); + break; + case RESFMT_CSV: + if (str) + printf("%s%s", i == 0 ? "" : ",", str); + else + printf("%s%ld", i == 0 ? "" : ",", val); + if (i == env.output_spec.spec_cnt - 1) + printf("\n"); + break; } } - if (!calc_len) - printf("\n"); + if (last && fmt == RESFMT_TABLE) + output_header_underlines(); } int main(int argc, char **argv) @@ -505,20 +546,18 @@ int main(int argc, char **argv) qsort(env.prog_stats, env.prog_stat_cnt, sizeof(*env.prog_stats), cmp_prog_stats); - /* calculate column widths */ - output_headers(true); - for (i = 0; i < env.prog_stat_cnt; i++) { - output_stats(&env.prog_stats[i], true); + if (env.out_fmt == RESFMT_TABLE) { + /* calculate column widths */ + output_headers(RESFMT_TABLE_CALCLEN); + for (i = 0; i < env.prog_stat_cnt; i++) + output_stats(&env.prog_stats[i], RESFMT_TABLE_CALCLEN, false); } /* actually output the table */ - output_headers(false); - output_header_underlines(); + output_headers(env.out_fmt); for (i = 0; i < env.prog_stat_cnt; i++) { - output_stats(&env.prog_stats[i], false); + output_stats(&env.prog_stats[i], env.out_fmt, i == env.prog_stat_cnt - 1); } - output_header_underlines(); - printf("\n"); printf("Done. Processed %d object files, %d programs.\n", env.filename_cnt, env.prog_stat_cnt); |