[PATCH 11/11] perf, tools, stat: Output generic dividedby metric
From: Andi KleenAdd 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
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 @@