* [PATCH] perf: add csv-style output to perf stat (v2) @ 2010-12-01 16:49 Stephane Eranian 2010-12-01 18:10 ` Arnaldo Carvalho de Melo 2010-12-02 11:48 ` [tip:perf/core] perf stat: Add csv-style output tip-bot for Stephane Eranian 0 siblings, 2 replies; 6+ messages in thread From: Stephane Eranian @ 2010-12-01 16:49 UTC (permalink / raw) To: linux-kernel Cc: peterz, mingo, paulus, davem, fweisbec, perfmon2-devel, eranian, eranian, robert.richter, acme This patch adds an option (-x/--field-separator) to print counts using a CSV-style output. The user can pass a custom separator. This makes it very easy to import counts directly into your favorite spreadsheet without having to write scripts. Example: $ perf stat --field-separator=, -a -- sleep 1 4009.961740,task-clock-msecs 13,context-switches 2,CPU-migrations 189,page-faults 9596385684,cycles 3493659441,instructions 872897069,branches 41562,branch-misses 22424,cache-references 1289,cache-misses Works also in non-aggregated mode: $ perf stat --x , -a -A -- sleep 1 CPU0,1002.526168,task-clock-msecs CPU1,1002.528365,task-clock-msecs CPU2,1002.523360,task-clock-msecs CPU3,1002.519878,task-clock-msecs CPU0,1,context-switches CPU1,5,context-switches CPU2,5,context-switches CPU3,6,context-switches CPU0,0,CPU-migrations CPU1,1,CPU-migrations CPU2,0,CPU-migrations CPU3,1,CPU-migrations CPU0,2,page-faults CPU1,6,page-faults CPU2,9,page-faults CPU3,174,page-faults CPU0,2399439771,cycles CPU1,2380369063,cycles CPU2,2399142710,cycles CPU3,2373161192,cycles CPU0,872900618,instructions CPU1,873030960,instructions CPU2,872714525,instructions CPU3,874460580,instructions CPU0,221556839,branches CPU1,218134342,branches CPU2,218161730,branches CPU3,218284093,branches CPU0,18556,branch-misses CPU1,1449,branch-misses CPU2,3447,branch-misses CPU3,12714,branch-misses CPU0,8330,cache-references CPU1,313844,cache-references CPU2,47993728,cache-references CPU3,826481,cache-references CPU0,272,cache-misses CPU1,5360,cache-misses CPU2,1342193,cache-misses CPU3,13992,cache-misses This second version adds the ability to name a separator and uses field-separator as the long option to be consistent with perf report. Signed-off-by: Stephane Eranian <eranian@google.com> --- diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index c405bca..2d31049 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -58,6 +58,11 @@ to activate system-wide monitoring. Default is to count on all CPUs. Do not aggregate counts across all monitored CPUs in system-wide mode (-a). This option is only valid in system-wide mode. +-x SEP:: +--field-separator SEP:: +print counts using a CSV-style output to make it easy to import directly into +spreadsheets. Columns are separated by the string specified in SEP. + EXAMPLES -------- diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 970a7f2..b1abe6a 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -52,6 +52,8 @@ #include <math.h> #include <locale.h> +#define DEFAULT_SEPARATOR " " + static struct perf_event_attr default_attrs[] = { { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, @@ -84,6 +86,8 @@ static pid_t child_pid = -1; static bool null_run = false; static bool big_num = false; static const char *cpu_list; +static const char *csv_sep = NULL; +static bool csv_output = false; static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; @@ -449,12 +453,18 @@ static void print_noise(int counter, double avg) static void nsec_printout(int cpu, int counter, double avg) { double msecs = avg / 1e6; + char cpustr[16] = { '\0', }; + const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-24s"; if (no_aggr) - fprintf(stderr, "CPU%-4d %18.6f %-24s", - cpumap[cpu], msecs, event_name(counter)); - else - fprintf(stderr, " %18.6f %-24s", msecs, event_name(counter)); + sprintf(cpustr, "CPU%*d%s", + csv_output ? 0 : -4, + cpumap[cpu], csv_sep); + + fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(counter)); + + if (csv_output) + return; if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { fprintf(stderr, " # %10.3f CPUs ", @@ -466,18 +476,26 @@ static void abs_printout(int cpu, int counter, double avg) { double total, ratio = 0.0; char cpustr[16] = { '\0', }; + const char *fmt; + + if (csv_output) + fmt = "%s%.0f%s%s"; + else if (big_num) + fmt = "%s%'18.0f%s%-24s"; + else + fmt = "%s%18.0f%s%-24s"; if (no_aggr) - sprintf(cpustr, "CPU%-4d", cpumap[cpu]); + sprintf(cpustr, "CPU%*d%s", + csv_output ? 0 : -4, + cpumap[cpu], csv_sep); else cpu = 0; - if (big_num) - fprintf(stderr, "%s %'18.0f %-24s", - cpustr, avg, event_name(counter)); - else - fprintf(stderr, "%s %18.0f %-24s", - cpustr, avg, event_name(counter)); + fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(counter)); + + if (csv_output) + return; if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { total = avg_stats(&runtime_cycles_stats[cpu]); @@ -515,8 +533,9 @@ static void print_counter_aggr(int counter) int scaled = event_scaled[counter]; if (scaled == -1) { - fprintf(stderr, " %18s %-24s\n", - "<not counted>", event_name(counter)); + fprintf(stderr, "%*s%s%-24s\n", + csv_output ? 0 : 18, + "<not counted>", csv_sep, event_name(counter)); return; } @@ -525,6 +544,11 @@ static void print_counter_aggr(int counter) else abs_printout(-1, counter, avg); + if (csv_output) { + fputc('\n', stderr); + return; + } + print_noise(counter, avg); if (scaled) { @@ -554,8 +578,12 @@ static void print_counter(int counter) ena = cpu_counts[cpu][counter].ena; run = cpu_counts[cpu][counter].run; if (run == 0 || ena == 0) { - fprintf(stderr, "CPU%-4d %18s %-24s", cpumap[cpu], - "<not counted>", event_name(counter)); + fprintf(stderr, "CPU%*d%s%*s%s%-24s", + csv_output ? 0 : -4, + cpumap[cpu], csv_sep, + csv_output ? 0 : 18, + "<not counted>", csv_sep, + event_name(counter)); fprintf(stderr, "\n"); continue; @@ -566,11 +594,13 @@ static void print_counter(int counter) else abs_printout(cpu, counter, val); - print_noise(counter, 1.0); + if (!csv_output) { + print_noise(counter, 1.0); - if (run != ena) { - fprintf(stderr, " (scaled from %.2f%%)", + if (run != ena) { + fprintf(stderr, " (scaled from %.2f%%)", 100.0 * run / ena); + } } fprintf(stderr, "\n"); } @@ -582,21 +612,23 @@ static void print_stat(int argc, const char **argv) fflush(stdout); - fprintf(stderr, "\n"); - fprintf(stderr, " Performance counter stats for "); - if(target_pid == -1 && target_tid == -1) { - fprintf(stderr, "\'%s", argv[0]); - for (i = 1; i < argc; i++) - fprintf(stderr, " %s", argv[i]); - } else if (target_pid != -1) - fprintf(stderr, "process id \'%d", target_pid); - else - fprintf(stderr, "thread id \'%d", target_tid); + if (!csv_output) { + fprintf(stderr, "\n"); + fprintf(stderr, " Performance counter stats for "); + if(target_pid == -1 && target_tid == -1) { + fprintf(stderr, "\'%s", argv[0]); + for (i = 1; i < argc; i++) + fprintf(stderr, " %s", argv[i]); + } else if (target_pid != -1) + fprintf(stderr, "process id \'%d", target_pid); + else + fprintf(stderr, "thread id \'%d", target_tid); - fprintf(stderr, "\'"); - if (run_count > 1) - fprintf(stderr, " (%d runs)", run_count); - fprintf(stderr, ":\n\n"); + fprintf(stderr, "\'"); + if (run_count > 1) + fprintf(stderr, " (%d runs)", run_count); + fprintf(stderr, ":\n\n"); + } if (no_aggr) { for (counter = 0; counter < nr_counters; counter++) @@ -606,15 +638,17 @@ static void print_stat(int argc, const char **argv) print_counter_aggr(counter); } - fprintf(stderr, "\n"); - fprintf(stderr, " %18.9f seconds time elapsed", - avg_stats(&walltime_nsecs_stats)/1e9); - if (run_count > 1) { - fprintf(stderr, " ( +- %7.3f%% )", + if (!csv_output) { + fprintf(stderr, "\n"); + fprintf(stderr, " %18.9f seconds time elapsed", + avg_stats(&walltime_nsecs_stats)/1e9); + if (run_count > 1) { + fprintf(stderr, " ( +- %7.3f%% )", 100*stddev_stats(&walltime_nsecs_stats) / avg_stats(&walltime_nsecs_stats)); + } + fprintf(stderr, "\n\n"); } - fprintf(stderr, "\n\n"); } static volatile int signr = -1; @@ -670,6 +704,8 @@ static const struct option options[] = { "list of cpus to monitor in system-wide"), OPT_BOOLEAN('A', "no-aggr", &no_aggr, "disable CPU count aggregation"), + OPT_STRING('x', "field-separator", &csv_sep, "separator", + "print counts with custom separator"), OPT_END() }; @@ -682,6 +718,20 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) argc = parse_options(argc, argv, options, stat_usage, PARSE_OPT_STOP_AT_NON_OPTION); + + if (csv_sep) + csv_output = true; + else + csv_sep = DEFAULT_SEPARATOR; + + /* + * let the spreadsheet do the pretty-printing + */ + if (csv_output && big_num) { + fprintf(stderr, "-B option not supported with -x\n"); + usage_with_options(stat_usage, options); + } + if (!argc && target_pid == -1 && target_tid == -1) usage_with_options(stat_usage, options); if (run_count <= 0) ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] perf: add csv-style output to perf stat (v2) 2010-12-01 16:49 [PATCH] perf: add csv-style output to perf stat (v2) Stephane Eranian @ 2010-12-01 18:10 ` Arnaldo Carvalho de Melo 2010-12-01 18:54 ` Arnaldo Carvalho de Melo 2010-12-02 11:48 ` [tip:perf/core] perf stat: Add csv-style output tip-bot for Stephane Eranian 1 sibling, 1 reply; 6+ messages in thread From: Arnaldo Carvalho de Melo @ 2010-12-01 18:10 UTC (permalink / raw) To: Stephane Eranian Cc: linux-kernel, peterz, mingo, paulus, davem, fweisbec, perfmon2-devel, eranian, robert.richter Em Wed, Dec 01, 2010 at 06:49:05PM +0200, Stephane Eranian escreveu: > This patch adds an option (-x/--field-separator) to print counts using > a CSV-style output. The user can pass a custom separator. This makes it > very easy to import counts directly into your favorite spreadsheet without > having to write scripts. > > Example: > $ perf stat --field-separator=, -a -- sleep 1 > 4009.961740,task-clock-msecs > 13,context-switches > 2,CPU-migrations > 189,page-faults > 9596385684,cycles > 3493659441,instructions > 872897069,branches > 41562,branch-misses > 22424,cache-references > 1289,cache-misses [root@mica ~]# perf stat -x, -a -A -- sleep 1 -B option not supported with -x usage: perf stat [<options>] [<command>] -e, --event <event> event selector. use 'perf list' to list available events -i, --no-inherit child tasks do not inherit counters -p, --pid <n> stat events on existing process id Guess we'll have to disable big_num automatically when -x is specified, but at the same time notice if the user _explicitely_ asked for -B. I'll fix this now. - Arnaldo ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] perf: add csv-style output to perf stat (v2) 2010-12-01 18:10 ` Arnaldo Carvalho de Melo @ 2010-12-01 18:54 ` Arnaldo Carvalho de Melo 2010-12-03 16:46 ` Stephane Eranian 0 siblings, 1 reply; 6+ messages in thread From: Arnaldo Carvalho de Melo @ 2010-12-01 18:54 UTC (permalink / raw) To: Stephane Eranian Cc: linux-kernel, peterz, mingo, paulus, davem, fweisbec, perfmon2-devel, eranian, robert.richter [-- Attachment #1: Type: text/plain, Size: 3175 bytes --] Em Wed, Dec 01, 2010 at 04:10:01PM -0200, Arnaldo Carvalho de Melo escreveu: > Em Wed, Dec 01, 2010 at 06:49:05PM +0200, Stephane Eranian escreveu: > > This patch adds an option (-x/--field-separator) to print counts using > > a CSV-style output. The user can pass a custom separator. This makes it > > very easy to import counts directly into your favorite spreadsheet without > > having to write scripts. > > [root@mica ~]# perf stat -x, -a -A -- sleep 1 > -B option not supported with -x > > usage: perf stat [<options>] [<command>] > > -e, --event <event> event selector. use 'perf list' to list > > Guess we'll have to disable big_num automatically when -x is specified, > but at the same time notice if the user _explicitely_ asked for -B. > > I'll fix this now. Should be OK now, patch attached. Please check if it works as expected and then I'll push it to Ingo, thanks. [root@mica ~]# perf stat -x, -a -A -- sleep 1 2>&1 | head -5 CPU0,998.225789,task-clock-msecs CPU1,998.385393,task-clock-msecs CPU2,998.370913,task-clock-msecs CPU3,998.356865,task-clock-msecs CPU0,2272,context-switches [root@mica ~]# perf stat -B -x, -a -A -- sleep 1 2>&1 | head -5 -B option not supported with -x usage: perf stat [<options>] [<command>] -e, --event <event> event selector. use 'perf list' to list available events [root@mica ~]# perf stat -B -a -- sleep 1 2>&1 | head -10 Performance counter stats for 'sleep 1': 3992.488962 task-clock-msecs # 3.988 CPUs 9,082 context-switches # 0.002 M/sec 15 CPU-migrations # 0.000 M/sec 160 page-faults # 0.000 M/sec 84,802,643 cycles # 21.241 M/sec (scaled from 70.03%) 45,056,634 instructions # 0.531 IPC (scaled from 80.02%) 8,672,889 branches # 2.172 M/sec (scaled from 80.01%) [root@mica ~]# perf stat -B -A -a -- sleep 1 2>&1 | head -10 Performance counter stats for 'sleep 1': CPU0 998.135082 task-clock-msecs # 0.997 CPUs CPU1 998.137405 task-clock-msecs # 0.997 CPUs CPU2 998.144046 task-clock-msecs # 0.997 CPUs CPU3 998.146202 task-clock-msecs # 0.997 CPUs CPU0 2,280 context-switches # 0.002 M/sec CPU1 2,282 context-switches # 0.002 M/sec CPU2 2,244 context-switches # 0.002 M/sec [root@mica ~]# perf stat --no-big-num -A -a -- sleep 1 2>&1 | head -10 Performance counter stats for 'sleep 1': CPU0 998.125848 task-clock-msecs # 0.997 CPUs CPU1 998.244633 task-clock-msecs # 0.997 CPUs CPU2 998.337969 task-clock-msecs # 0.997 CPUs CPU3 998.313756 task-clock-msecs # 0.997 CPUs CPU0 2268 context-switches # 0.002 M/sec CPU1 2218 context-switches # 0.002 M/sec CPU2 2218 context-switches # 0.002 M/sec [root@mica ~]# [-- Attachment #2: 0001-perf-stat-Add-csv-style-output.patch --] [-- Type: text/plain, Size: 10852 bytes --] >From d7470b6afca85ed4388fff57fc9d89f5a3be02ff Mon Sep 17 00:00:00 2001 From: Stephane Eranian <eranian@google.com> Date: Wed, 1 Dec 2010 18:49:05 +0200 Subject: [PATCH] perf stat: Add csv-style output This patch adds an option (-x/--field-separator) to print counts using a CSV-style output. The user can pass a custom separator. This makes it very easy to import counts directly into your favorite spreadsheet without having to write scripts. Example: $ perf stat --field-separator=, -a -- sleep 1 4009.961740,task-clock-msecs 13,context-switches 2,CPU-migrations 189,page-faults 9596385684,cycles 3493659441,instructions 872897069,branches 41562,branch-misses 22424,cache-references 1289,cache-misses Works also in non-aggregated mode: $ perf stat -x , -a -A -- sleep 1 CPU0,1002.526168,task-clock-msecs CPU1,1002.528365,task-clock-msecs CPU2,1002.523360,task-clock-msecs CPU3,1002.519878,task-clock-msecs CPU0,1,context-switches CPU1,5,context-switches CPU2,5,context-switches CPU3,6,context-switches CPU0,0,CPU-migrations CPU1,1,CPU-migrations CPU2,0,CPU-migrations CPU3,1,CPU-migrations CPU0,2,page-faults CPU1,6,page-faults CPU2,9,page-faults CPU3,174,page-faults CPU0,2399439771,cycles CPU1,2380369063,cycles CPU2,2399142710,cycles CPU3,2373161192,cycles CPU0,872900618,instructions CPU1,873030960,instructions CPU2,872714525,instructions CPU3,874460580,instructions CPU0,221556839,branches CPU1,218134342,branches CPU2,218161730,branches CPU3,218284093,branches CPU0,18556,branch-misses CPU1,1449,branch-misses CPU2,3447,branch-misses CPU3,12714,branch-misses CPU0,8330,cache-references CPU1,313844,cache-references CPU2,47993728,cache-references CPU3,826481,cache-references CPU0,272,cache-misses CPU1,5360,cache-misses CPU2,1342193,cache-misses CPU3,13992,cache-misses This second version adds the ability to name a separator and uses field-separator as the long option to be consistent with perf report. Commiter note: Since we enabled --big-num by default in 201e0b0 and -x can't be used with it, we need to notice if the user explicitely enabled or disabled -B, add code to disable big_num if the user didn't explicitely set --big_num when -x is used. Cc: David S. Miller <davem@davemloft.net> Cc: Frederik Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: paulus@samba.org Cc: Peter Zijlstra <peterz@infradead.org> Cc: Robert Richter <robert.richter@amd.com> LKML-Reference: <4cf68aa7.0fedd80a.5294.1203@mx.google.com> Signed-off-by: Stephane Eranian <eranian@google.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/Documentation/perf-stat.txt | 5 + tools/perf/builtin-stat.c | 144 +++++++++++++++++++++++--------- 2 files changed, 109 insertions(+), 40 deletions(-) diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index c469ba5..b6da7af 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -78,6 +78,11 @@ This option is only valid in system-wide mode. --verbose:: be more verbose (show counter open errors, etc) +-x SEP:: +--field-separator SEP:: +print counts using a CSV-style output to make it easy to import directly into +spreadsheets. Columns are separated by the string specified in SEP. + EXAMPLES -------- diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index acbf7cc..7ff746d 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -52,6 +52,8 @@ #include <math.h> #include <locale.h> +#define DEFAULT_SEPARATOR " " + static struct perf_event_attr default_attrs[] = { { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, @@ -83,7 +85,10 @@ static int thread_num = 0; static pid_t child_pid = -1; static bool null_run = false; static bool big_num = true; +static int big_num_opt = -1; static const char *cpu_list; +static const char *csv_sep = NULL; +static bool csv_output = false; static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; @@ -449,12 +454,18 @@ static void print_noise(int counter, double avg) static void nsec_printout(int cpu, int counter, double avg) { double msecs = avg / 1e6; + char cpustr[16] = { '\0', }; + const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-24s"; if (no_aggr) - fprintf(stderr, "CPU%-4d %18.6f %-24s", - cpumap[cpu], msecs, event_name(counter)); - else - fprintf(stderr, " %18.6f %-24s", msecs, event_name(counter)); + sprintf(cpustr, "CPU%*d%s", + csv_output ? 0 : -4, + cpumap[cpu], csv_sep); + + fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(counter)); + + if (csv_output) + return; if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { fprintf(stderr, " # %10.3f CPUs ", @@ -466,18 +477,26 @@ static void abs_printout(int cpu, int counter, double avg) { double total, ratio = 0.0; char cpustr[16] = { '\0', }; + const char *fmt; + + if (csv_output) + fmt = "%s%.0f%s%s"; + else if (big_num) + fmt = "%s%'18.0f%s%-24s"; + else + fmt = "%s%18.0f%s%-24s"; if (no_aggr) - sprintf(cpustr, "CPU%-4d", cpumap[cpu]); + sprintf(cpustr, "CPU%*d%s", + csv_output ? 0 : -4, + cpumap[cpu], csv_sep); else cpu = 0; - if (big_num) - fprintf(stderr, "%s %'18.0f %-24s", - cpustr, avg, event_name(counter)); - else - fprintf(stderr, "%s %18.0f %-24s", - cpustr, avg, event_name(counter)); + fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(counter)); + + if (csv_output) + return; if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { total = avg_stats(&runtime_cycles_stats[cpu]); @@ -515,8 +534,9 @@ static void print_counter_aggr(int counter) int scaled = event_scaled[counter]; if (scaled == -1) { - fprintf(stderr, " %18s %-24s\n", - "<not counted>", event_name(counter)); + fprintf(stderr, "%*s%s%-24s\n", + csv_output ? 0 : 18, + "<not counted>", csv_sep, event_name(counter)); return; } @@ -525,6 +545,11 @@ static void print_counter_aggr(int counter) else abs_printout(-1, counter, avg); + if (csv_output) { + fputc('\n', stderr); + return; + } + print_noise(counter, avg); if (scaled) { @@ -554,8 +579,12 @@ static void print_counter(int counter) ena = cpu_counts[cpu][counter].ena; run = cpu_counts[cpu][counter].run; if (run == 0 || ena == 0) { - fprintf(stderr, "CPU%-4d %18s %-24s", cpumap[cpu], - "<not counted>", event_name(counter)); + fprintf(stderr, "CPU%*d%s%*s%s%-24s", + csv_output ? 0 : -4, + cpumap[cpu], csv_sep, + csv_output ? 0 : 18, + "<not counted>", csv_sep, + event_name(counter)); fprintf(stderr, "\n"); continue; @@ -566,11 +595,13 @@ static void print_counter(int counter) else abs_printout(cpu, counter, val); - print_noise(counter, 1.0); + if (!csv_output) { + print_noise(counter, 1.0); - if (run != ena) { - fprintf(stderr, " (scaled from %.2f%%)", + if (run != ena) { + fprintf(stderr, " (scaled from %.2f%%)", 100.0 * run / ena); + } } fprintf(stderr, "\n"); } @@ -582,21 +613,23 @@ static void print_stat(int argc, const char **argv) fflush(stdout); - fprintf(stderr, "\n"); - fprintf(stderr, " Performance counter stats for "); - if(target_pid == -1 && target_tid == -1) { - fprintf(stderr, "\'%s", argv[0]); - for (i = 1; i < argc; i++) - fprintf(stderr, " %s", argv[i]); - } else if (target_pid != -1) - fprintf(stderr, "process id \'%d", target_pid); - else - fprintf(stderr, "thread id \'%d", target_tid); + if (!csv_output) { + fprintf(stderr, "\n"); + fprintf(stderr, " Performance counter stats for "); + if(target_pid == -1 && target_tid == -1) { + fprintf(stderr, "\'%s", argv[0]); + for (i = 1; i < argc; i++) + fprintf(stderr, " %s", argv[i]); + } else if (target_pid != -1) + fprintf(stderr, "process id \'%d", target_pid); + else + fprintf(stderr, "thread id \'%d", target_tid); - fprintf(stderr, "\'"); - if (run_count > 1) - fprintf(stderr, " (%d runs)", run_count); - fprintf(stderr, ":\n\n"); + fprintf(stderr, "\'"); + if (run_count > 1) + fprintf(stderr, " (%d runs)", run_count); + fprintf(stderr, ":\n\n"); + } if (no_aggr) { for (counter = 0; counter < nr_counters; counter++) @@ -606,15 +639,17 @@ static void print_stat(int argc, const char **argv) print_counter_aggr(counter); } - fprintf(stderr, "\n"); - fprintf(stderr, " %18.9f seconds time elapsed", - avg_stats(&walltime_nsecs_stats)/1e9); - if (run_count > 1) { - fprintf(stderr, " ( +- %7.3f%% )", + if (!csv_output) { + fprintf(stderr, "\n"); + fprintf(stderr, " %18.9f seconds time elapsed", + avg_stats(&walltime_nsecs_stats)/1e9); + if (run_count > 1) { + fprintf(stderr, " ( +- %7.3f%% )", 100*stddev_stats(&walltime_nsecs_stats) / avg_stats(&walltime_nsecs_stats)); + } + fprintf(stderr, "\n\n"); } - fprintf(stderr, "\n\n"); } static volatile int signr = -1; @@ -644,6 +679,13 @@ static const char * const stat_usage[] = { NULL }; +static int stat__set_big_num(const struct option *opt __used, + const char *s __used, int unset) +{ + big_num_opt = unset ? 0 : 1; + return 0; +} + static const struct option options[] = { OPT_CALLBACK('e', "event", NULL, "event", "event selector. use 'perf list' to list available events", @@ -664,12 +706,15 @@ static const struct option options[] = { "repeat command and print average + stddev (max: 100)"), OPT_BOOLEAN('n', "null", &null_run, "null run - dont start any counters"), - OPT_BOOLEAN('B', "big-num", &big_num, - "print large numbers with thousands\' separators"), + OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, + "print large numbers with thousands\' separators", + stat__set_big_num), OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to monitor in system-wide"), OPT_BOOLEAN('A', "no-aggr", &no_aggr, "disable CPU count aggregation"), + OPT_STRING('x', "field-separator", &csv_sep, "separator", + "print counts with custom separator"), OPT_END() }; @@ -682,6 +727,25 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) argc = parse_options(argc, argv, options, stat_usage, PARSE_OPT_STOP_AT_NON_OPTION); + + if (csv_sep) + csv_output = true; + else + csv_sep = DEFAULT_SEPARATOR; + + /* + * let the spreadsheet do the pretty-printing + */ + if (csv_output) { + /* User explicitely passed -B? */ + if (big_num_opt == 1) { + fprintf(stderr, "-B option not supported with -x\n"); + usage_with_options(stat_usage, options); + } else /* Nope, so disable big number formatting */ + big_num = false; + } else if (big_num_opt == 0) /* User passed --no-big-num */ + big_num = false; + if (!argc && target_pid == -1 && target_tid == -1) usage_with_options(stat_usage, options); if (run_count <= 0) -- 1.7.1.rc2 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] perf: add csv-style output to perf stat (v2) 2010-12-01 18:54 ` Arnaldo Carvalho de Melo @ 2010-12-03 16:46 ` Stephane Eranian 2010-12-03 18:29 ` Arnaldo Carvalho de Melo 0 siblings, 1 reply; 6+ messages in thread From: Stephane Eranian @ 2010-12-03 16:46 UTC (permalink / raw) To: Arnaldo Carvalho de Melo Cc: linux-kernel, peterz, mingo, paulus, davem, fweisbec, perfmon2-devel, eranian, robert.richter Arnaldo, sorry for the delay. The upstream version works for me. Thanks. On Wed, Dec 1, 2010 at 7:54 PM, Arnaldo Carvalho de Melo <acme@infradead.org> wrote: > Em Wed, Dec 01, 2010 at 04:10:01PM -0200, Arnaldo Carvalho de Melo escreveu: >> Em Wed, Dec 01, 2010 at 06:49:05PM +0200, Stephane Eranian escreveu: >> > This patch adds an option (-x/--field-separator) to print counts using >> > a CSV-style output. The user can pass a custom separator. This makes it >> > very easy to import counts directly into your favorite spreadsheet without >> > having to write scripts. >> >> [root@mica ~]# perf stat -x, -a -A -- sleep 1 >> -B option not supported with -x >> >> usage: perf stat [<options>] [<command>] >> >> -e, --event <event> event selector. use 'perf list' to list >> >> Guess we'll have to disable big_num automatically when -x is specified, >> but at the same time notice if the user _explicitely_ asked for -B. >> >> I'll fix this now. > > Should be OK now, patch attached. Please check if it works as expected > and then I'll push it to Ingo, thanks. > > [root@mica ~]# perf stat -x, -a -A -- sleep 1 2>&1 | head -5 > CPU0,998.225789,task-clock-msecs > CPU1,998.385393,task-clock-msecs > CPU2,998.370913,task-clock-msecs > CPU3,998.356865,task-clock-msecs > CPU0,2272,context-switches > [root@mica ~]# perf stat -B -x, -a -A -- sleep 1 2>&1 | head -5 > -B option not supported with -x > > usage: perf stat [<options>] [<command>] > > -e, --event <event> event selector. use 'perf list' to list available events > [root@mica ~]# perf stat -B -a -- sleep 1 2>&1 | head -10 > > Performance counter stats for 'sleep 1': > > 3992.488962 task-clock-msecs # 3.988 CPUs > 9,082 context-switches # 0.002 M/sec > 15 CPU-migrations # 0.000 M/sec > 160 page-faults # 0.000 M/sec > 84,802,643 cycles # 21.241 M/sec (scaled from 70.03%) > 45,056,634 instructions # 0.531 IPC (scaled from 80.02%) > 8,672,889 branches # 2.172 M/sec (scaled from 80.01%) > [root@mica ~]# perf stat -B -A -a -- sleep 1 2>&1 | head -10 > > Performance counter stats for 'sleep 1': > > CPU0 998.135082 task-clock-msecs # 0.997 CPUs > CPU1 998.137405 task-clock-msecs # 0.997 CPUs > CPU2 998.144046 task-clock-msecs # 0.997 CPUs > CPU3 998.146202 task-clock-msecs # 0.997 CPUs > CPU0 2,280 context-switches # 0.002 M/sec > CPU1 2,282 context-switches # 0.002 M/sec > CPU2 2,244 context-switches # 0.002 M/sec > [root@mica ~]# perf stat --no-big-num -A -a -- sleep 1 2>&1 | head -10 > > Performance counter stats for 'sleep 1': > > CPU0 998.125848 task-clock-msecs # 0.997 CPUs > CPU1 998.244633 task-clock-msecs # 0.997 CPUs > CPU2 998.337969 task-clock-msecs # 0.997 CPUs > CPU3 998.313756 task-clock-msecs # 0.997 CPUs > CPU0 2268 context-switches # 0.002 M/sec > CPU1 2218 context-switches # 0.002 M/sec > CPU2 2218 context-switches # 0.002 M/sec > [root@mica ~]# > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] perf: add csv-style output to perf stat (v2) 2010-12-03 16:46 ` Stephane Eranian @ 2010-12-03 18:29 ` Arnaldo Carvalho de Melo 0 siblings, 0 replies; 6+ messages in thread From: Arnaldo Carvalho de Melo @ 2010-12-03 18:29 UTC (permalink / raw) To: Stephane Eranian Cc: linux-kernel, peterz, mingo, paulus, davem, fweisbec, perfmon2-devel, eranian, robert.richter Em Fri, Dec 03, 2010 at 05:46:33PM +0100, Stephane Eranian escreveu: > Arnaldo, > > sorry for the delay. np > The upstream version works for me. Thanks for confirming! > Thanks. Best Regards, - Arnaldo ^ permalink raw reply [flat|nested] 6+ messages in thread
* [tip:perf/core] perf stat: Add csv-style output 2010-12-01 16:49 [PATCH] perf: add csv-style output to perf stat (v2) Stephane Eranian 2010-12-01 18:10 ` Arnaldo Carvalho de Melo @ 2010-12-02 11:48 ` tip-bot for Stephane Eranian 1 sibling, 0 replies; 6+ messages in thread From: tip-bot for Stephane Eranian @ 2010-12-02 11:48 UTC (permalink / raw) To: linux-tip-commits Cc: acme, linux-kernel, eranian, hpa, mingo, peterz, davem, fweisbec, robert.richter, tglx, mingo Commit-ID: d7470b6afca85ed4388fff57fc9d89f5a3be02ff Gitweb: http://git.kernel.org/tip/d7470b6afca85ed4388fff57fc9d89f5a3be02ff Author: Stephane Eranian <eranian@google.com> AuthorDate: Wed, 1 Dec 2010 18:49:05 +0200 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Wed, 1 Dec 2010 19:47:41 -0200 perf stat: Add csv-style output This patch adds an option (-x/--field-separator) to print counts using a CSV-style output. The user can pass a custom separator. This makes it very easy to import counts directly into your favorite spreadsheet without having to write scripts. Example: $ perf stat --field-separator=, -a -- sleep 1 4009.961740,task-clock-msecs 13,context-switches 2,CPU-migrations 189,page-faults 9596385684,cycles 3493659441,instructions 872897069,branches 41562,branch-misses 22424,cache-references 1289,cache-misses Works also in non-aggregated mode: $ perf stat -x , -a -A -- sleep 1 CPU0,1002.526168,task-clock-msecs CPU1,1002.528365,task-clock-msecs CPU2,1002.523360,task-clock-msecs CPU3,1002.519878,task-clock-msecs CPU0,1,context-switches CPU1,5,context-switches CPU2,5,context-switches CPU3,6,context-switches CPU0,0,CPU-migrations CPU1,1,CPU-migrations CPU2,0,CPU-migrations CPU3,1,CPU-migrations CPU0,2,page-faults CPU1,6,page-faults CPU2,9,page-faults CPU3,174,page-faults CPU0,2399439771,cycles CPU1,2380369063,cycles CPU2,2399142710,cycles CPU3,2373161192,cycles CPU0,872900618,instructions CPU1,873030960,instructions CPU2,872714525,instructions CPU3,874460580,instructions CPU0,221556839,branches CPU1,218134342,branches CPU2,218161730,branches CPU3,218284093,branches CPU0,18556,branch-misses CPU1,1449,branch-misses CPU2,3447,branch-misses CPU3,12714,branch-misses CPU0,8330,cache-references CPU1,313844,cache-references CPU2,47993728,cache-references CPU3,826481,cache-references CPU0,272,cache-misses CPU1,5360,cache-misses CPU2,1342193,cache-misses CPU3,13992,cache-misses This second version adds the ability to name a separator and uses field-separator as the long option to be consistent with perf report. Commiter note: Since we enabled --big-num by default in 201e0b0 and -x can't be used with it, we need to notice if the user explicitely enabled or disabled -B, add code to disable big_num if the user didn't explicitely set --big_num when -x is used. Cc: David S. Miller <davem@davemloft.net> Cc: Frederik Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: paulus@samba.org Cc: Peter Zijlstra <peterz@infradead.org> Cc: Robert Richter <robert.richter@amd.com> LKML-Reference: <4cf68aa7.0fedd80a.5294.1203@mx.google.com> Signed-off-by: Stephane Eranian <eranian@google.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/Documentation/perf-stat.txt | 5 + tools/perf/builtin-stat.c | 144 +++++++++++++++++++++++--------- 2 files changed, 109 insertions(+), 40 deletions(-) diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index c469ba5..b6da7af 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -78,6 +78,11 @@ This option is only valid in system-wide mode. --verbose:: be more verbose (show counter open errors, etc) +-x SEP:: +--field-separator SEP:: +print counts using a CSV-style output to make it easy to import directly into +spreadsheets. Columns are separated by the string specified in SEP. + EXAMPLES -------- diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index acbf7cc..7ff746d 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -52,6 +52,8 @@ #include <math.h> #include <locale.h> +#define DEFAULT_SEPARATOR " " + static struct perf_event_attr default_attrs[] = { { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, @@ -83,7 +85,10 @@ static int thread_num = 0; static pid_t child_pid = -1; static bool null_run = false; static bool big_num = true; +static int big_num_opt = -1; static const char *cpu_list; +static const char *csv_sep = NULL; +static bool csv_output = false; static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; @@ -449,12 +454,18 @@ static void print_noise(int counter, double avg) static void nsec_printout(int cpu, int counter, double avg) { double msecs = avg / 1e6; + char cpustr[16] = { '\0', }; + const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-24s"; if (no_aggr) - fprintf(stderr, "CPU%-4d %18.6f %-24s", - cpumap[cpu], msecs, event_name(counter)); - else - fprintf(stderr, " %18.6f %-24s", msecs, event_name(counter)); + sprintf(cpustr, "CPU%*d%s", + csv_output ? 0 : -4, + cpumap[cpu], csv_sep); + + fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(counter)); + + if (csv_output) + return; if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { fprintf(stderr, " # %10.3f CPUs ", @@ -466,18 +477,26 @@ static void abs_printout(int cpu, int counter, double avg) { double total, ratio = 0.0; char cpustr[16] = { '\0', }; + const char *fmt; + + if (csv_output) + fmt = "%s%.0f%s%s"; + else if (big_num) + fmt = "%s%'18.0f%s%-24s"; + else + fmt = "%s%18.0f%s%-24s"; if (no_aggr) - sprintf(cpustr, "CPU%-4d", cpumap[cpu]); + sprintf(cpustr, "CPU%*d%s", + csv_output ? 0 : -4, + cpumap[cpu], csv_sep); else cpu = 0; - if (big_num) - fprintf(stderr, "%s %'18.0f %-24s", - cpustr, avg, event_name(counter)); - else - fprintf(stderr, "%s %18.0f %-24s", - cpustr, avg, event_name(counter)); + fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(counter)); + + if (csv_output) + return; if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { total = avg_stats(&runtime_cycles_stats[cpu]); @@ -515,8 +534,9 @@ static void print_counter_aggr(int counter) int scaled = event_scaled[counter]; if (scaled == -1) { - fprintf(stderr, " %18s %-24s\n", - "<not counted>", event_name(counter)); + fprintf(stderr, "%*s%s%-24s\n", + csv_output ? 0 : 18, + "<not counted>", csv_sep, event_name(counter)); return; } @@ -525,6 +545,11 @@ static void print_counter_aggr(int counter) else abs_printout(-1, counter, avg); + if (csv_output) { + fputc('\n', stderr); + return; + } + print_noise(counter, avg); if (scaled) { @@ -554,8 +579,12 @@ static void print_counter(int counter) ena = cpu_counts[cpu][counter].ena; run = cpu_counts[cpu][counter].run; if (run == 0 || ena == 0) { - fprintf(stderr, "CPU%-4d %18s %-24s", cpumap[cpu], - "<not counted>", event_name(counter)); + fprintf(stderr, "CPU%*d%s%*s%s%-24s", + csv_output ? 0 : -4, + cpumap[cpu], csv_sep, + csv_output ? 0 : 18, + "<not counted>", csv_sep, + event_name(counter)); fprintf(stderr, "\n"); continue; @@ -566,11 +595,13 @@ static void print_counter(int counter) else abs_printout(cpu, counter, val); - print_noise(counter, 1.0); + if (!csv_output) { + print_noise(counter, 1.0); - if (run != ena) { - fprintf(stderr, " (scaled from %.2f%%)", + if (run != ena) { + fprintf(stderr, " (scaled from %.2f%%)", 100.0 * run / ena); + } } fprintf(stderr, "\n"); } @@ -582,21 +613,23 @@ static void print_stat(int argc, const char **argv) fflush(stdout); - fprintf(stderr, "\n"); - fprintf(stderr, " Performance counter stats for "); - if(target_pid == -1 && target_tid == -1) { - fprintf(stderr, "\'%s", argv[0]); - for (i = 1; i < argc; i++) - fprintf(stderr, " %s", argv[i]); - } else if (target_pid != -1) - fprintf(stderr, "process id \'%d", target_pid); - else - fprintf(stderr, "thread id \'%d", target_tid); + if (!csv_output) { + fprintf(stderr, "\n"); + fprintf(stderr, " Performance counter stats for "); + if(target_pid == -1 && target_tid == -1) { + fprintf(stderr, "\'%s", argv[0]); + for (i = 1; i < argc; i++) + fprintf(stderr, " %s", argv[i]); + } else if (target_pid != -1) + fprintf(stderr, "process id \'%d", target_pid); + else + fprintf(stderr, "thread id \'%d", target_tid); - fprintf(stderr, "\'"); - if (run_count > 1) - fprintf(stderr, " (%d runs)", run_count); - fprintf(stderr, ":\n\n"); + fprintf(stderr, "\'"); + if (run_count > 1) + fprintf(stderr, " (%d runs)", run_count); + fprintf(stderr, ":\n\n"); + } if (no_aggr) { for (counter = 0; counter < nr_counters; counter++) @@ -606,15 +639,17 @@ static void print_stat(int argc, const char **argv) print_counter_aggr(counter); } - fprintf(stderr, "\n"); - fprintf(stderr, " %18.9f seconds time elapsed", - avg_stats(&walltime_nsecs_stats)/1e9); - if (run_count > 1) { - fprintf(stderr, " ( +- %7.3f%% )", + if (!csv_output) { + fprintf(stderr, "\n"); + fprintf(stderr, " %18.9f seconds time elapsed", + avg_stats(&walltime_nsecs_stats)/1e9); + if (run_count > 1) { + fprintf(stderr, " ( +- %7.3f%% )", 100*stddev_stats(&walltime_nsecs_stats) / avg_stats(&walltime_nsecs_stats)); + } + fprintf(stderr, "\n\n"); } - fprintf(stderr, "\n\n"); } static volatile int signr = -1; @@ -644,6 +679,13 @@ static const char * const stat_usage[] = { NULL }; +static int stat__set_big_num(const struct option *opt __used, + const char *s __used, int unset) +{ + big_num_opt = unset ? 0 : 1; + return 0; +} + static const struct option options[] = { OPT_CALLBACK('e', "event", NULL, "event", "event selector. use 'perf list' to list available events", @@ -664,12 +706,15 @@ static const struct option options[] = { "repeat command and print average + stddev (max: 100)"), OPT_BOOLEAN('n', "null", &null_run, "null run - dont start any counters"), - OPT_BOOLEAN('B', "big-num", &big_num, - "print large numbers with thousands\' separators"), + OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, + "print large numbers with thousands\' separators", + stat__set_big_num), OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to monitor in system-wide"), OPT_BOOLEAN('A', "no-aggr", &no_aggr, "disable CPU count aggregation"), + OPT_STRING('x', "field-separator", &csv_sep, "separator", + "print counts with custom separator"), OPT_END() }; @@ -682,6 +727,25 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) argc = parse_options(argc, argv, options, stat_usage, PARSE_OPT_STOP_AT_NON_OPTION); + + if (csv_sep) + csv_output = true; + else + csv_sep = DEFAULT_SEPARATOR; + + /* + * let the spreadsheet do the pretty-printing + */ + if (csv_output) { + /* User explicitely passed -B? */ + if (big_num_opt == 1) { + fprintf(stderr, "-B option not supported with -x\n"); + usage_with_options(stat_usage, options); + } else /* Nope, so disable big number formatting */ + big_num = false; + } else if (big_num_opt == 0) /* User passed --no-big-num */ + big_num = false; + if (!argc && target_pid == -1 && target_tid == -1) usage_with_options(stat_usage, options); if (run_count <= 0) ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2010-12-03 18:30 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-12-01 16:49 [PATCH] perf: add csv-style output to perf stat (v2) Stephane Eranian 2010-12-01 18:10 ` Arnaldo Carvalho de Melo 2010-12-01 18:54 ` Arnaldo Carvalho de Melo 2010-12-03 16:46 ` Stephane Eranian 2010-12-03 18:29 ` Arnaldo Carvalho de Melo 2010-12-02 11:48 ` [tip:perf/core] perf stat: Add csv-style output tip-bot for Stephane Eranian
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.