summaryrefslogtreecommitdiff
path: root/tools/perf/util
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2026-06-22 18:27:46 -0700
committerNamhyung Kim <namhyung@kernel.org>2026-06-30 17:09:13 -0700
commite6ad1fb3458f9e77f63bcd555baf7a08008ecc2e (patch)
tree394c3fac58f5b1fc5202040034687621edc8d281 /tools/perf/util
parent5437e98903897246e3f223ab68f1f8bda8b5ed7e (diff)
downloadlinux-next-e6ad1fb3458f9e77f63bcd555baf7a08008ecc2e.tar.gz
linux-next-e6ad1fb3458f9e77f63bcd555baf7a08008ecc2e.zip
perf parse-events: Restrict core PMU bypass to --cputype option
Commit b1c5efbfd92e ("perf parse-events: Remove hard coded legacy hardware and cache parsing") introduced a bypass to PMU filtering to prevent uncore PMUs from being filtered out during event parsing, which was required for resolving `duration_time` and `uncore_freq` when running with `--cputype`. However, this bypass was active whenever `pmu_filter` was set, which also incorrectly bypassed filtering for the `--pmu-filter` option. Introduce a `cputype_filter` boolean flag in `parse_events_state` and `parse_events_option_args` to distinguish filtering initiated by `--cputype` from that initiated by `--pmu-filter`. Restrict the core-only check in `parse_events__filter_pmu()` to when `cputype_filter` is true. Fixes: b1c5efbfd92e ("perf parse-events: Remove hard coded legacy hardware and cache parsing") Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers <irogers@google.com> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/metricgroup.c26
-rw-r--r--tools/perf/util/metricgroup.h4
-rw-r--r--tools/perf/util/parse-events.c32
-rw-r--r--tools/perf/util/parse-events.h17
-rw-r--r--tools/perf/util/python.c3
5 files changed, 53 insertions, 29 deletions
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 8c7b299a55db..69bfa2a723b2 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -1262,7 +1262,8 @@ static int parse_ids(bool metric_no_merge, bool fake_pmu,
struct expr_parse_ctx *ids, const char *modifier,
bool group_events, const bool tool_events[TOOL_PMU__EVENT_MAX],
struct evlist **out_evlist,
- const char *filter_pmu)
+ const char *filter_pmu,
+ bool cputype_filter)
{
struct parse_events_error parse_error;
struct evlist *parsed_evlist;
@@ -1317,7 +1318,9 @@ static int parse_ids(bool metric_no_merge, bool fake_pmu,
pr_debug("Parsing metric events '%s'\n", events.buf);
parse_events_error__init(&parse_error);
ret = __parse_events(parsed_evlist, events.buf, filter_pmu,
- &parse_error, fake_pmu, /*warn_if_reordered=*/false,
+ cputype_filter,
+ &parse_error, fake_pmu,
+ /*warn_if_reordered=*/false,
/*fake_tp=*/false);
if (ret) {
parse_events_error__print(&parse_error, events.buf);
@@ -1382,7 +1385,7 @@ static struct evsel *pick_display_evsel(struct list_head *metric_list,
}
static int parse_groups(struct evlist *perf_evlist,
- const char *pmu, const char *str,
+ const char *pmu, bool cputype_filter, const char *str,
bool metric_no_group,
bool metric_no_merge,
bool metric_no_threshold,
@@ -1420,7 +1423,8 @@ static int parse_groups(struct evlist *perf_evlist,
/*group_events=*/false,
tool_events,
&combined_evlist,
- (pmu && strcmp(pmu, "all") == 0) ? NULL : pmu);
+ (pmu && strcmp(pmu, "all") == 0) ? NULL : pmu,
+ cputype_filter);
}
if (combined)
expr__ctx_free(combined);
@@ -1476,7 +1480,8 @@ static int parse_groups(struct evlist *perf_evlist,
if (!metric_evlist) {
ret = parse_ids(metric_no_merge, fake_pmu, m->pctx, m->modifier,
m->group_events, tool_events, &m->evlist,
- (pmu && strcmp(pmu, "all") == 0) ? NULL : pmu);
+ (pmu && strcmp(pmu, "all") == 0) ? NULL : pmu,
+ cputype_filter);
if (ret)
goto out;
@@ -1543,6 +1548,7 @@ static int parse_groups(struct evlist *perf_evlist,
if (combined_evlist) {
evlist__splice_list_tail(perf_evlist, &evlist__core(combined_evlist)->entries);
evlist__put(combined_evlist);
+ combined_evlist = NULL;
}
list_for_each_entry(m, &metric_list, nd) {
@@ -1551,12 +1557,15 @@ static int parse_groups(struct evlist *perf_evlist,
}
out:
+ if (combined_evlist)
+ evlist__put(combined_evlist);
metricgroup__free_metrics(&metric_list);
return ret;
}
int metricgroup__parse_groups(struct evlist *perf_evlist,
const char *pmu,
+ bool cputype_filter,
const char *str,
bool metric_no_group,
bool metric_no_merge,
@@ -1570,16 +1579,17 @@ int metricgroup__parse_groups(struct evlist *perf_evlist,
if (hardware_aware_grouping)
pr_debug("Use hardware aware grouping instead of traditional metric grouping method\n");
- return parse_groups(perf_evlist, pmu, str, metric_no_group, metric_no_merge,
+ return parse_groups(perf_evlist, pmu, cputype_filter, str, metric_no_group, metric_no_merge,
metric_no_threshold, user_requested_cpu_list, system_wide,
/*fake_pmu=*/false, table);
}
int metricgroup__parse_groups_test(struct evlist *evlist,
const struct pmu_metrics_table *table,
- const char *str)
+ const char *str,
+ bool cputype_filter)
{
- return parse_groups(evlist, "all", str,
+ return parse_groups(evlist, "all", cputype_filter, str,
/*metric_no_group=*/false,
/*metric_no_merge=*/false,
/*metric_no_threshold=*/false,
diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
index 4be6bfc13c46..6a66f14dd01b 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -71,6 +71,7 @@ struct metric_event *metricgroup__lookup(struct rblist *metric_events,
bool create);
int metricgroup__parse_groups(struct evlist *perf_evlist,
const char *pmu,
+ bool cputype_filter,
const char *str,
bool metric_no_group,
bool metric_no_merge,
@@ -80,7 +81,8 @@ int metricgroup__parse_groups(struct evlist *perf_evlist,
bool hardware_aware_grouping);
int metricgroup__parse_groups_test(struct evlist *evlist,
const struct pmu_metrics_table *table,
- const char *str);
+ const char *str,
+ bool cputype_filter);
int metricgroup__for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn,
void *data);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 194bc94dfc1e..cc7ad331a49f 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -429,6 +429,9 @@ bool parse_events__filter_pmu(const struct parse_events_state *parse_state,
if (parse_state->pmu_filter == NULL)
return false;
+ if (parse_state->cputype_filter && !pmu->is_core)
+ return false;
+
return perf_pmu__wildcard_match(pmu, parse_state->pmu_filter) == 0;
}
@@ -2288,18 +2291,20 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list)
return (idx_changed || num_leaders != orig_num_leaders) ? 1 : 0;
}
-int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filter,
+int __parse_events(struct evlist *evlist, const char *str,
+ const char *pmu_filter, bool cputype_filter,
struct parse_events_error *err, bool fake_pmu,
bool warn_if_reordered, bool fake_tp)
{
struct parse_events_state parse_state = {
- .list = LIST_HEAD_INIT(parse_state.list),
- .idx = evlist__nr_entries(evlist),
- .error = err,
- .stoken = PE_START_EVENTS,
- .fake_pmu = fake_pmu,
- .fake_tp = fake_tp,
- .pmu_filter = pmu_filter,
+ .list = LIST_HEAD_INIT(parse_state.list),
+ .idx = evlist__nr_entries(evlist),
+ .error = err,
+ .stoken = PE_START_EVENTS,
+ .fake_pmu = fake_pmu,
+ .fake_tp = fake_tp,
+ .pmu_filter = pmu_filter,
+ .cputype_filter = cputype_filter,
.match_legacy_cache_terms = true,
};
int ret, ret2;
@@ -2312,15 +2317,15 @@ int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filte
}
ret2 = parse_events__sort_events_and_fix_groups(&parse_state.list);
- if (ret2 < 0)
- return ret;
+ if (ret2 < 0 && !ret)
+ ret = ret2;
/*
* Add list to the evlist even with errors to allow callers to clean up.
*/
evlist__splice_list_tail(evlist, &parse_state.list);
- if (ret2 && warn_if_reordered && !parse_state.wild_card_pmus) {
+ if (ret2 > 0 && warn_if_reordered && !parse_state.wild_card_pmus) {
evlist__uniquify_evsel_names(evlist, &stat_config);
pr_warning("WARNING: events were regrouped to match PMUs\n");
@@ -2518,8 +2523,9 @@ int parse_events_option(const struct option *opt, const char *str,
int ret;
parse_events_error__init(&err);
- ret = __parse_events(*args->evlistp, str, args->pmu_filter, &err,
- /*fake_pmu=*/false, /*warn_if_reordered=*/true,
+ ret = __parse_events(*args->evlistp, str, args->pmu_filter,
+ args->cputype_filter, &err, /*fake_pmu=*/false,
+ /*warn_if_reordered=*/true,
/*fake_tp=*/false);
if (ret) {
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 3577ab213730..b14c832b03a1 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -26,20 +26,23 @@ const char *event_type(size_t type);
struct parse_events_option_args {
struct evlist **evlistp;
const char *pmu_filter;
+ bool cputype_filter;
};
int parse_events_option(const struct option *opt, const char *str, int unset);
int parse_events_option_new_evlist(const struct option *opt, const char *str, int unset);
-__attribute__((nonnull(1, 2, 4)))
-int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filter,
- struct parse_events_error *error, bool fake_pmu,
- bool warn_if_reordered, bool fake_tp);
+__attribute__((nonnull(1, 2, 5))) int
+__parse_events(struct evlist *evlist, const char *str, const char *pmu_filter,
+ bool cputype_filter, struct parse_events_error *error,
+ bool fake_pmu, bool warn_if_reordered, bool fake_tp);
__attribute__((nonnull(1, 2, 3)))
static inline int parse_events(struct evlist *evlist, const char *str,
struct parse_events_error *err)
{
- return __parse_events(evlist, str, /*pmu_filter=*/NULL, err, /*fake_pmu=*/false,
- /*warn_if_reordered=*/true, /*fake_tp=*/false);
+ return __parse_events(evlist, str, /*pmu_filter=*/NULL,
+ /*cputype_filter=*/false, err, /*fake_pmu=*/false,
+ /*warn_if_reordered=*/true,
+ /*fake_tp=*/false);
}
int parse_event(struct evlist *evlist, const char *str);
@@ -161,6 +164,8 @@ struct parse_events_state {
bool fake_tp;
/* If non-null, when wildcard matching only match the given PMU. */
const char *pmu_filter;
+ /* If true, the pmu_filter was set by --cputype option. */
+ bool cputype_filter;
/* Should PE_LEGACY_NAME tokens be generated for config terms? */
bool match_legacy_cache_terms;
/* Were multiple PMUs scanned to find events? */
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 11e1f39c1bea..af85c0771c44 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -3411,7 +3411,8 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
perf_evlist__set_maps(evlist__core(evlist), cpus, threads);
- ret = metricgroup__parse_groups(evlist, pmu ?: "all", input,
+ ret = metricgroup__parse_groups(evlist, pmu ?: "all",
+ /*cputype_filter=*/false, input,
/*metric_no_group=*/ false,
/*metric_no_merge=*/ false,
/*metric_no_threshold=*/ true,