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

perf stat: Delay metric parsing

Having metric parsing as part of argument processing causes issues as
flags like metric-no-group may be specified later. It also denies the
opportunity to optimize the events on SMT systems where fewer events
may be possible if we know the target is system-wide. Move metric
parsing to after command line option parsing. Because of how stat runs
this moves the parsing after record/report which fail to work with
metrics currently anyway.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Ahmad Yasin <ahmad.yasin@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Caleb Biggers <caleb.biggers@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: Kan Liang <kan.liang@linux.intel.com>
Cc: Kshipra Bopardikar <kshipra.bopardikar@intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Miaoqian Lin <linmq006@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Perry Taylor <perry.taylor@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Link: https://lore.kernel.org/r/20220831174926.579643-6-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
a4b8cfca cc2c4e26

+39 -18
+37 -15
tools/perf/builtin-stat.c
··· 191 191 static bool interval_count; 192 192 static const char *output_name; 193 193 static int output_fd; 194 + static char *metrics; 194 195 195 196 struct perf_stat { 196 197 bool record; ··· 1149 1148 return 0; 1150 1149 } 1151 1150 1152 - static int parse_metric_groups(const struct option *opt, 1151 + static int append_metric_groups(const struct option *opt __maybe_unused, 1153 1152 const char *str, 1154 1153 int unset __maybe_unused) 1155 1154 { 1156 - return metricgroup__parse_groups(opt, str, 1157 - stat_config.metric_no_group, 1158 - stat_config.metric_no_merge, 1159 - &stat_config.metric_events); 1155 + if (metrics) { 1156 + char *tmp; 1157 + 1158 + if (asprintf(&tmp, "%s,%s", metrics, str) < 0) 1159 + return -ENOMEM; 1160 + free(metrics); 1161 + metrics = tmp; 1162 + } else { 1163 + metrics = strdup(str); 1164 + if (!metrics) 1165 + return -ENOMEM; 1166 + } 1167 + return 0; 1160 1168 } 1161 1169 1162 1170 static int parse_control_option(const struct option *opt, ··· 1309 1299 "measure SMI cost"), 1310 1300 OPT_CALLBACK('M', "metrics", &evsel_list, "metric/metric group list", 1311 1301 "monitor specified metrics or metric groups (separated by ,)", 1312 - parse_metric_groups), 1302 + append_metric_groups), 1313 1303 OPT_BOOLEAN_FLAG(0, "all-kernel", &stat_config.all_kernel, 1314 1304 "Configure all used events to run in kernel space.", 1315 1305 PARSE_OPT_EXCLUSIVE), ··· 1802 1792 * on an architecture test for such a metric name. 1803 1793 */ 1804 1794 if (metricgroup__has_metric("transaction")) { 1805 - struct option opt = { .value = &evsel_list }; 1806 - 1807 - return metricgroup__parse_groups(&opt, "transaction", 1795 + return metricgroup__parse_groups(evsel_list, "transaction", 1808 1796 stat_config.metric_no_group, 1809 - stat_config.metric_no_merge, 1797 + stat_config.metric_no_merge, 1810 1798 &stat_config.metric_events); 1811 1799 } 1812 1800 ··· 2191 2183 input_name = "perf.data"; 2192 2184 } 2193 2185 2186 + perf_stat__init_shadow_stats(); 2187 + 2194 2188 perf_stat.data.path = input_name; 2195 2189 perf_stat.data.mode = PERF_DATA_MODE_READ; 2196 2190 ··· 2272 2262 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands, 2273 2263 (const char **) stat_usage, 2274 2264 PARSE_OPT_STOP_AT_NON_OPTION); 2275 - perf_stat__collect_metric_expr(evsel_list); 2276 - perf_stat__init_shadow_stats(); 2277 2265 2278 2266 if (stat_config.csv_sep) { 2279 2267 stat_config.csv_output = true; ··· 2438 2430 target.system_wide = true; 2439 2431 } 2440 2432 2433 + if ((stat_config.aggr_mode == AGGR_THREAD) && (target.system_wide)) 2434 + target.per_thread = true; 2435 + 2436 + /* 2437 + * Metric parsing needs to be delayed as metrics may optimize events 2438 + * knowing the target is system-wide. 2439 + */ 2440 + if (metrics) { 2441 + metricgroup__parse_groups(evsel_list, metrics, 2442 + stat_config.metric_no_group, 2443 + stat_config.metric_no_merge, 2444 + &stat_config.metric_events); 2445 + zfree(&metrics); 2446 + } 2447 + perf_stat__collect_metric_expr(evsel_list); 2448 + perf_stat__init_shadow_stats(); 2449 + 2441 2450 if (add_default_attributes()) 2442 2451 goto out; 2443 2452 ··· 2473 2448 goto out; 2474 2449 } 2475 2450 } 2476 - 2477 - if ((stat_config.aggr_mode == AGGR_THREAD) && (target.system_wide)) 2478 - target.per_thread = true; 2479 2451 2480 2452 if (evlist__fix_hybrid_cpus(evsel_list, target.cpu_list)) { 2481 2453 pr_err("failed to use cpu list %s\n", target.cpu_list);
+1 -2
tools/perf/util/metricgroup.c
··· 1646 1646 return ret; 1647 1647 } 1648 1648 1649 - int metricgroup__parse_groups(const struct option *opt, 1649 + int metricgroup__parse_groups(struct evlist *perf_evlist, 1650 1650 const char *str, 1651 1651 bool metric_no_group, 1652 1652 bool metric_no_merge, 1653 1653 struct rblist *metric_events) 1654 1654 { 1655 - struct evlist *perf_evlist = *(struct evlist **)opt->value; 1656 1655 const struct pmu_events_table *table = pmu_events_table__find(); 1657 1656 1658 1657 if (!table)
+1 -1
tools/perf/util/metricgroup.h
··· 64 64 struct metric_event *metricgroup__lookup(struct rblist *metric_events, 65 65 struct evsel *evsel, 66 66 bool create); 67 - int metricgroup__parse_groups(const struct option *opt, 67 + int metricgroup__parse_groups(struct evlist *perf_evlist, 68 68 const char *str, 69 69 bool metric_no_group, 70 70 bool metric_no_merge,