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 09/11] perf jevents: Add compiled-in model and sys table iterators
Date: Fri, 13 Nov 2026 13:11:00 -0800 [thread overview]
Message-ID: <20261113211105.3118281-10-irogers@google.com> (raw)
In-Reply-To: <20261113211105.3118281-1-irogers@google.com>
Record canonical model relative paths in struct pmu_events_map and
architecture/model paths in struct pmu_sys_events during jevents.py C
code generation, and expose pmu_events_map__for_each() and
pmu_sys_events__for_each() in pmu-events.h.
This keeps struct pmu_events_map and struct pmu_sys_events private to
pmu-events.c while allowing callers such as 'perf list --export-dir
--export-cpuid' to enumerate compiled-in CPU and system PMU tables
across all architectures without requiring an unbuilt JSON source tree.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/pmu-events/empty-pmu-events.c | 36 +++++++++++++++
tools/perf/pmu-events/jevents.py | 57 ++++++++++++++++++++++++
tools/perf/pmu-events/pmu-events.h | 15 +++++++
3 files changed, 108 insertions(+)
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index f4009e5c51ee..116ce8e39d5d 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -5419,6 +5419,7 @@ struct pmu_metrics_table {
struct pmu_events_map {
const char *arch;
const char *cpuid;
+ const char *model;
struct pmu_events_table event_table;
struct pmu_metrics_table metric_table;
};
@@ -5431,6 +5432,7 @@ static const struct pmu_events_map pmu_events_map[] = {
{
.arch = "common",
.cpuid = "common",
+ .model = "common",
.event_table = {
.pmus = pmu_events__common,
.num_pmus = ARRAY_SIZE(pmu_events__common),
@@ -5444,6 +5446,7 @@ static const struct pmu_events_map pmu_events_map[] = {
{
.arch = "testarch",
.cpuid = "testcpu",
+ .model = "test_soc/cpu",
.event_table = {
.pmus = pmu_events__test_soc_cpu,
.num_pmus = ARRAY_SIZE(pmu_events__test_soc_cpu),
@@ -5457,6 +5460,7 @@ static const struct pmu_events_map pmu_events_map[] = {
{
.arch = 0,
.cpuid = 0,
+ .model = 0,
.event_table = { 0, 0 },
.metric_table = { 0 },
}
@@ -5464,6 +5468,8 @@ static const struct pmu_events_map pmu_events_map[] = {
struct pmu_sys_events {
const char *name;
+ const char *arch;
+ const char *model;
struct pmu_events_table event_table;
struct pmu_metrics_table metric_table;
};
@@ -5475,6 +5481,8 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
.num_pmus = ARRAY_SIZE(pmu_events__test_soc_sys)
},
.name = "pmu_events__test_soc_sys",
+ .arch = "testarch",
+ .model = "test_soc/sys",
},
{
.event_table = { 0, 0 },
@@ -6041,6 +6049,34 @@ int pmu_metrics_table__iterate_tables(pmu_metrics_table_iter_t fn, void *data)
return 0;
}
+int pmu_events_map__for_each(pmu_events_map_iter_fn fn, void *data)
+{
+ for (size_t i = 0; pmu_events_map[i].arch; i++) {
+ const struct pmu_events_map *m = &pmu_events_map[i];
+ const struct pmu_events_table *et = m->event_table.pmus ? &m->event_table : NULL;
+ const struct pmu_metrics_table *mt = m->metric_table.pmus ? &m->metric_table : NULL;
+ int ret = fn(m->arch, m->cpuid, m->model, et, mt, data);
+
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+int pmu_sys_events__for_each(pmu_sys_events_iter_fn fn, void *data)
+{
+ for (size_t i = 0; pmu_sys_event_tables[i].name; i++) {
+ const struct pmu_sys_events *s = &pmu_sys_event_tables[i];
+ const struct pmu_events_table *et = s->event_table.pmus ? &s->event_table : NULL;
+ const struct pmu_metrics_table *mt = s->metric_table.pmus ? &s->metric_table : NULL;
+ int ret = fn(s->arch, s->model, et, mt, data);
+
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
static const uint32_t metricgroups[][2] = {
{ 130139, 128811 }, /* group1\000 => Test metricgroup 1\000 */
{ 130146, 128830 }, /* group1A\000 => Test metricgroup 1A\000 */
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 8c2f6531b0c5..972356ea84c3 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -25,6 +25,10 @@ _metric_tables: list[str] = []
_sys_metric_tables: list[str] = []
# Mapping between sys event table names and sys metric table names.
_sys_event_table_to_metric_table_mapping: Dict[str, str] = {}
+# Mapping from sys event/metric table names to (arch, model_rel_path).
+_sys_table_arch_model: Dict[str, Tuple[str, str]] = {}
+# Architecture directory currently being walked during code generation.
+_cur_arch: str = ''
# Map from an event name to an architecture standard
# JsonEvent. Architecture standard events are in json files in the top
# f'{_args.starting_dir}/{_args.arch}' directory.
@@ -1309,6 +1313,10 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
if item.name == 'sys':
_sys_event_table_to_metric_table_mapping[_pending_events_tblname] = _pending_metrics_tblname
+ c_arch = 'testarch' if _cur_arch == 'test' else _cur_arch
+ model_rel = '/'.join(list(parents) + [item.name])
+ _sys_table_arch_model[_pending_events_tblname] = (c_arch, model_rel)
+ _sys_table_arch_model[_pending_metrics_tblname] = (c_arch, model_rel)
return
# base dir or too deep
@@ -1352,6 +1360,7 @@ struct pmu_metrics_table {
struct pmu_events_map {
\tconst char *arch;
\tconst char *cpuid;
+\tconst char *model;
\tstruct pmu_events_table event_table;
\tstruct pmu_metrics_table metric_table;
};
@@ -1367,6 +1376,7 @@ static const struct pmu_events_map pmu_events_map[] = {
_args.output_file.write("""{
\t.arch = "testarch",
\t.cpuid = "testcpu",
+\t.model = "test_soc/cpu",
\t.event_table = {
\t\t.pmus = pmu_events__test_soc_cpu,
\t\t.num_pmus = ARRAY_SIZE(pmu_events__test_soc_cpu),
@@ -1382,6 +1392,7 @@ static const struct pmu_events_map pmu_events_map[] = {
_args.output_file.write("""{
\t.arch = "common",
\t.cpuid = "common",
+\t.model = "common",
\t.event_table = {
\t\t.pmus = pmu_events__common,
\t\t.num_pmus = ARRAY_SIZE(pmu_events__common),
@@ -1400,6 +1411,7 @@ static const struct pmu_events_map pmu_events_map[] = {
for row in table:
# Skip the first row or any row beginning with #.
if not first and len(row) > 0 and not row[0].startswith('#'):
+ model_rel = row[2].strip('/')
event_tblname = file_name_to_table_name('pmu_events_', [], row[2].replace('/', '_'))
if event_tblname in _event_tables:
event_size = f'ARRAY_SIZE({event_tblname})'
@@ -1417,9 +1429,11 @@ static const struct pmu_events_map pmu_events_map[] = {
if event_size == '0' and metric_size == '0':
continue
cpuid = row[0].replace('\\', '\\\\')
+ model_c = bytes_to_c_literal(model_rel.encode('utf-8'))
_args.output_file.write(f"""{{
\t.arch = "{arch}",
\t.cpuid = "{cpuid}",
+\t.model = "{model_c}",
\t.event_table = {{
\t\t.pmus = {event_tblname},
\t\t.num_pmus = {event_size}
@@ -1436,6 +1450,7 @@ static const struct pmu_events_map pmu_events_map[] = {
_args.output_file.write("""{
\t.arch = 0,
\t.cpuid = 0,
+\t.model = 0,
\t.event_table = { 0, 0 },
\t.metric_table = { 0 },
}
@@ -1479,6 +1494,34 @@ int pmu_metrics_table__iterate_tables(pmu_metrics_table_iter_t fn, void *data)
\t\tif (!pmu_sys_event_tables[i].metric_table.pmus)
\t\t\tcontinue;
\t\tret = fn(&pmu_sys_event_tables[i].metric_table, data);
+\t\tif (ret)
+\t\t\treturn ret;
+\t}
+\treturn 0;
+}
+
+int pmu_events_map__for_each(pmu_events_map_iter_fn fn, void *data)
+{
+\tfor (size_t i = 0; pmu_events_map[i].arch; i++) {
+\t\tconst struct pmu_events_map *m = &pmu_events_map[i];
+\t\tconst struct pmu_events_table *et = m->event_table.pmus ? &m->event_table : NULL;
+\t\tconst struct pmu_metrics_table *mt = m->metric_table.pmus ? &m->metric_table : NULL;
+\t\tint ret = fn(m->arch, m->cpuid, m->model, et, mt, data);
+
+\t\tif (ret)
+\t\t\treturn ret;
+\t}
+\treturn 0;
+}
+
+int pmu_sys_events__for_each(pmu_sys_events_iter_fn fn, void *data)
+{
+\tfor (size_t i = 0; pmu_sys_event_tables[i].name; i++) {
+\t\tconst struct pmu_sys_events *s = &pmu_sys_event_tables[i];
+\t\tconst struct pmu_events_table *et = s->event_table.pmus ? &s->event_table : NULL;
+\t\tconst struct pmu_metrics_table *mt = s->metric_table.pmus ? &s->metric_table : NULL;
+\t\tint ret = fn(s->arch, s->model, et, mt, data);
+
\t\tif (ret)
\t\t\treturn ret;
\t}
@@ -1493,6 +1536,8 @@ def print_system_mapping_table() -> None:
_args.output_file.write("""
struct pmu_sys_events {
\tconst char *name;
+\tconst char *arch;
+\tconst char *model;
\tstruct pmu_events_table event_table;
\tstruct pmu_metrics_table metric_table;
};
@@ -1501,6 +1546,9 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
""")
printed_metric_tables = []
for tblname in _sys_event_tables:
+ sys_arch, sys_model = _sys_table_arch_model.get(tblname, ('', ''))
+ sys_arch_c = bytes_to_c_literal(sys_arch.encode('utf-8'))
+ sys_model_c = bytes_to_c_literal(sys_model.encode('utf-8'))
_args.output_file.write(f"""\t{{
\t\t.event_table = {{
\t\t\t.pmus = {tblname},
@@ -1517,11 +1565,16 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
printed_metric_tables.append(metric_tblname)
_args.output_file.write(f"""
\t\t.name = \"{tblname}\",
+\t\t.arch = \"{sys_arch_c}\",
+\t\t.model = \"{sys_model_c}\",
\t}},
""")
for tblname in _sys_metric_tables:
if tblname in printed_metric_tables:
continue
+ sys_arch, sys_model = _sys_table_arch_model.get(tblname, ('', ''))
+ sys_arch_c = bytes_to_c_literal(sys_arch.encode('utf-8'))
+ sys_model_c = bytes_to_c_literal(sys_model.encode('utf-8'))
_args.output_file.write(f"""\t{{
\t\t.metric_table = {{
\t\t\t.name = "{tblname.replace('pmu_metrics__', '')}",
@@ -1529,6 +1582,8 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
\t\t\t.num_pmus = ARRAY_SIZE({tblname})
\t\t}},
\t\t.name = \"{tblname}\",
+\t\t.arch = \"{sys_arch_c}\",
+\t\t.model = \"{sys_model_c}\",
\t}},
""")
_args.output_file.write("""\t{
@@ -2568,7 +2623,9 @@ struct pmu_table_entry {
}
""")
_args.output_file.write('const char *pmu_events__get_string(uint32_t offset);\n\n')
+ global _cur_arch
for arch in archs:
+ _cur_arch = arch
arch_path = f'{_args.starting_dir}/{arch}'
ftw(arch_path, [], process_one_file)
print_pending_events()
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index cb55c9fbca43..77a58e238723 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -94,6 +94,19 @@ typedef int (*pmu_metric_iter_fn)(const struct pmu_metric *pm,
typedef int (*pmu_metrics_table_iter_t)(const struct pmu_metrics_table *table,
void *data);
+typedef int (*pmu_events_map_iter_fn)(const char *arch,
+ const char *cpuid,
+ const char *model,
+ const struct pmu_events_table *events_table,
+ const struct pmu_metrics_table *metrics_table,
+ void *data);
+
+typedef int (*pmu_sys_events_iter_fn)(const char *arch,
+ const char *model,
+ const struct pmu_events_table *events_table,
+ const struct pmu_metrics_table *metrics_table,
+ void *data);
+
int pmu_events_table__for_each_event(const struct pmu_events_table *table,
struct perf_pmu *pmu,
pmu_event_iter_fn fn,
@@ -143,6 +156,8 @@ const struct pmu_events_table *find_sys_events_table(const char *name);
const struct pmu_metrics_table *find_sys_metrics_table(const char *name);
int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data);
int pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data);
+int pmu_events_map__for_each(pmu_events_map_iter_fn fn, void *data);
+int pmu_sys_events__for_each(pmu_sys_events_iter_fn fn, void *data);
const char *describe_metricgroup(const char *group);
--
2.56.1.703.gf848ed807c-goog
next prev 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 ` [PATCH 06/11] perf pmu: Switch alias resolution and enumeration to layered PMU stack Ian Rogers
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 ` Ian Rogers [this message]
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-10-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®