[PATCH 10/10] perf, tools, stat: Output generic dividedby metric

2016-11-18 Thread Andi Kleen
From: Andi Kleen 

Add generic infrastructure to perf stat to output ratios for "DividedBy"
entries in the event lists. Many events are more useful as ratios
than in raw form, typically some count in relation to total ticks.

Transfer the dividedby information from the alias to the evsel.

We mark the events that need to be collected for DividedBy, and also
link the events using them with a pointer. The code is careful
to always prefer the right event in the same group to minimize
multiplexing errors.

Then add a rblist to the stat shadow code that remembers stats based
on the cpu and context.

Then finally update and retrieve and print these ratios similarly to the
existing hardcoded perf metrics.

Normally we just output the ratio as percent without further commentary,
but for --metric-only this would lead to empty columns. So for this
case use the original event as description.

So far there is no attempt to automatically add the DividedBy event,
if it is missing, however we suggest it to the user.

$ perf stat -a -I 1000 -e '{unc_p_clockticks,unc_p_freq_max_os_cycles}'
 1.000228813800,139,950  unc_p_clockticks
 1.000228813789,833,783  unc_p_freq_max_os_cycles  # 98.7%
 2.000654229800,308,990  unc_p_clockticks
 2.000654229396,214,238  unc_p_freq_max_os_cycles  # 49.5%

$ perf stat -a -I 1000 -e '{unc_p_clockticks,unc_p_freq_max_os_cycles}' 
--metric-only
 1.000206740 48.0%
 2.000451543 48.1%

Signed-off-by: Andi Kleen 
---
 tools/perf/builtin-stat.c  |   3 +
 tools/perf/util/evsel.c|   3 +
 tools/perf/util/evsel.h|   3 +
 tools/perf/util/parse-events.c |   1 +
 tools/perf/util/pmu.c  |   2 +
 tools/perf/util/pmu.h  |   1 +
 tools/perf/util/stat-shadow.c  | 139 +
 tools/perf/util/stat.h |   2 +
 8 files changed, 154 insertions(+)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 501d58a4925a..a83a72aebdcb 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1141,6 +1141,7 @@ static void printout(int id, int nr, struct perf_evsel 
*counter, double uval,
out.print_metric = pm;
out.new_line = nl;
out.ctx = &os;
+   out.force_header = false;
 
if (csv_output && !metric_only) {
print_noise(counter, noise);
@@ -1465,6 +1466,7 @@ static void print_metric_headers(const char *prefix, bool 
no_indent)
out.ctx = &os;
out.print_metric = print_metric_header;
out.new_line = new_line_metric;
+   out.force_header = true;
os.evsel = counter;
perf_stat__print_shadow_stats(counter, 0,
  0,
@@ -2447,6 +2449,7 @@ int cmd_stat(int argc, const char **argv, const char 
*prefix __maybe_unused)
argc = parse_options_subcommand(argc, argv, stat_options, 
stat_subcommands,
(const char **) stat_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
+   perf_stat__collect_dividedby(evsel_list);
perf_stat__init_shadow_stats();
 
if (csv_sep) {
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index e58a2fbf3b16..fabe36c58d99 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -236,6 +236,9 @@ void perf_evsel__init(struct perf_evsel *evsel,
evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
perf_evsel__calc_id_pos(evsel);
evsel->cmdline_group_boundary = false;
+   evsel->dividedby   = NULL;
+   evsel->div_event   = NULL;
+   evsel->collect_stat = false;
 }
 
 struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 343776422821..376106e623bd 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -131,6 +131,9 @@ struct perf_evsel {
struct list_headconfig_terms;
int bpf_fd;
boolmerged_stat;
+   const char *dividedby;
+   struct perf_evsel   *div_event;
+   boolcollect_stat;
 };
 
 union u64_swap {
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index fba53ba22431..02f10e72cb77 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1252,6 +1252,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data,
evsel->scale = info.scale;
evsel->per_pkg = info.per_pkg;
evsel->snapshot = info.snapshot;
+   evsel->dividedby = info.dividedby;
}
 
return evsel ? 0 : -ENOMEM;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 2e6f803cd56d..40c735036915 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.

[PATCH 10/10] perf, tools, stat: Output generic dividedby metric

2016-10-13 Thread Andi Kleen
From: Andi Kleen 

Add generic infrastructure to perf stat to output ratios for "DividedBy"
entries in the event lists. Many events are more useful as ratios
than in raw form, typically some count in relation to total ticks.

Transfer the dividedby information from the alias to the evsel.

We mark the events that need to be collected for DividedBy, and also
link the events using them with a pointer. The code is careful
to always prefer the right event in the same group to minimize
multiplexing errors.

Then add a rblist to the stat shadow code that remembers stats based
on the cpu and context.

Then finally update and retrieve and print these ratios similarly to the
existing hardcoded perf metrics.

Normally we just output the ratio as percent without further commentary,
but for --metric-only this would lead to empty columns. So for this
case use the original event as description.

So far there is no attempt to automatically add the DividedBy event,
if it is missing, however we suggest it to the user.

$ perf stat -a -I 1000 -e '{unc_p_clockticks,unc_p_freq_max_os_cycles}'
 1.000228813800,139,950  unc_p_clockticks
 1.000228813789,833,783  unc_p_freq_max_os_cycles  # 98.7%
 2.000654229800,308,990  unc_p_clockticks
 2.000654229396,214,238  unc_p_freq_max_os_cycles  # 49.5%

$ perf stat -a -I 1000 -e '{unc_p_clockticks,unc_p_freq_max_os_cycles}' 
--metric-only
 1.000206740 48.0%
 2.000451543 48.1%

Signed-off-by: Andi Kleen 
---
 tools/perf/builtin-stat.c  |   3 +
 tools/perf/util/evsel.c|   3 +
 tools/perf/util/evsel.h|   3 +
 tools/perf/util/parse-events.c |   1 +
 tools/perf/util/pmu.c  |   2 +
 tools/perf/util/pmu.h  |   1 +
 tools/perf/util/stat-shadow.c  | 139 +
 tools/perf/util/stat.h |   2 +
 8 files changed, 154 insertions(+)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 76304f27c090..b6702a8e0031 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1141,6 +1141,7 @@ static void printout(int id, int nr, struct perf_evsel 
*counter, double uval,
out.print_metric = pm;
out.new_line = nl;
out.ctx = &os;
+   out.force_header = false;
 
if (csv_output && !metric_only) {
print_noise(counter, noise);
@@ -1458,6 +1459,7 @@ static void print_metric_headers(const char *prefix, bool 
no_indent)
out.ctx = &os;
out.print_metric = print_metric_header;
out.new_line = new_line_metric;
+   out.force_header = true;
os.evsel = counter;
perf_stat__print_shadow_stats(counter, 0,
  0,
@@ -2440,6 +2442,7 @@ int cmd_stat(int argc, const char **argv, const char 
*prefix __maybe_unused)
argc = parse_options_subcommand(argc, argv, stat_options, 
stat_subcommands,
(const char **) stat_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
+   perf_stat__collect_dividedby(evsel_list);
perf_stat__init_shadow_stats();
 
if (csv_sep) {
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8bc271141d9d..3484c0c67f8d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -235,6 +235,9 @@ void perf_evsel__init(struct perf_evsel *evsel,
evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
perf_evsel__calc_id_pos(evsel);
evsel->cmdline_group_boundary = false;
+   evsel->dividedby   = NULL;
+   evsel->div_event   = NULL;
+   evsel->collect_stat = false;
 }
 
 struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 4e3158fe79c2..15afaf6a393e 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -129,6 +129,9 @@ struct perf_evsel {
struct list_headconfig_terms;
int bpf_fd;
boolalias;
+   const char *dividedby;
+   struct perf_evsel   *div_event;
+   boolcollect_stat;
 };
 
 union u64_swap {
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 8b2333278988..59234666b743 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1245,6 +1245,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data,
evsel->scale = info.scale;
evsel->per_pkg = info.per_pkg;
evsel->snapshot = info.snapshot;
+   evsel->dividedby = info.dividedby;
}
 
return evsel ? 0 : -ENOMEM;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index d298e7413a80..5c30a6ceee0c 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -