From: Ian Rogers <irogers@google.com>
To: Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Namhyung Kim <namhyung@kernel.org>, Jiri Olsa <jolsa@kernel.org>,
Ian Rogers <irogers@google.com>,
Adrian Hunter <adrian.hunter@intel.com>,
James Clark <james.clark@linaro.org>
Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v2 07/30] perf pmu: Add from_env parameter to perf_pmu__init()
Date: Fri, 13 Nov 2026 11:53:12 -0800 [thread overview]
Message-ID: <20261113195335.2865725-8-irogers@google.com> (raw)
In-Reply-To: <20261113195335.2865725-1-irogers@google.com>
Add a boolean from_env field to struct perf_pmu initialized via
perf_pmu__init() to distinguish PMUs reconstructed from perf_env
headers from live host PMUs. Guard tp_pmu, hwmon_pmu, and drm_pmu
callbacks on !pmu->from_env so perf.data-derived PMUs do not access
host tracepoints or cast plain struct perf_pmu allocations via
container_of(). The hwmon and drm evsel open and read callbacks fail
with -EINVAL for such PMUs.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/tests/pmu-events.c | 4 ++--
tools/perf/util/drm_pmu.c | 16 ++++++++++----
tools/perf/util/hwmon_pmu.c | 16 +++++++++++---
tools/perf/util/pmu.c | 41 +++++++++++++++++++----------------
tools/perf/util/pmu.h | 13 ++++++++++-
tools/perf/util/tool_pmu.c | 2 +-
6 files changed, 62 insertions(+), 30 deletions(-)
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index e6e4f4cf1fa2..acf8e8ee1237 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -514,7 +514,7 @@ static int __test_core_pmu_event_aliases(const char *pmu_name, int *count)
if (!pmu)
return -1;
- if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, pmu_name) != 0) {
+ if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, pmu_name, /*from_env=*/false) != 0) {
perf_pmu__delete(pmu);
return -1;
}
@@ -566,7 +566,7 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
if (!pmu)
return -1;
- if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, test_pmu->pmu_name) != 0) {
+ if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, test_pmu->pmu_name, /*from_env=*/false) != 0) {
perf_pmu__delete(pmu);
return -1;
}
diff --git a/tools/perf/util/drm_pmu.c b/tools/perf/util/drm_pmu.c
index 5e4bdd8e7fa8..7ef4126ee7e9 100644
--- a/tools/perf/util/drm_pmu.c
+++ b/tools/perf/util/drm_pmu.c
@@ -115,7 +115,7 @@ static struct drm_pmu *add_drm_pmu(struct list_head *pmus, char *line, size_t li
if (!drm)
return NULL;
- if (perf_pmu__init(&drm->pmu, type, name) != 0) {
+ if (perf_pmu__init(&drm->pmu, type, name, /*from_env=*/false) != 0) {
perf_pmu__delete(&drm->pmu);
return NULL;
}
@@ -515,10 +515,12 @@ int evsel__drm_pmu_open(struct evsel *evsel,
struct perf_thread_map *threads,
int start_cpu_map_idx, int end_cpu_map_idx)
{
- (void)evsel;
(void)threads;
(void)start_cpu_map_idx;
(void)end_cpu_map_idx;
+ /* PMUs reconstructed from a perf.data file can't be opened. */
+ if (!evsel->pmu || evsel->pmu->from_env)
+ return -EINVAL;
return 0;
}
@@ -657,11 +659,17 @@ static uint64_t drm_pmu__read_for_pid(struct drm_pmu *drm, struct evsel *evsel,
int evsel__drm_pmu_read(struct evsel *evsel, int cpu_map_idx, int thread)
{
- struct drm_pmu *drm = container_of(evsel->pmu, struct drm_pmu, pmu);
+ struct drm_pmu *drm;
struct perf_counts_values *count, *old_count = NULL;
- int pid = perf_thread_map__pid(evsel->core.threads, thread);
+ int pid;
uint64_t counter;
+ if (!evsel->pmu || evsel->pmu->from_env)
+ return -EINVAL;
+
+ drm = container_of(evsel->pmu, struct drm_pmu, pmu);
+ pid = perf_thread_map__pid(evsel->core.threads, thread);
+
if (pid != -1)
counter = drm_pmu__read_for_pid(drm, evsel, pid);
else
diff --git a/tools/perf/util/hwmon_pmu.c b/tools/perf/util/hwmon_pmu.c
index 96aeb379e169..1526afa37e87 100644
--- a/tools/perf/util/hwmon_pmu.c
+++ b/tools/perf/util/hwmon_pmu.c
@@ -365,7 +365,7 @@ struct perf_pmu *hwmon_pmu__new(struct list_head *pmus, const char *hwmon_dir,
if (!hwm)
return NULL;
- if (perf_pmu__init(&hwm->pmu, type, buf) != 0) {
+ if (perf_pmu__init(&hwm->pmu, type, buf, /*from_env=*/false) != 0) {
perf_pmu__delete(&hwm->pmu);
return NULL;
}
@@ -763,12 +763,18 @@ int evsel__hwmon_pmu_open(struct evsel *evsel,
struct perf_thread_map *threads,
int start_cpu_map_idx, int end_cpu_map_idx)
{
- struct hwmon_pmu *hwm = container_of(evsel->pmu, struct hwmon_pmu, pmu);
+ struct hwmon_pmu *hwm;
union hwmon_pmu_event_key key = {
.type_and_num = evsel->core.attr.config,
};
int idx = 0, thread = 0, nthreads, err = 0;
- int dir = open(hwm->hwmon_dir, O_CLOEXEC | O_DIRECTORY | O_RDONLY);
+ int dir;
+
+ if (!evsel->pmu || evsel->pmu->from_env)
+ return -EINVAL;
+
+ hwm = container_of(evsel->pmu, struct hwmon_pmu, pmu);
+ dir = open(hwm->hwmon_dir, O_CLOEXEC | O_DIRECTORY | O_RDONLY);
if (dir < 0)
return -errno;
@@ -815,6 +821,10 @@ int evsel__hwmon_pmu_read(struct evsel *evsel, int cpu_map_idx, int thread)
ssize_t len;
struct perf_counts_values *count, *old_count = NULL;
+ /* PMUs reconstructed from a perf.data file can't be read. */
+ if (!evsel->pmu || evsel->pmu->from_env)
+ return -EINVAL;
+
if (evsel->prev_raw_counts)
old_count = perf_counts(evsel->prev_raw_counts, cpu_map_idx, thread);
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 01753d5c69d1..531641e66ef4 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1188,9 +1188,10 @@ static bool aliases__equal(long key1, long key2, void *ctx __maybe_unused)
return strcasecmp((const char *)key1, (const char *)key2) == 0;
}
-int perf_pmu__init(struct perf_pmu *pmu, __u32 type, const char *name)
+int perf_pmu__init(struct perf_pmu *pmu, __u32 type, const char *name, bool from_env)
{
pmu->type = type;
+ pmu->from_env = from_env;
INIT_LIST_HEAD(&pmu->format);
INIT_LIST_HEAD(&pmu->caps);
@@ -1240,7 +1241,7 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char
if (!pmu)
return NULL;
- if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, name) != 0) {
+ if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, name, /*from_env=*/false) != 0) {
perf_pmu__delete(pmu);
return NULL;
}
@@ -1695,9 +1696,9 @@ int perf_pmu__config_terms(const struct perf_pmu *pmu,
struct parse_events_term *term;
if (perf_pmu__is_hwmon(pmu))
- return hwmon_pmu__config_terms(pmu, attr, terms, err);
+ return pmu->from_env ? -EINVAL : hwmon_pmu__config_terms(pmu, attr, terms, err);
if (perf_pmu__is_drm(pmu))
- return drm_pmu__config_terms(pmu, attr, terms, err);
+ return pmu->from_env ? -EINVAL : drm_pmu__config_terms(pmu, attr, terms, err);
list_for_each_entry(term, &terms->terms, list) {
if (pmu_config_term(pmu, attr, term, terms, zero, apply_hardcoded, err))
@@ -1857,11 +1858,11 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_
info->retirement_latency_max = 0.0;
if (perf_pmu__is_hwmon(pmu)) {
- ret = hwmon_pmu__check_alias(head_terms, info, err);
+ ret = pmu->from_env ? 0 : hwmon_pmu__check_alias(head_terms, info, err);
goto out;
}
if (perf_pmu__is_drm(pmu)) {
- ret = drm_pmu__check_alias(pmu, head_terms, info, err);
+ ret = pmu->from_env ? 0 : drm_pmu__check_alias(pmu, head_terms, info, err);
goto out;
}
@@ -2118,11 +2119,11 @@ bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name)
if (perf_pmu__is_tool(pmu) && tool_pmu__skip_event(name))
return false;
if (perf_pmu__is_tracepoint(pmu))
- return tp_pmu__have_event(pmu, name);
+ return pmu->from_env ? false : tp_pmu__have_event(pmu, name);
if (perf_pmu__is_hwmon(pmu))
- return hwmon_pmu__have_event(pmu, name);
+ return pmu->from_env ? false : hwmon_pmu__have_event(pmu, name);
if (perf_pmu__is_drm(pmu))
- return drm_pmu__have_event(pmu, name);
+ return pmu->from_env ? false : drm_pmu__have_event(pmu, name);
if (perf_pmu__find_alias(pmu, name, /*load=*/ true) != NULL)
return true;
if (pmu->cpu_aliases_added || (!pmu->events_table && !pmu->is_core))
@@ -2139,11 +2140,11 @@ size_t perf_pmu__num_events(struct perf_pmu *pmu)
size_t nr;
if (perf_pmu__is_tracepoint(pmu))
- return tp_pmu__num_events(pmu);
+ return pmu->from_env ? 0 : tp_pmu__num_events(pmu);
if (perf_pmu__is_hwmon(pmu))
- return hwmon_pmu__num_events(pmu);
+ return pmu->from_env ? 0 : hwmon_pmu__num_events(pmu);
if (perf_pmu__is_drm(pmu))
- return drm_pmu__num_events(pmu);
+ return pmu->from_env ? 0 : drm_pmu__num_events(pmu);
pmu_aliases_parse(pmu);
nr = pmu->sysfs_aliases + pmu->sys_json_aliases;
@@ -2275,11 +2276,11 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
size_t size_rem;
if (perf_pmu__is_tracepoint(pmu))
- return tp_pmu__for_each_event(pmu, state, cb);
+ return pmu->from_env ? 0 : tp_pmu__for_each_event(pmu, state, cb);
if (perf_pmu__is_hwmon(pmu))
- return hwmon_pmu__for_each_event(pmu, state, cb);
+ return pmu->from_env ? 0 : hwmon_pmu__for_each_event(pmu, state, cb);
if (perf_pmu__is_drm(pmu))
- return drm_pmu__for_each_event(pmu, state, cb);
+ return pmu->from_env ? 0 : drm_pmu__for_each_event(pmu, state, cb);
pmu_aliases_parse(pmu);
pmu_add_cpu_aliases(pmu);
@@ -2784,10 +2785,12 @@ void perf_pmu__delete(struct perf_pmu *pmu)
if (!pmu)
return;
- if (perf_pmu__is_hwmon(pmu))
- hwmon_pmu__exit(pmu);
- else if (perf_pmu__is_drm(pmu))
- drm_pmu__exit(pmu);
+ if (!pmu->from_env) {
+ if (perf_pmu__is_hwmon(pmu))
+ hwmon_pmu__exit(pmu);
+ else if (perf_pmu__is_drm(pmu))
+ drm_pmu__exit(pmu);
+ }
perf_pmu__del_formats(&pmu->format);
perf_pmu__del_aliases(pmu);
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 2c8916ad073e..ea55882ce670 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -161,6 +161,8 @@ struct perf_pmu {
uint32_t cpu_common_json_aliases;
/** @sysfs_aliases_loaded: Are sysfs aliases loaded from disk? */
bool sysfs_aliases_loaded;
+ /** @from_env: Was the PMU reconstructed from a perf_env header? */
+ bool from_env;
/**
* @cpu_aliases_added: Have all json events table entries for the PMU
* been added?
@@ -345,7 +347,16 @@ int perf_pmu__pathname_scnprintf(char *buf, size_t size,
int perf_pmu__event_source_devices_fd(void);
int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename, int flags);
-int perf_pmu__init(struct perf_pmu *pmu, __u32 type, const char *name);
+/**
+ * perf_pmu__init() - Initialize a pre-allocated struct perf_pmu.
+ * @pmu: The PMU structure to initialize.
+ * @type: The PMU type identifier (PERF_TYPE_* or dynamic sysfs type).
+ * @name: The PMU name string (copied via strdup).
+ * @from_env: True if reconstructed from a perf_env header rather than live sysfs.
+ *
+ * Return: 0 on success, -ENOMEM if duplicating @name fails.
+ */
+int perf_pmu__init(struct perf_pmu *pmu, __u32 type, const char *name, bool from_env);
struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *lookup_name,
bool eager_load);
struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pmus);
diff --git a/tools/perf/util/tool_pmu.c b/tools/perf/util/tool_pmu.c
index d2f7591747d9..6054d5d5aece 100644
--- a/tools/perf/util/tool_pmu.c
+++ b/tools/perf/util/tool_pmu.c
@@ -714,7 +714,7 @@ struct perf_pmu *tool_pmu__new(void)
if (!tool)
return NULL;
- if (perf_pmu__init(tool, PERF_PMU_TYPE_TOOL, "tool") != 0) {
+ if (perf_pmu__init(tool, PERF_PMU_TYPE_TOOL, "tool", /*from_env=*/false) != 0) {
perf_pmu__delete(tool);
return NULL;
}
--
2.56.1.703.gf848ed807c-goog
next prev parent reply other threads:[~2026-11-13 19:53 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 19:53 [PATCH v2 00/30] perf: Per-env PMUs, metric event sharing, and recorded event metrics Ian Rogers
2026-11-13 19:53 ` [PATCH v2 01/30] perf pmus: Don't skip core PMUs as duplicates Ian Rogers
2026-11-13 20:04 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 02/30] perf script: Fix metrics computed from samples Ian Rogers
2026-11-13 20:05 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 03/30] perf script: Don't drop metric samples for CPUs missing from the evsel Ian Rogers
2026-11-13 20:02 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 04/30] perf metricgroup: Don't prefer tool events for displaying a metric Ian Rogers
2026-11-13 19:59 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 05/30] perf env: Make lazy perf_env initialization thread-safe Ian Rogers
2026-11-13 20:05 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 06/30] perf env: Add host_env() singleton Ian Rogers
2026-11-13 20:47 ` sashiko-bot
2026-11-13 19:53 ` Ian Rogers [this message]
2026-11-13 20:10 ` [PATCH v2 07/30] perf pmu: Add from_env parameter to perf_pmu__init() sashiko-bot
2026-11-13 19:53 ` [PATCH v2 08/30] perf pmus: Introduce struct perf_pmus and perf_env__pmus() Ian Rogers
2026-11-13 20:36 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 09/30] perf pmus: Pass struct perf_pmus to find helpers Ian Rogers
2026-11-13 20:11 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 10/30] perf pmus: Pass struct perf_pmus to scan helpers Ian Rogers
2026-11-13 20:06 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 11/30] perf pmu-events: Add e_machine to struct pmu_events_map Ian Rogers
2026-11-13 20:12 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 12/30] perf pmu-events: Pass e_machine to find_core_*_table() Ian Rogers
2026-11-13 20:05 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 13/30] perf header: Pass e_machine to strcmp_cpuid_str() Ian Rogers
2026-11-13 20:01 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 14/30] perf header: Support CPUID matching across all architectures Ian Rogers
2026-11-13 20:05 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 15/30] perf test: Make the CPUID matching test architecture independent Ian Rogers
2026-11-13 20:02 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 16/30] perf test: Add CPUID matching tests for other architectures Ian Rogers
2026-11-13 20:03 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 17/30] perf dwarf-regs: Add e_machine__same_arch() Ian Rogers
2026-11-13 20:00 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 18/30] perf metricgroup: Pass struct perf_pmus to metricgroup__for_each_metric() Ian Rogers
2026-11-13 20:37 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 19/30] perf metricgroup: Move matching of metrics to recorded events from perf script Ian Rogers
2026-11-13 20:59 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 20/30] perf parse-events: Decode metric-id terms when adding events Ian Rogers
2026-11-13 20:33 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 21/30] perf evsel: Generalize metric_id to a set of metric_ids Ian Rogers
2026-11-13 20:31 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 22/30] perf pmu: Add perf_pmu__for_each_name_from_config() Ian Rogers
2026-11-13 20:13 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 23/30] perf metricgroup: Share metric events by their counter encoding Ian Rogers
2026-11-13 20:59 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 24/30] perf stat: Share events between metrics and command line events Ian Rogers
2026-11-13 20:14 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 25/30] perf pmus: Add perf_pmus__read_from_env() Ian Rogers
2026-11-13 21:05 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 26/30] perf metricgroup: Improve matching of metrics to recorded events Ian Rogers
2026-11-13 20:37 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 27/30] perf metricgroup: Add metricgroup__add_recorded_metrics() Ian Rogers
2026-11-13 20:42 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 28/30] perf stat report: Display metrics for recorded events Ian Rogers
2026-11-13 20:44 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 29/30] perf script: Display metrics for perf stat record data Ian Rogers
2026-11-13 20:47 ` sashiko-bot
2026-11-13 19:53 ` [PATCH v2 30/30] perf test: Add stat record metrics test Ian Rogers
2026-11-13 20:14 ` 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=20261113195335.2865725-8-irogers@google.com \
--to=irogers@google.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--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 \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.