Linux Perf Users
 help / color / mirror / Atom feed
From: Ian Rogers <irogers@google.com>
To: linux-perf-users@vger.kernel.org,
	 Arnaldo Carvalho de Melo <acme@kernel.org>,
	Namhyung Kim <namhyung@kernel.org>
Cc: linux-kernel@vger.kernel.org,
	Peter Zijlstra <peterz@infradead.org>,
	 Ingo Molnar <mingo@redhat.com>, Jiri Olsa <jolsa@kernel.org>,
	 Adrian Hunter <adrian.hunter@intel.com>,
	James Clark <james.clark@linaro.org>,
	 Kan Liang <kan.liang@linux.intel.com>,
	Dapeng Mi <dapeng1.mi@linux.intel.com>,
	 Thomas Falcon <thomas.falcon@intel.com>,
	John Garry <john.garry@linux.dev>,  Will Deacon <will@kernel.org>,
	Leo Yan <leo.yan@arm.com>,
	 Athira Rajeev <atrajeev@linux.ibm.com>,
	Thomas Richter <tmricht@linux.ibm.com>,
	 Ravi Bangoria <ravi.bangoria@amd.com>,
	Sandipan Das <sandipan.das@amd.com>,
	 Ian Rogers <irogers@google.com>
Subject: [PATCH v1 06/41] perf pmus: Pass struct perf_pmus to scan helpers
Date: Tue,  3 Nov 2026 15:44:22 -0800	[thread overview]
Message-ID: <20261103234502.1008382-7-irogers@google.com> (raw)
In-Reply-To: <20261103234502.1008382-1-irogers@google.com>

Update perf_pmus__scan() and perf_pmus__scan_core() to take a
struct perf_pmus * argument and update callers to pass the appropriate
environment's PMUs.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/arch/x86/tests/topdown.c           |  3 +-
 tools/perf/bench/pmu-scan.c                   |  6 ++--
 tools/perf/tests/event_groups.c               |  4 ++-
 tools/perf/tests/mmap-basic.c                 |  2 +-
 tools/perf/tests/parse-events.c               |  9 +++--
 tools/perf/tests/pmu-events.c                 |  4 ++-
 tools/perf/tests/uncore-event-sorting.c       |  6 ++--
 tools/perf/util/cputopo.c                     |  2 +-
 tools/perf/util/env.c                         |  7 ++--
 tools/perf/util/evlist.c                      |  3 +-
 tools/perf/util/header.c                      | 10 +++---
 tools/perf/util/mem-events.c                  |  5 ++-
 tools/perf/util/metricgroup.c                 |  2 +-
 tools/perf/util/parse-events.c                | 28 ++++++++--------
 .../perf/util/perf-regs-arch/perf_regs_x86.c  |  2 +-
 tools/perf/util/perf_api_probe.c              |  3 +-
 tools/perf/util/pmu.c                         |  4 ++-
 tools/perf/util/pmus.c                        | 33 +++++++------------
 tools/perf/util/pmus.h                        | 19 +++++++++--
 tools/perf/util/python.c                      |  4 +--
 20 files changed, 92 insertions(+), 64 deletions(-)

diff --git a/tools/perf/arch/x86/tests/topdown.c b/tools/perf/arch/x86/tests/topdown.c
index 827169b60813..fec51274e76e 100644
--- a/tools/perf/arch/x86/tests/topdown.c
+++ b/tools/perf/arch/x86/tests/topdown.c
@@ -65,13 +65,14 @@ static int event_cb(void *state, struct pmu_event_info *info)
 
 static int test__x86_topdown(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
 {
+	struct perf_pmus *pmus = perf_env__pmus(host_env());
 	int ret = TEST_OK;
 	struct perf_pmu *pmu = NULL;
 
 	if (!topdown_sys_has_perf_metrics())
 		return TEST_OK;
 
-	while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+	while ((pmu = perf_pmus__scan_core(pmus, pmu)) != NULL) {
 		if (perf_pmu__for_each_event(pmu, /*skip_duplicate_pmus=*/false, &ret, event_cb))
 			break;
 	}
diff --git a/tools/perf/bench/pmu-scan.c b/tools/perf/bench/pmu-scan.c
index 754486d1d87b..fe58fbfcf96d 100644
--- a/tools/perf/bench/pmu-scan.c
+++ b/tools/perf/bench/pmu-scan.c
@@ -48,7 +48,7 @@ static int save_result(void)
 	struct list_head *list;
 	struct pmu_scan_result *r;
 
-	while ((pmu = perf_pmus__scan(pmu)) != NULL) {
+	while ((pmu = perf_pmus__scan(pmus, pmu)) != NULL) {
 		r = realloc(results, (nr_pmus + 1) * sizeof(*r));
 		if (r == NULL)
 			return -ENOMEM;
@@ -153,9 +153,9 @@ static int run_pmu_scan(void)
 		for (unsigned int i = 0; i < iterations; i++) {
 			gettimeofday(&start, NULL);
 			if (core_only)
-				perf_pmus__scan_core(NULL);
+				perf_pmus__scan_core(pmus, NULL);
 			else
-				perf_pmus__scan(NULL);
+				perf_pmus__scan(pmus, NULL);
 			gettimeofday(&end, NULL);
 			timersub(&end, &start, &diff);
 			runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec;
diff --git a/tools/perf/tests/event_groups.c b/tools/perf/tests/event_groups.c
index c119ff114948..f52d2fb08820 100644
--- a/tools/perf/tests/event_groups.c
+++ b/tools/perf/tests/event_groups.c
@@ -5,6 +5,7 @@
 #include "linux/perf_event.h"
 #include "tests.h"
 #include "debug.h"
+#include "env.h"
 #include "pmu.h"
 #include "pmus.h"
 #include "header.h"
@@ -51,10 +52,11 @@ static int event_open(int type, unsigned long config, int group_fd)
 
 static int setup_uncore_event(void)
 {
+	struct perf_pmus *pmus = perf_env__pmus(host_env());
 	struct perf_pmu *pmu = NULL;
 	int i, fd;
 
-	while ((pmu = perf_pmus__scan(pmu)) != NULL) {
+	while ((pmu = perf_pmus__scan(pmus, pmu)) != NULL) {
 		for (i = 0; i < NR_UNCORE_PMUS; i++) {
 			if (!strcmp(uncore_pmus[i].name, pmu->name)) {
 				pr_debug("Using %s for uncore pmu event\n", pmu->name);
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index dada4af5fb68..a542aadb46a0 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -277,7 +277,7 @@ static int test_stat_user_read(u64 event, enum user_read_state enabled)
 	}
 	perf_thread_map__set_pid(threads, 0, 0);
 
-	while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+	while ((pmu = perf_pmus__scan_core(pmus, pmu)) != NULL) {
 		enum user_read_state saved_user_read_state = set_user_read(pmu, enabled);
 		struct perf_event_attr attr = {
 			.type	= PERF_TYPE_HARDWARE,
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index c95f6d6f5854..b1e72866e64a 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -142,6 +142,7 @@ static int test__checkevent_tracepoint_multi(struct evlist *evlist)
 
 static int test__checkevent_raw(struct evlist *evlist)
 {
+	struct perf_pmus *pmus __maybe_unused = perf_env__pmus(host_env());
 	struct evsel *evsel;
 	bool raw_type_match = false;
 
@@ -164,7 +165,7 @@ static int test__checkevent_raw(struct evlist *evlist)
 		 */
 		type_matched = raw_type_match = true;
 #else
-		while ((pmu = perf_pmus__scan(pmu)) != NULL) {
+		while ((pmu = perf_pmus__scan(pmus, pmu)) != NULL) {
 			if (pmu->type == evsel->core.attr.type) {
 				TEST_ASSERT_EVSEL("PMU type expected once", !type_matched, evsel);
 				type_matched = true;
@@ -1792,9 +1793,10 @@ static int test__intel_pt(struct evlist *evlist)
 
 static bool test__acr_valid(void)
 {
+	struct perf_pmus *pmus = perf_env__pmus(host_env());
 	struct perf_pmu *pmu = NULL;
 
-	while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+	while ((pmu = perf_pmus__scan_core(pmus, pmu)) != NULL) {
 		if (perf_pmu__has_format(pmu, "acr_mask"))
 			return true;
 	}
@@ -2703,10 +2705,11 @@ static int test__terms2(struct test_suite *test __maybe_unused, int subtest __ma
 
 static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
 {
+	struct perf_pmus *pmus = perf_env__pmus(host_env());
 	struct perf_pmu *pmu = NULL;
 	int ret = TEST_OK;
 
-	while ((pmu = perf_pmus__scan(pmu)) != NULL) {
+	while ((pmu = perf_pmus__scan(pmus, pmu)) != NULL) {
 		struct stat st;
 		char path[PATH_MAX];
 		char pmu_event[PATH_MAX];
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index acf8e8ee1237..cb0c2b05c1e8 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/zalloc.h>
 #include "debug.h"
+#include "env.h"
 #include "../pmu-events/pmu-events.h"
 #include <perf/evlist.h>
 #include "util/evlist.h"
@@ -726,10 +727,11 @@ static struct perf_pmu_test_pmu test_pmus[] = {
 static int test__aliases(struct test_suite *test __maybe_unused,
 			int subtest __maybe_unused)
 {
+	struct perf_pmus *pmus = perf_env__pmus(host_env());
 	struct perf_pmu *pmu = NULL;
 	unsigned long i;
 
-	while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+	while ((pmu = perf_pmus__scan_core(pmus, pmu)) != NULL) {
 		int count = 0;
 
 		if (list_empty(&pmu->format)) {
diff --git a/tools/perf/tests/uncore-event-sorting.c b/tools/perf/tests/uncore-event-sorting.c
index 7756777c54c2..99af4d88bb81 100644
--- a/tools/perf/tests/uncore-event-sorting.c
+++ b/tools/perf/tests/uncore-event-sorting.c
@@ -2,6 +2,7 @@
 #include <string.h>
 
 #include "debug.h"
+#include "env.h"
 #include "evlist.h"
 #include "parse-events.h"
 #include "pmu.h"
@@ -84,6 +85,7 @@ static int test__uncore_event_sorting(struct test_suite *test __maybe_unused,
 	struct evlist *evlist = NULL;
 	struct parse_events_error err;
 	struct evsel *evsel;
+	struct perf_pmus *pmus = perf_env__pmus(host_env());
 	struct perf_pmu *pmu = NULL;
 	char *pmu_prefix = NULL;
 	struct match_state m = { NULL, NULL };
@@ -92,7 +94,7 @@ static int test__uncore_event_sorting(struct test_suite *test __maybe_unused,
 
 	parse_events_error__init(&err);
 
-	while ((pmu = perf_pmus__scan(pmu)) != NULL) {
+	while ((pmu = perf_pmus__scan(pmus, pmu)) != NULL) {
 		size_t len;
 		struct perf_pmu *sibling;
 
@@ -104,7 +106,7 @@ static int test__uncore_event_sorting(struct test_suite *test __maybe_unused,
 			continue;
 
 		sibling = pmu;
-		while ((sibling = perf_pmus__scan(sibling)) != NULL) {
+		while ((sibling = perf_pmus__scan(pmus, sibling)) != NULL) {
 			if (sibling->is_core)
 				continue;
 			if (pmu_name_len_no_suffix(sibling->name) == len &&
diff --git a/tools/perf/util/cputopo.c b/tools/perf/util/cputopo.c
index 04ab4d010149..2e8e8754bb3f 100644
--- a/tools/perf/util/cputopo.c
+++ b/tools/perf/util/cputopo.c
@@ -483,7 +483,7 @@ struct hybrid_topology *hybrid_topology__new(void)
 		return NULL;
 
 	tp->nr = nr;
-	while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+	while ((pmu = perf_pmus__scan_core(pmus, pmu)) != NULL) {
 		if (load_hybrid_node(&tp->nodes[i], pmu)) {
 			hybrid_topology__delete(tp);
 			return NULL;
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 4f4ec49b6a6b..fec6a5a8ecb6 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -499,11 +499,12 @@ int perf_env__read_cpu_topology_map(struct perf_env *env)
 
 int perf_env__read_pmu_mappings(struct perf_env *env)
 {
+	struct perf_pmus *pmus = perf_env__pmus(host_env());
 	struct perf_pmu *pmu = NULL;
 	u32 pmu_num = 0;
 	struct strbuf sb;
 
-	while ((pmu = perf_pmus__scan(pmu)))
+	while ((pmu = perf_pmus__scan(pmus, pmu)))
 		pmu_num++;
 
 	if (!pmu_num) {
@@ -514,7 +515,7 @@ int perf_env__read_pmu_mappings(struct perf_env *env)
 	if (strbuf_init(&sb, 128 * pmu_num) < 0)
 		return -ENOMEM;
 
-	while ((pmu = perf_pmus__scan(pmu))) {
+	while ((pmu = perf_pmus__scan(pmus, pmu))) {
 		if (strbuf_addf(&sb, "%u:%s", pmu->type, pmu->name) < 0)
 			goto error;
 		/* include a NULL character at the end */
@@ -633,7 +634,7 @@ int perf_env__read_core_pmu_caps(struct perf_env *env)
 	if (!pmu_caps)
 		return -ENOMEM;
 
-	while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+	while ((pmu = perf_pmus__scan_core(pmus, pmu)) != NULL) {
 		if (perf_pmu__caps_parse(pmu) <= 0)
 			continue;
 		ret = __perf_env__read_core_pmu_caps(pmu, &pmu_caps[i].nr_caps,
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 4e641ccc176f..faf5ce62811b 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -128,10 +128,11 @@ struct evlist *evlist__new_default(const struct target *target, bool sample_call
 		if (err)
 			goto out_err;
 	} else {
+		struct perf_pmus *pmus = perf_env__pmus(host_env());
 		struct evsel *leader = NULL;
 
 		/* Fallback for cross-platform file analysis missing the topology header */
-		while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+		while ((pmu = perf_pmus__scan_core(pmus, pmu)) != NULL) {
 			snprintf(buf, sizeof(buf), "%s/cycles/%s", pmu->name,
 				can_profile_kernel ? "P" : "Pu");
 			err = parse_event(evlist, buf);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 48ff46c165fd..2c686095fe67 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -855,6 +855,7 @@ static int write_numa_topology(struct feat_fd *ff,
 static int write_pmu_mappings(struct feat_fd *ff,
 			      struct evlist *evlist __maybe_unused)
 {
+	struct perf_pmus *pmus = perf_env__pmus(host_env());
 	struct perf_pmu *pmu = NULL;
 	u32 pmu_num = 0;
 	int ret;
@@ -863,14 +864,14 @@ static int write_pmu_mappings(struct feat_fd *ff,
 	 * Do a first pass to count number of pmu to avoid lseek so this
 	 * works in pipe mode as well.
 	 */
-	while ((pmu = perf_pmus__scan(pmu)))
+	while ((pmu = perf_pmus__scan(pmus, pmu)))
 		pmu_num++;
 
 	ret = do_write(ff, &pmu_num, sizeof(pmu_num));
 	if (ret < 0)
 		return ret;
 
-	while ((pmu = perf_pmus__scan(pmu))) {
+	while ((pmu = perf_pmus__scan(pmus, pmu))) {
 		ret = do_write(ff, &pmu->type, sizeof(pmu->type));
 		if (ret < 0)
 			return ret;
@@ -1720,11 +1721,12 @@ static int write_cpu_pmu_caps(struct feat_fd *ff,
 static int write_pmu_caps(struct feat_fd *ff,
 			  struct evlist *evlist __maybe_unused)
 {
+	struct perf_pmus *pmus = perf_env__pmus(host_env());
 	struct perf_pmu *pmu = NULL;
 	int nr_pmu = 0;
 	int ret;
 
-	while ((pmu = perf_pmus__scan(pmu))) {
+	while ((pmu = perf_pmus__scan(pmus, pmu))) {
 		if (!strcmp(pmu->name, "cpu")) {
 			/*
 			 * The "cpu" PMU is special and covered by
@@ -1750,7 +1752,7 @@ static int write_pmu_caps(struct feat_fd *ff,
 	 * of perf_pmus__scan.
 	 */
 	pmu = NULL;
-	while ((pmu = perf_pmus__scan(pmu))) {
+	while ((pmu = perf_pmus__scan(pmus, pmu))) {
 		if (!strcmp(pmu->name, "cpu")) {
 			/* Skip as above. */
 			continue;
diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c
index 0cdcb47647bd..62543df0dca1 100644
--- a/tools/perf/util/mem-events.c
+++ b/tools/perf/util/mem-events.c
@@ -13,6 +13,7 @@
 #include "mem-events.h"
 #include "mem-info.h"
 #include "debug.h"
+#include "env.h"
 #include "evsel.h"
 #include "symbol.h"
 #include "pmu.h"
@@ -42,7 +43,9 @@ struct perf_mem_event *perf_pmu__mem_events_ptr(struct perf_pmu *pmu, int i)
 
 static struct perf_pmu *perf_pmus__scan_mem(struct perf_pmu *pmu)
 {
-	while ((pmu = perf_pmus__scan(pmu)) != NULL) {
+	struct perf_pmus *pmus = perf_env__pmus(host_env());
+
+	while ((pmu = perf_pmus__scan(pmus, pmu)) != NULL) {
 		if (pmu->mem_events)
 			return pmu;
 	}
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 4e1205c1d3b2..100f54338e8e 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -933,7 +933,7 @@ static int __add_metric(struct list_head *metric_list,
 		if (pm->pmu && pm->pmu[0] != '\0')
 			pmu = perf_pmus__find(pmus, pm->pmu);
 		else
-			pmu = perf_pmus__scan_core(/*pmu=*/ NULL);
+			pmu = perf_pmus__scan_core(pmus, /*pmu=*/NULL);
 
 		ret = resolve_metric(metric_list, pmus, pmu, modifier, metric_no_group,
 				     metric_no_threshold, user_requested_cpu_list,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index bb99588589f4..159d847f44ce 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -985,16 +985,16 @@ do {											\
 }
 
 static bool check_pmu_is_core(__u32 type, const struct parse_events_term *term,
-			      struct parse_events_error *err)
+			      struct parse_events_state *parse_state)
 {
 	struct perf_pmu *pmu = NULL;
 
 	/* Avoid loading all PMUs with perf_pmus__find_by_type, just scan the core ones. */
-	while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+	while ((pmu = perf_pmus__scan_core(parse_state->pmus, pmu)) != NULL) {
 		if (pmu->type == type)
 			return true;
 	}
-	parse_events_error__handle(err, term->err_val,
+	parse_events_error__handle(parse_state->error, term->err_val,
 				strdup("needs a core PMU"),
 				NULL);
 	return false;
@@ -1013,7 +1013,7 @@ static int config_term_pmu(struct perf_event_attr *attr,
 						   NULL);
 			return -EINVAL;
 		}
-		if (!check_pmu_is_core(attr->type, term, parse_state->error))
+		if (!check_pmu_is_core(attr->type, term, parse_state))
 			return -EINVAL;
 		attr->config = term->val.num;
 		if (perf_pmus__supports_extended_type(parse_state->pmus))
@@ -1038,7 +1038,7 @@ static int config_term_pmu(struct perf_event_attr *attr,
 						   NULL);
 			return -EINVAL;
 		}
-		if (!check_pmu_is_core(attr->type, term, parse_state->error))
+		if (!check_pmu_is_core(attr->type, term, parse_state))
 			return -EINVAL;
 		attr->config = term->val.num;
 		if (perf_pmus__supports_extended_type(parse_state->pmus))
@@ -1452,7 +1452,7 @@ int parse_events_add_numeric(struct parse_events_state *parse_state,
 	/* Wildcards on numeric values are only supported by core PMUs. */
 	if (wildcard && perf_pmus__supports_extended_type(parse_state->pmus)) {
 		struct evsel *first_wildcard_match = NULL;
-		while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+		while ((pmu = perf_pmus__scan_core(parse_state->pmus, pmu)) != NULL) {
 			int ret;
 
 			found_supported = true;
@@ -1986,7 +1986,8 @@ int parse_events_terms(struct parse_events_terms *terms, const char *str)
 }
 
 static int evsel__compute_group_pmu_name(struct evsel *evsel,
-					  const struct list_head *head)
+					  const struct list_head *head,
+					  struct perf_pmus *pmus)
 {
 	struct evsel *leader = evsel__leader(evsel);
 	struct evsel *pos;
@@ -1999,7 +2000,7 @@ static int evsel__compute_group_pmu_name(struct evsel *evsel,
 		 * is a core PMU, but in heterogeneous systems this is
 		 * unknown. For now pick the first core PMU.
 		 */
-		pmu = perf_pmus__scan_core(NULL);
+		pmu = perf_pmus__scan_core(pmus, NULL);
 	}
 	if (!pmu) {
 		pr_debug("No PMU found for '%s'\n", evsel__name(evsel));
@@ -2019,7 +2020,7 @@ static int evsel__compute_group_pmu_name(struct evsel *evsel,
 
 		if (!leader_pmu) {
 			/* As with determining pmu above. */
-			leader_pmu = perf_pmus__scan_core(NULL);
+			leader_pmu = perf_pmus__scan_core(pmus, NULL);
 		}
 		/*
 		 * Starting with the leader, find the first event with a named
@@ -2038,7 +2039,7 @@ static int evsel__compute_group_pmu_name(struct evsel *evsel,
 				pos_pmu = evsel__find_pmu(pos);
 				if (!pos_pmu) {
 					/* As with determining pmu above. */
-					pos_pmu = perf_pmus__scan_core(NULL);
+					pos_pmu = perf_pmus__scan_core(pmus, NULL);
 				}
 				if (pos_pmu && !perf_pmu__is_software(pos_pmu)) {
 					group_pmu_name = pos_pmu->name;
@@ -2128,7 +2129,8 @@ int __weak arch_evlist__add_required_events(struct list_head *list __always_unus
 	return 0;
 }
 
-static int parse_events__sort_events_and_fix_groups(struct list_head *list)
+static int parse_events__sort_events_and_fix_groups(struct list_head *list,
+						    struct perf_pmus *pmus)
 {
 	int idx = 0, force_grouped_idx = -1;
 	struct evsel *pos, *cur_leader = NULL;
@@ -2151,7 +2153,7 @@ static int parse_events__sort_events_and_fix_groups(struct list_head *list)
 	list_for_each_entry(pos, list, core.node) {
 		const struct evsel *pos_leader = evsel__leader(pos);
 
-		ret = evsel__compute_group_pmu_name(pos, list);
+		ret = evsel__compute_group_pmu_name(pos, list, pmus);
 		if (ret)
 			return ret;
 
@@ -2322,7 +2324,7 @@ int __parse_events(struct evlist *evlist, const char *str,
 		return -1;
 	}
 
-	ret2 = parse_events__sort_events_and_fix_groups(&parse_state.list);
+	ret2 = parse_events__sort_events_and_fix_groups(&parse_state.list, parse_state.pmus);
 	if (ret2 < 0 && !ret)
 		ret = ret2;
 
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_x86.c b/tools/perf/util/perf-regs-arch/perf_regs_x86.c
index 920f17b89659..8cb9dfa6c7d3 100644
--- a/tools/perf/util/perf-regs-arch/perf_regs_x86.c
+++ b/tools/perf/util/perf-regs-arch/perf_regs_x86.c
@@ -268,7 +268,7 @@ static uint64_t __arch__reg_mask(u64 sample_type, u64 mask, bool has_simd_regs)
 		 * The same register set is supported among different hybrid PMUs.
 		 * Only check the first available one.
 		 */
-		while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+		while ((pmu = perf_pmus__scan_core(pmus, pmu)) != NULL) {
 			type = pmu->type;
 			break;
 		}
diff --git a/tools/perf/util/perf_api_probe.c b/tools/perf/util/perf_api_probe.c
index f61c4ec52827..7a8b99f31985 100644
--- a/tools/perf/util/perf_api_probe.c
+++ b/tools/perf/util/perf_api_probe.c
@@ -6,6 +6,7 @@
 #include <perf/cpumap.h>
 
 #include "cloexec.h"
+#include "env.h"
 #include "evlist.h"
 #include "evsel.h"
 #include "parse-events.h"
@@ -78,7 +79,7 @@ static bool perf_probe_api(setup_probe_fn_t fn)
 	if (!ret)
 		return true;
 
-	pmu = perf_pmus__scan_core(/*pmu=*/NULL);
+	pmu = perf_pmus__scan_core(perf_env__pmus(host_env()), /*pmu=*/NULL);
 	if (pmu) {
 		const char *try[] = {"cycles", "instructions", NULL};
 		char buf[256];
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index ee6a217dde91..06c4912d2f65 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -2071,6 +2071,7 @@ bool is_pmu_core(const char *name)
  */
 bool is_pmu_core_len(struct perf_env *env, const char *name, size_t len)
 {
+	struct perf_pmus *pmus;
 	struct perf_pmu *pmu = NULL;
 
 	if (env && env->hybrid_nodes) {
@@ -2097,7 +2098,8 @@ bool is_pmu_core_len(struct perf_env *env, const char *name, size_t len)
 		return false;
 	}
 
-	while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+	pmus = perf_env__pmus(env ?: host_env());
+	while ((pmu = perf_pmus__scan_core(pmus, pmu)) != NULL) {
 		if (strlen(pmu->name) == len && !strncmp(name, pmu->name, len))
 			return true;
 	}
diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c
index 4ad715783165..c3a695ebf2ba 100644
--- a/tools/perf/util/pmus.c
+++ b/tools/perf/util/pmus.c
@@ -362,7 +362,7 @@ struct perf_pmu *perf_pmus__find_by_type(struct perf_pmus *pmus, unsigned int ty
  * pmu iterator: If pmu is NULL, we start at the begin, otherwise return the
  * next pmu. Returns NULL on end.
  */
-static struct perf_pmu *pmu_scan(struct perf_pmus *pmus, struct perf_pmu *pmu)
+struct perf_pmu *perf_pmus__scan(struct perf_pmus *pmus, struct perf_pmu *pmu)
 {
 	bool use_core_pmus = !pmu || pmu->is_core;
 
@@ -382,12 +382,7 @@ static struct perf_pmu *pmu_scan(struct perf_pmus *pmus, struct perf_pmu *pmu)
 	return NULL;
 }
 
-struct perf_pmu *perf_pmus__scan(struct perf_pmu *pmu)
-{
-	return pmu_scan(perf_env__pmus(host_env()), pmu);
-}
-
-static struct perf_pmu *pmu_scan_core(struct perf_pmus *pmus, struct perf_pmu *pmu)
+struct perf_pmu *perf_pmus__scan_core(struct perf_pmus *pmus, struct perf_pmu *pmu)
 {
 	if (!pmu) {
 		pmu_read_sysfs(pmus, PERF_TOOL_PMU_TYPE_PE_CORE_MASK);
@@ -399,11 +394,6 @@ static struct perf_pmu *pmu_scan_core(struct perf_pmus *pmus, struct perf_pmu *p
 	return NULL;
 }
 
-struct perf_pmu *perf_pmus__scan_core(struct perf_pmu *pmu)
-{
-	return pmu_scan_core(perf_env__pmus(host_env()), pmu);
-}
-
 struct perf_pmu *perf_pmus__scan_for_event(struct perf_pmus *pmus,
 					   struct perf_pmu *pmu, const char *event)
 {
@@ -492,7 +482,8 @@ struct perf_pmu *perf_pmus__scan_matching_wildcard(struct perf_pmus *pmus,
 	return NULL;
 }
 
-static struct perf_pmu *pmu_scan_skip_duplicates(struct perf_pmus *pmus, struct perf_pmu *pmu)
+static struct perf_pmu *
+perf_pmus__scan_skip_duplicates(struct perf_pmus *pmus, struct perf_pmu *pmu)
 {
 	bool use_core_pmus = !pmu || pmu->is_core;
 	int last_pmu_name_len = 0;
@@ -550,7 +541,7 @@ const struct perf_pmu *perf_pmus__pmu_for_pmu_filter(struct perf_pmus *pmus, con
 {
 	struct perf_pmu *pmu = NULL;
 
-	while ((pmu = pmu_scan(pmus, pmu)) != NULL) {
+	while ((pmu = perf_pmus__scan(pmus, pmu)) != NULL) {
 		if (!strcmp(pmu->name, str))
 			return pmu;
 		/* Ignore "uncore_" prefix. */
@@ -683,9 +674,9 @@ void perf_pmus__print_pmu_events(struct perf_pmus *pmus,
 	struct perf_pmu *(*scan_fn)(struct perf_pmus *p, struct perf_pmu *cur);
 
 	if (skip_duplicate_pmus)
-		scan_fn = pmu_scan_skip_duplicates;
+		scan_fn = perf_pmus__scan_skip_duplicates;
 	else
-		scan_fn = pmu_scan;
+		scan_fn = perf_pmus__scan;
 
 	pmu = NULL;
 	len = 0;
@@ -795,9 +786,9 @@ void perf_pmus__print_raw_pmu_events(struct perf_pmus *pmus,
 	struct perf_pmu *pmu = NULL;
 
 	if (skip_duplicate_pmus)
-		scan_fn = pmu_scan_skip_duplicates;
+		scan_fn = perf_pmus__scan_skip_duplicates;
 	else
-		scan_fn = pmu_scan;
+		scan_fn = perf_pmus__scan;
 
 	while ((pmu = scan_fn(pmus, pmu)) != NULL) {
 		struct build_format_string_args format_args = {
@@ -851,7 +842,7 @@ int perf_pmus__num_core_pmus(struct perf_pmus *pmus)
 	if (!pmus->num_core_pmus) {
 		struct perf_pmu *pmu = NULL;
 
-		while ((pmu = pmu_scan_core(pmus, pmu)) != NULL)
+		while ((pmu = perf_pmus__scan_core(pmus, pmu)) != NULL)
 			pmus->num_core_pmus++;
 	}
 	return pmus->num_core_pmus;
@@ -864,7 +855,7 @@ static bool __perf_pmus__supports_extended_type(struct perf_pmus *pmus)
 	if (perf_pmus__num_core_pmus(pmus) <= 1)
 		return false;
 
-	while ((pmu = pmu_scan_core(pmus, pmu)) != NULL) {
+	while ((pmu = perf_pmus__scan_core(pmus, pmu)) != NULL) {
 		if (!pmu->from_env &&
 		    !is_event_supported(PERF_TYPE_HARDWARE,
 					PERF_COUNT_HW_CPU_CYCLES |
@@ -943,7 +934,7 @@ struct perf_pmu *evsel__find_pmu(const struct evsel *evsel)
 
 struct perf_pmu *perf_pmus__find_core_pmu(struct perf_pmus *pmus)
 {
-	return pmu_scan_core(pmus, NULL);
+	return perf_pmus__scan_core(pmus, NULL);
 }
 
 struct perf_pmu *perf_pmus__add_test_pmu(struct perf_pmus *pmus,
diff --git a/tools/perf/util/pmus.h b/tools/perf/util/pmus.h
index cd0c14f8e04b..6e7c9f857aaf 100644
--- a/tools/perf/util/pmus.h
+++ b/tools/perf/util/pmus.h
@@ -103,8 +103,23 @@ struct perf_pmu *perf_pmus__find_by_type(struct perf_pmus *pmus, unsigned int ty
 struct perf_pmu *perf_pmus__find_by_attr(struct perf_pmus *pmus,
 					 const struct perf_event_attr *attr);
 
-struct perf_pmu *perf_pmus__scan(struct perf_pmu *pmu);
-struct perf_pmu *perf_pmus__scan_core(struct perf_pmu *pmu);
+/**
+ * perf_pmus__scan() - Iterate over all PMUs (core then other) in @pmus.
+ * @pmus: The PMU collection to scan.
+ * @pmu: Previous PMU returned by perf_pmus__scan(), or NULL to start.
+ *
+ * Return: Next struct perf_pmu in @pmus, or NULL when iteration completes.
+ */
+struct perf_pmu *perf_pmus__scan(struct perf_pmus *pmus, struct perf_pmu *pmu);
+
+/**
+ * perf_pmus__scan_core() - Iterate over core PMUs in @pmus.
+ * @pmus: The PMU collection to scan.
+ * @pmu: Previous core PMU returned by perf_pmus__scan_core(), or NULL to start.
+ *
+ * Return: Next core struct perf_pmu in @pmus, or NULL when iteration completes.
+ */
+struct perf_pmu *perf_pmus__scan_core(struct perf_pmus *pmus, struct perf_pmu *pmu);
 
 /**
  * perf_pmus__scan_for_event() - Iterate over PMUs in @pmus that have @event.
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 60dbe2dad5eb..065742a7431b 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -2162,7 +2162,7 @@ static PyObject *pyrf_pmu_iterator__new(PyTypeObject *type, PyObject *args __may
 	struct pyrf_pmu_iterator *itr = (void *)type->tp_alloc(type, 0);
 
 	if (itr != NULL)
-		itr->pmu = perf_pmus__scan(/*pmu=*/NULL);
+		itr->pmu = perf_pmus__scan(perf_env__pmus(host_env()), /*pmu=*/NULL);
 
 	return (PyObject *) itr;
 }
@@ -2187,7 +2187,7 @@ static PyObject *pyrf_pmu_iterator__iternext(PyObject *self)
 	if (ppmu) {
 		ppmu->pmu = itr->pmu;
 		// Advance iterator.
-		itr->pmu = perf_pmus__scan(itr->pmu);
+		itr->pmu = perf_pmus__scan(perf_env__pmus(host_env()), itr->pmu);
 	}
 	return (PyObject *)ppmu;
 }
-- 
2.56.0.385.gac671c819a-goog


  parent reply	other threads:[~2026-11-03 23:45 UTC|newest]

Thread overview: 83+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-03 23:44 [PATCH v1 00/41] perf: Per-env PMUs, recorded event metrics, and perf sysinfo Ian Rogers
2026-11-03 23:44 ` [PATCH v1 01/41] perf env: Make lazy perf_env initialization thread-safe Ian Rogers
2026-11-03 23:53   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 02/41] perf env: Add host_env() singleton Ian Rogers
2026-11-04  0:18   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 03/41] perf pmu: Add from_env parameter to perf_pmu__init() Ian Rogers
2026-11-04  0:31   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 04/41] perf pmus: Introduce struct perf_pmus and perf_env__pmus() Ian Rogers
2026-11-04  0:48   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 05/41] perf pmus: Pass struct perf_pmus to find helpers Ian Rogers
2026-11-04  0:56   ` sashiko-bot
2026-11-03 23:44 ` Ian Rogers [this message]
2026-11-04  1:01   ` [PATCH v1 06/41] perf pmus: Pass struct perf_pmus to scan helpers sashiko-bot
2026-11-03 23:44 ` [PATCH v1 07/41] perf pmu-events: Add e_machine to struct pmu_events_map Ian Rogers
2026-11-04  1:06   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 08/41] perf pmu-events: Pass e_machine to find_core_*_table() Ian Rogers
2026-11-04  1:14   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 09/41] perf header: Pass e_machine to strcmp_cpuid_str() Ian Rogers
2026-11-04  1:18   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 10/41] perf header: Support CPUID matching across all architectures Ian Rogers
2026-11-04  1:23   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 11/41] perf test: Make the CPUID matching test architecture independent Ian Rogers
2026-11-04  1:32   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 12/41] perf test: Add CPUID matching tests for other architectures Ian Rogers
2026-11-04  1:36   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 13/41] perf pmus: Add perf_pmus__read_from_env() Ian Rogers
2026-11-04  2:05   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 14/41] perf metricgroup: Pass struct perf_pmus to metricgroup__for_each_metric() Ian Rogers
2026-11-04  2:17   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 15/41] perf metricgroup: Move matching of metrics to recorded events from perf script Ian Rogers
2026-11-04  2:36   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 16/41] perf parse-events: Decode metric-id terms when adding events Ian Rogers
2026-11-04  2:44   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 17/41] perf evsel: Generalize metric_id to a set of metric_ids Ian Rogers
2026-11-04  3:17   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 18/41] perf pmu: Add perf_pmu__for_each_name_from_config() Ian Rogers
2026-11-04  3:23   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 19/41] perf metricgroup: Improve matching of metrics to recorded events Ian Rogers
2026-11-04  3:46   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 20/41] perf metricgroup: Add metricgroup__add_recorded_metrics() Ian Rogers
2026-11-04  4:10   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 21/41] perf script: Fix metrics computed from samples Ian Rogers
2026-11-04  4:16   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 22/41] perf script: Don't drop metric samples for CPUs missing from the evsel Ian Rogers
2026-11-04  4:22   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 23/41] perf stat report: Display metrics for recorded events Ian Rogers
2026-11-04  4:39   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 24/41] perf script: Display metrics for perf stat record data Ian Rogers
2026-11-04  4:47   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 25/41] perf test: Add stat record metrics test Ian Rogers
2026-11-04  5:01   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 26/41] perf pmus: Expose duplicate uncore PMU scanning helpers Ian Rogers
2026-11-04  5:08   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 27/41] perf mem-events: Expose PMU init and name formatting helpers Ian Rogers
2026-11-04  5:20   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 28/41] perf pmu: Add perf_pmu__probe() for basic open, counting, and sampling Ian Rogers
2026-11-04  5:39   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 29/41] perf pmu: Probe supported sample_type flags Ian Rogers
2026-11-04  5:49   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 30/41] perf pmu: Probe precise_ip levels Ian Rogers
2026-11-04  5:59   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 31/41] perf pmu: Probe privilege exclusion modifiers Ian Rogers
2026-11-04  6:04   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 32/41] perf pmu: Probe execution and AUX area features Ian Rogers
2026-11-04  6:19   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 33/41] perf pmu: Probe event group size limits Ian Rogers
2026-11-04  6:22   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 34/41] perf pmu: Probe user and interrupt sample register masks Ian Rogers
2026-11-04  6:44   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 35/41] perf pmu: Probe interrupt registers that require precise sampling Ian Rogers
2026-11-04  6:53   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 36/41] perf pmu: Probe memory profiling events and sample formats Ian Rogers
2026-11-04  7:04   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 37/41] perf pmu: Probe user-space mmap capabilities Ian Rogers
2026-11-04  7:27   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 38/41] perf pmu: Probe branch instruction skid Ian Rogers
2026-11-04  7:32   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 39/41] perf sysinfo: Add sysinfo subcommand Ian Rogers
2026-11-04  7:50   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 40/41] perf docs: Add perf-sysinfo man page Ian Rogers
2026-11-04  7:51   ` sashiko-bot
2026-11-03 23:44 ` [PATCH v1 41/41] perf test: Add perf sysinfo shell test Ian Rogers
2026-11-04  7:59   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261103234502.1008382-7-irogers@google.com \
    --to=irogers@google.com \
    --cc=acme@kernel.org \
    --cc=adrian.hunter@intel.com \
    --cc=atrajeev@linux.ibm.com \
    --cc=dapeng1.mi@linux.intel.com \
    --cc=james.clark@linaro.org \
    --cc=john.garry@linux.dev \
    --cc=jolsa@kernel.org \
    --cc=kan.liang@linux.intel.com \
    --cc=leo.yan@arm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=namhyung@kernel.org \
    --cc=peterz@infradead.org \
    --cc=ravi.bangoria@amd.com \
    --cc=sandipan.das@amd.com \
    --cc=thomas.falcon@intel.com \
    --cc=tmricht@linux.ibm.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox