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

2016-10-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 = 
+   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 = 
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 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 aae496a9bec1..324635fc2a72 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;
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 aa7efeb25893..040ff6b231d6 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 81a50b8f90d2..91060cee634b 100644
--- 

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

2016-10-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 = 
+   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 = 
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 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 aae496a9bec1..324635fc2a72 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;
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 aa7efeb25893..040ff6b231d6 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 81a50b8f90d2..91060cee634b 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@