Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Florian Fischer <florian.fischer@muhq.space>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Kim Phillips <kim.phillips@amd.com>
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Riccardo Mancini <rickyman7@gmail.com>
Cc: Shunsuke Nakamura <nakamura.shun@fujitsu.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Link: https://lore.kernel.org/r/20220507053410.3798748-5-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
9aa09230 79932d16

+75 -39
+51 -36
tools/perf/util/metricgroup.c
··· 728 728 { 729 729 struct hashmap_entry *cur; 730 730 size_t bkt; 731 - bool no_group = true, has_duration = false; 731 + bool no_group = true, has_tool_events = false; 732 + bool tool_events[PERF_TOOL_MAX] = {false}; 732 733 int ret = 0; 733 734 734 735 #define RETURN_IF_NON_ZERO(x) do { if (x) return x; } while (0) 735 736 736 737 hashmap__for_each_entry(ctx->ids, cur, bkt) { 737 738 const char *sep, *rsep, *id = cur->key; 739 + enum perf_tool_event ev; 738 740 739 741 pr_debug("found event %s\n", id); 740 - /* 741 - * Duration time maps to a software event and can make 742 - * groups not count. Always use it outside a 743 - * group. 744 - */ 745 - if (!strcmp(id, "duration_time")) { 746 - has_duration = true; 742 + 743 + /* Always move tool events outside of the group. */ 744 + ev = perf_tool_event__from_str(id); 745 + if (ev != PERF_TOOL_NONE) { 746 + has_tool_events = true; 747 + tool_events[ev] = true; 747 748 continue; 748 749 } 749 750 /* Separate events with commas and open the group if necessary. */ ··· 803 802 RETURN_IF_NON_ZERO(ret); 804 803 } 805 804 } 806 - if (has_duration) { 807 - if (no_group) { 808 - /* Strange case of a metric of just duration_time. */ 809 - ret = strbuf_addf(events, "duration_time"); 810 - } else if (!has_constraint) 811 - ret = strbuf_addf(events, "}:W,duration_time"); 812 - else 813 - ret = strbuf_addf(events, ",duration_time"); 814 - } else if (!no_group && !has_constraint) 805 + if (!no_group && !has_constraint) { 815 806 ret = strbuf_addf(events, "}:W"); 807 + RETURN_IF_NON_ZERO(ret); 808 + } 809 + if (has_tool_events) { 810 + int i; 811 + 812 + perf_tool_event__for_each_event(i) { 813 + if (tool_events[i]) { 814 + if (!no_group) { 815 + ret = strbuf_addch(events, ','); 816 + RETURN_IF_NON_ZERO(ret); 817 + } 818 + no_group = false; 819 + ret = strbuf_addstr(events, perf_tool_event__to_str(i)); 820 + RETURN_IF_NON_ZERO(ret); 821 + } 822 + } 823 + } 816 824 817 825 return ret; 818 826 #undef RETURN_IF_NON_ZERO ··· 1127 1117 1128 1118 /** 1129 1119 * metric_list_cmp - list_sort comparator that sorts metrics with more events to 1130 - * the front. duration_time is excluded from the count. 1120 + * the front. tool events are excluded from the count. 1131 1121 */ 1132 1122 static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l, 1133 1123 const struct list_head *r) ··· 1135 1125 const struct metric *left = container_of(l, struct metric, nd); 1136 1126 const struct metric *right = container_of(r, struct metric, nd); 1137 1127 struct expr_id_data *data; 1138 - int left_count, right_count; 1128 + int i, left_count, right_count; 1139 1129 1140 1130 left_count = hashmap__size(left->pctx->ids); 1141 - if (!expr__get_id(left->pctx, "duration_time", &data)) 1142 - left_count--; 1131 + perf_tool_event__for_each_event(i) { 1132 + if (!expr__get_id(left->pctx, perf_tool_event__to_str(i), &data)) 1133 + left_count--; 1134 + } 1143 1135 1144 1136 right_count = hashmap__size(right->pctx->ids); 1145 - if (!expr__get_id(right->pctx, "duration_time", &data)) 1146 - right_count--; 1137 + perf_tool_event__for_each_event(i) { 1138 + if (!expr__get_id(right->pctx, perf_tool_event__to_str(i), &data)) 1139 + right_count--; 1140 + } 1147 1141 1148 1142 return right_count - left_count; 1149 1143 } ··· 1345 1331 1346 1332 *out_evlist = NULL; 1347 1333 if (!metric_no_merge || hashmap__size(ids->ids) == 0) { 1348 - char *tmp; 1334 + int i; 1349 1335 /* 1350 - * We may fail to share events between metrics because 1351 - * duration_time isn't present in one metric. For example, a 1352 - * ratio of cache misses doesn't need duration_time but the same 1353 - * events may be used for a misses per second. Events without 1354 - * sharing implies multiplexing, that is best avoided, so place 1355 - * duration_time in every group. 1336 + * We may fail to share events between metrics because a tool 1337 + * event isn't present in one metric. For example, a ratio of 1338 + * cache misses doesn't need duration_time but the same events 1339 + * may be used for a misses per second. Events without sharing 1340 + * implies multiplexing, that is best avoided, so place 1341 + * all tool events in every group. 1356 1342 * 1357 1343 * Also, there may be no ids/events in the expression parsing 1358 1344 * context because of constant evaluation, e.g.: 1359 1345 * event1 if #smt_on else 0 1360 - * Add a duration_time event to avoid a parse error on an empty 1361 - * string. 1346 + * Add a tool event to avoid a parse error on an empty string. 1362 1347 */ 1363 - tmp = strdup("duration_time"); 1364 - if (!tmp) 1365 - return -ENOMEM; 1348 + perf_tool_event__for_each_event(i) { 1349 + char *tmp = strdup(perf_tool_event__to_str(i)); 1366 1350 1367 - ids__insert(ids->ids, tmp); 1351 + if (!tmp) 1352 + return -ENOMEM; 1353 + ids__insert(ids->ids, tmp); 1354 + } 1368 1355 } 1369 1356 ret = metricgroup__build_event_string(&events, ids, modifier, 1370 1357 has_constraint);
+24 -3
tools/perf/util/stat-shadow.c
··· 833 833 u64 metric_total = 0; 834 834 int source_count; 835 835 836 - if (!strcmp(metric_events[i]->name, "duration_time")) { 837 - stats = &walltime_nsecs_stats; 838 - scale = 1e-9; 836 + if (evsel__is_tool(metric_events[i])) { 839 837 source_count = 1; 838 + switch (metric_events[i]->tool_event) { 839 + case PERF_TOOL_DURATION_TIME: 840 + stats = &walltime_nsecs_stats; 841 + scale = 1e-9; 842 + break; 843 + case PERF_TOOL_USER_TIME: 844 + stats = &ru_stats.ru_utime_usec_stat; 845 + scale = 1e-6; 846 + break; 847 + case PERF_TOOL_SYSTEM_TIME: 848 + stats = &ru_stats.ru_stime_usec_stat; 849 + scale = 1e-6; 850 + break; 851 + case PERF_TOOL_NONE: 852 + pr_err("Invalid tool event 'none'"); 853 + abort(); 854 + case PERF_TOOL_MAX: 855 + pr_err("Invalid tool event 'max'"); 856 + abort(); 857 + default: 858 + pr_err("Unknown tool event '%s'", evsel__name(metric_events[i])); 859 + abort(); 860 + } 840 861 } else { 841 862 v = saved_value_lookup(metric_events[i], cpu_map_idx, false, 842 863 STAT_NONE, 0, st,