From 9aa09230f011a624b23c06870ccd5ff7b81e034e Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 6 May 2022 22:34:09 -0700 Subject: [PATCH] perf metrics: Support all tool events Previously duration_time was hard coded, which was ok until commit b03b89b350034f22 ("perf stat: Add user_time and system_time events") added additional tool events. Do for all tool events what was previously done just for duration_time. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Florian Fischer Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: John Garry Cc: Kim Phillips Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Riccardo Mancini Cc: Shunsuke Nakamura Cc: Stephane Eranian Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20220507053410.3798748-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/metricgroup.c | 87 ++++++++++++++++++++--------------- tools/perf/util/stat-shadow.c | 27 +++++++++-- 2 files changed, 75 insertions(+), 39 deletions(-) diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index d8492e339521..7a5f488aef02 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -728,22 +728,23 @@ static int metricgroup__build_event_string(struct strbuf *events, { struct hashmap_entry *cur; size_t bkt; - bool no_group = true, has_duration = false; + bool no_group = true, has_tool_events = false; + bool tool_events[PERF_TOOL_MAX] = {false}; int ret = 0; #define RETURN_IF_NON_ZERO(x) do { if (x) return x; } while (0) hashmap__for_each_entry(ctx->ids, cur, bkt) { const char *sep, *rsep, *id = cur->key; + enum perf_tool_event ev; pr_debug("found event %s\n", id); - /* - * Duration time maps to a software event and can make - * groups not count. Always use it outside a - * group. - */ - if (!strcmp(id, "duration_time")) { - has_duration = true; + + /* Always move tool events outside of the group. */ + ev = perf_tool_event__from_str(id); + if (ev != PERF_TOOL_NONE) { + has_tool_events = true; + tool_events[ev] = true; continue; } /* Separate events with commas and open the group if necessary. */ @@ -802,16 +803,25 @@ static int metricgroup__build_event_string(struct strbuf *events, RETURN_IF_NON_ZERO(ret); } } - if (has_duration) { - if (no_group) { - /* Strange case of a metric of just duration_time. */ - ret = strbuf_addf(events, "duration_time"); - } else if (!has_constraint) - ret = strbuf_addf(events, "}:W,duration_time"); - else - ret = strbuf_addf(events, ",duration_time"); - } else if (!no_group && !has_constraint) + if (!no_group && !has_constraint) { ret = strbuf_addf(events, "}:W"); + RETURN_IF_NON_ZERO(ret); + } + if (has_tool_events) { + int i; + + perf_tool_event__for_each_event(i) { + if (tool_events[i]) { + if (!no_group) { + ret = strbuf_addch(events, ','); + RETURN_IF_NON_ZERO(ret); + } + no_group = false; + ret = strbuf_addstr(events, perf_tool_event__to_str(i)); + RETURN_IF_NON_ZERO(ret); + } + } + } return ret; #undef RETURN_IF_NON_ZERO @@ -1117,7 +1127,7 @@ out: /** * metric_list_cmp - list_sort comparator that sorts metrics with more events to - * the front. duration_time is excluded from the count. + * the front. tool events are excluded from the count. */ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l, const struct list_head *r) @@ -1125,15 +1135,19 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l, const struct metric *left = container_of(l, struct metric, nd); const struct metric *right = container_of(r, struct metric, nd); struct expr_id_data *data; - int left_count, right_count; + int i, left_count, right_count; left_count = hashmap__size(left->pctx->ids); - if (!expr__get_id(left->pctx, "duration_time", &data)) - left_count--; + perf_tool_event__for_each_event(i) { + if (!expr__get_id(left->pctx, perf_tool_event__to_str(i), &data)) + left_count--; + } right_count = hashmap__size(right->pctx->ids); - if (!expr__get_id(right->pctx, "duration_time", &data)) - right_count--; + perf_tool_event__for_each_event(i) { + if (!expr__get_id(right->pctx, perf_tool_event__to_str(i), &data)) + right_count--; + } return right_count - left_count; } @@ -1331,26 +1345,27 @@ static int parse_ids(bool metric_no_merge, struct perf_pmu *fake_pmu, *out_evlist = NULL; if (!metric_no_merge || hashmap__size(ids->ids) == 0) { - char *tmp; + int i; /* - * We may fail to share events between metrics because - * duration_time isn't present in one metric. For example, a - * ratio of cache misses doesn't need duration_time but the same - * events may be used for a misses per second. Events without - * sharing implies multiplexing, that is best avoided, so place - * duration_time in every group. + * We may fail to share events between metrics because a tool + * event isn't present in one metric. For example, a ratio of + * cache misses doesn't need duration_time but the same events + * may be used for a misses per second. Events without sharing + * implies multiplexing, that is best avoided, so place + * all tool events in every group. * * Also, there may be no ids/events in the expression parsing * context because of constant evaluation, e.g.: * event1 if #smt_on else 0 - * Add a duration_time event to avoid a parse error on an empty - * string. + * Add a tool event to avoid a parse error on an empty string. */ - tmp = strdup("duration_time"); - if (!tmp) - return -ENOMEM; + perf_tool_event__for_each_event(i) { + char *tmp = strdup(perf_tool_event__to_str(i)); - ids__insert(ids->ids, tmp); + if (!tmp) + return -ENOMEM; + ids__insert(ids->ids, tmp); + } } ret = metricgroup__build_event_string(&events, ids, modifier, has_constraint); diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index ea4c35e4f1da..979c8cb918f7 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -833,10 +833,31 @@ static int prepare_metric(struct evsel **metric_events, u64 metric_total = 0; int source_count; - if (!strcmp(metric_events[i]->name, "duration_time")) { - stats = &walltime_nsecs_stats; - scale = 1e-9; + if (evsel__is_tool(metric_events[i])) { source_count = 1; + switch (metric_events[i]->tool_event) { + case PERF_TOOL_DURATION_TIME: + stats = &walltime_nsecs_stats; + scale = 1e-9; + break; + case PERF_TOOL_USER_TIME: + stats = &ru_stats.ru_utime_usec_stat; + scale = 1e-6; + break; + case PERF_TOOL_SYSTEM_TIME: + stats = &ru_stats.ru_stime_usec_stat; + scale = 1e-6; + break; + case PERF_TOOL_NONE: + pr_err("Invalid tool event 'none'"); + abort(); + case PERF_TOOL_MAX: + pr_err("Invalid tool event 'max'"); + abort(); + default: + pr_err("Unknown tool event '%s'", evsel__name(metric_events[i])); + abort(); + } } else { v = saved_value_lookup(metric_events[i], cpu_map_idx, false, STAT_NONE, 0, st,