perf tools: Add --pmu-filter option for filtering PMUs

This patch adds a new --pmu-filter option to perf-stat command to allow
filtering events on specific PMUs. This is useful when there are
multiple PMUs with same type (e.g. hisi_sicl2_cpa0 and hisi_sicl0_cpa0).

[root@localhost tmp]# perf stat -M cpa_p0_avg_bw
 Performance counter stats for 'system wide':

    19,417,779,115      hisi_sicl0_cpa0/cpa_cycles/      #     0.00 cpa_p0_avg_bw
                 0      hisi_sicl0_cpa0/cpa_p0_wr_dat/
                 0      hisi_sicl0_cpa0/cpa_p0_rd_dat_64b/
                 0      hisi_sicl0_cpa0/cpa_p0_rd_dat_32b/
    19,417,751,103      hisi_sicl10_cpa0/cpa_cycles/     #     0.00 cpa_p0_avg_bw
                 0      hisi_sicl10_cpa0/cpa_p0_wr_dat/
                 0      hisi_sicl10_cpa0/cpa_p0_rd_dat_64b/
                 0      hisi_sicl10_cpa0/cpa_p0_rd_dat_32b/
    19,417,730,679      hisi_sicl2_cpa0/cpa_cycles/      #     0.31 cpa_p0_avg_bw
        75,635,749      hisi_sicl2_cpa0/cpa_p0_wr_dat/
        18,520,640      hisi_sicl2_cpa0/cpa_p0_rd_dat_64b/
                 0      hisi_sicl2_cpa0/cpa_p0_rd_dat_32b/
    19,417,674,227      hisi_sicl8_cpa0/cpa_cycles/      #     0.00 cpa_p0_avg_bw
                 0      hisi_sicl8_cpa0/cpa_p0_wr_dat/
                 0      hisi_sicl8_cpa0/cpa_p0_rd_dat_64b/
                 0      hisi_sicl8_cpa0/cpa_p0_rd_dat_32b/

      19.417734480 seconds time elapsed

[root@localhost tmp]# perf stat --pmu-filter hisi_sicl2_cpa0 -M cpa_p0_avg_bw
 Performance counter stats for 'system wide':

     6,234,093,559      cpa_cycles                       #     0.60 cpa_p0_avg_bw
        50,548,465      cpa_p0_wr_dat
         7,552,182      cpa_p0_rd_dat_64b
                 0      cpa_p0_rd_dat_32b

       6.234139320 seconds time elapsed

Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
Qinxin Xia 2026-03-10 12:06:07 +08:00 committed by Namhyung Kim
parent e397dd81bc
commit 74e2dbe7be
4 changed files with 37 additions and 6 deletions

View File

@ -578,6 +578,10 @@ $ perf config stat.no-csv-summary=true
Only enable events on applying cpu with this type for hybrid platform Only enable events on applying cpu with this type for hybrid platform
(e.g. core or atom)" (e.g. core or atom)"
--pmu-filter::
Only enable events on applying pmu with specified for multiple
pmus with same type (e.g. hisi_sicl2_cpa0 or hisi_sicl0_cpa0)
EXAMPLES EXAMPLES
-------- --------

View File

@ -1214,6 +1214,21 @@ static int parse_cputype(const struct option *opt,
return 0; return 0;
} }
static int parse_pmu_filter(const struct option *opt,
const char *str,
int unset __maybe_unused)
{
struct evlist *evlist = *(struct evlist **)opt->value;
if (!list_empty(&evlist->core.entries)) {
fprintf(stderr, "Must define pmu-filter before events/metrics\n");
return -1;
}
parse_events_option_args.pmu_filter = str;
return 0;
}
static int parse_cache_level(const struct option *opt, static int parse_cache_level(const struct option *opt,
const char *str, const char *str,
int unset __maybe_unused) int unset __maybe_unused)
@ -2564,6 +2579,10 @@ int cmd_stat(int argc, const char **argv)
"Only enable events on applying cpu with this type " "Only enable events on applying cpu with this type "
"for hybrid platform (e.g. core or atom)", "for hybrid platform (e.g. core or atom)",
parse_cputype), parse_cputype),
OPT_CALLBACK(0, "pmu-filter", &evsel_list, "pmu",
"Only enable events on applying pmu with specified "
"for multiple pmus with same type(e.g. hisi_sicl2_cpa0 or hisi_sicl0_cpa0)",
parse_pmu_filter),
#ifdef HAVE_LIBPFM #ifdef HAVE_LIBPFM
OPT_CALLBACK(0, "pfm-events", &evsel_list, "event", OPT_CALLBACK(0, "pfm-events", &evsel_list, "event",
"libpfm4 event selector. use 'perf list' to list available events", "libpfm4 event selector. use 'perf list' to list available events",

View File

@ -387,8 +387,13 @@ static bool match_pm_metric_or_groups(const struct pmu_metric *pm, const char *p
const char *metric_or_groups) const char *metric_or_groups)
{ {
const char *pm_pmu = pm->pmu ?: "cpu"; const char *pm_pmu = pm->pmu ?: "cpu";
struct perf_pmu *perf_pmu = NULL;
if (strcmp(pmu, "all") && strcmp(pm_pmu, pmu)) if (pm->pmu)
perf_pmu = perf_pmus__find(pm->pmu);
if (strcmp(pmu, "all") && strcmp(pm_pmu, pmu) &&
(perf_pmu && !perf_pmu__name_wildcard_match(perf_pmu, pmu)))
return false; return false;
return match_metric_or_groups(pm->metric_group, metric_or_groups) || return match_metric_or_groups(pm->metric_group, metric_or_groups) ||
@ -1259,7 +1264,8 @@ static int build_combined_expr_ctx(const struct list_head *metric_list,
static int parse_ids(bool metric_no_merge, bool fake_pmu, static int parse_ids(bool metric_no_merge, bool fake_pmu,
struct expr_parse_ctx *ids, const char *modifier, struct expr_parse_ctx *ids, const char *modifier,
bool group_events, const bool tool_events[TOOL_PMU__EVENT_MAX], bool group_events, const bool tool_events[TOOL_PMU__EVENT_MAX],
struct evlist **out_evlist) struct evlist **out_evlist,
const char *filter_pmu)
{ {
struct parse_events_error parse_error; struct parse_events_error parse_error;
struct evlist *parsed_evlist; struct evlist *parsed_evlist;
@ -1313,7 +1319,7 @@ static int parse_ids(bool metric_no_merge, bool fake_pmu,
} }
pr_debug("Parsing metric events '%s'\n", events.buf); pr_debug("Parsing metric events '%s'\n", events.buf);
parse_events_error__init(&parse_error); parse_events_error__init(&parse_error);
ret = __parse_events(parsed_evlist, events.buf, /*pmu_filter=*/NULL, ret = __parse_events(parsed_evlist, events.buf, filter_pmu,
&parse_error, fake_pmu, /*warn_if_reordered=*/false, &parse_error, fake_pmu, /*warn_if_reordered=*/false,
/*fake_tp=*/false); /*fake_tp=*/false);
if (ret) { if (ret) {
@ -1416,7 +1422,8 @@ static int parse_groups(struct evlist *perf_evlist,
/*modifier=*/NULL, /*modifier=*/NULL,
/*group_events=*/false, /*group_events=*/false,
tool_events, tool_events,
&combined_evlist); &combined_evlist,
(pmu && strcmp(pmu, "all") == 0) ? NULL : pmu);
} }
if (combined) if (combined)
expr__ctx_free(combined); expr__ctx_free(combined);
@ -1471,7 +1478,8 @@ static int parse_groups(struct evlist *perf_evlist,
} }
if (!metric_evlist) { if (!metric_evlist) {
ret = parse_ids(metric_no_merge, fake_pmu, m->pctx, m->modifier, ret = parse_ids(metric_no_merge, fake_pmu, m->pctx, m->modifier,
m->group_events, tool_events, &m->evlist); m->group_events, tool_events, &m->evlist,
(pmu && strcmp(pmu, "all") == 0) ? NULL : pmu);
if (ret) if (ret)
goto out; goto out;

View File

@ -429,7 +429,7 @@ bool parse_events__filter_pmu(const struct parse_events_state *parse_state,
if (parse_state->pmu_filter == NULL) if (parse_state->pmu_filter == NULL)
return false; return false;
return strcmp(parse_state->pmu_filter, pmu->name) != 0; return perf_pmu__wildcard_match(pmu, parse_state->pmu_filter) == 0;
} }
static int parse_events_add_pmu(struct parse_events_state *parse_state, static int parse_events_add_pmu(struct parse_events_state *parse_state,