mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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>
Cc: Jiri Olsa <jolsa@kernel.org>,
	Adrian Hunter <adrian.hunter@intel.com>,
	 James Clark <james.clark@linaro.org>,
	linux-perf-users@vger.kernel.org,  linux-kernel@vger.kernel.org,
	Ian Rogers <irogers@google.com>
Subject: [PATCH 06/11] perf pmu: Switch alias resolution and enumeration to layered PMU stack
Date: Fri, 13 Nov 2026 13:10:57 -0800	[thread overview]
Message-ID: <20261113211105.3118281-7-irogers@google.com> (raw)
In-Reply-To: <20261113211105.3118281-1-irogers@google.com>

Route perf_pmu__find_alias(), pmu_find_alias(),
perf_pmu__have_event(), perf_pmu__num_events(),
perf_pmu__for_each_event(), and perf_pmu__name_from_config() through
pmu_layer__find_event() and pmu_layer__load_events().

This replaces the inverted EVENT_SRC_SYSFS + update_alias() in-place
mutation pipeline with uniform top-down attribute merging across the
four-tier stack:

  1. pmu-events.dir user/system overlay directories (when configured)
  2. Compiled-in CPUID and system/SoC JSON tables (PMU_LAYER_BUILTIN_CPU)
  3. Kernel sysfs /sys/bus/event_source/devices/<pmu>/ (PMU_LAYER_SYSFS)
  4. Compiled-in cross-CPU common JSON tables (PMU_LAYER_BUILTIN_COMMON)

Keeping compiled-in CPUID/sys JSON ahead of kernel sysfs and kernel
sysfs ahead of common fallback JSON matches existing upstream perf
precedence (for example, per-CPU JSON enriches or overrides same-named
sysfs events while sysfs events take priority over arch/common
fallbacks), and preserves single-event lazy openat() sysfs lookups
without full readdir().

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/util/pmu.c | 665 ++----------------------------------------
 tools/perf/util/pmu.h |  11 -
 2 files changed, 32 insertions(+), 644 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 685c61935f50..a3e1630c5a84 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -44,20 +44,6 @@
 #include "util/evsel_config.h"
 #include <regex.h>
 
-enum event_source {
-	/* An event loaded from /sys/bus/event_source/devices/<pmu>/events. */
-	EVENT_SRC_SYSFS,
-	/* An event loaded from a CPUID matched json file. */
-	EVENT_SRC_CPU_JSON,
-	/*
-	 * An event loaded from a /sys/bus/event_source/devices/<pmu>/identifier matched json
-	 * file.
-	 */
-	EVENT_SRC_SYS_JSON,
-};
-
-static int pmu_aliases_parse(struct perf_pmu *pmu);
-
 static struct perf_pmu_format *perf_pmu__new_format(struct list_head *list, char *name)
 {
 	struct perf_pmu_format *format;
@@ -269,11 +255,6 @@ enum pmu_event_file_kind pmu_event_file_kind(const char *name, size_t *base_len)
 	return PMU_EVENT_FILE_BASE;
 }
 
-static inline bool pmu_alias_info_file(const char *name)
-{
-	return pmu_event_file_kind(name, NULL) != PMU_EVENT_FILE_BASE;
-}
-
 static const struct {
 	const char *suffix;
 	size_t len;
@@ -310,120 +291,6 @@ enum pmu_metric_file_kind pmu_metric_file_kind(const char *name, size_t *base_le
 	return PMU_METRIC_FILE_BASE;
 }
 
-static int perf_pmu__parse_scale_at(int events_dir_fd, const char *event_name,
-				    struct perf_pmu_alias *alias)
-{
-	ssize_t sret;
-	char scale[128];
-	char filename[NAME_MAX + 16];
-	int fd, ret = -1;
-
-	scnprintf(filename, sizeof(filename), "%s.scale", event_name);
-	fd = openat(events_dir_fd, filename, O_RDONLY);
-	if (fd == -1)
-		return -1;
-
-	sret = read(fd, scale, sizeof(scale) - 1);
-	if (sret <= 0)
-		goto error;
-
-	if (scale[sret - 1] == '\n')
-		scale[sret - 1] = '\0';
-	else
-		scale[sret] = '\0';
-
-	ret = perf_pmu__convert_scale(scale, NULL, &alias->scale);
-	if (!ret)
-		alias->has_scale = true;
-error:
-	close(fd);
-	return ret;
-}
-
-static int perf_pmu__parse_unit_at(int events_dir_fd, const char *event_name,
-				   struct perf_pmu_alias *alias)
-{
-	char filename[NAME_MAX + 16];
-	ssize_t sret;
-	int fd;
-
-	scnprintf(filename, sizeof(filename), "%s.unit", event_name);
-	fd = openat(events_dir_fd, filename, O_RDONLY);
-	if (fd == -1)
-		return -1;
-
-	sret = read(fd, alias->unit, UNIT_MAX_LEN);
-	if (sret <= 0)
-		goto error;
-
-	close(fd);
-
-	if (alias->unit[sret - 1] == '\n')
-		alias->unit[sret - 1] = '\0';
-	else
-		alias->unit[sret] = '\0';
-
-	alias->has_unit = true;
-	return 0;
-error:
-	close(fd);
-	alias->unit[0] = '\0';
-	return -1;
-}
-
-static int perf_pmu__parse_bool_at(int events_dir_fd, const char *event_name,
-				   const char *suffix, bool *out_val)
-{
-	char filename[NAME_MAX + 32];
-	char buf[16];
-	ssize_t sret;
-	int fd;
-
-	scnprintf(filename, sizeof(filename), "%s.%s", event_name, suffix);
-	fd = openat(events_dir_fd, filename, O_RDONLY);
-	if (fd == -1)
-		return -ENOENT;
-
-	sret = read(fd, buf, sizeof(buf) - 1);
-	close(fd);
-	if (sret <= 0)
-		return -EINVAL;
-
-	while (sret > 0 && isspace(buf[sret - 1]))
-		sret--;
-	buf[sret] = '\0';
-
-	if (!strcmp(buf, "1") || !strcasecmp(buf, "true") || !strcasecmp(buf, "yes")) {
-		*out_val = true;
-		return 0;
-	}
-	if (!strcmp(buf, "0") || !strcasecmp(buf, "false") || !strcasecmp(buf, "no")) {
-		*out_val = false;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static void read_alias_info_at(int events_dir_fd, struct perf_pmu_alias *alias)
-{
-	bool val;
-
-	if (!alias->from_sysfs || alias->info_loaded || events_dir_fd < 0)
-		return;
-
-	perf_pmu__parse_unit_at(events_dir_fd, alias->name, alias);
-	perf_pmu__parse_scale_at(events_dir_fd, alias->name, alias);
-	if (perf_pmu__parse_bool_at(events_dir_fd, alias->name, "per-pkg", &val) == 0) {
-		alias->per_pkg = val;
-		alias->has_per_pkg = true;
-	}
-	if (perf_pmu__parse_bool_at(events_dir_fd, alias->name, "snapshot", &val) == 0) {
-		alias->snapshot = val;
-		alias->has_snapshot = true;
-	}
-	alias->info_loaded = true;
-}
-
 /* Delete an alias entry. */
 void perf_pmu_free_alias(struct perf_pmu_alias *alias)
 {
@@ -536,393 +403,22 @@ static void perf_pmu__del_metricgroups(struct perf_pmu *pmu)
 	pmu->metricgroups = NULL;
 }
 
-static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
-			       const char *desc, const char *val, int val_fd,
-			       const struct pmu_event *pe, enum event_source src,
-			       int events_dir_fd);
-
 static struct perf_pmu_alias *perf_pmu__find_alias(struct perf_pmu *pmu,
 						   const char *name,
 						   bool load)
 {
 	struct perf_pmu_alias *alias = NULL;
-	char path[PATH_MAX];
-	char lower_name[NAME_MAX];
-	char upper_name[NAME_MAX];
-	const char *candidates[3];
-	size_t nr_candidates = 0, name_len, path_len;
-	int events_dir_fd;
-
-	if (hashmap__find(pmu->aliases, name, &alias))
-		return alias;
-
-	if (!load || pmu->sysfs_aliases_loaded)
-		return NULL;
-
-	name_len = strlen(name);
-	if (name_len == 0 || name_len >= NAME_MAX || name[0] == '.' ||
-	    strchr(name, '/') || pmu_alias_info_file(name))
-		return NULL;
 
-	path_len = perf_pmu__event_source_devices_scnprintf(path, sizeof(path));
-	if (!path_len)
+	if (!pmu || !name)
 		return NULL;
-	scnprintf(path + path_len, sizeof(path) - path_len, "%s/events", pmu->name);
 
-	events_dir_fd = open(path, O_DIRECTORY | O_RDONLY);
-	if (events_dir_fd == -1) {
-		if (errno == ENOENT)
-			pmu->sysfs_aliases_loaded = true;
+	if (!load) {
+		if (hashmap__find(pmu->aliases, name, &alias))
+			return alias->terms ? alias : NULL;
 		return NULL;
 	}
 
-	candidates[nr_candidates++] = name;
-	for (size_t i = 0; i < name_len; i++) {
-		lower_name[i] = tolower((unsigned char)name[i]);
-		upper_name[i] = toupper((unsigned char)name[i]);
-	}
-	lower_name[name_len] = '\0';
-	upper_name[name_len] = '\0';
-
-	if (strcmp(lower_name, name) != 0)
-		candidates[nr_candidates++] = lower_name;
-	if (strcmp(upper_name, name) != 0 && strcmp(upper_name, lower_name) != 0)
-		candidates[nr_candidates++] = upper_name;
-
-	/*
-	 * Lazily open only the requested event and its sidecars via openat()
-	 * rather than scanning every file in sysfs/events/.
-	 */
-	for (size_t i = 0; i < nr_candidates; i++) {
-		struct stat st;
-		int fd = openat(events_dir_fd, candidates[i], O_RDONLY);
-
-		if (fd < 0)
-			continue;
-		if (fstat(fd, &st) == 0 && !S_ISDIR(st.st_mode)) {
-			if (perf_pmu__new_alias(pmu, candidates[i], /*desc=*/NULL,
-						/*val=*/NULL, fd, /*pe=*/NULL,
-						EVENT_SRC_SYSFS, events_dir_fd) == 0 &&
-			    hashmap__find(pmu->aliases, name, &alias)) {
-				read_alias_info_at(events_dir_fd, alias);
-				close(fd);
-				break;
-			}
-		}
-		close(fd);
-	}
-
-	close(events_dir_fd);
-	return alias;
-}
-
-static bool assign_str(const char *name, const char *field, char **old_str,
-				const char *new_str)
-{
-	if (!*old_str && new_str) {
-		*old_str = strdup(new_str);
-		return true;
-	}
-
-	if (!new_str || !strcasecmp(*old_str, new_str))
-		return false; /* Nothing to update. */
-
-	pr_debug("alias %s differs in field '%s' ('%s' != '%s')\n",
-		name, field, *old_str, new_str);
-	zfree(old_str);
-	*old_str = strdup(new_str);
-	return true;
-}
-
-static void read_alias_info(struct perf_pmu *pmu, struct perf_pmu_alias *alias)
-{
-	char path[PATH_MAX];
-	size_t len;
-	int events_dir_fd;
-
-	if (!alias->from_sysfs || alias->info_loaded)
-		return;
-
-	len = perf_pmu__event_source_devices_scnprintf(path, sizeof(path));
-	if (!len)
-		return;
-	scnprintf(path + len, sizeof(path) - len, "%s/events", pmu->name);
-
-	events_dir_fd = open(path, O_DIRECTORY | O_RDONLY);
-	if (events_dir_fd == -1)
-		return;
-
-	read_alias_info_at(events_dir_fd, alias);
-	close(events_dir_fd);
-}
-
-struct update_alias_data {
-	struct perf_pmu *pmu;
-	struct perf_pmu_alias *alias;
-	int events_dir_fd;
-	bool legacy;
-};
-
-static int update_alias(const struct pmu_event *pe,
-			const struct pmu_events_table *table __maybe_unused,
-			void *vdata)
-{
-	struct update_alias_data *data = vdata;
-	int ret = 0;
-
-	if (data->events_dir_fd >= 0)
-		read_alias_info_at(data->events_dir_fd, data->alias);
-	else
-		read_alias_info(data->pmu, data->alias);
-	assign_str(pe->name, "desc", &data->alias->desc, pe->desc);
-	assign_str(pe->name, "long_desc", &data->alias->long_desc, pe->long_desc);
-	assign_str(pe->name, "topic", &data->alias->topic, pe->topic);
-	data->alias->per_pkg = pe->perpkg;
-	if (pe->event) {
-		if (data->legacy) {
-			zfree(&data->alias->legacy_terms);
-			data->alias->legacy_terms = strdup(pe->event);
-		} else {
-			zfree(&data->alias->terms);
-			data->alias->terms = strdup(pe->event);
-		}
-	}
-	if (!ret && pe->unit) {
-		char *unit;
-
-		ret = perf_pmu__convert_scale(pe->unit, &unit, &data->alias->scale);
-		if (!ret)
-			snprintf(data->alias->unit, sizeof(data->alias->unit), "%s", unit);
-	}
-	if (!ret && pe->retirement_latency_mean) {
-		ret = parse_double(pe->retirement_latency_mean, NULL,
-					      &data->alias->retirement_latency_mean);
-	}
-	if (!ret && pe->retirement_latency_min) {
-		ret = parse_double(pe->retirement_latency_min, NULL,
-					      &data->alias->retirement_latency_min);
-	}
-	if (!ret && pe->retirement_latency_max) {
-		ret = parse_double(pe->retirement_latency_max, NULL,
-					      &data->alias->retirement_latency_max);
-	}
-	return ret;
-}
-
-static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
-			       const char *desc, const char *val, int val_fd,
-			       const struct pmu_event *pe, enum event_source src,
-			       int events_dir_fd)
-{
-	struct perf_pmu_alias *alias, *old_alias;
-	int ret = 0;
-	const char *long_desc = NULL, *topic = NULL, *unit = NULL, *pmu_name = NULL;
-	bool deprecated = false, perpkg = false;
-
-	if (perf_pmu__find_alias(pmu, name, /*load=*/ false)) {
-		/* Alias was already created/loaded. */
-		return 0;
-	}
-
-	if (pe) {
-		long_desc = pe->long_desc;
-		topic = pe->topic;
-		unit = pe->unit;
-		perpkg = pe->perpkg;
-		deprecated = pe->deprecated;
-		if (pe->pmu && strcmp(pe->pmu, "default_core"))
-			pmu_name = pe->pmu;
-	}
-
-	alias = zalloc(sizeof(*alias));
-	if (!alias)
-		return -ENOMEM;
-
-	alias->scale = 1.0;
-	alias->unit[0] = '\0';
-	alias->per_pkg = perpkg;
-	alias->snapshot = false;
-	alias->deprecated = deprecated;
-	alias->retirement_latency_mean = 0.0;
-	alias->retirement_latency_min = 0.0;
-	alias->retirement_latency_max = 0.0;
-
-	if (!ret && pe && pe->retirement_latency_mean) {
-		ret = parse_double(pe->retirement_latency_mean, NULL,
-				   &alias->retirement_latency_mean);
-	}
-	if (!ret && pe && pe->retirement_latency_min) {
-		ret = parse_double(pe->retirement_latency_min, NULL,
-				   &alias->retirement_latency_min);
-	}
-	if (!ret && pe && pe->retirement_latency_max) {
-		ret = parse_double(pe->retirement_latency_max, NULL,
-				   &alias->retirement_latency_max);
-	}
-	if (ret) {
-		perf_pmu_free_alias(alias);
-		return ret;
-	}
-
-	if (val_fd < 0) {
-		alias->terms = strdup(val);
-	} else {
-		char buf[256];
-		struct io io;
-		size_t line_len;
-
-		io__init(&io, val_fd, buf, sizeof(buf));
-		ret = io__getline(&io, &alias->terms, &line_len) < 0 ? -errno : 0;
-		if (ret) {
-			pr_err("Failed to read alias %s\n", name);
-			perf_pmu_free_alias(alias);
-			return ret;
-		}
-		if (line_len >= 1 && alias->terms[line_len - 1] == '\n')
-			alias->terms[line_len - 1] = '\0';
-	}
-	alias->name = strdup(name);
-	alias->desc = desc ? strdup(desc) : NULL;
-	alias->long_desc = long_desc ? strdup(long_desc) : NULL;
-	alias->topic = topic ? strdup(topic) : NULL;
-	alias->pmu_name = pmu_name ? strdup(pmu_name) : NULL;
-	alias->compat = (pe && pe->compat) ? strdup(pe->compat) : NULL;
-	if (unit) {
-		if (perf_pmu__convert_scale(unit, (char **)&unit, &alias->scale) < 0) {
-			perf_pmu_free_alias(alias);
-			return -1;
-		}
-		snprintf(alias->unit, sizeof(alias->unit), "%s", unit);
-	}
-	switch (src) {
-	default:
-	case EVENT_SRC_SYSFS:
-		alias->from_sysfs = true;
-		if (pmu->events_table || pmu->is_core) {
-			/* Update an event from sysfs with json data. */
-			struct update_alias_data data = {
-				.pmu = pmu,
-				.alias = alias,
-				.events_dir_fd = events_dir_fd,
-				.legacy = false,
-			};
-			if ((pmu_events_table__find_event(pmu->events_table, pmu, name,
-							  update_alias, &data) == 0)) {
-				/*
-				 * Override sysfs encodings with json encodings
-				 * specific to the cpuid.
-				 */
-				pmu->cpu_common_json_aliases++;
-			}
-			if (pmu->is_core) {
-				/* Add in legacy encodings. */
-				data.legacy = true;
-				if (pmu_events_table__find_event(
-						perf_pmu__default_core_events_table(),
-						pmu, name, update_alias, &data) == 0)
-					pmu->cpu_common_json_aliases++;
-			}
-		}
-		pmu->sysfs_aliases++;
-		break;
-	case  EVENT_SRC_CPU_JSON:
-		pmu->cpu_json_aliases++;
-		break;
-	case  EVENT_SRC_SYS_JSON:
-		pmu->sys_json_aliases++;
-		break;
-
-	}
-	hashmap__set(pmu->aliases, alias->name, alias, /*old_key=*/ NULL, &old_alias);
-	perf_pmu_free_alias(old_alias);
-	return 0;
-}
-
-/*
- * Reading the pmu event aliases definition, which should be located at:
- * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
- */
-static int __pmu_aliases_parse(struct perf_pmu *pmu, int events_dir_fd, bool eager_info)
-{
-	struct io_dirent64 *evt_ent;
-	struct io_dir event_dir;
-
-	io_dir__init(&event_dir, events_dir_fd);
-
-	while ((evt_ent = io_dir__readdir(&event_dir))) {
-		char *name = evt_ent->d_name;
-		int fd;
-
-		if (!strcmp(name, ".") || !strcmp(name, "..") || name[0] == '.')
-			continue;
-
-		/*
-		 * skip info files parsed in perf_pmu__new_alias()
-		 */
-		if (pmu_alias_info_file(name))
-			continue;
-
-		fd = openat(events_dir_fd, name, O_RDONLY);
-		if (fd == -1) {
-			pr_debug("Cannot open %s\n", name);
-			continue;
-		}
-
-		if (perf_pmu__new_alias(pmu, name, /*desc=*/ NULL,
-					/*val=*/ NULL, fd, /*pe=*/ NULL,
-					EVENT_SRC_SYSFS, events_dir_fd) < 0)
-			pr_debug("Cannot set up %s\n", name);
-		else if (eager_info) {
-			struct perf_pmu_alias *alias;
-
-			if (hashmap__find(pmu->aliases, name, &alias))
-				read_alias_info_at(events_dir_fd, alias);
-		}
-		close(fd);
-	}
-
-	pmu->sysfs_aliases_loaded = true;
-	return 0;
-}
-
-static int pmu_aliases_parse(struct perf_pmu *pmu)
-{
-	char path[PATH_MAX];
-	size_t len;
-	int events_dir_fd, ret;
-
-	if (pmu->sysfs_aliases_loaded)
-		return 0;
-
-	len = perf_pmu__event_source_devices_scnprintf(path, sizeof(path));
-	if (!len)
-		return 0;
-	scnprintf(path + len, sizeof(path) - len, "%s/events", pmu->name);
-
-	events_dir_fd = open(path, O_DIRECTORY);
-	if (events_dir_fd == -1) {
-		pmu->sysfs_aliases_loaded = true;
-		return 0;
-	}
-	ret = __pmu_aliases_parse(pmu, events_dir_fd, /*eager_info=*/false);
-	close(events_dir_fd);
-	return ret;
-}
-
-static int pmu_aliases_parse_eager(struct perf_pmu *pmu, int sysfs_fd)
-{
-	char path[NAME_MAX + 8];
-	int ret, events_dir_fd;
-
-	scnprintf(path, sizeof(path), "%s/events", pmu->name);
-	events_dir_fd = openat(sysfs_fd, path, O_DIRECTORY, 0);
-	if (events_dir_fd == -1) {
-		pmu->sysfs_aliases_loaded = true;
-		return 0;
-	}
-	ret = __pmu_aliases_parse(pmu, events_dir_fd, /*eager_info=*/true);
-	close(events_dir_fd);
-	return ret;
+	return pmu_layer__find_event(pmu, name);
 }
 
 static int pmu_alias_terms(struct perf_pmu_alias *alias, struct list_head *terms)
@@ -1205,78 +701,18 @@ bool pmu_uncore_identifier_match(const char *compat, const char *id)
 	return match;
 }
 
-static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
-					const struct pmu_events_table *table __maybe_unused,
-					void *vdata)
-{
-	struct perf_pmu *pmu = vdata;
-
-	perf_pmu__new_alias(pmu, pe->name, pe->desc, pe->event, /*val_fd=*/ -1,
-			    pe, EVENT_SRC_CPU_JSON, /*events_dir_fd=*/ -1);
-	return 0;
-}
-
 /*
  * From the pmu_events_table, find the events that correspond to the given
- * PMU and add them to the list 'head'.
+ * PMU and merge them into pmu->aliases.
  */
 void pmu_add_cpu_aliases_table(struct perf_pmu *pmu, const struct pmu_events_table *table)
 {
-	pmu_events_table__for_each_event(table, pmu, pmu_add_cpu_aliases_map_callback, pmu);
-}
-
-static void pmu_add_cpu_aliases(struct perf_pmu *pmu)
-{
-	if (!pmu->events_table && !pmu->is_core)
-		return;
-
-	if (pmu->cpu_aliases_added)
-		return;
-
-	pmu_add_cpu_aliases_table(pmu, pmu->events_table);
-	if (pmu->is_core)
-		pmu_add_cpu_aliases_table(pmu, perf_pmu__default_core_events_table());
-
-	pmu->cpu_aliases_added = true;
-}
-
-static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe,
-				       const struct pmu_events_table *table __maybe_unused,
-				       void *vdata)
-{
-	struct perf_pmu *pmu = vdata;
-
-	if (!pe->compat || !pe->pmu) {
-		/* No data to match. */
-		return 0;
-	}
-
-	if (!perf_pmu__match_wildcard_uncore(pmu->name, pe->pmu) &&
-	    !perf_pmu__match_wildcard_uncore(pmu->alias_name, pe->pmu)) {
-		/* PMU name/alias_name don't match. */
-		return 0;
-	}
-
-	if (pmu_uncore_identifier_match(pe->compat, pmu->id)) {
-		/* Id matched. */
-		perf_pmu__new_alias(pmu,
-				pe->name,
-				pe->desc,
-				pe->event,
-				/*val_fd=*/ -1,
-				pe,
-				EVENT_SRC_SYS_JSON,
-				/*events_dir_fd=*/ -1);
-	}
-	return 0;
+	pmu_layer__merge_event_table(pmu, table);
 }
 
 void pmu_add_sys_aliases(struct perf_pmu *pmu)
 {
-	if (!pmu->id)
-		return;
-
-	pmu_for_each_sys_event(pmu_add_sys_aliases_iter_fn, pmu);
+	pmu_layer__merge_sys_events(pmu);
 }
 
 static char *pmu_find_alias_name(struct perf_pmu *pmu, int dirfd)
@@ -1466,21 +902,12 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char
 	pmu->alias_name = pmu_find_alias_name(pmu, dirfd);
 	pmu->events_table = perf_pmu__find_events_table(pmu);
 	pmu->metrics_table = perf_pmu__lookup_metrics_table(pmu);
-	/*
-	 * Load the sys json events/aliases when loading the PMU as each event
-	 * may have a different compat regular expression. We therefore can't
-	 * know the number of sys json events/aliases without computing the
-	 * regular expressions for them all.
-	 */
-	pmu_add_sys_aliases(pmu);
 	list_add_tail(&pmu->list, pmus);
 
 	perf_pmu__arch_init(pmu);
 
-	if (eager_load) {
-		pmu_aliases_parse_eager(pmu, dirfd);
-		pmu->eager_sysfs_loaded = true;
-	}
+	if (eager_load)
+		pmu_layer__load_events_at(pmu, dirfd);
 
 	return pmu;
 }
@@ -1917,7 +1344,6 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
 static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
 					     struct parse_events_term *term)
 {
-	struct perf_pmu_alias *alias;
 	const char *name;
 
 	if (parse_events__is_hardcoded_term(term))
@@ -1938,32 +1364,16 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
 		return NULL;
 	}
 
-	alias = perf_pmu__find_alias(pmu, name, /*load=*/ true);
-	if (alias || pmu->cpu_aliases_added)
-		return alias;
-
-	/* Alias doesn't exist, try to get it from the json events. */
-	if ((pmu_events_table__find_event(pmu->events_table, pmu, name,
-					  pmu_add_cpu_aliases_map_callback,
-					  pmu) == 0) ||
-	    (pmu->is_core &&
-	     pmu_events_table__find_event(perf_pmu__default_core_events_table(),
-					  pmu, name,
-					  pmu_add_cpu_aliases_map_callback,
-					  pmu) == 0)) {
-		alias = perf_pmu__find_alias(pmu, name, /*load=*/ false);
-	}
-	return alias;
+	return perf_pmu__find_alias(pmu, name, /*load=*/true);
 }
 
 
-static int check_info_data(struct perf_pmu *pmu,
+static int check_info_data(struct perf_pmu *pmu __maybe_unused,
 			   struct perf_pmu_alias *alias,
 			   struct perf_pmu_info *info,
 			   struct parse_events_error *err,
 			   int column)
 {
-	read_alias_info(pmu, alias);
 	/*
 	 * Only one term in event definition can
 	 * define unit, scale and snapshot, fail
@@ -2311,20 +1721,13 @@ bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name)
 		return hwmon_pmu__have_event(pmu, name);
 	if (perf_pmu__is_drm(pmu))
 		return 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))
-		return false;
-	if (pmu_events_table__find_event(pmu->events_table, pmu, name, NULL, NULL) == 0)
-		return true;
-	return pmu->is_core &&
-		pmu_events_table__find_event(perf_pmu__default_core_events_table(),
-					     pmu, name, NULL, NULL) == 0;
+	return perf_pmu__find_alias(pmu, name, /*load=*/true) != NULL;
 }
 
 size_t perf_pmu__num_events(struct perf_pmu *pmu)
 {
-	size_t nr;
+	struct hashmap_entry *entry;
+	size_t bkt, nr = 0;
 
 	if (perf_pmu__is_tracepoint(pmu))
 		return tp_pmu__num_events(pmu);
@@ -2333,25 +1736,17 @@ size_t perf_pmu__num_events(struct perf_pmu *pmu)
 	if (perf_pmu__is_drm(pmu))
 		return drm_pmu__num_events(pmu);
 
-	pmu_aliases_parse(pmu);
-	nr = pmu->sysfs_aliases + pmu->sys_json_aliases;
+	pmu_layer__load_events(pmu);
+	hashmap__for_each_entry(pmu->aliases, entry, bkt) {
+		struct perf_pmu_alias *event = entry->pvalue;
 
-	if (pmu->cpu_aliases_added) {
-		nr += pmu->cpu_json_aliases;
-	} else if (pmu->events_table || pmu->is_core) {
-		nr += pmu_events_table__num_events(pmu->events_table, pmu);
-		if (pmu->is_core) {
-			nr += pmu_events_table__num_events(
-				perf_pmu__default_core_events_table(), pmu);
-		}
-		nr -= pmu->cpu_common_json_aliases;
-	} else {
-		assert(pmu->cpu_json_aliases == 0 && pmu->cpu_common_json_aliases == 0);
+		if (!event->terms)
+			continue;
+		if (perf_pmu__is_tool(pmu) && tool_pmu__skip_event(event->name))
+			continue;
+		nr++;
 	}
 
-	if (perf_pmu__is_tool(pmu))
-		nr -= tool_pmu__num_skip_events();
-
 	return pmu->selectable ? nr + 1 : nr;
 }
 
@@ -2469,12 +1864,13 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
 	if (perf_pmu__is_drm(pmu))
 		return drm_pmu__for_each_event(pmu, state, cb);
 
-	pmu_aliases_parse(pmu);
-	pmu_add_cpu_aliases(pmu);
+	pmu_layer__load_events(pmu);
 	hashmap__for_each_entry(pmu->aliases, entry, bkt) {
 		struct perf_pmu_alias *event = entry->pvalue;
 		size_t buf_used, pmu_name_len;
 
+		if (!event->terms)
+			continue;
 		if (perf_pmu__is_tool(pmu) && tool_pmu__skip_event(event->name))
 			continue;
 
@@ -2999,12 +2395,15 @@ const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config)
 	if (!pmu)
 		return NULL;
 
-	pmu_aliases_parse(pmu);
-	pmu_add_cpu_aliases(pmu);
+	pmu_layer__load_events(pmu);
 	hashmap__for_each_entry(pmu->aliases, entry, bkt) {
 		struct perf_pmu_alias *event = entry->pvalue;
 		struct perf_event_attr attr = {.config = 0,};
-		int ret = perf_pmu__parse_terms_to_attr(pmu, event->terms, &attr);
+		int ret;
+
+		if (!event->terms)
+			continue;
+		ret = perf_pmu__parse_terms_to_attr(pmu, event->terms, &attr);
 
 		if (ret == 0 && config == attr.config)
 			return event->name;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 2587279fa0ce..42a0f5655b1c 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -160,17 +160,6 @@ struct perf_pmu {
 	 * @metrics_table: The metrics table for json metrics in pmu-events.c.
 	 */
 	const struct pmu_metrics_table *metrics_table;
-	/** @sysfs_aliases: Number of sysfs aliases loaded. */
-	uint32_t sysfs_aliases;
-	/** @cpu_json_aliases: Number of json event aliases loaded specific to the CPUID. */
-	uint32_t cpu_json_aliases;
-	/** @sys_json_aliases: Number of json event aliases loaded matching the PMU's identifier. */
-	uint32_t sys_json_aliases;
-	/**
-	 * @cpu_common_json_aliases: Number of json events that overlapped with sysfs when
-	 * loading all sysfs events.
-	 */
-	uint32_t cpu_common_json_aliases;
 	/** @sysfs_aliases_loaded: Are sysfs aliases loaded from disk? */
 	bool sysfs_aliases_loaded;
 	/**
-- 
2.56.1.703.gf848ed807c-goog


  parent reply	other threads:[~2026-11-13 21:11 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-13 21:10 [PATCH 00/11] perf pmu: Layered sysfs-style PMU event and metric directories Ian Rogers
2026-11-13 21:10 ` [PATCH 01/11] perf pmu: Generalize pmu_alias_info_file() and lazy single-event sysfs loading Ian Rogers
2026-11-13 21:10 ` [PATCH 02/11] perf pmu: Add metric and metricgroup storage on struct perf_pmu Ian Rogers
2026-11-13 21:10 ` [PATCH 03/11] perf pmu-layer: Introduce stateless struct pmu_layer abstraction and builtin adapter Ian Rogers
2026-11-13 21:10 ` [PATCH 04/11] perf pmu-layer: Add openat-based directory layer with literal CPUID/symlink lookup Ian Rogers
2026-11-13 21:10 ` [PATCH 05/11] perf config: Add pmu-events.dir configuration option Ian Rogers
2026-11-13 21:10 ` Ian Rogers [this message]
2026-11-13 21:10 ` [PATCH 07/11] perf metricgroup: Route metric and metricgroup lookups through struct perf_pmu Ian Rogers
2026-11-13 21:10 ` [PATCH 08/11] perf list, jevents: Add --export-dir and --output-dir sysfs-style exporters Ian Rogers
2026-11-13 21:11 ` [PATCH 09/11] perf jevents: Add compiled-in model and sys table iterators Ian Rogers
2026-11-13 21:11 ` [PATCH 10/11] perf list: Add --export-cpuid to export compiled-in CPU models Ian Rogers
2026-11-13 21:11 ` [PATCH 11/11] perf tests: Add round-trip export, CPUID symlink, and pmu-events.dir overlay tests 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=20261113211105.3118281-7-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 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®