mirror of https://lore.kernel.org/lkml/
 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 13/41] perf pmus: Add perf_pmus__read_from_env()
Date: Tue,  3 Nov 2026 15:44:29 -0800	[thread overview]
Message-ID: <20261103234502.1008382-14-irogers@google.com> (raw)
In-Reply-To: <20261103234502.1008382-1-irogers@google.com>

Add perf_pmus__read_from_env() and perf_pmu__add_cap() to reconstruct
core_pmus and other_pmus lists and their capabilities in a
struct perf_pmus from HEADER_PMU_MAPPINGS, HEADER_HYBRID_TOPOLOGY,
HEADER_PMU_CAPS, and HEADER_CPU_PMU_CAPS in a perf.data header
environment, and lazily populate env->pmus in perf_env__pmus(). An
environment without any PMU header metadata, such as one used while
recording, falls back to the live host's PMUs rather than re-reading
sysfs into its own copy.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/util/env.c    |  18 ++++
 tools/perf/util/env.h    |   5 +
 tools/perf/util/header.c |  22 ++++
 tools/perf/util/pmu.c    |  31 ++++++
 tools/perf/util/pmu.h    |   9 ++
 tools/perf/util/pmus.c   | 219 +++++++++++++++++++++++++++++++++++++++
 tools/perf/util/pmus.h   |  15 ++-
 7 files changed, 318 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index fec6a5a8ecb6..04f4db90cc60 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -341,6 +341,24 @@ struct perf_env *host_env(void)
 
 struct perf_pmus *perf_env__pmus(struct perf_env *env)
 {
+	struct perf_env *host = host_env();
+
+	if (env == host ||
+	    !(env->nr_pmu_mappings || env->nr_hybrid_nodes ||
+	      env->nr_cpu_pmu_caps || env->nr_pmus_with_caps)) {
+		/* No PMU metadata of its own, use the live host's PMUs. */
+		return &host->pmus;
+	}
+
+	mutex_lock(&env->lock);
+	if (!env->pmus.core_pmus.next || !env->pmus.other_pmus.next)
+		perf_pmus__init(&env->pmus);
+	mutex_unlock(&env->lock);
+
+	mutex_lock(&env->pmus.lock);
+	if (env->pmus.read_pmu_types == 0)
+		perf_pmus__read_from_env(&env->pmus, env);
+	mutex_unlock(&env->pmus.lock);
 	return &env->pmus;
 }
 
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index e38e953060c9..ef583161583f 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -238,6 +238,11 @@ struct perf_env *host_env(void);
  * perf_env__pmus() - Return the struct perf_pmus associated with @env.
  * @env: Environment whose PMU collection to retrieve.
  *
+ * For non-host environments with PMU header metadata (HEADER_PMU_MAPPINGS,
+ * HEADER_HYBRID_TOPOLOGY, HEADER_CPU_PMU_CAPS or HEADER_PMU_CAPS), lazily
+ * populates @env->pmus from the perf.data header on first access. If @env has
+ * no PMU metadata of its own, falls back to the live host's PMU collection.
+ *
  * Return: Pointer to the struct perf_pmus for @env.
  */
 struct perf_pmus *perf_env__pmus(struct perf_env *env);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index a442f2a904a9..27fc21fa3a6a 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -5765,6 +5765,28 @@ int perf_event__process_feature(const struct perf_tool *tool __maybe_unused,
 		goto out;
 	}
 
+	switch (feat) {
+	case HEADER_ARCH:
+	case HEADER_CPUID:
+	case HEADER_NRCPUS:
+	case HEADER_PMU_MAPPINGS:
+	case HEADER_CPU_PMU_CAPS:
+	case HEADER_HYBRID_TOPOLOGY:
+	case HEADER_PMU_CAPS:
+		mutex_lock(&header->env.pmus.lock);
+		if (session->evlist) {
+			struct evsel *evsel;
+
+			evlist__for_each_entry(session->evlist, evsel)
+				evsel->pmu = NULL;
+		}
+		perf_pmus__exit(&header->env.pmus);
+		mutex_unlock(&header->env.pmus.lock);
+		break;
+	default:
+		break;
+	}
+
 	if (session->tool->show_feat_hdr) {
 		if (!feat_ops[feat].full_only ||
 		    session->tool->show_feat_hdr >= SHOW_FEAT_HEADER_FULL_INFO) {
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 06c4912d2f65..ee52fd18c927 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -2570,6 +2570,37 @@ static int perf_pmu__new_caps(struct list_head *list, char *name, char *value)
 	return -ENOMEM;
 }
 
+int perf_pmu__add_cap(struct perf_pmu *pmu, const char *name, const char *value)
+{
+	struct perf_pmu_caps *caps;
+
+	if (!pmu || !name || !value)
+		return -EINVAL;
+	if (perf_pmu__get_cap(pmu, name))
+		return 0;
+
+	caps = zalloc(sizeof(*caps));
+	if (!caps)
+		return -ENOMEM;
+
+	caps->name = strdup(name);
+	if (!caps->name) {
+		free(caps);
+		return -ENOMEM;
+	}
+	caps->value = strdup(value);
+	if (!caps->value) {
+		zfree(&caps->name);
+		free(caps);
+		return -ENOMEM;
+	}
+	list_add_tail(&caps->list, &pmu->caps);
+	pmu->nr_caps++;
+	if (!strcmp(name, "max_precise"))
+		pmu->max_precise = atoi(value);
+	return 0;
+}
+
 static void perf_pmu__del_caps(struct perf_pmu *pmu)
 {
 	struct perf_pmu_caps *caps, *tmp;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 7605c3859337..06f922ce1f68 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -334,6 +334,15 @@ bool pmu_uncore_identifier_match(const char *compat, const char *id);
 int perf_pmu__convert_scale(const char *scale, char **end, double *sval);
 
 struct perf_pmu_caps *perf_pmu__get_cap(struct perf_pmu *pmu, const char *name);
+/**
+ * perf_pmu__add_cap() - Add a name/value capability entry to @pmu->caps.
+ * @pmu: The PMU to add the capability to.
+ * @name: Capability name.
+ * @value: Capability value string.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int perf_pmu__add_cap(struct perf_pmu *pmu, const char *name, const char *value);
 
 int perf_pmu__caps_parse(struct perf_pmu *pmu);
 
diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c
index c3a695ebf2ba..908959abbd3d 100644
--- a/tools/perf/util/pmus.c
+++ b/tools/perf/util/pmus.c
@@ -7,7 +7,9 @@
 #include <subcmd/pager.h>
 #include <sys/types.h>
 #include <ctype.h>
+#include <errno.h>
 #include <pthread.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -980,3 +982,220 @@ struct perf_pmu *perf_pmus__fake_pmu(void)
 
 	return &fake;
 }
+
+/*
+ * Determine whether a PMU name reconstructed from perf.data headers is a
+ * core PMU, checking common core PMU prefixes, hybrid topology nodes, and
+ * the host architecture's is_pmu_core() when architectures match.
+ */
+static bool env_is_pmu_core(const char *name, struct perf_env *env)
+{
+	if (!strcmp(name, "cpu") || !strcmp(name, "cpum_cf") ||
+	    !strcmp(name, "default_core") || !strcmp(name, "arc_pct") ||
+	    strstarts(name, "cpu_") || strstarts(name, "armv") ||
+	    (strstarts(name, "apple_") && strstr(name, "_pmu")))
+		return true;
+
+	if (env && env->hybrid_nodes) {
+		for (int i = 0; i < env->nr_hybrid_nodes; i++) {
+			const char *pmu_name = env->hybrid_nodes[i].pmu_name;
+
+			if (pmu_name && !strcmp(name, pmu_name))
+				return true;
+		}
+		return false;
+	}
+
+	if (!env || !strcmp(perf_env__arch(env), perf_env__arch(host_env())))
+		return is_pmu_core(name);
+
+	return false;
+}
+
+/*
+ * Look up @name in @pmus or allocate and initialize a new perf_env-backed
+ * struct perf_pmu, upgrading PERF_PMU_TYPE_FAKE if a real type is later
+ * discovered.
+ */
+static struct perf_pmu *env_pmu_find_or_add(struct perf_pmus *pmus,
+					    const char *name, __u32 type,
+					    struct perf_env *env,
+					    const struct pmu_events_table *core_table)
+{
+	struct perf_pmu *pmu = pmu_find(pmus, name);
+
+	if (pmu) {
+		if (pmu->type == PERF_PMU_TYPE_FAKE && type != PERF_PMU_TYPE_FAKE) {
+			pmu->type = type;
+			pmu->is_uncore = !pmu->is_core && !pmu->auxtrace &&
+					 !perf_pmu__is_software(pmu) &&
+					 perf_pmu__kind(pmu) == PERF_PMU_KIND_PE;
+			if (!pmu->is_core && !pmu->is_uncore &&
+			    pmu->events_table == core_table)
+				pmu->events_table = NULL;
+		}
+		return pmu;
+	}
+
+	pmu = zalloc(sizeof(*pmu));
+	if (!pmu)
+		return NULL;
+
+	if (perf_pmu__init(pmu, type, name, /*from_env=*/true) != 0) {
+		perf_pmu__delete(pmu);
+		return NULL;
+	}
+
+	pmu->pmus = pmus;
+	pmu->sysfs_aliases_loaded = true;
+	pmu->caps_initialized = true;
+	pmu->max_precise = -1;
+	pmu->is_core = env_is_pmu_core(name, env);
+	pmu->auxtrace = !strcmp(name, "intel_pt") ||
+			!strcmp(name, "intel_bts") ||
+			!strcmp(name, "cs_etm") ||
+			strstarts(name, "arm_spe") ||
+			strstarts(name, "hisi_ptt");
+	pmu->is_uncore = !pmu->is_core && !pmu->auxtrace &&
+			 !perf_pmu__is_software(pmu) &&
+			 (perf_pmu__kind(pmu) == PERF_PMU_KIND_PE ||
+			  pmu->type == PERF_PMU_TYPE_FAKE);
+
+	if (!strcmp(name, "software") || !strcmp(name, "tool"))
+		pmu->events_table = perf_pmu__default_core_events_table();
+	else if (core_table && (pmu->is_core || pmu->is_uncore))
+		pmu->events_table = core_table;
+
+	list_add_tail(&pmu->list, pmu->is_core ? &pmus->core_pmus : &pmus->other_pmus);
+	return pmu;
+}
+
+/* Parse "key=value" capability strings from perf_env into @pmu->caps. */
+static void env_pmu_add_caps_strings(struct perf_pmu *pmu, int nr_caps, char **caps)
+{
+	if (!pmu || nr_caps <= 0 || !caps)
+		return;
+
+	for (int i = 0; i < nr_caps; i++) {
+		const char *eq;
+
+		if (!caps[i])
+			continue;
+		eq = strchr(caps[i], '=');
+
+		if (eq) {
+			char *key = strndup(caps[i], eq - caps[i]);
+
+			if (key) {
+				perf_pmu__add_cap(pmu, key, eq + 1);
+				free(key);
+			}
+		} else {
+			perf_pmu__add_cap(pmu, caps[i], "");
+		}
+	}
+}
+
+int perf_pmus__read_from_env(struct perf_pmus *pmus, struct perf_env *env)
+{
+	const struct pmu_events_table *core_table = NULL;
+	struct perf_pmu *pmu;
+
+	if (!pmus || !env)
+		return -EINVAL;
+
+	perf_pmus__exit(pmus);
+	pmus->read_pmu_types = PERF_TOOL_PMU_TYPE_ALL_MASK;
+
+	if (env->cpuid)
+		core_table = find_core_events_table(perf_env__e_machine(env, /*e_flags=*/NULL),
+						    env->cpuid);
+
+	/* 1. Populate from HEADER_PMU_MAPPINGS */
+	if (env->nr_pmu_mappings > 0 && env->pmu_mappings) {
+		char *str = env->pmu_mappings;
+
+		for (int i = 0; i < env->nr_pmu_mappings; i++) {
+			char *colon = NULL;
+			unsigned long type = strtoul(str, &colon, 0);
+
+			if (!colon || *colon != ':')
+				break;
+			str = colon + 1;
+			env_pmu_find_or_add(pmus, str, (__u32)type, env, core_table);
+			str += strlen(str) + 1;
+		}
+	}
+
+	/* 2. Populate/enrich from HEADER_HYBRID_TOPOLOGY */
+	for (int i = 0; i < env->nr_hybrid_nodes; i++) {
+		struct hybrid_node *hn = &env->hybrid_nodes[i];
+
+		if (!hn->pmu_name)
+			continue;
+		pmu = env_pmu_find_or_add(pmus, hn->pmu_name, PERF_PMU_TYPE_FAKE,
+					  env, core_table);
+		if (!pmu)
+			continue;
+		if (!pmu->is_core) {
+			pmu->is_core = true;
+			if (!pmu->events_table && core_table)
+				pmu->events_table = core_table;
+			list_move_tail(&pmu->list, &pmus->core_pmus);
+		}
+		if (hn->cpus && !pmu->cpus)
+			pmu->cpus = perf_cpu_map__new(hn->cpus);
+	}
+
+	/* 3. Populate/enrich from HEADER_PMU_CAPS */
+	for (int i = 0; i < env->nr_pmus_with_caps; i++) {
+		struct pmu_caps *pc = &env->pmu_caps[i];
+
+		if (!pc->pmu_name)
+			continue;
+		pmu = env_pmu_find_or_add(pmus, pc->pmu_name, PERF_PMU_TYPE_FAKE,
+					  env, core_table);
+		if (pmu)
+			env_pmu_add_caps_strings(pmu, pc->nr_caps, pc->caps);
+	}
+
+	/*
+	 * 4. Populate/enrich from HEADER_CPU_PMU_CAPS.
+	 * HEADER_CPU_PMU_CAPS holds the capabilities of the first core PMU,
+	 * named "cpu" on x86 but e.g. "armv8_pmuv3_0" or "cpum_cf" elsewhere.
+	 * On hybrid systems it duplicates the first core PMU's entry in
+	 * HEADER_PMU_CAPS. Attach the capabilities to "cpu" if present,
+	 * otherwise to the first core PMU when it has no capabilities yet,
+	 * creating a "cpu" PMU only if no core PMUs exist.
+	 */
+	if (env->nr_cpu_pmu_caps > 0 && env->cpu_pmu_caps) {
+		pmu = pmu_find(pmus, "cpu");
+		if (!pmu && !list_empty(&pmus->core_pmus)) {
+			/* Match the writer's perf_pmus__find_core_pmu() order. */
+			list_sort(NULL, &pmus->core_pmus, pmus_cmp);
+			pmu = list_first_entry(&pmus->core_pmus, struct perf_pmu, list);
+			if (pmu->nr_caps > 0)
+				pmu = NULL;
+		} else if (!pmu) {
+			pmu = env_pmu_find_or_add(pmus, "cpu", PERF_TYPE_RAW,
+						  env, core_table);
+		}
+		if (pmu)
+			env_pmu_add_caps_strings(pmu, env->nr_cpu_pmu_caps, env->cpu_pmu_caps);
+	}
+
+	/* 5. Set default core CPUs on non-hybrid systems */
+	if (env->nr_cpus_avail > 0 && env->nr_hybrid_nodes == 0) {
+		char buf[64];
+
+		snprintf(buf, sizeof(buf), "0-%d", env->nr_cpus_avail - 1);
+		list_for_each_entry(pmu, &pmus->core_pmus, list) {
+			if (!pmu->cpus)
+				pmu->cpus = perf_cpu_map__new(buf);
+		}
+	}
+
+	list_sort(NULL, &pmus->core_pmus, pmus_cmp);
+	list_sort(NULL, &pmus->other_pmus, pmus_cmp);
+	return 0;
+}
diff --git a/tools/perf/util/pmus.h b/tools/perf/util/pmus.h
index 6e7c9f857aaf..2b784cf648f3 100644
--- a/tools/perf/util/pmus.h
+++ b/tools/perf/util/pmus.h
@@ -8,6 +8,7 @@
 #include "mutex.h"
 
 struct perf_event_attr;
+struct perf_env;
 struct perf_pmu;
 struct print_callbacks;
 
@@ -49,7 +50,10 @@ struct perf_pmus {
 	 * encoding in perf_event_attr::config is supported.
 	 */
 	enum perf_pmus_extended_type extended_type;
-	/** @lock: Protects lazy initialization of @extended_type. */
+	/**
+	 * @lock: Protects lazy initialization of @extended_type and
+	 * perf_pmus__read_from_env().
+	 */
 	struct mutex lock;
 };
 
@@ -75,6 +79,15 @@ void perf_pmus__init(struct perf_pmus *pmus);
  */
 void perf_pmus__exit(struct perf_pmus *pmus);
 
+/**
+ * perf_pmus__read_from_env() - Populate @pmus from perf.data header metadata.
+ * @pmus: The PMU collection to populate.
+ * @env: The perf_env containing header PMU mappings, hybrid topology, and caps.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int perf_pmus__read_from_env(struct perf_pmus *pmus, struct perf_env *env);
+
 /**
  * perf_pmus__find() - Find a PMU by name in @pmus.
  * @pmus: The PMU collection to search.
-- 
2.56.0.385.gac671c819a-goog


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

Thread overview: 42+ 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:44 ` [PATCH v1 02/41] perf env: Add host_env() singleton Ian Rogers
2026-11-03 23:44 ` [PATCH v1 03/41] perf pmu: Add from_env parameter to perf_pmu__init() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 04/41] perf pmus: Introduce struct perf_pmus and perf_env__pmus() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 05/41] perf pmus: Pass struct perf_pmus to find helpers Ian Rogers
2026-11-03 23:44 ` [PATCH v1 06/41] perf pmus: Pass struct perf_pmus to scan helpers Ian Rogers
2026-11-03 23:44 ` [PATCH v1 07/41] perf pmu-events: Add e_machine to struct pmu_events_map Ian Rogers
2026-11-03 23:44 ` [PATCH v1 08/41] perf pmu-events: Pass e_machine to find_core_*_table() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 09/41] perf header: Pass e_machine to strcmp_cpuid_str() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 10/41] perf header: Support CPUID matching across all architectures Ian Rogers
2026-11-03 23:44 ` [PATCH v1 11/41] perf test: Make the CPUID matching test architecture independent Ian Rogers
2026-11-03 23:44 ` [PATCH v1 12/41] perf test: Add CPUID matching tests for other architectures Ian Rogers
2026-11-03 23:44 ` Ian Rogers [this message]
2026-11-03 23:44 ` [PATCH v1 14/41] perf metricgroup: Pass struct perf_pmus to metricgroup__for_each_metric() Ian Rogers
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-03 23:44 ` [PATCH v1 16/41] perf parse-events: Decode metric-id terms when adding events Ian Rogers
2026-11-03 23:44 ` [PATCH v1 17/41] perf evsel: Generalize metric_id to a set of metric_ids Ian Rogers
2026-11-03 23:44 ` [PATCH v1 18/41] perf pmu: Add perf_pmu__for_each_name_from_config() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 19/41] perf metricgroup: Improve matching of metrics to recorded events Ian Rogers
2026-11-03 23:44 ` [PATCH v1 20/41] perf metricgroup: Add metricgroup__add_recorded_metrics() Ian Rogers
2026-11-03 23:44 ` [PATCH v1 21/41] perf script: Fix metrics computed from samples Ian Rogers
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-03 23:44 ` [PATCH v1 23/41] perf stat report: Display metrics for recorded events Ian Rogers
2026-11-03 23:44 ` [PATCH v1 24/41] perf script: Display metrics for perf stat record data Ian Rogers
2026-11-03 23:44 ` [PATCH v1 25/41] perf test: Add stat record metrics test Ian Rogers
2026-11-03 23:44 ` [PATCH v1 26/41] perf pmus: Expose duplicate uncore PMU scanning helpers Ian Rogers
2026-11-03 23:44 ` [PATCH v1 27/41] perf mem-events: Expose PMU init and name formatting helpers Ian Rogers
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-03 23:44 ` [PATCH v1 29/41] perf pmu: Probe supported sample_type flags Ian Rogers
2026-11-03 23:44 ` [PATCH v1 30/41] perf pmu: Probe precise_ip levels Ian Rogers
2026-11-03 23:44 ` [PATCH v1 31/41] perf pmu: Probe privilege exclusion modifiers Ian Rogers
2026-11-03 23:44 ` [PATCH v1 32/41] perf pmu: Probe execution and AUX area features Ian Rogers
2026-11-03 23:44 ` [PATCH v1 33/41] perf pmu: Probe event group size limits Ian Rogers
2026-11-03 23:44 ` [PATCH v1 34/41] perf pmu: Probe user and interrupt sample register masks Ian Rogers
2026-11-03 23:44 ` [PATCH v1 35/41] perf pmu: Probe interrupt registers that require precise sampling Ian Rogers
2026-11-03 23:44 ` [PATCH v1 36/41] perf pmu: Probe memory profiling events and sample formats Ian Rogers
2026-11-03 23:44 ` [PATCH v1 37/41] perf pmu: Probe user-space mmap capabilities Ian Rogers
2026-11-03 23:44 ` [PATCH v1 38/41] perf pmu: Probe branch instruction skid Ian Rogers
2026-11-03 23:44 ` [PATCH v1 39/41] perf sysinfo: Add sysinfo subcommand Ian Rogers
2026-11-03 23:44 ` [PATCH v1 40/41] perf docs: Add perf-sysinfo man page Ian Rogers
2026-11-03 23:44 ` [PATCH v1 41/41] perf test: Add perf sysinfo shell test Ian Rogers

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-14-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

all inboxes | Powered by JetHome®