jevents.py creates a number of large arrays from the json events. The
arrays contain pointers to strings that need relocating. The
relocations have file size, run time and memory costs. These changes
refactor the pmu_events API so that the storage of the pmu_event
struct isn't exposed. The format is then changed to an offset within a
combined big string, with adjacent pmu_event struct variables being
next to each other in the string separated by \0 - meaning only the
first variable of the struct needs its offset recording.
Some related fixes are contained with the patches. The architecture
jevents.py creates tables for can now be set by the JEVENTS_ARCH make
variable, with a new 'all' that generates the events and metrics for
all architectures.
An example of the improvement to the file size on x86 is:
no jevents - the same 19,788,464bytes
x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
default build options plus NO_LIBBFD=1.
I originally suggested fixing this problem in:
https://lore.kernel.org/linux-perf-users/CAP-5=fVB8G4bdb9T=FncRTh9oBVKCS=+=eowAO+YSgAhab+Dtg@mail.gmail.com/
v4. Fixed an issue with the empty-pmu-events.c spotted by John Garry
<[email protected]>.
v3. Fix an ARM build issue with a missed weak symbol. Perform some
pytype clean up.
v2. Split the substring folding optimization to its own patch and
comment tweaks as suggested by Namhyung Kim
<[email protected]>. Recompute the file size savings with the
latest json events and metrics.
Ian Rogers (17):
perf jevents: Clean up pytype warnings
perf jevents: Simplify generation of C-string
perf jevents: Add JEVENTS_ARCH make option
perf jevent: Add an 'all' architecture argument
perf jevents: Remove the type/version variables
perf jevents: Provide path to json file on error
perf jevents: Sort json files entries
perf pmu-events: Hide pmu_sys_event_tables
perf pmu-events: Avoid passing pmu_events_map
perf pmu-events: Hide pmu_events_map
perf test: Use full metric resolution
perf pmu-events: Move test events/metrics to json
perf pmu-events: Don't assume pmu_event is an array
perf pmu-events: Hide the pmu_events
perf metrics: Copy entire pmu_event in find metric
perf jevents: Compress the pmu_events_table
perf jevents: Fold strings optimization
tools/perf/arch/arm64/util/pmu.c | 4 +-
tools/perf/pmu-events/Build | 6 +-
.../arch/test/test_soc/cpu/metrics.json | 64 +++
tools/perf/pmu-events/empty-pmu-events.c | 204 +++++++-
tools/perf/pmu-events/jevents.py | 495 ++++++++++++++----
tools/perf/pmu-events/pmu-events.h | 40 +-
tools/perf/tests/expand-cgroup.c | 25 +-
tools/perf/tests/parse-metric.c | 77 +--
tools/perf/tests/pmu-events.c | 466 +++++++----------
tools/perf/util/metricgroup.c | 275 ++++++----
tools/perf/util/metricgroup.h | 5 +-
tools/perf/util/pmu.c | 139 ++---
tools/perf/util/pmu.h | 8 +-
tools/perf/util/s390-sample-raw.c | 50 +-
14 files changed, 1140 insertions(+), 718 deletions(-)
create mode 100644 tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
--
2.37.1.559.g78731f0fdb-goog
Move arrays of pmu_events into the json code so that it may be
regenerated and modified by the jevents.py script.
Signed-off-by: Ian Rogers <[email protected]>
---
.../arch/test/test_soc/cpu/metrics.json | 64 +++++++++++++++++
tools/perf/pmu-events/empty-pmu-events.c | 64 +++++++++++++++++
tools/perf/tests/expand-cgroup.c | 17 +----
tools/perf/tests/parse-metric.c | 68 +------------------
4 files changed, 132 insertions(+), 81 deletions(-)
create mode 100644 tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
diff --git a/tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json b/tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
new file mode 100644
index 000000000000..42d9b5242fd7
--- /dev/null
+++ b/tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
@@ -0,0 +1,64 @@
+[
+ {
+ "MetricExpr": "1 / IPC",
+ "MetricName": "CPI"
+ },
+ {
+ "MetricExpr": "inst_retired.any / cpu_clk_unhalted.thread",
+ "MetricName": "IPC",
+ "MetricGroup": "group1"
+ },
+ {
+ "MetricExpr": "idq_uops_not_delivered.core / (4 * (( ( cpu_clk_unhalted.thread / 2 ) * ( 1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk ) )))",
+ "MetricName": "Frontend_Bound_SMT"
+ },
+ {
+ "MetricExpr": "l1d\\-loads\\-misses / inst_retired.any",
+ "MetricName": "dcache_miss_cpi"
+ },
+ {
+ "MetricExpr": "l1i\\-loads\\-misses / inst_retired.any",
+ "MetricName": "icache_miss_cycles"
+ },
+ {
+ "MetricExpr": "(dcache_miss_cpi + icache_miss_cycles)",
+ "MetricName": "cache_miss_cycles",
+ "MetricGroup": "group1"
+ },
+ {
+ "MetricExpr": "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
+ "MetricName": "DCache_L2_All_Hits"
+ },
+ {
+ "MetricExpr": "max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss",
+ "MetricName": "DCache_L2_All_Miss"
+ },
+ {
+ "MetricExpr": "dcache_l2_all_hits + dcache_l2_all_miss",
+ "MetricName": "DCache_L2_All"
+ },
+ {
+ "MetricExpr": "d_ratio(dcache_l2_all_hits, dcache_l2_all)",
+ "MetricName": "DCache_L2_Hits"
+ },
+ {
+ "MetricExpr": "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
+ "MetricName": "DCache_L2_Misses"
+ },
+ {
+ "MetricExpr": "ipc + M2",
+ "MetricName": "M1"
+ },
+ {
+ "MetricExpr": "ipc + M1",
+ "MetricName": "M2"
+ },
+ {
+ "MetricExpr": "1/M3",
+ "MetricName": "M3"
+ },
+ {
+ "MetricExpr": "64 * l1d.replacement / 1000000000 / duration_time",
+ "MetricName": "L1D_Cache_Fill_BW"
+ }
+]
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 8ef75aff996c..028f44efe48d 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -105,6 +105,70 @@ static const struct pmu_event pme_test_soc_cpu[] = {
.desc = "L2 BTB Correction",
.topic = "branch",
},
+ {
+ .metric_expr = "1 / IPC",
+ .metric_name = "CPI",
+ },
+ {
+ .metric_expr = "inst_retired.any / cpu_clk_unhalted.thread",
+ .metric_name = "IPC",
+ .metric_group = "group1",
+ },
+ {
+ .metric_expr = "idq_uops_not_delivered.core / (4 * (( ( cpu_clk_unhalted.thread / 2 ) * "
+ "( 1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk ) )))",
+ .metric_name = "Frontend_Bound_SMT",
+ },
+ {
+ .metric_expr = "l1d\\-loads\\-misses / inst_retired.any",
+ .metric_name = "dcache_miss_cpi",
+ },
+ {
+ .metric_expr = "l1i\\-loads\\-misses / inst_retired.any",
+ .metric_name = "icache_miss_cycles",
+ },
+ {
+ .metric_expr = "(dcache_miss_cpi + icache_miss_cycles)",
+ .metric_name = "cache_miss_cycles",
+ .metric_group = "group1",
+ },
+ {
+ .metric_expr = "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
+ .metric_name = "DCache_L2_All_Hits",
+ },
+ {
+ .metric_expr = "max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + "
+ "l2_rqsts.pf_miss + l2_rqsts.rfo_miss",
+ .metric_name = "DCache_L2_All_Miss",
+ },
+ {
+ .metric_expr = "dcache_l2_all_hits + dcache_l2_all_miss",
+ .metric_name = "DCache_L2_All",
+ },
+ {
+ .metric_expr = "d_ratio(dcache_l2_all_hits, dcache_l2_all)",
+ .metric_name = "DCache_L2_Hits",
+ },
+ {
+ .metric_expr = "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
+ .metric_name = "DCache_L2_Misses",
+ },
+ {
+ .metric_expr = "ipc + M2",
+ .metric_name = "M1",
+ },
+ {
+ .metric_expr = "ipc + M1",
+ .metric_name = "M2",
+ },
+ {
+ .metric_expr = "1/M3",
+ .metric_name = "M3",
+ },
+ {
+ .metric_expr = "64 * l1d.replacement / 1000000000 / duration_time",
+ .metric_name = "L1D_Cache_Fill_BW",
+ },
{
.name = 0,
.event = 0,
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index 411fc578e5a4..e79ee8621a90 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -180,26 +180,13 @@ static int expand_metric_events(void)
struct evlist *evlist;
struct rblist metric_events;
const char metric_str[] = "CPI";
-
- struct pmu_event pme_test[] = {
- {
- .metric_expr = "instructions / cycles",
- .metric_name = "IPC",
- },
- {
- .metric_expr = "1 / IPC",
- .metric_name = "CPI",
- },
- {
- .metric_expr = NULL,
- .metric_name = NULL,
- },
- };
+ const struct pmu_event *pme_test;
evlist = evlist__new();
TEST_ASSERT_VAL("failed to get evlist", evlist);
rblist__init(&metric_events);
+ pme_test = find_core_events_table("testarch", "testcpu");
ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str,
false, false, &metric_events);
if (ret < 0) {
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 7aebde7c37ec..30c7091857b8 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -13,72 +13,6 @@
#include "stat.h"
#include "pmu.h"
-static struct pmu_event pme_test[] = {
-{
- .metric_expr = "inst_retired.any / cpu_clk_unhalted.thread",
- .metric_name = "IPC",
- .metric_group = "group1",
-},
-{
- .metric_expr = "idq_uops_not_delivered.core / (4 * (( ( cpu_clk_unhalted.thread / 2 ) * "
- "( 1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk ) )))",
- .metric_name = "Frontend_Bound_SMT",
-},
-{
- .metric_expr = "l1d\\-loads\\-misses / inst_retired.any",
- .metric_name = "dcache_miss_cpi",
-},
-{
- .metric_expr = "l1i\\-loads\\-misses / inst_retired.any",
- .metric_name = "icache_miss_cycles",
-},
-{
- .metric_expr = "(dcache_miss_cpi + icache_miss_cycles)",
- .metric_name = "cache_miss_cycles",
- .metric_group = "group1",
-},
-{
- .metric_expr = "l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit",
- .metric_name = "DCache_L2_All_Hits",
-},
-{
- .metric_expr = "max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + "
- "l2_rqsts.pf_miss + l2_rqsts.rfo_miss",
- .metric_name = "DCache_L2_All_Miss",
-},
-{
- .metric_expr = "dcache_l2_all_hits + dcache_l2_all_miss",
- .metric_name = "DCache_L2_All",
-},
-{
- .metric_expr = "d_ratio(dcache_l2_all_hits, dcache_l2_all)",
- .metric_name = "DCache_L2_Hits",
-},
-{
- .metric_expr = "d_ratio(dcache_l2_all_miss, dcache_l2_all)",
- .metric_name = "DCache_L2_Misses",
-},
-{
- .metric_expr = "ipc + m2",
- .metric_name = "M1",
-},
-{
- .metric_expr = "ipc + m1",
- .metric_name = "M2",
-},
-{
- .metric_expr = "1/m3",
- .metric_name = "M3",
-},
-{
- .metric_expr = "64 * l1d.replacement / 1000000000 / duration_time",
- .metric_name = "L1D_Cache_Fill_BW",
-},
-{
- .name = NULL,
-}
-};
-
struct value {
const char *event;
u64 val;
@@ -138,6 +72,7 @@ static int __compute_metric(const char *name, struct value *vals,
struct rblist metric_events = {
.nr_entries = 0,
};
+ const struct pmu_event *pme_test;
struct perf_cpu_map *cpus;
struct runtime_stat st;
struct evlist *evlist;
@@ -161,6 +96,7 @@ static int __compute_metric(const char *name, struct value *vals,
runtime_stat__init(&st);
/* Parse the metric into metric_events list. */
+ pme_test = find_core_events_table("testarch", "testcpu");
err = metricgroup__parse_groups_test(evlist, pme_test, name,
false, false,
&metric_events);
--
2.37.1.559.g78731f0fdb-goog
Preparation for hiding pmu_events_map as an implementation detail. While
the map is passed, the table of events is all that is normally wanted.
Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/arch/arm64/util/pmu.c | 4 +-
tools/perf/tests/expand-cgroup.c | 6 +--
tools/perf/tests/parse-metric.c | 7 +--
tools/perf/tests/pmu-events.c | 63 +++++++++++-------------
tools/perf/util/metricgroup.c | 82 +++++++++++++++----------------
tools/perf/util/metricgroup.h | 4 +-
tools/perf/util/pmu.c | 33 +++++++------
tools/perf/util/pmu.h | 6 +--
tools/perf/util/s390-sample-raw.c | 12 ++---
9 files changed, 99 insertions(+), 118 deletions(-)
diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
index 79124bba713e..646af8603227 100644
--- a/tools/perf/arch/arm64/util/pmu.c
+++ b/tools/perf/arch/arm64/util/pmu.c
@@ -3,7 +3,7 @@
#include "../../../util/cpumap.h"
#include "../../../util/pmu.h"
-const struct pmu_events_map *pmu_events_map__find(void)
+const struct pmu_event *pmu_events_map__find(void)
{
struct perf_pmu *pmu = NULL;
@@ -18,7 +18,7 @@ const struct pmu_events_map *pmu_events_map__find(void)
if (pmu->cpus->nr != cpu__max_cpu().cpu)
return NULL;
- return perf_pmu__find_map(pmu);
+ return perf_pmu__find_table(pmu);
}
return NULL;
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index dc4038f997d7..411fc578e5a4 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -195,16 +195,12 @@ static int expand_metric_events(void)
.metric_name = NULL,
},
};
- const struct pmu_events_map ev_map = {
- .cpuid = "test",
- .table = pme_test,
- };
evlist = evlist__new();
TEST_ASSERT_VAL("failed to get evlist", evlist);
rblist__init(&metric_events);
- ret = metricgroup__parse_groups_test(evlist, &ev_map, metric_str,
+ ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str,
false, false, &metric_events);
if (ret < 0) {
pr_debug("failed to parse '%s' metric\n", metric_str);
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 1b811a26f4ee..7aebde7c37ec 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -79,11 +79,6 @@ static struct pmu_event pme_test[] = {
}
};
-static const struct pmu_events_map map = {
- .cpuid = "test",
- .table = pme_test,
-};
-
struct value {
const char *event;
u64 val;
@@ -166,7 +161,7 @@ static int __compute_metric(const char *name, struct value *vals,
runtime_stat__init(&st);
/* Parse the metric into metric_events list. */
- err = metricgroup__parse_groups_test(evlist, &map, name,
+ err = metricgroup__parse_groups_test(evlist, pme_test, name,
false, false,
&metric_events);
if (err)
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index a39a2c99ede6..b3cde5f98982 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -272,13 +272,11 @@ static bool is_same(const char *reference, const char *test)
return !strcmp(reference, test);
}
-static const struct pmu_events_map *__test_pmu_get_events_map(void)
+static const struct pmu_event *__test_pmu_get_events_table(void)
{
- const struct pmu_events_map *map;
-
- for (map = &pmu_events_map[0]; map->cpuid; map++) {
+ for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
if (!strcmp(map->cpuid, "testcpu"))
- return map;
+ return map->table;
}
pr_err("could not find test events map\n");
@@ -440,8 +438,7 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
- const struct pmu_events_map *map = __test_pmu_get_events_map();
- const struct pmu_event *table;
+ const struct pmu_event *table = __test_pmu_get_events_table();
int map_events = 0, expected_events;
/* ignore 3x sentinels */
@@ -449,10 +446,10 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
ARRAY_SIZE(uncore_events) +
ARRAY_SIZE(sys_events) - 3;
- if (!map || !sys_event_tables)
+ if (!table || !sys_event_tables)
return -1;
- for (table = map->table; table->name; table++) {
+ for (; table->name; table++) {
struct perf_pmu_test_event const **test_event_table;
bool found = false;
@@ -537,10 +534,10 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
struct perf_pmu *pmu;
LIST_HEAD(aliases);
int res = 0;
- const struct pmu_events_map *map = __test_pmu_get_events_map();
+ const struct pmu_event *table = __test_pmu_get_events_table();
struct perf_pmu_alias *a, *tmp;
- if (!map)
+ if (!table)
return -1;
test_event_table = &core_events[0];
@@ -551,7 +548,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
pmu->name = pmu_name;
- pmu_add_cpu_aliases_map(&aliases, pmu, map);
+ pmu_add_cpu_aliases_map(&aliases, pmu, table);
for (; *test_event_table; test_event_table++) {
struct perf_pmu_test_event const *test_event = *test_event_table;
@@ -590,14 +587,14 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
struct perf_pmu *pmu = &test_pmu->pmu;
const char *pmu_name = pmu->name;
struct perf_pmu_alias *a, *tmp, *alias;
- const struct pmu_events_map *map;
+ const struct pmu_event *events_table;
LIST_HEAD(aliases);
int res = 0;
- map = __test_pmu_get_events_map();
- if (!map)
+ events_table = __test_pmu_get_events_table();
+ if (!events_table)
return -1;
- pmu_add_cpu_aliases_map(&aliases, pmu, map);
+ pmu_add_cpu_aliases_map(&aliases, pmu, events_table);
pmu_add_sys_aliases(&aliases, pmu);
/* Count how many aliases we generated */
@@ -848,13 +845,9 @@ static int check_parse_fake(const char *id)
return ret;
}
-static void expr_failure(const char *msg,
- const struct pmu_events_map *map,
- const struct pmu_event *pe)
+static void expr_failure(const char *msg, const struct pmu_event *pe)
{
- pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
- pr_debug("On metric %s\n", pe->metric_name);
- pr_debug("On expression %s\n", pe->metric_expr);
+ pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
}
struct metric {
@@ -864,7 +857,7 @@ struct metric {
static int resolve_metric_simple(struct expr_parse_ctx *pctx,
struct list_head *compound_list,
- const struct pmu_events_map *map,
+ const struct pmu_event *map,
const char *metric_name)
{
struct hashmap_entry *cur, *cur_tmp;
@@ -925,8 +918,7 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx,
static int test__parsing(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
- const struct pmu_events_map *cpus_map = pmu_events_map__find();
- const struct pmu_events_map *map;
+ const struct pmu_event *cpus_table = pmu_events_map__find();
const struct pmu_event *pe;
int i, j, k;
int ret = 0;
@@ -940,7 +932,8 @@ static int test__parsing(struct test_suite *test __maybe_unused,
}
i = 0;
for (;;) {
- map = &pmu_events_map[i++];
+ const struct pmu_events_map *map = &pmu_events_map[i++];
+
if (!map->table)
break;
j = 0;
@@ -957,14 +950,14 @@ static int test__parsing(struct test_suite *test __maybe_unused,
continue;
expr__ctx_clear(ctx);
if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
- expr_failure("Parse find ids failed", map, pe);
+ expr_failure("Parse find ids failed", pe);
ret++;
continue;
}
- if (resolve_metric_simple(ctx, &compound_list, map,
+ if (resolve_metric_simple(ctx, &compound_list, map->table,
pe->metric_name)) {
- expr_failure("Could not resolve metrics", map, pe);
+ expr_failure("Could not resolve metrics", pe);
ret++;
goto exit; /* Don't tolerate errors due to severity */
}
@@ -979,7 +972,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
expr__add_id_val(ctx, strdup(cur->key), k++);
hashmap__for_each_entry(ctx->ids, cur, bkt) {
- if (check_parse_cpu(cur->key, map == cpus_map,
+ if (check_parse_cpu(cur->key, map->table == cpus_table,
pe))
ret++;
}
@@ -999,7 +992,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
hashmap__for_each_entry(ctx->ids, cur, bkt)
expr__add_id_val(ctx, strdup(cur->key), k--);
if (expr__parse(&result, ctx, pe->metric_expr)) {
- expr_failure("Parse failed", map, pe);
+ expr_failure("Parse failed", pe);
ret++;
}
}
@@ -1088,8 +1081,6 @@ static int metric_parse_fake(const char *str)
static int test__parsing_fake(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
- const struct pmu_events_map *map;
- const struct pmu_event *pe;
unsigned int i, j;
int err = 0;
@@ -1101,12 +1092,14 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused,
i = 0;
for (;;) {
- map = &pmu_events_map[i++];
+ const struct pmu_events_map *map = &pmu_events_map[i++];
+
if (!map->table)
break;
j = 0;
for (;;) {
- pe = &map->table[j++];
+ const struct pmu_event *pe = &map->table[j++];
+
if (!pe->name && !pe->metric_group && !pe->metric_name)
break;
if (!pe->metric_expr)
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 8f7baeabc5cf..4d32b4fbf67d 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -539,9 +539,6 @@ static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *d
void metricgroup__print(bool metrics, bool metricgroups, char *filter,
bool raw, bool details, const char *pmu_name)
{
- const struct pmu_events_map *map = pmu_events_map__find();
- const struct pmu_event *pe;
- int i;
struct rblist groups;
struct rb_node *node, *next;
struct strlist *metriclist = NULL;
@@ -556,8 +553,7 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
groups.node_new = mep_new;
groups.node_cmp = mep_cmp;
groups.node_delete = mep_delete;
- for (i = 0; map; i++) {
- pe = &map->table[i];
+ for (const struct pmu_event *pe = pmu_events_map__find(); pe; pe++) {
if (!pe->name && !pe->metric_group && !pe->metric_name)
break;
@@ -850,7 +846,7 @@ struct metricgroup_add_iter_data {
bool metric_no_group;
struct metric *root_metric;
const struct visited_metric *visited;
- const struct pmu_events_map *map;
+ const struct pmu_event *table;
};
static int add_metric(struct list_head *metric_list,
@@ -859,7 +855,7 @@ static int add_metric(struct list_head *metric_list,
bool metric_no_group,
struct metric *root_metric,
const struct visited_metric *visited,
- const struct pmu_events_map *map);
+ const struct pmu_event *table);
/**
* resolve_metric - Locate metrics within the root metric and recursively add
@@ -874,7 +870,7 @@ static int add_metric(struct list_head *metric_list,
* metrics. When adding a root this argument is NULL.
* @visited: A singly linked list of metric names being added that is used to
* detect recursion.
- * @map: The map that is searched for metrics, most commonly the table for the
+ * @table: The table that is searched for metrics, most commonly the table for the
* architecture perf is running upon.
*/
static int resolve_metric(struct list_head *metric_list,
@@ -882,7 +878,7 @@ static int resolve_metric(struct list_head *metric_list,
bool metric_no_group,
struct metric *root_metric,
const struct visited_metric *visited,
- const struct pmu_events_map *map)
+ const struct pmu_event *table)
{
struct hashmap_entry *cur;
size_t bkt;
@@ -904,7 +900,7 @@ static int resolve_metric(struct list_head *metric_list,
hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
const struct pmu_event *pe;
- pe = metricgroup__find_metric(cur->key, map);
+ pe = metricgroup__find_metric(cur->key, table);
if (pe) {
pending = realloc(pending,
(pending_cnt + 1) * sizeof(struct to_resolve));
@@ -927,7 +923,7 @@ static int resolve_metric(struct list_head *metric_list,
*/
for (i = 0; i < pending_cnt; i++) {
ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group,
- root_metric, visited, map);
+ root_metric, visited, table);
if (ret)
break;
}
@@ -950,7 +946,7 @@ static int resolve_metric(struct list_head *metric_list,
* metrics. When adding a root this argument is NULL.
* @visited: A singly linked list of metric names being added that is used to
* detect recursion.
- * @map: The map that is searched for metrics, most commonly the table for the
+ * @table: The table that is searched for metrics, most commonly the table for the
* architecture perf is running upon.
*/
static int __add_metric(struct list_head *metric_list,
@@ -960,7 +956,7 @@ static int __add_metric(struct list_head *metric_list,
int runtime,
struct metric *root_metric,
const struct visited_metric *visited,
- const struct pmu_events_map *map)
+ const struct pmu_event *table)
{
const struct visited_metric *vm;
int ret;
@@ -1032,7 +1028,7 @@ static int __add_metric(struct list_head *metric_list,
} else {
/* Resolve referenced metrics. */
ret = resolve_metric(metric_list, modifier, metric_no_group, root_metric,
- &visited_node, map);
+ &visited_node, table);
}
if (ret) {
@@ -1045,25 +1041,25 @@ static int __add_metric(struct list_head *metric_list,
return ret;
}
-#define map_for_each_event(__pe, __idx, __map) \
- if (__map) \
- for (__idx = 0, __pe = &__map->table[__idx]; \
+#define table_for_each_event(__pe, __idx, __table) \
+ if (__table) \
+ for (__idx = 0, __pe = &__table[__idx]; \
__pe->name || __pe->metric_group || __pe->metric_name; \
- __pe = &__map->table[++__idx])
+ __pe = &__table[++__idx])
-#define map_for_each_metric(__pe, __idx, __map, __metric) \
- map_for_each_event(__pe, __idx, __map) \
+#define table_for_each_metric(__pe, __idx, __table, __metric) \
+ table_for_each_event(__pe, __idx, __table) \
if (__pe->metric_expr && \
(match_metric(__pe->metric_group, __metric) || \
match_metric(__pe->metric_name, __metric)))
const struct pmu_event *metricgroup__find_metric(const char *metric,
- const struct pmu_events_map *map)
+ const struct pmu_event *table)
{
const struct pmu_event *pe;
int i;
- map_for_each_event(pe, i, map) {
+ table_for_each_event(pe, i, table) {
if (match_metric(pe->metric_name, metric))
return pe;
}
@@ -1077,7 +1073,7 @@ static int add_metric(struct list_head *metric_list,
bool metric_no_group,
struct metric *root_metric,
const struct visited_metric *visited,
- const struct pmu_events_map *map)
+ const struct pmu_event *table)
{
int ret = 0;
@@ -1085,7 +1081,7 @@ static int add_metric(struct list_head *metric_list,
if (!strstr(pe->metric_expr, "?")) {
ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
- root_metric, visited, map);
+ root_metric, visited, table);
} else {
int j, count;
@@ -1098,7 +1094,7 @@ static int add_metric(struct list_head *metric_list,
for (j = 0; j < count && !ret; j++)
ret = __add_metric(metric_list, pe, modifier, metric_no_group, j,
- root_metric, visited, map);
+ root_metric, visited, table);
}
return ret;
@@ -1114,7 +1110,7 @@ static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
return 0;
ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
- d->root_metric, d->visited, d->map);
+ d->root_metric, d->visited, d->table);
if (ret)
goto out;
@@ -1162,13 +1158,13 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
* global. Grouping is the default but due to multiplexing the
* user may override.
* @metric_list: The list that the metric or metric group are added to.
- * @map: The map that is searched for metrics, most commonly the table for the
+ * @table: The table that is searched for metrics, most commonly the table for the
* architecture perf is running upon.
*/
static int metricgroup__add_metric(const char *metric_name, const char *modifier,
bool metric_no_group,
struct list_head *metric_list,
- const struct pmu_events_map *map)
+ const struct pmu_event *table)
{
const struct pmu_event *pe;
LIST_HEAD(list);
@@ -1179,11 +1175,11 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
* Iterate over all metrics seeing if metric matches either the name or
* group. When it does add the metric to the list.
*/
- map_for_each_metric(pe, i, map, metric_name) {
+ table_for_each_metric(pe, i, table, metric_name) {
has_match = true;
ret = add_metric(&list, pe, modifier, metric_no_group,
/*root_metric=*/NULL,
- /*visited_metrics=*/NULL, map);
+ /*visited_metrics=*/NULL, table);
if (ret)
goto out;
}
@@ -1198,7 +1194,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
.metric_no_group = metric_no_group,
.has_match = &has_match,
.ret = &ret,
- .map = map,
+ .table = table,
},
};
@@ -1227,12 +1223,12 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
* global. Grouping is the default but due to multiplexing the
* user may override.
* @metric_list: The list that metrics are added to.
- * @map: The map that is searched for metrics, most commonly the table for the
+ * @table: The table that is searched for metrics, most commonly the table for the
* architecture perf is running upon.
*/
static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
struct list_head *metric_list,
- const struct pmu_events_map *map)
+ const struct pmu_event *table)
{
char *list_itr, *list_copy, *metric_name, *modifier;
int ret, count = 0;
@@ -1249,7 +1245,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
ret = metricgroup__add_metric(metric_name, modifier,
metric_no_group, metric_list,
- map);
+ table);
if (ret == -EINVAL)
pr_err("Cannot find metric or group `%s'\n", metric_name);
@@ -1440,7 +1436,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
bool metric_no_merge,
struct perf_pmu *fake_pmu,
struct rblist *metric_events_list,
- const struct pmu_events_map *map)
+ const struct pmu_event *table)
{
struct evlist *combined_evlist = NULL;
LIST_HEAD(metric_list);
@@ -1451,7 +1447,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
if (metric_events_list->nr_entries == 0)
metricgroup__rblist_init(metric_events_list);
ret = metricgroup__add_metric_list(str, metric_no_group,
- &metric_list, map);
+ &metric_list, table);
if (ret)
goto out;
@@ -1586,34 +1582,34 @@ int metricgroup__parse_groups(const struct option *opt,
struct rblist *metric_events)
{
struct evlist *perf_evlist = *(struct evlist **)opt->value;
- const struct pmu_events_map *map = pmu_events_map__find();
+ const struct pmu_event *table = pmu_events_map__find();
return parse_groups(perf_evlist, str, metric_no_group,
- metric_no_merge, NULL, metric_events, map);
+ metric_no_merge, NULL, metric_events, table);
}
int metricgroup__parse_groups_test(struct evlist *evlist,
- const struct pmu_events_map *map,
+ const struct pmu_event *table,
const char *str,
bool metric_no_group,
bool metric_no_merge,
struct rblist *metric_events)
{
return parse_groups(evlist, str, metric_no_group,
- metric_no_merge, &perf_pmu__fake, metric_events, map);
+ metric_no_merge, &perf_pmu__fake, metric_events, table);
}
bool metricgroup__has_metric(const char *metric)
{
- const struct pmu_events_map *map = pmu_events_map__find();
+ const struct pmu_event *table = pmu_events_map__find();
const struct pmu_event *pe;
int i;
- if (!map)
+ if (!table)
return false;
for (i = 0; ; i++) {
- pe = &map->table[i];
+ pe = &table[i];
if (!pe->name && !pe->metric_group && !pe->metric_name)
break;
diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
index 2b42b778d1bf..5a1390e73d25 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -71,9 +71,9 @@ int metricgroup__parse_groups(const struct option *opt,
bool metric_no_merge,
struct rblist *metric_events);
const struct pmu_event *metricgroup__find_metric(const char *metric,
- const struct pmu_events_map *map);
+ const struct pmu_event *table);
int metricgroup__parse_groups_test(struct evlist *evlist,
- const struct pmu_events_map *map,
+ const struct pmu_event *table,
const char *str,
bool metric_no_group,
bool metric_no_merge,
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index d8717c4548a4..f3e3c4a147e9 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -710,9 +710,9 @@ static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
return cpuid;
}
-const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
{
- const struct pmu_events_map *map;
+ const struct pmu_event *table = NULL;
char *cpuid = perf_pmu__getcpuid(pmu);
int i;
@@ -724,22 +724,23 @@ const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
i = 0;
for (;;) {
- map = &pmu_events_map[i++];
- if (!map->table) {
- map = NULL;
+ const struct pmu_events_map *map = &pmu_events_map[i++];
+
+ if (!map->table)
break;
- }
- if (!strcmp_cpuid_str(map->cpuid, cpuid))
+ if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
+ table = map->table;
break;
+ }
}
free(cpuid);
- return map;
+ return table;
}
-const struct pmu_events_map *__weak pmu_events_map__find(void)
+__weak const struct pmu_event *pmu_events_map__find(void)
{
- return perf_pmu__find_map(NULL);
+ return perf_pmu__find_table(NULL);
}
/*
@@ -824,7 +825,7 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
* as aliases.
*/
void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
- const struct pmu_events_map *map)
+ const struct pmu_event *table)
{
int i;
const char *name = pmu->name;
@@ -834,7 +835,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
i = 0;
while (1) {
const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
- const struct pmu_event *pe = &map->table[i++];
+ const struct pmu_event *pe = &table[i++];
const char *pname = pe->pmu ? pe->pmu : cpu_name;
if (!pe->name) {
@@ -859,13 +860,13 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
{
- const struct pmu_events_map *map;
+ const struct pmu_event *table;
- map = perf_pmu__find_map(pmu);
- if (!map)
+ table = perf_pmu__find_table(pmu);
+ if (!table)
return;
- pmu_add_cpu_aliases_map(head, pmu, map);
+ pmu_add_cpu_aliases_map(head, pmu, table);
}
struct pmu_sys_event_iter_data {
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 7e667eec2a01..015242c83698 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -126,10 +126,10 @@ int perf_pmu__test(void);
struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
- const struct pmu_events_map *map);
+ const struct pmu_event *map);
-const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu);
-const struct pmu_events_map *pmu_events_map__find(void);
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
+const struct pmu_event *pmu_events_map__find(void);
bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
void perf_pmu_free_alias(struct perf_pmu_alias *alias);
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index cd3a34840389..1ecb718fc0eb 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -135,12 +135,12 @@ static int get_counterset_start(int setnr)
* the name of this counter.
* If no match is found a NULL pointer is returned.
*/
-static const char *get_counter_name(int set, int nr, const struct pmu_events_map *map)
+static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
{
int rc, event_nr, wanted = get_counterset_start(set) + nr;
- if (map) {
- const struct pmu_event *evp = map->table;
+ if (table) {
+ const struct pmu_event *evp = table;
for (; evp->name || evp->event || evp->desc; ++evp) {
if (evp->name == NULL || evp->event == NULL)
@@ -159,10 +159,10 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
unsigned char *buf = sample->raw_data;
const char *color = PERF_COLOR_BLUE;
struct cf_ctrset_entry *cep, ce;
- const struct pmu_events_map *map;
+ const struct pmu_event *table;
u64 *p;
- map = pmu_events_map__find();
+ table = pmu_events_map__find();
while (offset < len) {
cep = (struct cf_ctrset_entry *)(buf + offset);
@@ -180,7 +180,7 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
color_fprintf(stdout, color, " [%#08zx] Counterset:%d"
" Counters:%d\n", offset, ce.set, ce.ctr);
for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) {
- const char *ev_name = get_counter_name(ce.set, i, map);
+ const char *ev_name = get_counter_name(ce.set, i, table);
color_fprintf(stdout, color,
"\tCounter:%03d %s Value:%#018lx\n", i,
--
2.37.1.559.g78731f0fdb-goog
If a JSONDecoderError or similar is raised then it is useful to know the
path. Print this and then raise the exception agan.
Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/pmu-events/jevents.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 98d18d5c3830..12d2daf3570c 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -224,7 +224,12 @@ class JsonEvent:
def read_json_events(path: str) -> Sequence[JsonEvent]:
"""Read json events from the specified file."""
- return json.load(open(path), object_hook=lambda d: JsonEvent(d))
+
+ try:
+ return json.load(open(path), object_hook=lambda d: JsonEvent(d))
+ except BaseException as err:
+ print(f"Exception processing {path}")
+ raise
def preprocess_arch_std_files(archpath: str) -> None:
--
2.37.1.559.g78731f0fdb-goog
Allow the architecture built into pmu-events.c to be set on the make
command line with JEVENTS_ARCH.
Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/pmu-events/Build | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
index 28a9d01b08af..04ef95174660 100644
--- a/tools/perf/pmu-events/Build
+++ b/tools/perf/pmu-events/Build
@@ -7,6 +7,10 @@ JSON_TEST = $(shell [ -d $(JDIR_TEST) ] && \
find $(JDIR_TEST) -name '*.json')
JEVENTS_PY = pmu-events/jevents.py
+ifeq ($(JEVENTS_ARCH),)
+JEVENTS_ARCH=$(SRCARCH)
+endif
+
#
# Locate/process JSON files in pmu-events/arch/
# directory and create tables in pmu-events.c.
@@ -19,5 +23,5 @@ $(OUTPUT)pmu-events/pmu-events.c: pmu-events/empty-pmu-events.c
else
$(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JSON_TEST) $(JEVENTS_PY)
$(call rule_mkdir)
- $(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(SRCARCH) pmu-events/arch $@
+ $(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) pmu-events/arch $@
endif
--
2.37.1.559.g78731f0fdb-goog
When 'all' is passed as the architecture generate a mapping table for
all architectures. This simplifies testing. To identify the table for an
architecture add an arch variable to the pmu_events_map.
Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/pmu-events/empty-pmu-events.c | 2 +
tools/perf/pmu-events/jevents.py | 70 +++++++++++++++---------
tools/perf/pmu-events/pmu-events.h | 1 +
tools/perf/tests/pmu-events.c | 3 +-
4 files changed, 47 insertions(+), 29 deletions(-)
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 77e655c6f116..d8cf9283e486 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -110,12 +110,14 @@ static const struct pmu_event pme_test_soc_cpu[] = {
const struct pmu_events_map pmu_events_map[] = {
{
+ .arch = "testarch",
.cpuid = "testcpu",
.version = "v1",
.type = "core",
.table = pme_test_soc_cpu,
},
{
+ .arch = 0,
.cpuid = 0,
.version = 0,
.type = 0,
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index cdfa4e0e7557..e6e6c42c3f8a 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -304,38 +304,45 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
print_events_table_entries(item, get_topic(item.name))
-def print_mapping_table() -> None:
+def print_mapping_table(archs: Sequence[str]) -> None:
"""Read the mapfile and generate the struct from cpuid string to event table."""
- with open(f'{_args.starting_dir}/{_args.arch}/mapfile.csv') as csvfile:
- table = csv.reader(csvfile)
- _args.output_file.write(
- 'const struct pmu_events_map pmu_events_map[] = {\n')
- first = True
- 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('#'):
- tblname = file_name_to_table_name([], row[2].replace('/', '_'))
- _args.output_file.write("""{
-\t.cpuid = \"%s\",
-\t.version = \"%s\",
-\t.type = \"%s\",
-\t.table = %s
-},
-""" % (row[0].replace('\\', '\\\\'), row[1], row[3], tblname))
- first = False
-
- _args.output_file.write("""{
+ _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
+ for arch in archs:
+ if arch == 'test':
+ _args.output_file.write("""{
+\t.arch = "testarch",
\t.cpuid = "testcpu",
\t.version = "v1",
\t.type = "core",
\t.table = pme_test_soc_cpu,
},
-{
+""")
+ else:
+ with open(f'{_args.starting_dir}/{arch}/mapfile.csv') as csvfile:
+ table = csv.reader(csvfile)
+ first = True
+ 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('#'):
+ tblname = file_name_to_table_name([], row[2].replace('/', '_'))
+ cpuid = row[0].replace('\\', '\\\\')
+ _args.output_file.write(f"""{{
+\t.arch = "{arch}",
+\t.cpuid = "{cpuid}",
+\t.version = "{row[1]}",
+\t.type = "{row[3]}",
+\t.table = {tblname}
+}},
+""")
+ first = False
+
+ _args.output_file.write("""{
+\t.arch = 0,
\t.cpuid = 0,
\t.version = 0,
\t.type = 0,
\t.table = 0,
-},
+}
};
""")
@@ -386,15 +393,24 @@ def main() -> None:
_args = ap.parse_args()
_args.output_file.write("#include \"pmu-events/pmu-events.h\"\n")
- for path in [_args.arch, 'test']:
- arch_path = f'{_args.starting_dir}/{path}'
- if not os.path.isdir(arch_path):
- raise IOError(f'Missing architecture directory in \'{arch_path}\'')
+ archs = []
+ for item in os.scandir(_args.starting_dir):
+ if not item.is_dir():
+ continue
+ if item.name == _args.arch or _args.arch == 'all' or item.name == 'test':
+ archs.append(item.name)
+
+ if len(archs) < 2:
+ raise IOError(f'Missing architecture directory \'{_args.arch}\'')
+
+ archs.sort()
+ for arch in archs:
+ arch_path = f'{_args.starting_dir}/{arch}'
preprocess_arch_std_files(arch_path)
ftw(arch_path, [], process_one_file)
print_events_table_suffix()
- print_mapping_table()
+ print_mapping_table(archs)
print_system_mapping_table()
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 6efe73976440..7a360792635f 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -38,6 +38,7 @@ struct pmu_event {
* The cpuid can contain any character other than the comma.
*/
struct pmu_events_map {
+ const char *arch;
const char *cpuid;
const char *version;
const char *type; /* core, uncore etc */
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index 263cbb67c861..82192f1a7bf7 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -864,8 +864,7 @@ static void expr_failure(const char *msg,
const struct pmu_events_map *map,
const struct pmu_event *pe)
{
- pr_debug("%s for map %s %s %s\n",
- msg, map->cpuid, map->version, map->type);
+ pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
pr_debug("On metric %s\n", pe->metric_name);
pr_debug("On expression %s\n", pe->metric_expr);
}
--
2.37.1.559.g78731f0fdb-goog
Hide that the pmu_event structs are an array with a new wrapper struct.
Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/arch/arm64/util/pmu.c | 2 +-
tools/perf/pmu-events/empty-pmu-events.c | 44 ++++++++++++----------
tools/perf/pmu-events/jevents.py | 47 +++++++++++++-----------
tools/perf/pmu-events/pmu-events.h | 12 +++---
tools/perf/tests/expand-cgroup.c | 2 +-
tools/perf/tests/parse-metric.c | 2 +-
tools/perf/tests/pmu-events.c | 16 ++++----
tools/perf/util/metricgroup.c | 42 ++++++++++-----------
tools/perf/util/metricgroup.h | 5 +--
tools/perf/util/pmu.c | 10 ++---
tools/perf/util/pmu.h | 4 +-
tools/perf/util/s390-sample-raw.c | 6 +--
12 files changed, 101 insertions(+), 91 deletions(-)
diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
index 646af8603227..149fb334b40b 100644
--- a/tools/perf/arch/arm64/util/pmu.c
+++ b/tools/perf/arch/arm64/util/pmu.c
@@ -3,7 +3,7 @@
#include "../../../util/cpumap.h"
#include "../../../util/pmu.h"
-const struct pmu_event *pmu_events_map__find(void)
+const struct pmu_events_table *pmu_events_map__find(void)
{
struct perf_pmu *pmu = NULL;
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index bee1967baa2b..5ed8c0aa4817 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -176,6 +176,10 @@ static const struct pmu_event pme_test_soc_cpu[] = {
},
};
+/* Struct used to make the PMU event table implementation opaque to callers. */
+struct pmu_events_table {
+ const struct pmu_event *entries;
+};
/*
* Map a CPU to its table of PMU events. The CPU is identified by the
@@ -188,7 +192,7 @@ static const struct pmu_event pme_test_soc_cpu[] = {
struct pmu_events_map {
const char *arch;
const char *cpuid;
- const struct pmu_event *table;
+ const struct pmu_events_table table;
};
/*
@@ -199,12 +203,12 @@ static const struct pmu_events_map pmu_events_map[] = {
{
.arch = "testarch",
.cpuid = "testcpu",
- .table = pme_test_soc_cpu,
+ .table = { pme_test_soc_cpu },
},
{
.arch = 0,
.cpuid = 0,
- .table = 0,
+ .table = { 0 },
},
};
@@ -234,23 +238,23 @@ static const struct pmu_event pme_test_soc_sys[] = {
struct pmu_sys_events {
const char *name;
- const struct pmu_event *table;
+ const struct pmu_events_table table;
};
static const struct pmu_sys_events pmu_sys_event_tables[] = {
{
- .table = pme_test_soc_sys,
+ .table = { pme_test_soc_sys },
.name = "pme_test_soc_sys",
},
{
- .table = 0
+ .table = { 0 }
},
};
-int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
void *data)
{
- for (const struct pmu_event *pe = &table[0];
+ for (const struct pmu_event *pe = &table->entries[0];
pe->name || pe->metric_group || pe->metric_name;
pe++) {
int ret = fn(pe, table, data);
@@ -261,9 +265,9 @@ int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_ite
return 0;
}
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
{
- const struct pmu_event *table = NULL;
+ const struct pmu_events_table *table = NULL;
char *cpuid = perf_pmu__getcpuid(pmu);
int i;
@@ -277,11 +281,11 @@ const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
for (;;) {
const struct pmu_events_map *map = &pmu_events_map[i++];
- if (!map->table)
+ if (!map->cpuid)
break;
if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
- table = map->table;
+ table = &map->table;
break;
}
}
@@ -289,13 +293,13 @@ const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
return table;
}
-const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid)
{
for (const struct pmu_events_map *tables = &pmu_events_map[0];
- tables->table;
+ tables->arch;
tables++) {
if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
- return tables->table;
+ return &tables->table;
}
return NULL;
}
@@ -303,9 +307,9 @@ const struct pmu_event *find_core_events_table(const char *arch, const char *cpu
int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
{
for (const struct pmu_events_map *tables = &pmu_events_map[0];
- tables->table;
+ tables->arch;
tables++) {
- int ret = pmu_events_table_for_each_event(tables->table, fn, data);
+ int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
if (ret)
return ret;
@@ -313,13 +317,13 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
return 0;
}
-const struct pmu_event *find_sys_events_table(const char *name)
+const struct pmu_events_table *find_sys_events_table(const char *name)
{
for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
tables->name;
tables++) {
if (!strcmp(tables->name, name))
- return tables->table;
+ return &tables->table;
}
return NULL;
}
@@ -329,7 +333,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
tables->name;
tables++) {
- int ret = pmu_events_table_for_each_event(tables->table, fn, data);
+ int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
if (ret)
return ret;
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 365c960202b0..aa8df649025a 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -334,6 +334,11 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
def print_mapping_table(archs: Sequence[str]) -> None:
"""Read the mapfile and generate the struct from cpuid string to event table."""
_args.output_file.write("""
+/* Struct used to make the PMU event table implementation opaque to callers. */
+struct pmu_events_table {
+ const struct pmu_event *entries;
+};
+
/*
* Map a CPU to its table of PMU events. The CPU is identified by the
* cpuid field, which is an arch-specific identifier for the CPU.
@@ -345,7 +350,7 @@ def print_mapping_table(archs: Sequence[str]) -> None:
struct pmu_events_map {
const char *arch;
const char *cpuid;
- const struct pmu_event *table;
+ struct pmu_events_table table;
};
/*
@@ -359,7 +364,7 @@ const struct pmu_events_map pmu_events_map[] = {
_args.output_file.write("""{
\t.arch = "testarch",
\t.cpuid = "testcpu",
-\t.table = pme_test_soc_cpu,
+\t.table = { pme_test_soc_cpu },
},
""")
else:
@@ -374,7 +379,7 @@ const struct pmu_events_map pmu_events_map[] = {
_args.output_file.write(f"""{{
\t.arch = "{arch}",
\t.cpuid = "{cpuid}",
-\t.table = {tblname}
+\t.table = {{ {tblname} }}
}},
""")
first = False
@@ -382,7 +387,7 @@ const struct pmu_events_map pmu_events_map[] = {
_args.output_file.write("""{
\t.arch = 0,
\t.cpuid = 0,
-\t.table = 0,
+\t.table = { 0 },
}
};
""")
@@ -393,26 +398,26 @@ def print_system_mapping_table() -> None:
_args.output_file.write("""
struct pmu_sys_events {
\tconst char *name;
-\tconst struct pmu_event *table;
+\tstruct pmu_events_table table;
};
static const struct pmu_sys_events pmu_sys_event_tables[] = {
""")
for tblname in _sys_event_tables:
_args.output_file.write(f"""\t{{
-\t\t.table = {tblname},
+\t\t.table = {{ {tblname} }},
\t\t.name = \"{tblname}\",
\t}},
""")
_args.output_file.write("""\t{
-\t\t.table = 0
+\t\t.table = { 0 }
\t},
};
-int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
void *data)
{
- for (const struct pmu_event *pe = &table[0];
+ for (const struct pmu_event *pe = &table->entries[0];
pe->name || pe->metric_group || pe->metric_name;
pe++) {
int ret = fn(pe, table, data);
@@ -423,9 +428,9 @@ int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_ite
return 0;
}
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
{
- const struct pmu_event *table = NULL;
+ const struct pmu_events_table *table = NULL;
char *cpuid = perf_pmu__getcpuid(pmu);
int i;
@@ -438,11 +443,11 @@ const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
i = 0;
for (;;) {
const struct pmu_events_map *map = &pmu_events_map[i++];
- if (!map->table)
+ if (!map->arch)
break;
if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
- table = map->table;
+ table = &map->table;
break;
}
}
@@ -450,13 +455,13 @@ const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
return table;
}
-const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid)
{
for (const struct pmu_events_map *tables = &pmu_events_map[0];
- tables->table;
+ tables->arch;
tables++) {
if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
- return tables->table;
+ return &tables->table;
}
return NULL;
}
@@ -464,9 +469,9 @@ const struct pmu_event *find_core_events_table(const char *arch, const char *cpu
int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
{
for (const struct pmu_events_map *tables = &pmu_events_map[0];
- tables->table;
+ tables->arch;
tables++) {
- int ret = pmu_events_table_for_each_event(tables->table, fn, data);
+ int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
if (ret)
return ret;
@@ -474,13 +479,13 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
return 0;
}
-const struct pmu_event *find_sys_events_table(const char *name)
+const struct pmu_events_table *find_sys_events_table(const char *name)
{
for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
tables->name;
tables++) {
if (!strcmp(tables->name, name))
- return tables->table;
+ return &tables->table;
}
return NULL;
}
@@ -490,7 +495,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
tables->name;
tables++) {
- int ret = pmu_events_table_for_each_event(tables->table, fn, data);
+ int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
if (ret)
return ret;
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 70672842f77f..fe343c4d8016 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -30,18 +30,20 @@ struct pmu_event {
const char *metric_constraint;
};
+struct pmu_events_table;
+
typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
- const struct pmu_event *table,
+ const struct pmu_events_table *table,
void *data);
-int pmu_events_table_for_each_event(const struct pmu_event *table, pmu_event_iter_fn fn,
+int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
void *data);
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
-const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid);
+const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu);
+const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid);
int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data);
-const struct pmu_event *find_sys_events_table(const char *name);
+const struct pmu_events_table *find_sys_events_table(const char *name);
int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data);
#endif
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index e79ee8621a90..51fb5f34c1dd 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -180,7 +180,7 @@ static int expand_metric_events(void)
struct evlist *evlist;
struct rblist metric_events;
const char metric_str[] = "CPI";
- const struct pmu_event *pme_test;
+ const struct pmu_events_table *pme_test;
evlist = evlist__new();
TEST_ASSERT_VAL("failed to get evlist", evlist);
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 30c7091857b8..68f5a2a03242 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -72,7 +72,7 @@ static int __compute_metric(const char *name, struct value *vals,
struct rblist metric_events = {
.nr_entries = 0,
};
- const struct pmu_event *pme_test;
+ const struct pmu_events_table *pme_test;
struct perf_cpu_map *cpus;
struct runtime_stat st;
struct evlist *evlist;
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index 1c3479e5890e..9111725041d0 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -424,7 +424,7 @@ static int compare_alias_to_test_event(struct perf_pmu_alias *alias,
}
static int test__pmu_event_table_core_callback(const struct pmu_event *pe,
- const struct pmu_event *table __maybe_unused,
+ const struct pmu_events_table *table __maybe_unused,
void *data)
{
int *map_events = data;
@@ -461,7 +461,7 @@ static int test__pmu_event_table_core_callback(const struct pmu_event *pe,
}
static int test__pmu_event_table_sys_callback(const struct pmu_event *pe,
- const struct pmu_event *table __maybe_unused,
+ const struct pmu_events_table *table __maybe_unused,
void *data)
{
int *map_events = data;
@@ -495,8 +495,8 @@ static int test__pmu_event_table_sys_callback(const struct pmu_event *pe,
static int test__pmu_event_table(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
- const struct pmu_event *sys_event_table = find_sys_events_table("pme_test_soc_sys");
- const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
+ const struct pmu_events_table *sys_event_table = find_sys_events_table("pme_test_soc_sys");
+ const struct pmu_events_table *table = find_core_events_table("testarch", "testcpu");
int map_events = 0, expected_events, err;
/* ignore 3x sentinels */
@@ -544,7 +544,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
struct perf_pmu *pmu;
LIST_HEAD(aliases);
int res = 0;
- const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
+ const struct pmu_events_table *table = find_core_events_table("testarch", "testcpu");
struct perf_pmu_alias *a, *tmp;
if (!table)
@@ -597,7 +597,7 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
struct perf_pmu *pmu = &test_pmu->pmu;
const char *pmu_name = pmu->name;
struct perf_pmu_alias *a, *tmp, *alias;
- const struct pmu_event *events_table;
+ const struct pmu_events_table *events_table;
LIST_HEAD(aliases);
int res = 0;
@@ -839,7 +839,7 @@ struct metric {
struct metric_ref metric_ref;
};
-static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_event *table,
+static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_events_table *table,
void *data)
{
int *failures = data;
@@ -1016,7 +1016,7 @@ static int metric_parse_fake(const char *str)
}
static int test__parsing_fake_callback(const struct pmu_event *pe,
- const struct pmu_event *table __maybe_unused,
+ const struct pmu_events_table *table __maybe_unused,
void *data __maybe_unused)
{
if (!pe->metric_expr)
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index f702b73a7609..8ef44f4b5e9a 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -508,7 +508,7 @@ struct metricgroup_iter_data {
};
static int metricgroup__sys_event_iter(const struct pmu_event *pe,
- const struct pmu_event *table __maybe_unused,
+ const struct pmu_events_table *table,
void *data)
{
struct metricgroup_iter_data *d = data;
@@ -529,7 +529,7 @@ static int metricgroup__sys_event_iter(const struct pmu_event *pe,
}
static int metricgroup__print_sys_event_iter(const struct pmu_event *pe,
- const struct pmu_event *table __maybe_unused,
+ const struct pmu_events_table *table __maybe_unused,
void *data)
{
struct metricgroup_print_sys_idata *d = data;
@@ -549,7 +549,7 @@ struct metricgroup_print_data {
};
static int metricgroup__print_callback(const struct pmu_event *pe,
- const struct pmu_event *table __maybe_unused,
+ const struct pmu_events_table *table __maybe_unused,
void *vdata)
{
struct metricgroup_print_data *data = vdata;
@@ -571,7 +571,7 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
struct rblist groups;
struct rb_node *node, *next;
struct strlist *metriclist = NULL;
- const struct pmu_event *table;
+ const struct pmu_events_table *table;
if (!metricgroups) {
metriclist = strlist__new(NULL, NULL);
@@ -876,7 +876,7 @@ struct metricgroup_add_iter_data {
bool metric_no_group;
struct metric *root_metric;
const struct visited_metric *visited;
- const struct pmu_event *table;
+ const struct pmu_events_table *table;
};
static int add_metric(struct list_head *metric_list,
@@ -885,7 +885,7 @@ static int add_metric(struct list_head *metric_list,
bool metric_no_group,
struct metric *root_metric,
const struct visited_metric *visited,
- const struct pmu_event *table);
+ const struct pmu_events_table *table);
/**
* resolve_metric - Locate metrics within the root metric and recursively add
@@ -908,7 +908,7 @@ static int resolve_metric(struct list_head *metric_list,
bool metric_no_group,
struct metric *root_metric,
const struct visited_metric *visited,
- const struct pmu_event *table)
+ const struct pmu_events_table *table)
{
struct hashmap_entry *cur;
size_t bkt;
@@ -986,7 +986,7 @@ static int __add_metric(struct list_head *metric_list,
int runtime,
struct metric *root_metric,
const struct visited_metric *visited,
- const struct pmu_event *table)
+ const struct pmu_events_table *table)
{
const struct visited_metric *vm;
int ret;
@@ -1077,7 +1077,7 @@ struct metricgroup__find_metric_data {
};
static int metricgroup__find_metric_callback(const struct pmu_event *pe,
- const struct pmu_event *table __maybe_unused,
+ const struct pmu_events_table *table __maybe_unused,
void *vdata)
{
struct metricgroup__find_metric_data *data = vdata;
@@ -1090,7 +1090,7 @@ static int metricgroup__find_metric_callback(const struct pmu_event *pe,
}
const struct pmu_event *metricgroup__find_metric(const char *metric,
- const struct pmu_event *table)
+ const struct pmu_events_table *table)
{
struct metricgroup__find_metric_data data = {
.metric = metric,
@@ -1108,7 +1108,7 @@ static int add_metric(struct list_head *metric_list,
bool metric_no_group,
struct metric *root_metric,
const struct visited_metric *visited,
- const struct pmu_event *table)
+ const struct pmu_events_table *table)
{
int ret = 0;
@@ -1136,8 +1136,8 @@ static int add_metric(struct list_head *metric_list,
}
static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
- const struct pmu_event *table __maybe_unused,
- void *data)
+ const struct pmu_events_table *table __maybe_unused,
+ void *data)
{
struct metricgroup_add_iter_data *d = data;
int ret;
@@ -1193,7 +1193,7 @@ struct metricgroup__add_metric_data {
};
static int metricgroup__add_metric_callback(const struct pmu_event *pe,
- const struct pmu_event *table,
+ const struct pmu_events_table *table,
void *vdata)
{
struct metricgroup__add_metric_data *data = vdata;
@@ -1227,7 +1227,7 @@ static int metricgroup__add_metric_callback(const struct pmu_event *pe,
static int metricgroup__add_metric(const char *metric_name, const char *modifier,
bool metric_no_group,
struct list_head *metric_list,
- const struct pmu_event *table)
+ const struct pmu_events_table *table)
{
LIST_HEAD(list);
int ret;
@@ -1296,7 +1296,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
*/
static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
struct list_head *metric_list,
- const struct pmu_event *table)
+ const struct pmu_events_table *table)
{
char *list_itr, *list_copy, *metric_name, *modifier;
int ret, count = 0;
@@ -1504,7 +1504,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
bool metric_no_merge,
struct perf_pmu *fake_pmu,
struct rblist *metric_events_list,
- const struct pmu_event *table)
+ const struct pmu_events_table *table)
{
struct evlist *combined_evlist = NULL;
LIST_HEAD(metric_list);
@@ -1650,14 +1650,14 @@ int metricgroup__parse_groups(const struct option *opt,
struct rblist *metric_events)
{
struct evlist *perf_evlist = *(struct evlist **)opt->value;
- const struct pmu_event *table = pmu_events_map__find();
+ const struct pmu_events_table *table = pmu_events_map__find();
return parse_groups(perf_evlist, str, metric_no_group,
metric_no_merge, NULL, metric_events, table);
}
int metricgroup__parse_groups_test(struct evlist *evlist,
- const struct pmu_event *table,
+ const struct pmu_events_table *table,
const char *str,
bool metric_no_group,
bool metric_no_merge,
@@ -1668,7 +1668,7 @@ int metricgroup__parse_groups_test(struct evlist *evlist,
}
static int metricgroup__has_metric_callback(const struct pmu_event *pe,
- const struct pmu_event *table __maybe_unused,
+ const struct pmu_events_table *table __maybe_unused,
void *vdata)
{
const char *metric = vdata;
@@ -1684,7 +1684,7 @@ static int metricgroup__has_metric_callback(const struct pmu_event *pe,
bool metricgroup__has_metric(const char *metric)
{
- const struct pmu_event *table = pmu_events_map__find();
+ const struct pmu_events_table *table = pmu_events_map__find();
if (!table)
return false;
diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
index 5a1390e73d25..f54d170043e9 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -11,7 +11,6 @@ struct evlist;
struct evsel;
struct option;
struct rblist;
-struct pmu_events_map;
struct cgroup;
/**
@@ -71,9 +70,9 @@ int metricgroup__parse_groups(const struct option *opt,
bool metric_no_merge,
struct rblist *metric_events);
const struct pmu_event *metricgroup__find_metric(const char *metric,
- const struct pmu_event *table);
+ const struct pmu_events_table *table);
int metricgroup__parse_groups_test(struct evlist *evlist,
- const struct pmu_event *table,
+ const struct pmu_events_table *table,
const char *str,
bool metric_no_group,
bool metric_no_merge,
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index ab94d672d7bf..a84fa532817f 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -710,7 +710,7 @@ char *perf_pmu__getcpuid(struct perf_pmu *pmu)
return cpuid;
}
-__weak const struct pmu_event *pmu_events_map__find(void)
+__weak const struct pmu_events_table *pmu_events_map__find(void)
{
return perf_pmu__find_table(NULL);
}
@@ -799,7 +799,7 @@ struct pmu_add_cpu_aliases_map_data {
};
static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
- const struct pmu_event *table __maybe_unused,
+ const struct pmu_events_table *table __maybe_unused,
void *vdata)
{
struct pmu_add_cpu_aliases_map_data *data = vdata;
@@ -827,7 +827,7 @@ static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
* as aliases.
*/
void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
- const struct pmu_event *table)
+ const struct pmu_events_table *table)
{
struct pmu_add_cpu_aliases_map_data data = {
.head = head,
@@ -841,7 +841,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
{
- const struct pmu_event *table;
+ const struct pmu_events_table *table;
table = perf_pmu__find_table(pmu);
if (!table)
@@ -856,7 +856,7 @@ struct pmu_sys_event_iter_data {
};
static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe,
- const struct pmu_event *table __maybe_unused,
+ const struct pmu_events_table *table __maybe_unused,
void *data)
{
struct pmu_sys_event_iter_data *idata = data;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 06df99ba2029..78f87b46ddf3 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -126,10 +126,10 @@ int perf_pmu__test(void);
struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
- const struct pmu_event *map);
+ const struct pmu_events_table *map);
char *perf_pmu__getcpuid(struct perf_pmu *pmu);
-const struct pmu_event *pmu_events_map__find(void);
+const struct pmu_events_table *pmu_events_map__find(void);
bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
void perf_pmu_free_alias(struct perf_pmu_alias *alias);
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index b1c052c176bb..fad1e96c74ba 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -135,7 +135,7 @@ struct get_counter_name_data {
};
static int get_counter_name_callback(const struct pmu_event *evp,
- const struct pmu_event *table __maybe_unused,
+ const struct pmu_events_table *table __maybe_unused,
void *vdata)
{
struct get_counter_name_data *data = vdata;
@@ -157,7 +157,7 @@ static int get_counter_name_callback(const struct pmu_event *evp,
* the name of this counter.
* If no match is found a NULL pointer is returned.
*/
-static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
+static const char *get_counter_name(int set, int nr, const struct pmu_events_table *table)
{
struct get_counter_name_data data = {
.wanted = get_counterset_start(set) + nr,
@@ -177,7 +177,7 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
unsigned char *buf = sample->raw_data;
const char *color = PERF_COLOR_BLUE;
struct cf_ctrset_entry *cep, ce;
- const struct pmu_event *table;
+ const struct pmu_events_table *table;
u64 *p;
table = pmu_events_map__find();
--
2.37.1.559.g78731f0fdb-goog
The pmu_event passed to the pmu_events_table_for_each_event is invalid
after the loop. Copy the entire struct in metricgroup__find_metric.
Reduce the scope of this function to static.
Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/util/metricgroup.c | 33 ++++++++++++++++++---------------
tools/perf/util/metricgroup.h | 2 --
2 files changed, 18 insertions(+), 17 deletions(-)
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 8ef44f4b5e9a..95f4b46dba09 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -879,6 +879,10 @@ struct metricgroup_add_iter_data {
const struct pmu_events_table *table;
};
+static bool metricgroup__find_metric(const char *metric,
+ const struct pmu_events_table *table,
+ struct pmu_event *pe);
+
static int add_metric(struct list_head *metric_list,
const struct pmu_event *pe,
const char *modifier,
@@ -914,7 +918,7 @@ static int resolve_metric(struct list_head *metric_list,
size_t bkt;
struct to_resolve {
/* The metric to resolve. */
- const struct pmu_event *pe;
+ struct pmu_event pe;
/*
* The key in the IDs map, this may differ from in case,
* etc. from pe->metric_name.
@@ -928,16 +932,15 @@ static int resolve_metric(struct list_head *metric_list,
* the pending array.
*/
hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
- const struct pmu_event *pe;
+ struct pmu_event pe;
- pe = metricgroup__find_metric(cur->key, table);
- if (pe) {
+ if (metricgroup__find_metric(cur->key, table, &pe)) {
pending = realloc(pending,
(pending_cnt + 1) * sizeof(struct to_resolve));
if (!pending)
return -ENOMEM;
- pending[pending_cnt].pe = pe;
+ memcpy(&pending[pending_cnt].pe, &pe, sizeof(pe));
pending[pending_cnt].key = cur->key;
pending_cnt++;
}
@@ -952,7 +955,7 @@ static int resolve_metric(struct list_head *metric_list,
* context.
*/
for (i = 0; i < pending_cnt; i++) {
- ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group,
+ ret = add_metric(metric_list, &pending[i].pe, modifier, metric_no_group,
root_metric, visited, table);
if (ret)
break;
@@ -1073,7 +1076,7 @@ static int __add_metric(struct list_head *metric_list,
struct metricgroup__find_metric_data {
const char *metric;
- const struct pmu_event *pe;
+ struct pmu_event *pe;
};
static int metricgroup__find_metric_callback(const struct pmu_event *pe,
@@ -1085,21 +1088,21 @@ static int metricgroup__find_metric_callback(const struct pmu_event *pe,
if (!match_metric(pe->metric_name, data->metric))
return 0;
- data->pe = pe;
- return -1;
+ memcpy(data->pe, pe, sizeof(*pe));
+ return 1;
}
-const struct pmu_event *metricgroup__find_metric(const char *metric,
- const struct pmu_events_table *table)
+static bool metricgroup__find_metric(const char *metric,
+ const struct pmu_events_table *table,
+ struct pmu_event *pe)
{
struct metricgroup__find_metric_data data = {
.metric = metric,
- .pe = NULL,
+ .pe = pe,
};
- pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data);
-
- return data.pe;
+ return pmu_events_table_for_each_event(table, metricgroup__find_metric_callback, &data)
+ ? true : false;
}
static int add_metric(struct list_head *metric_list,
diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
index f54d170043e9..016b3b1a289a 100644
--- a/tools/perf/util/metricgroup.h
+++ b/tools/perf/util/metricgroup.h
@@ -69,8 +69,6 @@ int metricgroup__parse_groups(const struct option *opt,
bool metric_no_group,
bool metric_no_merge,
struct rblist *metric_events);
-const struct pmu_event *metricgroup__find_metric(const char *metric,
- const struct pmu_events_table *table);
int metricgroup__parse_groups_test(struct evlist *evlist,
const struct pmu_events_table *table,
const char *str,
--
2.37.1.559.g78731f0fdb-goog
Improve type hints to clean up pytype warnings.
Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/pmu-events/jevents.py | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 83e0dcbeac9a..5b72048d50da 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -6,8 +6,7 @@ import csv
import json
import os
import sys
-from typing import Callable
-from typing import Sequence
+from typing import (Callable, Optional, Sequence)
# Global command line arguments.
_args = None
@@ -57,7 +56,7 @@ class JsonEvent:
'. '), '.').replace('\n', '\\n').replace(
'\"', '\\"').replace('\r', '\\r')
- def convert_aggr_mode(aggr_mode: str) -> str:
+ def convert_aggr_mode(aggr_mode: str) -> Optional[str]:
"""Returns the aggr_mode_class enum value associated with the JSON string."""
if not aggr_mode:
return None
@@ -67,7 +66,7 @@ class JsonEvent:
}
return aggr_mode_to_enum[aggr_mode]
- def lookup_msr(num: str) -> str:
+ def lookup_msr(num: str) -> Optional[str]:
"""Converts the msr number, or first in a list to the appropriate event field."""
if not num:
return None
@@ -79,7 +78,7 @@ class JsonEvent:
}
return msrmap[int(num.split(',', 1)[0], 0)]
- def real_event(name: str, event: str) -> str:
+ def real_event(name: str, event: str) -> Optional[str]:
"""Convert well known event names to an event string otherwise use the event argument."""
fixed = {
'inst_retired.any': 'event=0xc0,period=2000003',
@@ -95,7 +94,7 @@ class JsonEvent:
return fixed[name.lower()]
return event
- def unit_to_pmu(unit: str) -> str:
+ def unit_to_pmu(unit: str) -> Optional[str]:
"""Convert a JSON Unit to Linux PMU name."""
if not unit:
return None
@@ -154,7 +153,7 @@ class JsonEvent:
if self.metric_expr:
self.metric_expr = self.metric_expr.replace('\\', '\\\\')
arch_std = jd.get('ArchStdEvent')
- if precise and self.desc and not '(Precise Event)' in self.desc:
+ if precise and self.desc and '(Precise Event)' not in self.desc:
extra_desc += ' (Must be precise)' if precise == '2' else (' (Precise '
'event)')
event = f'config={llx(configcode)}' if configcode is not None else f'event={llx(eventcode)}'
--
2.37.1.559.g78731f0fdb-goog
Move usage of the table to pmu-events.c so it may be hidden. By
abstracting the table the implementation can later be changed.
Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/pmu-events/empty-pmu-events.c | 81 ++++++++-
tools/perf/pmu-events/jevents.py | 81 ++++++++-
tools/perf/pmu-events/pmu-events.h | 29 +--
tools/perf/tests/pmu-events.c | 218 +++++++++++------------
tools/perf/util/metricgroup.c | 15 +-
tools/perf/util/pmu.c | 34 +---
tools/perf/util/pmu.h | 2 +-
7 files changed, 280 insertions(+), 180 deletions(-)
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index 216ea0482c37..8ef75aff996c 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -6,6 +6,8 @@
* The test cpu/soc is provided for testing.
*/
#include "pmu-events/pmu-events.h"
+#include "util/header.h"
+#include "util/pmu.h"
#include <string.h>
#include <stddef.h>
@@ -110,7 +112,26 @@ static const struct pmu_event pme_test_soc_cpu[] = {
},
};
-const struct pmu_events_map pmu_events_map[] = {
+
+/*
+ * Map a CPU to its table of PMU events. The CPU is identified by the
+ * cpuid field, which is an arch-specific identifier for the CPU.
+ * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
+ * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
+ *
+ * The cpuid can contain any character other than the comma.
+ */
+struct pmu_events_map {
+ const char *arch;
+ const char *cpuid;
+ const struct pmu_event *table;
+};
+
+/*
+ * Global table mapping each known CPU for the architecture to its
+ * table of PMU events.
+ */
+static const struct pmu_events_map pmu_events_map[] = {
{
.arch = "testarch",
.cpuid = "testcpu",
@@ -162,6 +183,62 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
},
};
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+{
+ const struct pmu_event *table = NULL;
+ char *cpuid = perf_pmu__getcpuid(pmu);
+ int i;
+
+ /* on some platforms which uses cpus map, cpuid can be NULL for
+ * PMUs other than CORE PMUs.
+ */
+ if (!cpuid)
+ return NULL;
+
+ i = 0;
+ for (;;) {
+ const struct pmu_events_map *map = &pmu_events_map[i++];
+
+ if (!map->table)
+ break;
+
+ if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
+ table = map->table;
+ break;
+ }
+ }
+ free(cpuid);
+ return table;
+}
+
+const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+{
+ for (const struct pmu_events_map *tables = &pmu_events_map[0];
+ tables->table;
+ tables++) {
+ if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
+ return tables->table;
+ }
+ return NULL;
+}
+
+int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
+{
+ for (const struct pmu_events_map *tables = &pmu_events_map[0];
+ tables->table;
+ tables++) {
+ for (const struct pmu_event *pe = &tables->table[0];
+ pe->name || pe->metric_group || pe->metric_name;
+ pe++) {
+ int ret = fn(pe, &tables->table[0], data);
+
+ if (ret)
+ return ret;
+ }
+ }
+ return 0;
+}
+
const struct pmu_event *find_sys_events_table(const char *name)
{
for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
@@ -181,7 +258,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
for (const struct pmu_event *pe = &tables->table[0];
pe->name || pe->metric_group || pe->metric_name;
pe++) {
- int ret = fn(pe, data);
+ int ret = fn(pe, &tables->table[0], data);
if (ret)
return ret;
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index dd21bc9eeeed..e976c5e8e80b 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -333,7 +333,27 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
def print_mapping_table(archs: Sequence[str]) -> None:
"""Read the mapfile and generate the struct from cpuid string to event table."""
- _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
+ _args.output_file.write("""
+/*
+ * Map a CPU to its table of PMU events. The CPU is identified by the
+ * cpuid field, which is an arch-specific identifier for the CPU.
+ * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
+ * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
+ *
+ * The cpuid can contain any character other than the comma.
+ */
+struct pmu_events_map {
+ const char *arch;
+ const char *cpuid;
+ const struct pmu_event *table;
+};
+
+/*
+ * Global table mapping each known CPU for the architecture to its
+ * table of PMU events.
+ */
+const struct pmu_events_map pmu_events_map[] = {
+""")
for arch in archs:
if arch == 'test':
_args.output_file.write("""{
@@ -389,6 +409,61 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
\t},
};
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+{
+ const struct pmu_event *table = NULL;
+ char *cpuid = perf_pmu__getcpuid(pmu);
+ int i;
+
+ /* on some platforms which uses cpus map, cpuid can be NULL for
+ * PMUs other than CORE PMUs.
+ */
+ if (!cpuid)
+ return NULL;
+
+ i = 0;
+ for (;;) {
+ const struct pmu_events_map *map = &pmu_events_map[i++];
+ if (!map->table)
+ break;
+
+ if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
+ table = map->table;
+ break;
+ }
+ }
+ free(cpuid);
+ return table;
+}
+
+const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+{
+ for (const struct pmu_events_map *tables = &pmu_events_map[0];
+ tables->table;
+ tables++) {
+ if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
+ return tables->table;
+ }
+ return NULL;
+}
+
+int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
+{
+ for (const struct pmu_events_map *tables = &pmu_events_map[0];
+ tables->table;
+ tables++) {
+ for (const struct pmu_event *pe = &tables->table[0];
+ pe->name || pe->metric_group || pe->metric_name;
+ pe++) {
+ int ret = fn(pe, &tables->table[0], data);
+
+ if (ret)
+ return ret;
+ }
+ }
+ return 0;
+}
+
const struct pmu_event *find_sys_events_table(const char *name)
{
for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
@@ -408,7 +483,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
for (const struct pmu_event *pe = &tables->table[0];
pe->name || pe->metric_group || pe->metric_name;
pe++) {
- int ret = fn(pe, data);
+ int ret = fn(pe, &tables->table[0], data);
if (ret)
return ret;
@@ -449,6 +524,8 @@ def main() -> None:
_args.output_file.write("""
#include "pmu-events/pmu-events.h"
+#include "util/header.h"
+#include "util/pmu.h"
#include <string.h>
#include <stddef.h>
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 2386212b1df0..485e730f9922 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -2,6 +2,8 @@
#ifndef PMU_EVENTS_H
#define PMU_EVENTS_H
+struct perf_pmu;
+
enum aggr_mode_class {
PerChip = 1,
PerCore
@@ -28,30 +30,15 @@ struct pmu_event {
const char *metric_constraint;
};
-/*
- *
- * Map a CPU to its table of PMU events. The CPU is identified by the
- * cpuid field, which is an arch-specific identifier for the CPU.
- * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
- * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
- *
- * The cpuid can contain any character other than the comma.
- */
-struct pmu_events_map {
- const char *arch;
- const char *cpuid;
- const struct pmu_event *table;
-};
+typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
+ const struct pmu_event *table,
+ void *data);
-/*
- * Global table mapping each known CPU for the architecture to its
- * table of PMU events.
- */
-extern const struct pmu_events_map pmu_events_map[];
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
+const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid);
+int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data);
const struct pmu_event *find_sys_events_table(const char *name);
-
-typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe, void *data);
int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data);
#endif
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index b3cde5f98982..ea8b41b5c4e3 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -272,18 +272,6 @@ static bool is_same(const char *reference, const char *test)
return !strcmp(reference, test);
}
-static const struct pmu_event *__test_pmu_get_events_table(void)
-{
- for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
- if (!strcmp(map->cpuid, "testcpu"))
- return map->table;
- }
-
- pr_err("could not find test events map\n");
-
- return NULL;
-}
-
static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event *e2)
{
if (!is_same(e1->name, e2->name)) {
@@ -438,7 +426,7 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
- const struct pmu_event *table = __test_pmu_get_events_table();
+ const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
int map_events = 0, expected_events;
/* ignore 3x sentinels */
@@ -534,7 +522,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
struct perf_pmu *pmu;
LIST_HEAD(aliases);
int res = 0;
- const struct pmu_event *table = __test_pmu_get_events_table();
+ const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
struct perf_pmu_alias *a, *tmp;
if (!table)
@@ -591,7 +579,7 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
LIST_HEAD(aliases);
int res = 0;
- events_table = __test_pmu_get_events_table();
+ events_table = find_core_events_table("testarch", "testcpu");
if (!events_table)
return -1;
pmu_add_cpu_aliases_map(&aliases, pmu, events_table);
@@ -845,11 +833,6 @@ static int check_parse_fake(const char *id)
return ret;
}
-static void expr_failure(const char *msg, const struct pmu_event *pe)
-{
- pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
-}
-
struct metric {
struct list_head list;
struct metric_ref metric_ref;
@@ -915,93 +898,100 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx,
}
-static int test__parsing(struct test_suite *test __maybe_unused,
- int subtest __maybe_unused)
+static void expr_failure(const char *msg, const struct pmu_event *pe)
{
- const struct pmu_event *cpus_table = pmu_events_map__find();
- const struct pmu_event *pe;
- int i, j, k;
- int ret = 0;
+ pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
+}
+
+
+struct test__parsing_data {
+ const struct pmu_event *cpus_table;
struct expr_parse_ctx *ctx;
+ int failures;
+};
+
+static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_event *table,
+ void *vdata)
+{
+ struct test__parsing_data *data = vdata;
+ struct metric *metric, *tmp;
+ struct hashmap_entry *cur;
+ LIST_HEAD(compound_list);
+ size_t bkt;
+ int k;
double result;
- ctx = expr__ctx_new();
- if (!ctx) {
- pr_debug("expr__ctx_new failed");
- return TEST_FAIL;
+ if (!pe->metric_expr)
+ return 0;
+
+ pr_debug("Found metric '%s'\n", pe->metric_name);
+
+ expr__ctx_clear(data->ctx);
+ if (expr__find_ids(pe->metric_expr, NULL, data->ctx) < 0) {
+ expr_failure("Parse find ids failed", pe);
+ data->failures++;
+ return 0;
}
- i = 0;
- for (;;) {
- const struct pmu_events_map *map = &pmu_events_map[i++];
- if (!map->table)
- break;
- j = 0;
- for (;;) {
- struct metric *metric, *tmp;
- struct hashmap_entry *cur;
- LIST_HEAD(compound_list);
- size_t bkt;
-
- pe = &map->table[j++];
- if (!pe->name && !pe->metric_group && !pe->metric_name)
- break;
- if (!pe->metric_expr)
- continue;
- expr__ctx_clear(ctx);
- if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
- expr_failure("Parse find ids failed", pe);
- ret++;
- continue;
- }
+ if (resolve_metric_simple(data->ctx, &compound_list, table,
+ pe->metric_name)) {
+ expr_failure("Could not resolve metrics", pe);
+ data->failures++;
+ return TEST_FAIL; /* Don't tolerate errors due to severity */
+ }
- if (resolve_metric_simple(ctx, &compound_list, map->table,
- pe->metric_name)) {
- expr_failure("Could not resolve metrics", pe);
- ret++;
- goto exit; /* Don't tolerate errors due to severity */
- }
+ /*
+ * Add all ids with a made up value. The value may trigger divide by
+ * zero when subtracted and so try to make them unique.
+ */
+ k = 1;
+ hashmap__for_each_entry(data->ctx->ids, cur, bkt)
+ expr__add_id_val(data->ctx, strdup(cur->key), k++);
- /*
- * Add all ids with a made up value. The value may
- * trigger divide by zero when subtracted and so try to
- * make them unique.
- */
- k = 1;
- hashmap__for_each_entry(ctx->ids, cur, bkt)
- expr__add_id_val(ctx, strdup(cur->key), k++);
-
- hashmap__for_each_entry(ctx->ids, cur, bkt) {
- if (check_parse_cpu(cur->key, map->table == cpus_table,
- pe))
- ret++;
- }
+ hashmap__for_each_entry(data->ctx->ids, cur, bkt) {
+ if (check_parse_cpu(cur->key, table == data->cpus_table, pe))
+ data->failures++;
+ }
- list_for_each_entry_safe(metric, tmp, &compound_list, list) {
- expr__add_ref(ctx, &metric->metric_ref);
- free(metric);
- }
+ list_for_each_entry_safe(metric, tmp, &compound_list, list) {
+ expr__add_ref(data->ctx, &metric->metric_ref);
+ free(metric);
+ }
- if (expr__parse(&result, ctx, pe->metric_expr)) {
- /*
- * Parsing failed, make numbers go from large to
- * small which can resolve divide by zero
- * issues.
- */
- k = 1024;
- hashmap__for_each_entry(ctx->ids, cur, bkt)
- expr__add_id_val(ctx, strdup(cur->key), k--);
- if (expr__parse(&result, ctx, pe->metric_expr)) {
- expr_failure("Parse failed", pe);
- ret++;
- }
- }
+ if (expr__parse(&result, data->ctx, pe->metric_expr)) {
+ /*
+ * Parsing failed, make numbers go from large to small which can
+ * resolve divide by zero issues.
+ */
+ k = 1024;
+ hashmap__for_each_entry(data->ctx->ids, cur, bkt)
+ expr__add_id_val(data->ctx, strdup(cur->key), k--);
+ if (expr__parse(&result, data->ctx, pe->metric_expr)) {
+ expr_failure("Parse failed", pe);
+ data->failures++;
}
}
- expr__ctx_free(ctx);
- /* TODO: fail when not ok */
-exit:
- return ret == 0 ? TEST_OK : TEST_SKIP;
+ return 0;
+}
+
+static int test__parsing(struct test_suite *test __maybe_unused,
+ int subtest __maybe_unused)
+{
+ struct test__parsing_data data = {
+ .cpus_table = pmu_events_map__find(),
+ .ctx = expr__ctx_new(),
+ .failures = 0,
+ };
+
+ if (!data.ctx) {
+ pr_debug("expr__ctx_new failed");
+ return TEST_FAIL;
+ }
+ pmu_for_each_core_event(test__parsing_callback, &data);
+ pmu_for_each_sys_event(test__parsing_callback, &data);
+
+ expr__ctx_free(data.ctx);
+ return data.failures == 0 ? TEST_OK : TEST_FAIL;
}
struct test_metric {
@@ -1073,6 +1063,16 @@ static int metric_parse_fake(const char *str)
return ret;
}
+static int test__parsing_fake_callback(const struct pmu_event *pe,
+ const struct pmu_event *table __maybe_unused,
+ void *data __maybe_unused)
+{
+ if (!pe->metric_expr)
+ return 0;
+
+ return metric_parse_fake(pe->metric_expr);
+}
+
/*
* Parse all the metrics for current architecture,
* or all defined cpus via the 'fake_pmu'
@@ -1081,37 +1081,19 @@ static int metric_parse_fake(const char *str)
static int test__parsing_fake(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
- unsigned int i, j;
int err = 0;
- for (i = 0; i < ARRAY_SIZE(metrics); i++) {
+ for (size_t i = 0; i < ARRAY_SIZE(metrics); i++) {
err = metric_parse_fake(metrics[i].str);
if (err)
return err;
}
- i = 0;
- for (;;) {
- const struct pmu_events_map *map = &pmu_events_map[i++];
+ err = pmu_for_each_core_event(test__parsing_fake_callback, NULL);
+ if (err)
+ return err;
- if (!map->table)
- break;
- j = 0;
- for (;;) {
- const struct pmu_event *pe = &map->table[j++];
-
- if (!pe->name && !pe->metric_group && !pe->metric_name)
- break;
- if (!pe->metric_expr)
- continue;
- pr_debug("Found metric '%s' for '%s'\n", pe->metric_name, map->cpuid);
- err = metric_parse_fake(pe->metric_expr);
- if (err)
- return err;
- }
- }
-
- return 0;
+ return pmu_for_each_sys_event(test__parsing_fake_callback, NULL);
}
static struct test_case pmu_events_tests[] = {
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 4d32b4fbf67d..680f7c63838d 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -502,14 +502,14 @@ struct metricgroup_print_sys_idata {
bool details;
};
-typedef int (*metricgroup_sys_event_iter_fn)(const struct pmu_event *pe, void *);
-
struct metricgroup_iter_data {
- metricgroup_sys_event_iter_fn fn;
+ pmu_event_iter_fn fn;
void *data;
};
-static int metricgroup__sys_event_iter(const struct pmu_event *pe, void *data)
+static int metricgroup__sys_event_iter(const struct pmu_event *pe,
+ const struct pmu_event *table __maybe_unused,
+ void *data)
{
struct metricgroup_iter_data *d = data;
struct perf_pmu *pmu = NULL;
@@ -522,13 +522,15 @@ static int metricgroup__sys_event_iter(const struct pmu_event *pe, void *data)
if (!pmu->id || strcmp(pmu->id, pe->compat))
continue;
- return d->fn(pe, d->data);
+ return d->fn(pe, table, d->data);
}
return 0;
}
-static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *data)
+static int metricgroup__print_sys_event_iter(const struct pmu_event *pe,
+ const struct pmu_event *table __maybe_unused,
+ void *data)
{
struct metricgroup_print_sys_idata *d = data;
@@ -1101,6 +1103,7 @@ static int add_metric(struct list_head *metric_list,
}
static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
+ const struct pmu_event *table __maybe_unused,
void *data)
{
struct metricgroup_add_iter_data *d = data;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index f3e3c4a147e9..5bb03d4e52a3 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -690,7 +690,7 @@ static int is_arm_pmu_core(const char *name)
return file_available(path);
}
-static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
+char *perf_pmu__getcpuid(struct perf_pmu *pmu)
{
char *cpuid;
static bool printed;
@@ -710,34 +710,6 @@ static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
return cpuid;
}
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
-{
- const struct pmu_event *table = NULL;
- char *cpuid = perf_pmu__getcpuid(pmu);
- int i;
-
- /* on some platforms which uses cpus map, cpuid can be NULL for
- * PMUs other than CORE PMUs.
- */
- if (!cpuid)
- return NULL;
-
- i = 0;
- for (;;) {
- const struct pmu_events_map *map = &pmu_events_map[i++];
-
- if (!map->table)
- break;
-
- if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
- table = map->table;
- break;
- }
- }
- free(cpuid);
- return table;
-}
-
__weak const struct pmu_event *pmu_events_map__find(void)
{
return perf_pmu__find_table(NULL);
@@ -874,7 +846,9 @@ struct pmu_sys_event_iter_data {
struct perf_pmu *pmu;
};
-static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe, void *data)
+static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe,
+ const struct pmu_event *table __maybe_unused,
+ void *data)
{
struct pmu_sys_event_iter_data *idata = data;
struct perf_pmu *pmu = idata->pmu;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 015242c83698..06df99ba2029 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -128,7 +128,7 @@ struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
const struct pmu_event *map);
-const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
+char *perf_pmu__getcpuid(struct perf_pmu *pmu);
const struct pmu_event *pmu_events_map__find(void);
bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
void perf_pmu_free_alias(struct perf_pmu_alias *alias);
--
2.37.1.559.g78731f0fdb-goog
The pmu_events array requires 15 pointers per entry which in position
independent code need relocating. Change the array to be an array of
offsets within a big C string. Only the offset of the first variable is
required, subsequent variables are stored in order after the \0
terminator (requiring a byte per variable rather than 4 bytes per
offset).
The file size savings are:
no jevents - the same 19,788,464bytes
x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
default build options plus NO_LIBBFD=1.
For example, the x86 build savings come from .rela.dyn and
.data.rel.ro becoming smaller by 3,157,032bytes and 3,042,016bytes
respectively. .rodata increases by 1,432,448bytes, giving an overall
4,766,600bytes saving.
To make metric strings more shareable, the topic is changed from say
'skx metrics' to just 'metrics'.
To try to help with the memory layout the pmu_events are ordered as used
by perf qsort comparator functions.
Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/pmu-events/jevents.py | 207 ++++++++++++++++++++++++-------
1 file changed, 162 insertions(+), 45 deletions(-)
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index aa8df649025a..a5e162558994 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -6,7 +6,8 @@ import csv
import json
import os
import sys
-from typing import (Callable, Optional, Sequence)
+from typing import (Callable, Dict, Optional, Sequence, Set, Tuple)
+import collections
# Global command line arguments.
_args = None
@@ -20,6 +21,19 @@ _arch_std_events = {}
_close_table = False
# Events to write out when the table is closed
_pending_events = []
+# Global BigCString shared by all structures.
+_bcs = None
+# Order specific JsonEvent attributes will be visited.
+_json_event_attributes = [
+ # cmp_sevent related attributes.
+ 'name', 'pmu', 'topic', 'desc', 'metric_name', 'metric_group',
+ # Seems useful, put it early.
+ 'event',
+ # Short things in alphabetical order.
+ 'aggr_mode', 'compat', 'deprecated', 'perpkg', 'unit',
+ # Longer things (the last won't be iterated over during decompress).
+ 'metric_constraint', 'metric_expr', 'long_desc'
+]
def removesuffix(s: str, suffix: str) -> str:
@@ -39,6 +53,66 @@ def file_name_to_table_name(parents: Sequence[str], dirname: str) -> str:
tblname += '_' + dirname
return tblname.replace('-', '_')
+def c_len(s: str) -> int:
+ """Return the length of s a C string
+
+ This doesn't handle all escape characters properly. It first assumes
+ all \ are for escaping, it then adjusts as it will have over counted
+ \\. The code uses \000 rather than \0 as a terminator as an adjacent
+ number would be folded into a string of \0 (ie. "\0" + "5" doesn't
+ equal a terminator followed by the number 5 but the escape of
+ \05). The code adjusts for \000 but not properly for all octal, hex
+ or unicode values.
+ """
+ try:
+ utf = s.encode(encoding='utf-8',errors='strict')
+ except:
+ print(f'broken string {s}')
+ raise
+ return len(utf) - utf.count(b'\\') + utf.count(b'\\\\') - (utf.count(b'\\000') * 2)
+
+class BigCString:
+ """A class to hold many strings concatenated together.
+
+ Generating a large number of stand-alone C strings creates a large
+ number of relocations in position independent code. The BigCString
+ is a helper for this case. It builds a single string which within it
+ are all the other C strings (to avoid memory issues the string
+ itself is held as a list of strings). The offsets within the big
+ string are recorded and when stored to disk these don't need
+ relocation.
+ """
+ strings: Set[str]
+ big_string: Sequence[str]
+ offsets: Dict[str, int]
+
+ def __init__(self):
+ self.strings = set()
+
+ def add(self, s: str) -> None:
+ """Called to add to the big string."""
+ self.strings.add(s)
+
+ def compute(self) -> None:
+ """Called once all strings are added to compute the string and offsets."""
+
+ # big_string_offset is the current location within the C string
+ # being appended to - comments, etc. don't count. big_string is
+ # the string contents represented as a list. Strings are immutable
+ # in Python and so appending to one causes memory issues, while
+ # lists are mutable.
+ big_string_offset = 0
+ self.big_string = []
+ self.offsets = {}
+ # Emit all strings in a sorted manner.
+ for s in sorted(self.strings):
+ self.offsets[s] = big_string_offset
+ self.big_string.append(f'/* offset={big_string_offset} */ "')
+ self.big_string.append(s)
+ self.big_string.append('"\n')
+ big_string_offset += c_len(s)
+
+_bcs = BigCString()
class JsonEvent:
"""Representation of an event loaded from a json file dictionary."""
@@ -202,26 +276,18 @@ class JsonEvent:
s += f'\t{attr} = {value},\n'
return s + '}'
+ def build_c_string(self) -> str:
+ s = ''
+ for attr in _json_event_attributes:
+ x = getattr(self, attr)
+ s += f'{x}\\000' if x else '\\000'
+ return s
+
def to_c_string(self) -> str:
"""Representation of the event as a C struct initializer."""
- def attr_string(attr: str, value: str) -> str:
- return f'\t.{attr} = \"{value}\",\n'
-
- def str_if_present(self, attr: str) -> str:
- if not getattr(self, attr):
- return ''
- return attr_string(attr, getattr(self, attr))
-
- s = '{\n'
- for attr in [
- 'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
- 'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
- 'name', 'perpkg', 'pmu', 'topic', 'unit'
- ]:
- s += str_if_present(self, attr)
- s += '},\n'
- return s
+ s = self.build_c_string()
+ return f'{{ { _bcs.offsets[s] } }}, /* {s} */\n'
def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
@@ -236,7 +302,6 @@ def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
event.topic = topic
return result
-
def preprocess_arch_std_files(archpath: str) -> None:
"""Read in all architecture standard events."""
global _arch_std_events
@@ -252,7 +317,7 @@ def print_events_table_prefix(tblname: str) -> None:
global _close_table
if _close_table:
raise IOError('Printing table prefix but last table has no suffix')
- _args.output_file.write(f'static const struct pmu_event {tblname}[] = {{\n')
+ _args.output_file.write(f'static const struct compact_pmu_event {tblname}[] = {{\n')
_close_table = True
@@ -267,13 +332,13 @@ def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
def print_events_table_suffix() -> None:
"""Optionally close events table."""
- def event_cmp_key(j: JsonEvent):
- def fix_none(s: str):
+ def event_cmp_key(j: JsonEvent) -> Tuple[bool, str, str, str, str]:
+ def fix_none(s: Optional[str]) -> str:
if s is None:
return ''
return s
- return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
+ return (j.desc is not None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
fix_none(j.metric_name))
global _close_table
@@ -285,23 +350,37 @@ def print_events_table_suffix() -> None:
_args.output_file.write(event.to_c_string())
_pending_events = []
- _args.output_file.write("""{
-\t.name = 0,
-\t.event = 0,
-\t.desc = 0,
-},
-};
-""")
+ _args.output_file.write('};\n\n')
_close_table = False
+def get_topic(topic: str) -> str:
+ if topic.endswith('metrics.json'):
+ return 'metrics'
+ return removesuffix(topic, '.json').replace('-', ' ')
+
+def preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
+
+ if item.is_dir():
+ return
+
+ # base dir or too deep
+ level = len(parents)
+ if level == 0 or level > 4:
+ return
+
+ # Ignore other directories. If the file name does not have a .json
+ # extension, ignore it. It could be a readme.txt for instance.
+ if not item.is_file() or not item.name.endswith('.json'):
+ return
+
+ topic = get_topic(item.name)
+ for event in read_json_events(item.path, topic):
+ _bcs.add(event.build_c_string())
def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
"""Process a JSON file during the main walk."""
global _sys_event_tables
- def get_topic(topic: str) -> str:
- return removesuffix(topic, '.json').replace('-', ' ')
-
def is_leaf_dir(path: str) -> bool:
for item in os.scandir(path):
if item.is_dir():
@@ -336,7 +415,8 @@ def print_mapping_table(archs: Sequence[str]) -> None:
_args.output_file.write("""
/* Struct used to make the PMU event table implementation opaque to callers. */
struct pmu_events_table {
- const struct pmu_event *entries;
+ const struct compact_pmu_event *entries;
+ size_t length;
};
/*
@@ -364,7 +444,10 @@ const struct pmu_events_map pmu_events_map[] = {
_args.output_file.write("""{
\t.arch = "testarch",
\t.cpuid = "testcpu",
-\t.table = { pme_test_soc_cpu },
+\t.table = {
+\t.entries = pme_test_soc_cpu,
+\t.length = ARRAY_SIZE(pme_test_soc_cpu),
+\t}
},
""")
else:
@@ -379,7 +462,10 @@ const struct pmu_events_map pmu_events_map[] = {
_args.output_file.write(f"""{{
\t.arch = "{arch}",
\t.cpuid = "{cpuid}",
-\t.table = {{ {tblname} }}
+\t.table = {{
+\t\t.entries = {tblname},
+\t\t.length = ARRAY_SIZE({tblname})
+\t}}
}},
""")
first = False
@@ -387,7 +473,7 @@ const struct pmu_events_map pmu_events_map[] = {
_args.output_file.write("""{
\t.arch = 0,
\t.cpuid = 0,
-\t.table = { 0 },
+\t.table = { 0, 0 },
}
};
""")
@@ -405,23 +491,41 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
""")
for tblname in _sys_event_tables:
_args.output_file.write(f"""\t{{
-\t\t.table = {{ {tblname} }},
+\t\t.table = {{
+\t\t\t.entries = {tblname},
+\t\t\t.length = ARRAY_SIZE({tblname})
+\t\t}},
\t\t.name = \"{tblname}\",
\t}},
""")
_args.output_file.write("""\t{
-\t\t.table = { 0 }
+\t\t.table = { 0, 0 }
\t},
};
-int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
+static void decompress(int offset, struct pmu_event *pe)
+{
+\tconst char *p = &big_c_string[offset];
+""")
+ for attr in _json_event_attributes:
+ _args.output_file.write(f"""
+\tpe->{attr} = (*p == '\\0' ? NULL : p);
+""")
+ if attr == _json_event_attributes[-1]:
+ continue
+ _args.output_file.write('\twhile (*p++);')
+ _args.output_file.write("""}
+
+int pmu_events_table_for_each_event(const struct pmu_events_table *table,
+ pmu_event_iter_fn fn,
void *data)
{
- for (const struct pmu_event *pe = &table->entries[0];
- pe->name || pe->metric_group || pe->metric_name;
- pe++) {
- int ret = fn(pe, table, data);
+ for (size_t i = 0; i < table->length; i++) {
+ struct pmu_event pe;
+ int ret;
+ decompress(table->entries[i].offset, &pe);
+ ret = fn(&pe, table, data);
if (ret)
return ret;
}
@@ -530,7 +634,7 @@ def main() -> None:
help='Root of tree containing architecture directories containing json files'
)
ap.add_argument(
- 'output_file', type=argparse.FileType('w'), nargs='?', default=sys.stdout)
+ 'output_file', type=argparse.FileType('w', encoding='utf-8'), nargs='?', default=sys.stdout)
_args = ap.parse_args()
_args.output_file.write("""
@@ -540,6 +644,10 @@ def main() -> None:
#include <string.h>
#include <stddef.h>
+struct compact_pmu_event {
+ int offset;
+};
+
""")
archs = []
for item in os.scandir(_args.starting_dir):
@@ -555,6 +663,15 @@ def main() -> None:
for arch in archs:
arch_path = f'{_args.starting_dir}/{arch}'
preprocess_arch_std_files(arch_path)
+ ftw(arch_path, [], preprocess_one_file)
+
+ _bcs.compute()
+ _args.output_file.write('static const char *const big_c_string =\n')
+ for s in _bcs.big_string:
+ _args.output_file.write(s)
+ _args.output_file.write(';\n\n')
+ for arch in archs:
+ arch_path = f'{_args.starting_dir}/{arch}'
ftw(arch_path, [], process_one_file)
print_events_table_suffix()
--
2.37.1.559.g78731f0fdb-goog
pmu_events_map has a type variable that is always initialized to "core"
and a version variable that is never read. Remove these from the API as
it is straightforward to add them back when necessary.
Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/pmu-events/empty-pmu-events.c | 4 ----
tools/perf/pmu-events/jevents.py | 6 ------
tools/perf/pmu-events/pmu-events.h | 2 --
tools/perf/tests/expand-cgroup.c | 2 --
tools/perf/tests/parse-metric.c | 2 --
5 files changed, 16 deletions(-)
diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
index d8cf9283e486..4182a986f505 100644
--- a/tools/perf/pmu-events/empty-pmu-events.c
+++ b/tools/perf/pmu-events/empty-pmu-events.c
@@ -112,15 +112,11 @@ const struct pmu_events_map pmu_events_map[] = {
{
.arch = "testarch",
.cpuid = "testcpu",
- .version = "v1",
- .type = "core",
.table = pme_test_soc_cpu,
},
{
.arch = 0,
.cpuid = 0,
- .version = 0,
- .type = 0,
.table = 0,
},
};
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index e6e6c42c3f8a..98d18d5c3830 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -312,8 +312,6 @@ def print_mapping_table(archs: Sequence[str]) -> None:
_args.output_file.write("""{
\t.arch = "testarch",
\t.cpuid = "testcpu",
-\t.version = "v1",
-\t.type = "core",
\t.table = pme_test_soc_cpu,
},
""")
@@ -329,8 +327,6 @@ def print_mapping_table(archs: Sequence[str]) -> None:
_args.output_file.write(f"""{{
\t.arch = "{arch}",
\t.cpuid = "{cpuid}",
-\t.version = "{row[1]}",
-\t.type = "{row[3]}",
\t.table = {tblname}
}},
""")
@@ -339,8 +335,6 @@ def print_mapping_table(archs: Sequence[str]) -> None:
_args.output_file.write("""{
\t.arch = 0,
\t.cpuid = 0,
-\t.version = 0,
-\t.type = 0,
\t.table = 0,
}
};
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index 7a360792635f..a491b117c8ac 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -40,8 +40,6 @@ struct pmu_event {
struct pmu_events_map {
const char *arch;
const char *cpuid;
- const char *version;
- const char *type; /* core, uncore etc */
const struct pmu_event *table;
};
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index dfefe5b60eb2..dc4038f997d7 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -197,8 +197,6 @@ static int expand_metric_events(void)
};
const struct pmu_events_map ev_map = {
.cpuid = "test",
- .version = "1",
- .type = "core",
.table = pme_test,
};
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 07b6f4ec024f..1b811a26f4ee 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -81,8 +81,6 @@ static struct pmu_event pme_test[] = {
static const struct pmu_events_map map = {
.cpuid = "test",
- .version = "1",
- .type = "core",
.table = pme_test,
};
--
2.37.1.559.g78731f0fdb-goog
If a shorter string ends a longer string then the shorter string may
reuse the longer string at an offset. For example, on x86 the event
arith.cycles_div_busy and cycles_div_busy can be folded, even though
they have difference names the strings are identical after 6
characters. cycles_div_busy can reuse the arith.cycles_div_busy string
at an offset of 6.
In pmu-events.c this looks like the following where the 'also:' lists
folded strings:
/* offset=177541 */ "arith.cycles_div_busy\000\000pipeline\000Cycles the divider is busy\000\000\000event=0x14,period=2000000,umask=0x1\000\000\000\000\000\000\000\000\000" /* also: cycles_div_busy\000\000pipeline\000Cycles the divider is busy\000\000\000event=0x14,period=2000000,umask=0x1\000\000\000\000\000\000\000\000\000 */
As jevents.py combines multiple strings for an event into a larger
string, the amount of folding is minimal as all parts of the event must
align. Other organizations can benefit more from folding, but lose space
by say recording more offsets.
Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/pmu-events/jevents.py | 55 ++++++++++++++++++++++++++++----
1 file changed, 48 insertions(+), 7 deletions(-)
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index a5e162558994..e5545758c92d 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -80,7 +80,9 @@ class BigCString:
are all the other C strings (to avoid memory issues the string
itself is held as a list of strings). The offsets within the big
string are recorded and when stored to disk these don't need
- relocation.
+ relocation. To reduce the size of the string further, identical
+ strings are merged. If a longer string ends-with the same value as a
+ shorter string, these entries are also merged.
"""
strings: Set[str]
big_string: Sequence[str]
@@ -96,6 +98,33 @@ class BigCString:
def compute(self) -> None:
"""Called once all strings are added to compute the string and offsets."""
+ folded_strings = {}
+ # Determine if two strings can be folded, ie. let 1 string use the
+ # end of another. First reverse all strings and sort them.
+ sorted_reversed_strings = sorted([x[::-1] for x in self.strings])
+
+ # Strings 'xyz' and 'yz' will now be [ 'zy', 'zyx' ]. Scan forward
+ # for each string to see if there is a better candidate to fold it
+ # into, in the example rather than using 'yz' we can use'xyz' at
+ # an offset of 1. We record which string can be folded into which
+ # in folded_strings, we don't need to record the offset as it is
+ # trivially computed from the string lengths.
+ for pos,s in enumerate(sorted_reversed_strings):
+ best_pos = pos
+ for check_pos in range(pos + 1, len(sorted_reversed_strings)):
+ if sorted_reversed_strings[check_pos].startswith(s):
+ best_pos = check_pos
+ else:
+ break
+ if pos != best_pos:
+ folded_strings[s[::-1]] = sorted_reversed_strings[best_pos][::-1]
+
+ # Compute reverse mappings for debugging.
+ fold_into_strings = collections.defaultdict(set)
+ for key, val in folded_strings.items():
+ if key != val:
+ fold_into_strings[val].add(key)
+
# big_string_offset is the current location within the C string
# being appended to - comments, etc. don't count. big_string is
# the string contents represented as a list. Strings are immutable
@@ -104,13 +133,25 @@ class BigCString:
big_string_offset = 0
self.big_string = []
self.offsets = {}
- # Emit all strings in a sorted manner.
+
+ # Emit all strings that aren't folded in a sorted manner.
for s in sorted(self.strings):
- self.offsets[s] = big_string_offset
- self.big_string.append(f'/* offset={big_string_offset} */ "')
- self.big_string.append(s)
- self.big_string.append('"\n')
- big_string_offset += c_len(s)
+ if s not in folded_strings:
+ self.offsets[s] = big_string_offset
+ self.big_string.append(f'/* offset={big_string_offset} */ "')
+ self.big_string.append(s)
+ self.big_string.append('"')
+ if s in fold_into_strings:
+ self.big_string.append(' /* also: ' + ', '.join(fold_into_strings[s]) + ' */')
+ self.big_string.append('\n')
+ big_string_offset += c_len(s)
+ continue
+
+ # Compute the offsets of the folded strings.
+ for s in folded_strings.keys():
+ assert s not in self.offsets
+ folded_s = folded_strings[s]
+ self.offsets[s] = self.offsets[folded_s] + c_len(folded_s) - c_len(s)
_bcs = BigCString()
--
2.37.1.559.g78731f0fdb-goog
The simple metric resolution doesn't handle recursion properly, switch
to use the full resolution as with the parse-metric tests which also
increases coverage. Don't set the values for the metric backward as
failures to generate a result are ignored.
Signed-off-by: Ian Rogers <[email protected]>
---
tools/perf/tests/pmu-events.c | 222 ++++++++++++----------------------
1 file changed, 77 insertions(+), 145 deletions(-)
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index ea8b41b5c4e3..e8df6bc26ebd 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -9,10 +9,12 @@
#include <linux/zalloc.h>
#include "debug.h"
#include "../pmu-events/pmu-events.h"
+#include <perf/evlist.h>
#include "util/evlist.h"
#include "util/expr.h"
#include "util/parse-events.h"
#include "metricgroup.h"
+#include "stat.h"
struct perf_pmu_test_event {
/* used for matching against events from generated pmu-events.c */
@@ -801,27 +803,6 @@ static int check_parse_id(const char *id, struct parse_events_error *error,
return ret;
}
-static int check_parse_cpu(const char *id, bool same_cpu, const struct pmu_event *pe)
-{
- struct parse_events_error error;
- int ret;
-
- parse_events_error__init(&error);
- ret = check_parse_id(id, &error, NULL);
- if (ret && same_cpu) {
- pr_warning("Parse event failed metric '%s' id '%s' expr '%s'\n",
- pe->metric_name, id, pe->metric_expr);
- pr_warning("Error string '%s' help '%s'\n", error.str,
- error.help);
- } else if (ret) {
- pr_debug3("Parse event failed, but for an event that may not be supported by this CPU.\nid '%s' metric '%s' expr '%s'\n",
- id, pe->metric_name, pe->metric_expr);
- ret = 0;
- }
- parse_events_error__exit(&error);
- return ret;
-}
-
static int check_parse_fake(const char *id)
{
struct parse_events_error error;
@@ -838,160 +819,111 @@ struct metric {
struct metric_ref metric_ref;
};
-static int resolve_metric_simple(struct expr_parse_ctx *pctx,
- struct list_head *compound_list,
- const struct pmu_event *map,
- const char *metric_name)
-{
- struct hashmap_entry *cur, *cur_tmp;
- struct metric *metric, *tmp;
- size_t bkt;
- bool all;
- int rc;
-
- do {
- all = true;
- hashmap__for_each_entry_safe(pctx->ids, cur, cur_tmp, bkt) {
- struct metric_ref *ref;
- const struct pmu_event *pe;
-
- pe = metricgroup__find_metric(cur->key, map);
- if (!pe)
- continue;
-
- if (!strcmp(metric_name, (char *)cur->key)) {
- pr_warning("Recursion detected for metric %s\n", metric_name);
- rc = -1;
- goto out_err;
- }
-
- all = false;
-
- /* The metric key itself needs to go out.. */
- expr__del_id(pctx, cur->key);
-
- metric = malloc(sizeof(*metric));
- if (!metric) {
- rc = -ENOMEM;
- goto out_err;
- }
-
- ref = &metric->metric_ref;
- ref->metric_name = pe->metric_name;
- ref->metric_expr = pe->metric_expr;
- list_add_tail(&metric->list, compound_list);
-
- rc = expr__find_ids(pe->metric_expr, NULL, pctx);
- if (rc)
- goto out_err;
- break; /* The hashmap has been modified, so restart */
- }
- } while (!all);
-
- return 0;
-
-out_err:
- list_for_each_entry_safe(metric, tmp, compound_list, list)
- free(metric);
-
- return rc;
-
-}
-
-static void expr_failure(const char *msg, const struct pmu_event *pe)
-{
- pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
-}
-
-
-struct test__parsing_data {
- const struct pmu_event *cpus_table;
- struct expr_parse_ctx *ctx;
- int failures;
-};
-
static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_event *table,
- void *vdata)
+ void *data)
{
- struct test__parsing_data *data = vdata;
- struct metric *metric, *tmp;
- struct hashmap_entry *cur;
- LIST_HEAD(compound_list);
- size_t bkt;
+ int *failures = data;
int k;
- double result;
+ struct evlist *evlist;
+ struct perf_cpu_map *cpus;
+ struct runtime_stat st;
+ struct evsel *evsel;
+ struct rblist metric_events = {
+ .nr_entries = 0,
+ };
+ int err = 0;
if (!pe->metric_expr)
return 0;
pr_debug("Found metric '%s'\n", pe->metric_name);
+ (*failures)++;
- expr__ctx_clear(data->ctx);
- if (expr__find_ids(pe->metric_expr, NULL, data->ctx) < 0) {
- expr_failure("Parse find ids failed", pe);
- data->failures++;
- return 0;
+ /*
+ * We need to prepare evlist for stat mode running on CPU 0
+ * because that's where all the stats are going to be created.
+ */
+ evlist = evlist__new();
+ if (!evlist)
+ return -ENOMEM;
+
+ cpus = perf_cpu_map__new("0");
+ if (!cpus) {
+ evlist__delete(evlist);
+ return -ENOMEM;
}
- if (resolve_metric_simple(data->ctx, &compound_list, table,
- pe->metric_name)) {
- expr_failure("Could not resolve metrics", pe);
- data->failures++;
- return TEST_FAIL; /* Don't tolerate errors due to severity */
+ perf_evlist__set_maps(&evlist->core, cpus, NULL);
+ runtime_stat__init(&st);
+
+ err = metricgroup__parse_groups_test(evlist, table, pe->metric_name,
+ false, false,
+ &metric_events);
+ if (err) {
+ if (!strcmp(pe->metric_name, "M1") || !strcmp(pe->metric_name, "M2") ||
+ !strcmp(pe->metric_name, "M3")) {
+ (*failures)--;
+ pr_debug("Expected broken metric %s skipping\n", pe->metric_name);
+ err = 0;
+ }
+ goto out_err;
}
+ err = evlist__alloc_stats(evlist, false);
+ if (err)
+ goto out_err;
/*
* Add all ids with a made up value. The value may trigger divide by
* zero when subtracted and so try to make them unique.
*/
k = 1;
- hashmap__for_each_entry(data->ctx->ids, cur, bkt)
- expr__add_id_val(data->ctx, strdup(cur->key), k++);
-
- hashmap__for_each_entry(data->ctx->ids, cur, bkt) {
- if (check_parse_cpu(cur->key, table == data->cpus_table, pe))
- data->failures++;
+ perf_stat__reset_shadow_stats();
+ evlist__for_each_entry(evlist, evsel) {
+ perf_stat__update_shadow_stats(evsel, k, 0, &st);
+ if (!strcmp(evsel->name, "duration_time"))
+ update_stats(&walltime_nsecs_stats, k);
+ k++;
}
+ evlist__for_each_entry(evlist, evsel) {
+ struct metric_event *me = metricgroup__lookup(&metric_events, evsel, false);
- list_for_each_entry_safe(metric, tmp, &compound_list, list) {
- expr__add_ref(data->ctx, &metric->metric_ref);
- free(metric);
- }
+ if (me != NULL) {
+ struct metric_expr *mexp;
- if (expr__parse(&result, data->ctx, pe->metric_expr)) {
- /*
- * Parsing failed, make numbers go from large to small which can
- * resolve divide by zero issues.
- */
- k = 1024;
- hashmap__for_each_entry(data->ctx->ids, cur, bkt)
- expr__add_id_val(data->ctx, strdup(cur->key), k--);
- if (expr__parse(&result, data->ctx, pe->metric_expr)) {
- expr_failure("Parse failed", pe);
- data->failures++;
+ list_for_each_entry (mexp, &me->head, nd) {
+ if (strcmp(mexp->metric_name, pe->metric_name))
+ continue;
+ pr_debug("Result %f\n", test_generic_metric(mexp, 0, &st));
+ err = 0;
+ (*failures)--;
+ goto out_err;
+ }
}
}
- return 0;
+ pr_debug("Didn't find parsed metric %s", pe->metric_name);
+ err = 1;
+out_err:
+ if (err)
+ pr_debug("Broken metric %s\n", pe->metric_name);
+
+ /* ... cleanup. */
+ metricgroup__rblist_exit(&metric_events);
+ runtime_stat__exit(&st);
+ evlist__free_stats(evlist);
+ perf_cpu_map__put(cpus);
+ evlist__delete(evlist);
+ return err;
}
static int test__parsing(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
- struct test__parsing_data data = {
- .cpus_table = pmu_events_map__find(),
- .ctx = expr__ctx_new(),
- .failures = 0,
- };
+ int failures = 0;
- if (!data.ctx) {
- pr_debug("expr__ctx_new failed");
- return TEST_FAIL;
- }
- pmu_for_each_core_event(test__parsing_callback, &data);
- pmu_for_each_sys_event(test__parsing_callback, &data);
+ pmu_for_each_core_event(test__parsing_callback, &failures);
+ pmu_for_each_sys_event(test__parsing_callback, &failures);
- expr__ctx_free(data.ctx);
- return data.failures == 0 ? TEST_OK : TEST_FAIL;
+ return failures == 0 ? TEST_OK : TEST_FAIL;
}
struct test_metric {
--
2.37.1.559.g78731f0fdb-goog
On 04/08/2022 23:18, Ian Rogers wrote:
> Allow the architecture built into pmu-events.c to be set on the make
> command line with JEVENTS_ARCH.
>
> Signed-off-by: Ian Rogers <[email protected]>
Seems reasonable, so:
Reviewed-by: John Garry <[email protected]>
I assume that if we run on the wrong arch (than we build for) then it
has same effect as if pmu-events is not supported.
> ---
> tools/perf/pmu-events/Build | 6 +++++-
> 1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
> index 28a9d01b08af..04ef95174660 100644
> --- a/tools/perf/pmu-events/Build
> +++ b/tools/perf/pmu-events/Build
> @@ -7,6 +7,10 @@ JSON_TEST = $(shell [ -d $(JDIR_TEST) ] && \
> find $(JDIR_TEST) -name '*.json')
> JEVENTS_PY = pmu-events/jevents.py
>
> +ifeq ($(JEVENTS_ARCH),)
> +JEVENTS_ARCH=$(SRCARCH)
> +endif
> +
> #
> # Locate/process JSON files in pmu-events/arch/
> # directory and create tables in pmu-events.c.
> @@ -19,5 +23,5 @@ $(OUTPUT)pmu-events/pmu-events.c: pmu-events/empty-pmu-events.c
> else
> $(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JSON_TEST) $(JEVENTS_PY)
> $(call rule_mkdir)
> - $(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(SRCARCH) pmu-events/arch $@
> + $(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) pmu-events/arch $@
> endif
On 04/08/2022 23:18, Ian Rogers wrote:
> pmu_events_map has a type variable that is always initialized to "core"
> and a version variable that is never read. Remove these from the API as
> it is straightforward to add them back when necessary.
>
it might be worth mentioning why we don't want the fields removed from
the per-arch mapfile.csv
> Signed-off-by: Ian Rogers<[email protected]>
Reviewed-by: John Garry <[email protected]>
On 04/08/2022 23:18, Ian Rogers wrote:
> When 'all' is passed as the architecture generate a mapping table for
> all architectures. This simplifies testing. To identify the table for an
> architecture add an arch variable to the pmu_events_map.
so could this 'all' arg ever passed for perf test? I thought maybe we
could use to verify tables for all architectures - I didn't think that
we did it today.
Thanks,
John
>
> Signed-off-by: Ian Rogers <[email protected]>
> ---
> tools/perf/pmu-events/empty-pmu-events.c | 2 +
> tools/perf/pmu-events/jevents.py | 70 +++++++++++++++---------
> tools/perf/pmu-events/pmu-events.h | 1 +
> tools/perf/tests/pmu-events.c | 3 +-
> 4 files changed, 47 insertions(+), 29 deletions(-)
>
> diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> index 77e655c6f116..d8cf9283e486 100644
> --- a/tools/perf/pmu-events/empty-pmu-events.c
> +++ b/tools/perf/pmu-events/empty-pmu-events.c
> @@ -110,12 +110,14 @@ static const struct pmu_event pme_test_soc_cpu[] = {
>
> const struct pmu_events_map pmu_events_map[] = {
> {
> + .arch = "testarch",
> .cpuid = "testcpu",
> .version = "v1",
> .type = "core",
> .table = pme_test_soc_cpu,
> },
> {
> + .arch = 0,
> .cpuid = 0,
> .version = 0,
> .type = 0,
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index cdfa4e0e7557..e6e6c42c3f8a 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -304,38 +304,45 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> print_events_table_entries(item, get_topic(item.name))
>
>
> -def print_mapping_table() -> None:
> +def print_mapping_table(archs: Sequence[str]) -> None:
> """Read the mapfile and generate the struct from cpuid string to event table."""
> - with open(f'{_args.starting_dir}/{_args.arch}/mapfile.csv') as csvfile:
> - table = csv.reader(csvfile)
> - _args.output_file.write(
> - 'const struct pmu_events_map pmu_events_map[] = {\n')
> - first = True
> - 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('#'):
> - tblname = file_name_to_table_name([], row[2].replace('/', '_'))
> - _args.output_file.write("""{
> -\t.cpuid = \"%s\",
> -\t.version = \"%s\",
> -\t.type = \"%s\",
> -\t.table = %s
> -},
> -""" % (row[0].replace('\\', '\\\\'), row[1], row[3], tblname))
> - first = False
> -
> - _args.output_file.write("""{
> + _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
> + for arch in archs:
> + if arch == 'test':
> + _args.output_file.write("""{
> +\t.arch = "testarch",
> \t.cpuid = "testcpu",
> \t.version = "v1",
> \t.type = "core",
> \t.table = pme_test_soc_cpu,
> },
> -{
> +""")
> + else:
> + with open(f'{_args.starting_dir}/{arch}/mapfile.csv') as csvfile:
> + table = csv.reader(csvfile)
> + first = True
> + 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('#'):
> + tblname = file_name_to_table_name([], row[2].replace('/', '_'))
> + cpuid = row[0].replace('\\', '\\\\')
> + _args.output_file.write(f"""{{
> +\t.arch = "{arch}",
> +\t.cpuid = "{cpuid}",
> +\t.version = "{row[1]}",
> +\t.type = "{row[3]}",
> +\t.table = {tblname}
> +}},
> +""")
> + first = False
> +
> + _args.output_file.write("""{
> +\t.arch = 0,
> \t.cpuid = 0,
> \t.version = 0,
> \t.type = 0,
> \t.table = 0,
> -},
> +}
> };
> """)
>
> @@ -386,15 +393,24 @@ def main() -> None:
> _args = ap.parse_args()
>
> _args.output_file.write("#include \"pmu-events/pmu-events.h\"\n")
> - for path in [_args.arch, 'test']:
> - arch_path = f'{_args.starting_dir}/{path}'
> - if not os.path.isdir(arch_path):
> - raise IOError(f'Missing architecture directory in \'{arch_path}\'')
> + archs = []
> + for item in os.scandir(_args.starting_dir):
> + if not item.is_dir():
> + continue
> + if item.name == _args.arch or _args.arch == 'all' or item.name == 'test':
> + archs.append(item.name)
> +
> + if len(archs) < 2:
> + raise IOError(f'Missing architecture directory \'{_args.arch}\'')
> +
> + archs.sort()
> + for arch in archs:
> + arch_path = f'{_args.starting_dir}/{arch}'
> preprocess_arch_std_files(arch_path)
> ftw(arch_path, [], process_one_file)
> print_events_table_suffix()
>
> - print_mapping_table()
> + print_mapping_table(archs)
> print_system_mapping_table()
>
>
> diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
> index 6efe73976440..7a360792635f 100644
> --- a/tools/perf/pmu-events/pmu-events.h
> +++ b/tools/perf/pmu-events/pmu-events.h
> @@ -38,6 +38,7 @@ struct pmu_event {
> * The cpuid can contain any character other than the comma.
> */
> struct pmu_events_map {
> + const char *arch;
> const char *cpuid;
> const char *version;
> const char *type; /* core, uncore etc */
> diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> index 263cbb67c861..82192f1a7bf7 100644
> --- a/tools/perf/tests/pmu-events.c
> +++ b/tools/perf/tests/pmu-events.c
> @@ -864,8 +864,7 @@ static void expr_failure(const char *msg,
> const struct pmu_events_map *map,
> const struct pmu_event *pe)
> {
> - pr_debug("%s for map %s %s %s\n",
> - msg, map->cpuid, map->version, map->type);
> + pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
> pr_debug("On metric %s\n", pe->metric_name);
> pr_debug("On expression %s\n", pe->metric_expr);
> }
On 04/08/2022 23:18, Ian Rogers wrote:
> Preparation for hiding pmu_events_map as an implementation detail. While
> the map is passed, the table of events is all that is normally wanted.
>
> Signed-off-by: Ian Rogers <[email protected]>
Apart from comments on naming, below:
Reviewed-by: John Garry <[email protected]>
As an aside, I will mention that reviewing this series is not helped by
limited description of the changes in the cover letter. A primer would
be nice. As I go through the series, I am often assuming that the
motivation for the change is sound.
Thanks,
John
> ---
> tools/perf/arch/arm64/util/pmu.c | 4 +-
> tools/perf/tests/expand-cgroup.c | 6 +--
> tools/perf/tests/parse-metric.c | 7 +--
> tools/perf/tests/pmu-events.c | 63 +++++++++++-------------
> tools/perf/util/metricgroup.c | 82 +++++++++++++++----------------
> tools/perf/util/metricgroup.h | 4 +-
> tools/perf/util/pmu.c | 33 +++++++------
> tools/perf/util/pmu.h | 6 +--
> tools/perf/util/s390-sample-raw.c | 12 ++---
> 9 files changed, 99 insertions(+), 118 deletions(-)
>
> diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
> index 79124bba713e..646af8603227 100644
> --- a/tools/perf/arch/arm64/util/pmu.c
> +++ b/tools/perf/arch/arm64/util/pmu.c
> @@ -3,7 +3,7 @@
> #include "../../../util/cpumap.h"
> #include "../../../util/pmu.h"
>
> -const struct pmu_events_map *pmu_events_map__find(void)
> +const struct pmu_event *pmu_events_map__find(void)
The function name is no longer appropriate
> {
> struct perf_pmu *pmu = NULL;
>
> @@ -18,7 +18,7 @@ const struct pmu_events_map *pmu_events_map__find(void)
> if (pmu->cpus->nr != cpu__max_cpu().cpu)
> return NULL;
>
> - return perf_pmu__find_map(pmu);
> + return perf_pmu__find_table(pmu);
> }
>
> return NULL;
> diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
> index dc4038f997d7..411fc578e5a4 100644
> --- a/tools/perf/tests/expand-cgroup.c
> +++ b/tools/perf/tests/expand-cgroup.c
> @@ -195,16 +195,12 @@ static int expand_metric_events(void)
> .metric_name = NULL,
> },
> };
> - const struct pmu_events_map ev_map = {
> - .cpuid = "test",
> - .table = pme_test,
> - };
>
> evlist = evlist__new();
> TEST_ASSERT_VAL("failed to get evlist", evlist);
>
> rblist__init(&metric_events);
> - ret = metricgroup__parse_groups_test(evlist, &ev_map, metric_str,
> + ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str,
> false, false, &metric_events);
> if (ret < 0) {
> pr_debug("failed to parse '%s' metric\n", metric_str);
> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> index 1b811a26f4ee..7aebde7c37ec 100644
> --- a/tools/perf/tests/parse-metric.c
> +++ b/tools/perf/tests/parse-metric.c
> @@ -79,11 +79,6 @@ static struct pmu_event pme_test[] = {
> }
> };
>
> -static const struct pmu_events_map map = {
> - .cpuid = "test",
> - .table = pme_test,
> -};
> -
> struct value {
> const char *event;
> u64 val;
> @@ -166,7 +161,7 @@ static int __compute_metric(const char *name, struct value *vals,
> runtime_stat__init(&st);
>
> /* Parse the metric into metric_events list. */
> - err = metricgroup__parse_groups_test(evlist, &map, name,
> + err = metricgroup__parse_groups_test(evlist, pme_test, name,
> false, false,
> &metric_events);
> if (err)
> diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> index a39a2c99ede6..b3cde5f98982 100644
> --- a/tools/perf/tests/pmu-events.c
> +++ b/tools/perf/tests/pmu-events.c
> @@ -272,13 +272,11 @@ static bool is_same(const char *reference, const char *test)
> return !strcmp(reference, test);
> }
>
> -static const struct pmu_events_map *__test_pmu_get_events_map(void)
> +static const struct pmu_event *__test_pmu_get_events_table(void)
> {
> - const struct pmu_events_map *map;
> -
> - for (map = &pmu_events_map[0]; map->cpuid; map++) {
> + for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
> if (!strcmp(map->cpuid, "testcpu"))
> - return map;
> + return map->table;
> }
>
> pr_err("could not find test events map\n");
> @@ -440,8 +438,7 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
> int subtest __maybe_unused)
> {
> const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
> - const struct pmu_events_map *map = __test_pmu_get_events_map();
> - const struct pmu_event *table;
> + const struct pmu_event *table = __test_pmu_get_events_table();
> int map_events = 0, expected_events;
>
> /* ignore 3x sentinels */
> @@ -449,10 +446,10 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
> ARRAY_SIZE(uncore_events) +
> ARRAY_SIZE(sys_events) - 3;
>
> - if (!map || !sys_event_tables)
> + if (!table || !sys_event_tables)
> return -1;
>
> - for (table = map->table; table->name; table++) {
> + for (; table->name; table++) {
> struct perf_pmu_test_event const **test_event_table;
> bool found = false;
>
> @@ -537,10 +534,10 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
> struct perf_pmu *pmu;
> LIST_HEAD(aliases);
> int res = 0;
> - const struct pmu_events_map *map = __test_pmu_get_events_map();
> + const struct pmu_event *table = __test_pmu_get_events_table();
> struct perf_pmu_alias *a, *tmp;
>
> - if (!map)
> + if (!table)
> return -1;
>
> test_event_table = &core_events[0];
> @@ -551,7 +548,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
>
> pmu->name = pmu_name;
>
> - pmu_add_cpu_aliases_map(&aliases, pmu, map);
> + pmu_add_cpu_aliases_map(&aliases, pmu, table);
>
> for (; *test_event_table; test_event_table++) {
> struct perf_pmu_test_event const *test_event = *test_event_table;
> @@ -590,14 +587,14 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
> struct perf_pmu *pmu = &test_pmu->pmu;
> const char *pmu_name = pmu->name;
> struct perf_pmu_alias *a, *tmp, *alias;
> - const struct pmu_events_map *map;
> + const struct pmu_event *events_table;
> LIST_HEAD(aliases);
> int res = 0;
>
> - map = __test_pmu_get_events_map();
> - if (!map)
> + events_table = __test_pmu_get_events_table();
> + if (!events_table)
> return -1;
> - pmu_add_cpu_aliases_map(&aliases, pmu, map);
> + pmu_add_cpu_aliases_map(&aliases, pmu, events_table);
> pmu_add_sys_aliases(&aliases, pmu);
>
> /* Count how many aliases we generated */
> @@ -848,13 +845,9 @@ static int check_parse_fake(const char *id)
> return ret;
> }
>
> -static void expr_failure(const char *msg,
> - const struct pmu_events_map *map,
> - const struct pmu_event *pe)
> +static void expr_failure(const char *msg, const struct pmu_event *pe)
> {
> - pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
> - pr_debug("On metric %s\n", pe->metric_name);
> - pr_debug("On expression %s\n", pe->metric_expr);
> + pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
> }
>
> struct metric {
> @@ -864,7 +857,7 @@ struct metric {
>
> static int resolve_metric_simple(struct expr_parse_ctx *pctx,
> struct list_head *compound_list,
> - const struct pmu_events_map *map,
> + const struct pmu_event *map,
> const char *metric_name)
> {
> struct hashmap_entry *cur, *cur_tmp;
> @@ -925,8 +918,7 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx,
> static int test__parsing(struct test_suite *test __maybe_unused,
> int subtest __maybe_unused)
> {
> - const struct pmu_events_map *cpus_map = pmu_events_map__find();
> - const struct pmu_events_map *map;
> + const struct pmu_event *cpus_table = pmu_events_map__find();
> const struct pmu_event *pe;
> int i, j, k;
> int ret = 0;
> @@ -940,7 +932,8 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> }
> i = 0;
> for (;;) {
> - map = &pmu_events_map[i++];
> + const struct pmu_events_map *map = &pmu_events_map[i++];
> +
> if (!map->table)
> break;
> j = 0;
> @@ -957,14 +950,14 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> continue;
> expr__ctx_clear(ctx);
> if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
> - expr_failure("Parse find ids failed", map, pe);
> + expr_failure("Parse find ids failed", pe);
> ret++;
> continue;
> }
>
> - if (resolve_metric_simple(ctx, &compound_list, map,
> + if (resolve_metric_simple(ctx, &compound_list, map->table,
> pe->metric_name)) {
> - expr_failure("Could not resolve metrics", map, pe);
> + expr_failure("Could not resolve metrics", pe);
> ret++;
> goto exit; /* Don't tolerate errors due to severity */
> }
> @@ -979,7 +972,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> expr__add_id_val(ctx, strdup(cur->key), k++);
>
> hashmap__for_each_entry(ctx->ids, cur, bkt) {
> - if (check_parse_cpu(cur->key, map == cpus_map,
> + if (check_parse_cpu(cur->key, map->table == cpus_table,
> pe))
> ret++;
> }
> @@ -999,7 +992,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> hashmap__for_each_entry(ctx->ids, cur, bkt)
> expr__add_id_val(ctx, strdup(cur->key), k--);
> if (expr__parse(&result, ctx, pe->metric_expr)) {
> - expr_failure("Parse failed", map, pe);
> + expr_failure("Parse failed", pe);
> ret++;
> }
> }
> @@ -1088,8 +1081,6 @@ static int metric_parse_fake(const char *str)
> static int test__parsing_fake(struct test_suite *test __maybe_unused,
> int subtest __maybe_unused)
> {
> - const struct pmu_events_map *map;
> - const struct pmu_event *pe;
> unsigned int i, j;
> int err = 0;
>
> @@ -1101,12 +1092,14 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused,
>
> i = 0;
> for (;;) {
> - map = &pmu_events_map[i++];
> + const struct pmu_events_map *map = &pmu_events_map[i++];
> +
> if (!map->table)
> break;
> j = 0;
> for (;;) {
> - pe = &map->table[j++];
> + const struct pmu_event *pe = &map->table[j++];
> +
> if (!pe->name && !pe->metric_group && !pe->metric_name)
> break;
> if (!pe->metric_expr)
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index 8f7baeabc5cf..4d32b4fbf67d 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -539,9 +539,6 @@ static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *d
> void metricgroup__print(bool metrics, bool metricgroups, char *filter,
> bool raw, bool details, const char *pmu_name)
> {
> - const struct pmu_events_map *map = pmu_events_map__find();
> - const struct pmu_event *pe;
> - int i;
> struct rblist groups;
> struct rb_node *node, *next;
> struct strlist *metriclist = NULL;
> @@ -556,8 +553,7 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
> groups.node_new = mep_new;
> groups.node_cmp = mep_cmp;
> groups.node_delete = mep_delete;
> - for (i = 0; map; i++) {
> - pe = &map->table[i];
> + for (const struct pmu_event *pe = pmu_events_map__find(); pe; pe++) {
>
> if (!pe->name && !pe->metric_group && !pe->metric_name)
> break;
> @@ -850,7 +846,7 @@ struct metricgroup_add_iter_data {
> bool metric_no_group;
> struct metric *root_metric;
> const struct visited_metric *visited;
> - const struct pmu_events_map *map;
> + const struct pmu_event *table;
> };
>
> static int add_metric(struct list_head *metric_list,
> @@ -859,7 +855,7 @@ static int add_metric(struct list_head *metric_list,
> bool metric_no_group,
> struct metric *root_metric,
> const struct visited_metric *visited,
> - const struct pmu_events_map *map);
> + const struct pmu_event *table);
>
> /**
> * resolve_metric - Locate metrics within the root metric and recursively add
> @@ -874,7 +870,7 @@ static int add_metric(struct list_head *metric_list,
> * metrics. When adding a root this argument is NULL.
> * @visited: A singly linked list of metric names being added that is used to
> * detect recursion.
> - * @map: The map that is searched for metrics, most commonly the table for the
> + * @table: The table that is searched for metrics, most commonly the table for the
> * architecture perf is running upon.
> */
> static int resolve_metric(struct list_head *metric_list,
> @@ -882,7 +878,7 @@ static int resolve_metric(struct list_head *metric_list,
> bool metric_no_group,
> struct metric *root_metric,
> const struct visited_metric *visited,
> - const struct pmu_events_map *map)
> + const struct pmu_event *table)
> {
> struct hashmap_entry *cur;
> size_t bkt;
> @@ -904,7 +900,7 @@ static int resolve_metric(struct list_head *metric_list,
> hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
> const struct pmu_event *pe;
>
> - pe = metricgroup__find_metric(cur->key, map);
> + pe = metricgroup__find_metric(cur->key, table);
> if (pe) {
> pending = realloc(pending,
> (pending_cnt + 1) * sizeof(struct to_resolve));
> @@ -927,7 +923,7 @@ static int resolve_metric(struct list_head *metric_list,
> */
> for (i = 0; i < pending_cnt; i++) {
> ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group,
> - root_metric, visited, map);
> + root_metric, visited, table);
> if (ret)
> break;
> }
> @@ -950,7 +946,7 @@ static int resolve_metric(struct list_head *metric_list,
> * metrics. When adding a root this argument is NULL.
> * @visited: A singly linked list of metric names being added that is used to
> * detect recursion.
> - * @map: The map that is searched for metrics, most commonly the table for the
> + * @table: The table that is searched for metrics, most commonly the table for the
> * architecture perf is running upon.
> */
> static int __add_metric(struct list_head *metric_list,
> @@ -960,7 +956,7 @@ static int __add_metric(struct list_head *metric_list,
> int runtime,
> struct metric *root_metric,
> const struct visited_metric *visited,
> - const struct pmu_events_map *map)
> + const struct pmu_event *table)
> {
> const struct visited_metric *vm;
> int ret;
> @@ -1032,7 +1028,7 @@ static int __add_metric(struct list_head *metric_list,
> } else {
> /* Resolve referenced metrics. */
> ret = resolve_metric(metric_list, modifier, metric_no_group, root_metric,
> - &visited_node, map);
> + &visited_node, table);
> }
>
> if (ret) {
> @@ -1045,25 +1041,25 @@ static int __add_metric(struct list_head *metric_list,
> return ret;
> }
>
> -#define map_for_each_event(__pe, __idx, __map) \
> - if (__map) \
> - for (__idx = 0, __pe = &__map->table[__idx]; \
> +#define table_for_each_event(__pe, __idx, __table) \
> + if (__table) \
> + for (__idx = 0, __pe = &__table[__idx]; \
> __pe->name || __pe->metric_group || __pe->metric_name; \
> - __pe = &__map->table[++__idx])
> + __pe = &__table[++__idx])
>
> -#define map_for_each_metric(__pe, __idx, __map, __metric) \
> - map_for_each_event(__pe, __idx, __map) \
> +#define table_for_each_metric(__pe, __idx, __table, __metric) \
> + table_for_each_event(__pe, __idx, __table) \
> if (__pe->metric_expr && \
> (match_metric(__pe->metric_group, __metric) || \
> match_metric(__pe->metric_name, __metric)))
>
> const struct pmu_event *metricgroup__find_metric(const char *metric,
> - const struct pmu_events_map *map)
> + const struct pmu_event *table)
> {
> const struct pmu_event *pe;
> int i;
>
> - map_for_each_event(pe, i, map) {
> + table_for_each_event(pe, i, table) {
> if (match_metric(pe->metric_name, metric))
> return pe;
> }
> @@ -1077,7 +1073,7 @@ static int add_metric(struct list_head *metric_list,
> bool metric_no_group,
> struct metric *root_metric,
> const struct visited_metric *visited,
> - const struct pmu_events_map *map)
> + const struct pmu_event *table)
> {
> int ret = 0;
>
> @@ -1085,7 +1081,7 @@ static int add_metric(struct list_head *metric_list,
>
> if (!strstr(pe->metric_expr, "?")) {
> ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
> - root_metric, visited, map);
> + root_metric, visited, table);
> } else {
> int j, count;
>
> @@ -1098,7 +1094,7 @@ static int add_metric(struct list_head *metric_list,
>
> for (j = 0; j < count && !ret; j++)
> ret = __add_metric(metric_list, pe, modifier, metric_no_group, j,
> - root_metric, visited, map);
> + root_metric, visited, table);
> }
>
> return ret;
> @@ -1114,7 +1110,7 @@ static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
> return 0;
>
> ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
> - d->root_metric, d->visited, d->map);
> + d->root_metric, d->visited, d->table);
> if (ret)
> goto out;
>
> @@ -1162,13 +1158,13 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
> * global. Grouping is the default but due to multiplexing the
> * user may override.
> * @metric_list: The list that the metric or metric group are added to.
> - * @map: The map that is searched for metrics, most commonly the table for the
> + * @table: The table that is searched for metrics, most commonly the table for the
> * architecture perf is running upon.
> */
> static int metricgroup__add_metric(const char *metric_name, const char *modifier,
> bool metric_no_group,
> struct list_head *metric_list,
> - const struct pmu_events_map *map)
> + const struct pmu_event *table)
> {
> const struct pmu_event *pe;
> LIST_HEAD(list);
> @@ -1179,11 +1175,11 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
> * Iterate over all metrics seeing if metric matches either the name or
> * group. When it does add the metric to the list.
> */
> - map_for_each_metric(pe, i, map, metric_name) {
> + table_for_each_metric(pe, i, table, metric_name) {
> has_match = true;
> ret = add_metric(&list, pe, modifier, metric_no_group,
> /*root_metric=*/NULL,
> - /*visited_metrics=*/NULL, map);
> + /*visited_metrics=*/NULL, table);
> if (ret)
> goto out;
> }
> @@ -1198,7 +1194,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
> .metric_no_group = metric_no_group,
> .has_match = &has_match,
> .ret = &ret,
> - .map = map,
> + .table = table,
> },
> };
>
> @@ -1227,12 +1223,12 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
> * global. Grouping is the default but due to multiplexing the
> * user may override.
> * @metric_list: The list that metrics are added to.
> - * @map: The map that is searched for metrics, most commonly the table for the
> + * @table: The table that is searched for metrics, most commonly the table for the
> * architecture perf is running upon.
> */
> static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
> struct list_head *metric_list,
> - const struct pmu_events_map *map)
> + const struct pmu_event *table)
> {
> char *list_itr, *list_copy, *metric_name, *modifier;
> int ret, count = 0;
> @@ -1249,7 +1245,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
>
> ret = metricgroup__add_metric(metric_name, modifier,
> metric_no_group, metric_list,
> - map);
> + table);
> if (ret == -EINVAL)
> pr_err("Cannot find metric or group `%s'\n", metric_name);
>
> @@ -1440,7 +1436,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
> bool metric_no_merge,
> struct perf_pmu *fake_pmu,
> struct rblist *metric_events_list,
> - const struct pmu_events_map *map)
> + const struct pmu_event *table)
> {
> struct evlist *combined_evlist = NULL;
> LIST_HEAD(metric_list);
> @@ -1451,7 +1447,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
> if (metric_events_list->nr_entries == 0)
> metricgroup__rblist_init(metric_events_list);
> ret = metricgroup__add_metric_list(str, metric_no_group,
> - &metric_list, map);
> + &metric_list, table);
> if (ret)
> goto out;
>
> @@ -1586,34 +1582,34 @@ int metricgroup__parse_groups(const struct option *opt,
> struct rblist *metric_events)
> {
> struct evlist *perf_evlist = *(struct evlist **)opt->value;
> - const struct pmu_events_map *map = pmu_events_map__find();
> + const struct pmu_event *table = pmu_events_map__find();
>
> return parse_groups(perf_evlist, str, metric_no_group,
> - metric_no_merge, NULL, metric_events, map);
> + metric_no_merge, NULL, metric_events, table);
> }
>
> int metricgroup__parse_groups_test(struct evlist *evlist,
> - const struct pmu_events_map *map,
> + const struct pmu_event *table,
> const char *str,
> bool metric_no_group,
> bool metric_no_merge,
> struct rblist *metric_events)
> {
> return parse_groups(evlist, str, metric_no_group,
> - metric_no_merge, &perf_pmu__fake, metric_events, map);
> + metric_no_merge, &perf_pmu__fake, metric_events, table);
> }
>
> bool metricgroup__has_metric(const char *metric)
> {
> - const struct pmu_events_map *map = pmu_events_map__find();
> + const struct pmu_event *table = pmu_events_map__find();
> const struct pmu_event *pe;
> int i;
>
> - if (!map)
> + if (!table)
> return false;
>
> for (i = 0; ; i++) {
> - pe = &map->table[i];
> + pe = &table[i];
>
> if (!pe->name && !pe->metric_group && !pe->metric_name)
> break;
> diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
> index 2b42b778d1bf..5a1390e73d25 100644
> --- a/tools/perf/util/metricgroup.h
> +++ b/tools/perf/util/metricgroup.h
> @@ -71,9 +71,9 @@ int metricgroup__parse_groups(const struct option *opt,
> bool metric_no_merge,
> struct rblist *metric_events);
> const struct pmu_event *metricgroup__find_metric(const char *metric,
> - const struct pmu_events_map *map);
> + const struct pmu_event *table);
> int metricgroup__parse_groups_test(struct evlist *evlist,
> - const struct pmu_events_map *map,
> + const struct pmu_event *table,
> const char *str,
> bool metric_no_group,
> bool metric_no_merge,
> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> index d8717c4548a4..f3e3c4a147e9 100644
> --- a/tools/perf/util/pmu.c
> +++ b/tools/perf/util/pmu.c
> @@ -710,9 +710,9 @@ static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
> return cpuid;
> }
>
> -const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> {
> - const struct pmu_events_map *map;
> + const struct pmu_event *table = NULL;
> char *cpuid = perf_pmu__getcpuid(pmu);
> int i;
>
> @@ -724,22 +724,23 @@ const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
>
> i = 0;
> for (;;) {
> - map = &pmu_events_map[i++];
> - if (!map->table) {
> - map = NULL;
> + const struct pmu_events_map *map = &pmu_events_map[i++];
> +
> + if (!map->table)
> break;
> - }
>
> - if (!strcmp_cpuid_str(map->cpuid, cpuid))
> + if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> + table = map->table;
> break;
> + }
> }
> free(cpuid);
> - return map;
> + return table;
> }
>
> -const struct pmu_events_map *__weak pmu_events_map__find(void)
> +__weak const struct pmu_event *pmu_events_map__find(void)
> {
> - return perf_pmu__find_map(NULL);
> + return perf_pmu__find_table(NULL);
> }
>
> /*
> @@ -824,7 +825,7 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
> * as aliases.
> */
> void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
Again, it seems that this name should be changed
> - const struct pmu_events_map *map)
> + const struct pmu_event *table)
> {
> int i;
> const char *name = pmu->name;
> @@ -834,7 +835,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
> i = 0;
> while (1) {
> const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
> - const struct pmu_event *pe = &map->table[i++];
> + const struct pmu_event *pe = &table[i++];
> const char *pname = pe->pmu ? pe->pmu : cpu_name;
>
> if (!pe->name) {
> @@ -859,13 +860,13 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
>
> static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
> {
> - const struct pmu_events_map *map;
> + const struct pmu_event *table;
>
> - map = perf_pmu__find_map(pmu);
> - if (!map)
> + table = perf_pmu__find_table(pmu);
> + if (!table)
> return;
>
> - pmu_add_cpu_aliases_map(head, pmu, map);
> + pmu_add_cpu_aliases_map(head, pmu, table);
> }
>
> struct pmu_sys_event_iter_data {
> diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
> index 7e667eec2a01..015242c83698 100644
> --- a/tools/perf/util/pmu.h
> +++ b/tools/perf/util/pmu.h
> @@ -126,10 +126,10 @@ int perf_pmu__test(void);
>
> struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
> void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
> - const struct pmu_events_map *map);
> + const struct pmu_event *map);
>
> -const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu);
> -const struct pmu_events_map *pmu_events_map__find(void);
> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
> +const struct pmu_event *pmu_events_map__find(void);
> bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
> void perf_pmu_free_alias(struct perf_pmu_alias *alias);
>
> diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
> index cd3a34840389..1ecb718fc0eb 100644
> --- a/tools/perf/util/s390-sample-raw.c
> +++ b/tools/perf/util/s390-sample-raw.c
> @@ -135,12 +135,12 @@ static int get_counterset_start(int setnr)
> * the name of this counter.
> * If no match is found a NULL pointer is returned.
> */
> -static const char *get_counter_name(int set, int nr, const struct pmu_events_map *map)
> +static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
> {
> int rc, event_nr, wanted = get_counterset_start(set) + nr;
>
> - if (map) {
> - const struct pmu_event *evp = map->table;
> + if (table) {
> + const struct pmu_event *evp = table;
>
> for (; evp->name || evp->event || evp->desc; ++evp) {
> if (evp->name == NULL || evp->event == NULL)
> @@ -159,10 +159,10 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
> unsigned char *buf = sample->raw_data;
> const char *color = PERF_COLOR_BLUE;
> struct cf_ctrset_entry *cep, ce;
> - const struct pmu_events_map *map;
> + const struct pmu_event *table;
> u64 *p;
>
> - map = pmu_events_map__find();
> + table = pmu_events_map__find();
> while (offset < len) {
> cep = (struct cf_ctrset_entry *)(buf + offset);
>
> @@ -180,7 +180,7 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
> color_fprintf(stdout, color, " [%#08zx] Counterset:%d"
> " Counters:%d\n", offset, ce.set, ce.ctr);
> for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) {
> - const char *ev_name = get_counter_name(ce.set, i, map);
> + const char *ev_name = get_counter_name(ce.set, i, table);
>
> color_fprintf(stdout, color,
> "\tCounter:%03d %s Value:%#018lx\n", i,
On 04/08/2022 23:18, Ian Rogers wrote:
> Move usage of the table to pmu-events.c so it may be hidden. By
> abstracting the table the implementation can later be changed.
>
> Signed-off-by: Ian Rogers <[email protected]>
> ---
> tools/perf/pmu-events/empty-pmu-events.c | 81 ++++++++-
> tools/perf/pmu-events/jevents.py | 81 ++++++++-
> tools/perf/pmu-events/pmu-events.h | 29 +--
> tools/perf/tests/pmu-events.c | 218 +++++++++++------------
> tools/perf/util/metricgroup.c | 15 +-
> tools/perf/util/pmu.c | 34 +---
> tools/perf/util/pmu.h | 2 +-
> 7 files changed, 280 insertions(+), 180 deletions(-)
>
> diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> index 216ea0482c37..8ef75aff996c 100644
> --- a/tools/perf/pmu-events/empty-pmu-events.c
> +++ b/tools/perf/pmu-events/empty-pmu-events.c
> @@ -6,6 +6,8 @@
> * The test cpu/soc is provided for testing.
> */
> #include "pmu-events/pmu-events.h"
> +#include "util/header.h"
> +#include "util/pmu.h"
> #include <string.h>
> #include <stddef.h>
>
> @@ -110,7 +112,26 @@ static const struct pmu_event pme_test_soc_cpu[] = {
> },
> };
>
> -const struct pmu_events_map pmu_events_map[] = {
> +
> +/*
> + * Map a CPU to its table of PMU events. The CPU is identified by the
> + * cpuid field, which is an arch-specific identifier for the CPU.
> + * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
> + * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
> + *
> + * The cpuid can contain any character other than the comma.
> + */
> +struct pmu_events_map {
> + const char *arch;
> + const char *cpuid;
> + const struct pmu_event *table;
> +};
> +
> +/*
> + * Global table mapping each known CPU for the architecture to its
> + * table of PMU events.
> + */
> +static const struct pmu_events_map pmu_events_map[] = {
> {
> .arch = "testarch",
> .cpuid = "testcpu",
> @@ -162,6 +183,62 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> },
> };
>
> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> +{
> + const struct pmu_event *table = NULL;
> + char *cpuid = perf_pmu__getcpuid(pmu);
> + int i;
> +
> + /* on some platforms which uses cpus map, cpuid can be NULL for
> + * PMUs other than CORE PMUs.
> + */
> + if (!cpuid)
> + return NULL;
> +
> + i = 0;
> + for (;;) {
> + const struct pmu_events_map *map = &pmu_events_map[i++];
> +
> + if (!map->table)
> + break;
> +
> + if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> + table = map->table;
> + break;
> + }
> + }
> + free(cpuid);
> + return table;
> +}
> +
> +const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
> +{
> + for (const struct pmu_events_map *tables = &pmu_events_map[0];
> + tables->table;
> + tables++) {
> + if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
> + return tables->table;
> + }
> + return NULL;
> +}
> +
> +int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
> +{
> + for (const struct pmu_events_map *tables = &pmu_events_map[0];
> + tables->table;
> + tables++) {
> + for (const struct pmu_event *pe = &tables->table[0];
> + pe->name || pe->metric_group || pe->metric_name;
> + pe++) {
> + int ret = fn(pe, &tables->table[0], data);
> +
> + if (ret)
> + return ret;
> + }
> + }
> + return 0;
> +}
> +
> const struct pmu_event *find_sys_events_table(const char *name)
> {
> for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
> @@ -181,7 +258,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
> for (const struct pmu_event *pe = &tables->table[0];
> pe->name || pe->metric_group || pe->metric_name;
> pe++) {
> - int ret = fn(pe, data);
> + int ret = fn(pe, &tables->table[0], data);
>
> if (ret)
> return ret;
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index dd21bc9eeeed..e976c5e8e80b 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -333,7 +333,27 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
>
> def print_mapping_table(archs: Sequence[str]) -> None:
> """Read the mapfile and generate the struct from cpuid string to event table."""
> - _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
> + _args.output_file.write("""
> +/*
> + * Map a CPU to its table of PMU events. The CPU is identified by the
> + * cpuid field, which is an arch-specific identifier for the CPU.
> + * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
> + * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
> + *
> + * The cpuid can contain any character other than the comma.
> + */
> +struct pmu_events_map {
> + const char *arch;
> + const char *cpuid;
> + const struct pmu_event *table;
> +};
> +
> +/*
> + * Global table mapping each known CPU for the architecture to its
> + * table of PMU events.
> + */
> +const struct pmu_events_map pmu_events_map[] = {
> +""")
> for arch in archs:
> if arch == 'test':
> _args.output_file.write("""{
> @@ -389,6 +409,61 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> \t},
> };
>
> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> +{
> + const struct pmu_event *table = NULL;
> + char *cpuid = perf_pmu__getcpuid(pmu);
This seems an identical implementation to that in empty-pmu-events.c -
can we reduce this duplication? Maybe a seperate common c file which can
be linked in
The indentation seems different also - this version seems to use whitespaces
> + int i;
> +
> + /* on some platforms which uses cpus map, cpuid can be NULL for
> + * PMUs other than CORE PMUs.
> + */
> + if (!cpuid)
> + return NULL;
> +
> + i = 0;
> + for (;;) {
> + const struct pmu_events_map *map = &pmu_events_map[i++];
> + if (!map->table)
> + break;
> +
> + if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> + table = map->table;
> + break;
> + }
> + }
> + free(cpuid);
> + return table;
> +}
On 04/08/2022 23:18, Ian Rogers wrote:
> Move arrays of pmu_events into the json code so that it may be
> regenerated and modified by the jevents.py script.
>
> Signed-off-by: Ian Rogers<[email protected]>
Reviewed-by: John Garry <[email protected]>
On 04/08/2022 23:18, Ian Rogers wrote:
> The pmu_events array requires 15 pointers per entry which in position
> independent code need relocating. Change the array to be an array of
> offsets within a big C string. Only the offset of the first variable is
> required, subsequent variables are stored in order after the \0
> terminator (requiring a byte per variable rather than 4 bytes per
> offset).
>
> The file size savings are:
> no jevents - the same 19,788,464bytes
> x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
> all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
> default build options plus NO_LIBBFD=1.
>
> For example, the x86 build savings come from .rela.dyn and
> .data.rel.ro becoming smaller by 3,157,032bytes and 3,042,016bytes
> respectively. .rodata increases by 1,432,448bytes, giving an overall
> 4,766,600bytes saving.
>
> To make metric strings more shareable, the topic is changed from say
> 'skx metrics' to just 'metrics'.
>
> To try to help with the memory layout the pmu_events are ordered as used
> by perf qsort comparator functions.
>
> Signed-off-by: Ian Rogers <[email protected]>
> ---
> tools/perf/pmu-events/jevents.py | 207 ++++++++++++++++++++++++-------
> 1 file changed, 162 insertions(+), 45 deletions(-)
>
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index aa8df649025a..a5e162558994 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -6,7 +6,8 @@ import csv
> import json
> import os
> import sys
> -from typing import (Callable, Optional, Sequence)
> +from typing import (Callable, Dict, Optional, Sequence, Set, Tuple)
> +import collections
>
> # Global command line arguments.
> _args = None
> @@ -20,6 +21,19 @@ _arch_std_events = {}
> _close_table = False
> # Events to write out when the table is closed
> _pending_events = []
> +# Global BigCString shared by all structures.
> +_bcs = None
> +# Order specific JsonEvent attributes will be visited.
> +_json_event_attributes = [
> + # cmp_sevent related attributes.
> + 'name', 'pmu', 'topic', 'desc', 'metric_name', 'metric_group',
> + # Seems useful, put it early.
> + 'event',
> + # Short things in alphabetical order.
> + 'aggr_mode', 'compat', 'deprecated', 'perpkg', 'unit',
> + # Longer things (the last won't be iterated over during decompress).
> + 'metric_constraint', 'metric_expr', 'long_desc'
> +]
>
>
> def removesuffix(s: str, suffix: str) -> str:
> @@ -39,6 +53,66 @@ def file_name_to_table_name(parents: Sequence[str], dirname: str) -> str:
> tblname += '_' + dirname
> return tblname.replace('-', '_')
>
> +def c_len(s: str) -> int:
> + """Return the length of s a C string
> +
> + This doesn't handle all escape characters properly. It first assumes
> + all \ are for escaping, it then adjusts as it will have over counted
> + \\. The code uses \000 rather than \0 as a terminator as an adjacent
> + number would be folded into a string of \0 (ie. "\0" + "5" doesn't
> + equal a terminator followed by the number 5 but the escape of
> + \05). The code adjusts for \000 but not properly for all octal, hex
> + or unicode values.
> + """
> + try:
> + utf = s.encode(encoding='utf-8',errors='strict')
> + except:
> + print(f'broken string {s}')
> + raise
> + return len(utf) - utf.count(b'\\') + utf.count(b'\\\\') - (utf.count(b'\\000') * 2)
> +
> +class BigCString:
> + """A class to hold many strings concatenated together.
> +
> + Generating a large number of stand-alone C strings creates a large
> + number of relocations in position independent code. The BigCString
> + is a helper for this case. It builds a single string which within it
> + are all the other C strings (to avoid memory issues the string
> + itself is held as a list of strings). The offsets within the big
> + string are recorded and when stored to disk these don't need
> + relocation.
> + """
> + strings: Set[str]
> + big_string: Sequence[str]
> + offsets: Dict[str, int]
> +
> + def __init__(self):
> + self.strings = set()
> +
> + def add(self, s: str) -> None:
> + """Called to add to the big string."""
> + self.strings.add(s)
> +
> + def compute(self) -> None:
> + """Called once all strings are added to compute the string and offsets."""
> +
> + # big_string_offset is the current location within the C string
> + # being appended to - comments, etc. don't count. big_string is
> + # the string contents represented as a list. Strings are immutable
> + # in Python and so appending to one causes memory issues, while
> + # lists are mutable.
> + big_string_offset = 0
> + self.big_string = []
> + self.offsets = {}
> + # Emit all strings in a sorted manner.
> + for s in sorted(self.strings):
> + self.offsets[s] = big_string_offset
> + self.big_string.append(f'/* offset={big_string_offset} */ "')
> + self.big_string.append(s)
> + self.big_string.append('"\n')
> + big_string_offset += c_len(s)
> +
> +_bcs = BigCString()
>
> class JsonEvent:
> """Representation of an event loaded from a json file dictionary."""
> @@ -202,26 +276,18 @@ class JsonEvent:
> s += f'\t{attr} = {value},\n'
> return s + '}'
>
> + def build_c_string(self) -> str:
> + s = ''
> + for attr in _json_event_attributes:
> + x = getattr(self, attr)
> + s += f'{x}\\000' if x else '\\000'
> + return s
> +
> def to_c_string(self) -> str:
> """Representation of the event as a C struct initializer."""
>
> - def attr_string(attr: str, value: str) -> str:
> - return f'\t.{attr} = \"{value}\",\n'
> -
> - def str_if_present(self, attr: str) -> str:
> - if not getattr(self, attr):
> - return ''
> - return attr_string(attr, getattr(self, attr))
> -
> - s = '{\n'
> - for attr in [
> - 'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
> - 'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
> - 'name', 'perpkg', 'pmu', 'topic', 'unit'
> - ]:
> - s += str_if_present(self, attr)
> - s += '},\n'
> - return s
> + s = self.build_c_string()
> + return f'{{ { _bcs.offsets[s] } }}, /* {s} */\n'
>
>
> def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
> @@ -236,7 +302,6 @@ def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
> event.topic = topic
> return result
>
> -
> def preprocess_arch_std_files(archpath: str) -> None:
> """Read in all architecture standard events."""
> global _arch_std_events
> @@ -252,7 +317,7 @@ def print_events_table_prefix(tblname: str) -> None:
> global _close_table
> if _close_table:
> raise IOError('Printing table prefix but last table has no suffix')
> - _args.output_file.write(f'static const struct pmu_event {tblname}[] = {{\n')
> + _args.output_file.write(f'static const struct compact_pmu_event {tblname}[] = {{\n')
> _close_table = True
>
>
> @@ -267,13 +332,13 @@ def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
> def print_events_table_suffix() -> None:
> """Optionally close events table."""
>
> - def event_cmp_key(j: JsonEvent):
> - def fix_none(s: str):
> + def event_cmp_key(j: JsonEvent) -> Tuple[bool, str, str, str, str]:
> + def fix_none(s: Optional[str]) -> str:
> if s is None:
> return ''
> return s
>
> - return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> + return (j.desc is not None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> fix_none(j.metric_name))
>
> global _close_table
> @@ -285,23 +350,37 @@ def print_events_table_suffix() -> None:
> _args.output_file.write(event.to_c_string())
> _pending_events = []
>
> - _args.output_file.write("""{
> -\t.name = 0,
> -\t.event = 0,
> -\t.desc = 0,
> -},
> -};
> -""")
> + _args.output_file.write('};\n\n')
> _close_table = False
>
> +def get_topic(topic: str) -> str:
> + if topic.endswith('metrics.json'):
> + return 'metrics'
> + return removesuffix(topic, '.json').replace('-', ' ')
> +
> +def preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> +
> + if item.is_dir():
> + return
> +
> + # base dir or too deep
> + level = len(parents)
> + if level == 0 or level > 4:
> + return
> +
> + # Ignore other directories. If the file name does not have a .json
> + # extension, ignore it. It could be a readme.txt for instance.
> + if not item.is_file() or not item.name.endswith('.json'):
> + return
> +
> + topic = get_topic(item.name)
> + for event in read_json_events(item.path, topic):
> + _bcs.add(event.build_c_string())
>
> def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> """Process a JSON file during the main walk."""
> global _sys_event_tables
>
> - def get_topic(topic: str) -> str:
> - return removesuffix(topic, '.json').replace('-', ' ')
> -
> def is_leaf_dir(path: str) -> bool:
> for item in os.scandir(path):
> if item.is_dir():
> @@ -336,7 +415,8 @@ def print_mapping_table(archs: Sequence[str]) -> None:
> _args.output_file.write("""
> /* Struct used to make the PMU event table implementation opaque to callers. */
> struct pmu_events_table {
> - const struct pmu_event *entries;
> + const struct compact_pmu_event *entries;
> + size_t length;
> };
>
> /*
> @@ -364,7 +444,10 @@ const struct pmu_events_map pmu_events_map[] = {
> _args.output_file.write("""{
> \t.arch = "testarch",
> \t.cpuid = "testcpu",
> -\t.table = { pme_test_soc_cpu },
> +\t.table = {
> +\t.entries = pme_test_soc_cpu,
> +\t.length = ARRAY_SIZE(pme_test_soc_cpu),
> +\t}
> },
> """)
> else:
> @@ -379,7 +462,10 @@ const struct pmu_events_map pmu_events_map[] = {
> _args.output_file.write(f"""{{
> \t.arch = "{arch}",
> \t.cpuid = "{cpuid}",
> -\t.table = {{ {tblname} }}
> +\t.table = {{
> +\t\t.entries = {tblname},
> +\t\t.length = ARRAY_SIZE({tblname})
> +\t}}
> }},
> """)
> first = False
> @@ -387,7 +473,7 @@ const struct pmu_events_map pmu_events_map[] = {
> _args.output_file.write("""{
> \t.arch = 0,
> \t.cpuid = 0,
> -\t.table = { 0 },
> +\t.table = { 0, 0 },
> }
> };
> """)
> @@ -405,23 +491,41 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> """)
> for tblname in _sys_event_tables:
> _args.output_file.write(f"""\t{{
> -\t\t.table = {{ {tblname} }},
> +\t\t.table = {{
> +\t\t\t.entries = {tblname},
> +\t\t\t.length = ARRAY_SIZE({tblname})
> +\t\t}},
> \t\t.name = \"{tblname}\",
> \t}},
> """)
> _args.output_file.write("""\t{
> -\t\t.table = { 0 }
> +\t\t.table = { 0, 0 }
> \t},
> };
>
> -int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
> +static void decompress(int offset, struct pmu_event *pe)
> +{
> +\tconst char *p = &big_c_string[offset];
> +""")
> + for attr in _json_event_attributes:
> + _args.output_file.write(f"""
> +\tpe->{attr} = (*p == '\\0' ? NULL : p);
> +""")
> + if attr == _json_event_attributes[-1]:
> + continue
> + _args.output_file.write('\twhile (*p++);')
> + _args.output_file.write("""}
I get this in generated pmu-events.c:
static void decompress(int offset, struct pmu_event *pe)
{
const char *p = &big_c_string[offset];
pe->name = (*p == '\0' ? NULL : p);
while (*p++);
pe->pmu = (*p == '\0' ? NULL : p);
while (*p++);
pe->topic = (*p == '\0' ? NULL : p);
while (*p++);
pe->desc = (*p == '\0' ? NULL : p);
while (*p++);
pe->metric_name = (*p == '\0' ? NULL : p);
while (*p++);
pe->metric_group = (*p == '\0' ? NULL : p);
while (*p++);
pe->event = (*p == '\0' ? NULL : p);
while (*p++);
pe->aggr_mode = (*p == '\0' ? NULL : p);
while (*p++);
pe->compat = (*p == '\0' ? NULL : p);
while (*p++);
pe->deprecated = (*p == '\0' ? NULL : p);
while (*p++);
pe->perpkg = (*p == '\0' ? NULL : p);
while (*p++);
pe->unit = (*p == '\0' ? NULL : p);
while (*p++);
pe->metric_constraint = (*p == '\0' ? NULL : p);
while (*p++);
pe->metric_expr = (*p == '\0' ? NULL : p);
while (*p++);
pe->long_desc = (*p == '\0' ? NULL : p);
}
int pmu_events_table_for_each_event(const struct pmu_events_table *table,
pmu_event_iter_fn fn,
void *data)
{
for (size_t i = 0; i < table->length; i++) {
struct pmu_event pe;
int ret;
decompress(table->entries[i].offset, &pe);
ret = fn(&pe, table, data);
if (ret)
return ret;
}
return 0;
}
--->8---
This seems a bit inefficient in terms of performance - if that really is
a requirement, but I figure that it isn't really.
Another observation is that although we compress and reduce size in this
method, we are now losing out on some sharing of strings. For example,
this is an extract from big_string:
/* offset=3342573 */
"unc_p_core0_transition_cycles\000uncore_pcu\000uncore power\000Core 0 C
State Transition Cycles. Unit: uncore_pcu
\000\000\000event=0x70\000\000\000\0001\000\000\000\000Number of cycles
spent performing core C state transitions. There is one event per core\000"
/* offset=3342789 */
"unc_p_core0_transition_cycles\000uncore_pcu\000uncore power\000Core C
State Transition Cycles. Unit: uncore_pcu
\000\000\000event=0x103\000\000\000\0001\000\000\000\000Number of cycles
spent performing core C state transitions. There is one event per core\000"
These super-strings are not identical, but many sub-strings are, like
"Number of cycles spent performing core C state transitions. There is
one event per core", so we are losing out there on sharing strings there.
Thanks,
John
> +
> +int pmu_events_table_for_each_event(const struct pmu_events_table *table,
> + pmu_event_iter_fn fn,
> void *data)
> {
> - for (const struct pmu_event *pe = &table->entries[0];
> - pe->name || pe->metric_group || pe->metric_name;
> - pe++) {
> - int ret = fn(pe, table, data);
> + for (size_t i = 0; i < table->length; i++) {
> + struct pmu_event pe;
> + int ret;
>
> + decompress(table->entries[i].offset, &pe);
> + ret = fn(&pe, table, data);
> if (ret)
> return ret;
> }
> @@ -530,7 +634,7 @@ def main() -> None:
> help='Root of tree containing architecture directories containing json files'
> )
> ap.add_argument(
> - 'output_file', type=argparse.FileType('w'), nargs='?', default=sys.stdout)
> + 'output_file', type=argparse.FileType('w', encoding='utf-8'), nargs='?', default=sys.stdout)
> _args = ap.parse_args()
>
> _args.output_file.write("""
> @@ -540,6 +644,10 @@ def main() -> None:
> #include <string.h>
> #include <stddef.h>
>
> +struct compact_pmu_event {
> + int offset;
> +};
> +
> """)
> archs = []
> for item in os.scandir(_args.starting_dir):
> @@ -555,6 +663,15 @@ def main() -> None:
> for arch in archs:
> arch_path = f'{_args.starting_dir}/{arch}'
> preprocess_arch_std_files(arch_path)
> + ftw(arch_path, [], preprocess_one_file)
> +
> + _bcs.compute()
> + _args.output_file.write('static const char *const big_c_string =\n')
> + for s in _bcs.big_string:
> + _args.output_file.write(s)
> + _args.output_file.write(';\n\n')
> + for arch in archs:
> + arch_path = f'{_args.starting_dir}/{arch}'
> ftw(arch_path, [], process_one_file)
> print_events_table_suffix()
>
Em Thu, Aug 04, 2022 at 03:18:00PM -0700, Ian Rogers escreveu:
> Improve type hints to clean up pytype warnings.
Thanks, applied.
- Arnaldo
> Signed-off-by: Ian Rogers <[email protected]>
> ---
> tools/perf/pmu-events/jevents.py | 13 ++++++-------
> 1 file changed, 6 insertions(+), 7 deletions(-)
>
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index 83e0dcbeac9a..5b72048d50da 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -6,8 +6,7 @@ import csv
> import json
> import os
> import sys
> -from typing import Callable
> -from typing import Sequence
> +from typing import (Callable, Optional, Sequence)
>
> # Global command line arguments.
> _args = None
> @@ -57,7 +56,7 @@ class JsonEvent:
> '. '), '.').replace('\n', '\\n').replace(
> '\"', '\\"').replace('\r', '\\r')
>
> - def convert_aggr_mode(aggr_mode: str) -> str:
> + def convert_aggr_mode(aggr_mode: str) -> Optional[str]:
> """Returns the aggr_mode_class enum value associated with the JSON string."""
> if not aggr_mode:
> return None
> @@ -67,7 +66,7 @@ class JsonEvent:
> }
> return aggr_mode_to_enum[aggr_mode]
>
> - def lookup_msr(num: str) -> str:
> + def lookup_msr(num: str) -> Optional[str]:
> """Converts the msr number, or first in a list to the appropriate event field."""
> if not num:
> return None
> @@ -79,7 +78,7 @@ class JsonEvent:
> }
> return msrmap[int(num.split(',', 1)[0], 0)]
>
> - def real_event(name: str, event: str) -> str:
> + def real_event(name: str, event: str) -> Optional[str]:
> """Convert well known event names to an event string otherwise use the event argument."""
> fixed = {
> 'inst_retired.any': 'event=0xc0,period=2000003',
> @@ -95,7 +94,7 @@ class JsonEvent:
> return fixed[name.lower()]
> return event
>
> - def unit_to_pmu(unit: str) -> str:
> + def unit_to_pmu(unit: str) -> Optional[str]:
> """Convert a JSON Unit to Linux PMU name."""
> if not unit:
> return None
> @@ -154,7 +153,7 @@ class JsonEvent:
> if self.metric_expr:
> self.metric_expr = self.metric_expr.replace('\\', '\\\\')
> arch_std = jd.get('ArchStdEvent')
> - if precise and self.desc and not '(Precise Event)' in self.desc:
> + if precise and self.desc and '(Precise Event)' not in self.desc:
> extra_desc += ' (Must be precise)' if precise == '2' else (' (Precise '
> 'event)')
> event = f'config={llx(configcode)}' if configcode is not None else f'event={llx(eventcode)}'
> --
> 2.37.1.559.g78731f0fdb-goog
--
- Arnaldo
Em Thu, Aug 04, 2022 at 03:17:59PM -0700, Ian Rogers escreveu:
> jevents.py creates a number of large arrays from the json events. The
> arrays contain pointers to strings that need relocating. The
> relocations have file size, run time and memory costs. These changes
> refactor the pmu_events API so that the storage of the pmu_event
> struct isn't exposed. The format is then changed to an offset within a
> combined big string, with adjacent pmu_event struct variables being
> next to each other in the string separated by \0 - meaning only the
> first variable of the struct needs its offset recording.
>
> Some related fixes are contained with the patches. The architecture
> jevents.py creates tables for can now be set by the JEVENTS_ARCH make
> variable, with a new 'all' that generates the events and metrics for
> all architectures.
>
> An example of the improvement to the file size on x86 is:
> no jevents - the same 19,788,464bytes
> x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
> all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
> default build options plus NO_LIBBFD=1.
Applied the first four patches, waiting for the review comments to be
discussed.
- Arnaldo
> I originally suggested fixing this problem in:
> https://lore.kernel.org/linux-perf-users/CAP-5=fVB8G4bdb9T=FncRTh9oBVKCS=+=eowAO+YSgAhab+Dtg@mail.gmail.com/
>
> v4. Fixed an issue with the empty-pmu-events.c spotted by John Garry
> <[email protected]>.
> v3. Fix an ARM build issue with a missed weak symbol. Perform some
> pytype clean up.
> v2. Split the substring folding optimization to its own patch and
> comment tweaks as suggested by Namhyung Kim
> <[email protected]>. Recompute the file size savings with the
> latest json events and metrics.
>
> Ian Rogers (17):
> perf jevents: Clean up pytype warnings
> perf jevents: Simplify generation of C-string
> perf jevents: Add JEVENTS_ARCH make option
> perf jevent: Add an 'all' architecture argument
> perf jevents: Remove the type/version variables
> perf jevents: Provide path to json file on error
> perf jevents: Sort json files entries
> perf pmu-events: Hide pmu_sys_event_tables
> perf pmu-events: Avoid passing pmu_events_map
> perf pmu-events: Hide pmu_events_map
> perf test: Use full metric resolution
> perf pmu-events: Move test events/metrics to json
> perf pmu-events: Don't assume pmu_event is an array
> perf pmu-events: Hide the pmu_events
> perf metrics: Copy entire pmu_event in find metric
> perf jevents: Compress the pmu_events_table
> perf jevents: Fold strings optimization
>
> tools/perf/arch/arm64/util/pmu.c | 4 +-
> tools/perf/pmu-events/Build | 6 +-
> .../arch/test/test_soc/cpu/metrics.json | 64 +++
> tools/perf/pmu-events/empty-pmu-events.c | 204 +++++++-
> tools/perf/pmu-events/jevents.py | 495 ++++++++++++++----
> tools/perf/pmu-events/pmu-events.h | 40 +-
> tools/perf/tests/expand-cgroup.c | 25 +-
> tools/perf/tests/parse-metric.c | 77 +--
> tools/perf/tests/pmu-events.c | 466 +++++++----------
> tools/perf/util/metricgroup.c | 275 ++++++----
> tools/perf/util/metricgroup.h | 5 +-
> tools/perf/util/pmu.c | 139 ++---
> tools/perf/util/pmu.h | 8 +-
> tools/perf/util/s390-sample-raw.c | 50 +-
> 14 files changed, 1140 insertions(+), 718 deletions(-)
> create mode 100644 tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
>
> --
> 2.37.1.559.g78731f0fdb-goog
--
- Arnaldo
Em Fri, Aug 05, 2022 at 10:55:50AM +0100, John Garry escreveu:
> On 04/08/2022 23:18, Ian Rogers wrote:
> > Allow the architecture built into pmu-events.c to be set on the make
> > command line with JEVENTS_ARCH.
> >
> > Signed-off-by: Ian Rogers <[email protected]>
>
> Seems reasonable, so:
>
> Reviewed-by: John Garry <[email protected]>
Thanks, applied.
- Arnaldo
> I assume that if we run on the wrong arch (than we build for) then it has
> same effect as if pmu-events is not supported.
>
> > ---
> > tools/perf/pmu-events/Build | 6 +++++-
> > 1 file changed, 5 insertions(+), 1 deletion(-)
> >
> > diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
> > index 28a9d01b08af..04ef95174660 100644
> > --- a/tools/perf/pmu-events/Build
> > +++ b/tools/perf/pmu-events/Build
> > @@ -7,6 +7,10 @@ JSON_TEST = $(shell [ -d $(JDIR_TEST) ] && \
> > find $(JDIR_TEST) -name '*.json')
> > JEVENTS_PY = pmu-events/jevents.py
> > +ifeq ($(JEVENTS_ARCH),)
> > +JEVENTS_ARCH=$(SRCARCH)
> > +endif
> > +
> > #
> > # Locate/process JSON files in pmu-events/arch/
> > # directory and create tables in pmu-events.c.
> > @@ -19,5 +23,5 @@ $(OUTPUT)pmu-events/pmu-events.c: pmu-events/empty-pmu-events.c
> > else
> > $(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JSON_TEST) $(JEVENTS_PY)
> > $(call rule_mkdir)
> > - $(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(SRCARCH) pmu-events/arch $@
> > + $(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) pmu-events/arch $@
> > endif
--
- Arnaldo
Em Tue, Aug 09, 2022 at 04:40:43PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Thu, Aug 04, 2022 at 03:17:59PM -0700, Ian Rogers escreveu:
> > jevents.py creates a number of large arrays from the json events. The
> > arrays contain pointers to strings that need relocating. The
> > relocations have file size, run time and memory costs. These changes
> > refactor the pmu_events API so that the storage of the pmu_event
> > struct isn't exposed. The format is then changed to an offset within a
> > combined big string, with adjacent pmu_event struct variables being
> > next to each other in the string separated by \0 - meaning only the
> > first variable of the struct needs its offset recording.
> >
> > Some related fixes are contained with the patches. The architecture
> > jevents.py creates tables for can now be set by the JEVENTS_ARCH make
> > variable, with a new 'all' that generates the events and metrics for
> > all architectures.
> >
> > An example of the improvement to the file size on x86 is:
> > no jevents - the same 19,788,464bytes
> > x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
> > all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
> > default build options plus NO_LIBBFD=1.
>
> Applied the first four patches, waiting for the review comments to be
Sorry, three.
> discussed.
>
> - Arnaldo
>
> > I originally suggested fixing this problem in:
> > https://lore.kernel.org/linux-perf-users/CAP-5=fVB8G4bdb9T=FncRTh9oBVKCS=+=eowAO+YSgAhab+Dtg@mail.gmail.com/
> >
> > v4. Fixed an issue with the empty-pmu-events.c spotted by John Garry
> > <[email protected]>.
> > v3. Fix an ARM build issue with a missed weak symbol. Perform some
> > pytype clean up.
> > v2. Split the substring folding optimization to its own patch and
> > comment tweaks as suggested by Namhyung Kim
> > <[email protected]>. Recompute the file size savings with the
> > latest json events and metrics.
> >
> > Ian Rogers (17):
> > perf jevents: Clean up pytype warnings
> > perf jevents: Simplify generation of C-string
> > perf jevents: Add JEVENTS_ARCH make option
> > perf jevent: Add an 'all' architecture argument
> > perf jevents: Remove the type/version variables
> > perf jevents: Provide path to json file on error
> > perf jevents: Sort json files entries
> > perf pmu-events: Hide pmu_sys_event_tables
> > perf pmu-events: Avoid passing pmu_events_map
> > perf pmu-events: Hide pmu_events_map
> > perf test: Use full metric resolution
> > perf pmu-events: Move test events/metrics to json
> > perf pmu-events: Don't assume pmu_event is an array
> > perf pmu-events: Hide the pmu_events
> > perf metrics: Copy entire pmu_event in find metric
> > perf jevents: Compress the pmu_events_table
> > perf jevents: Fold strings optimization
> >
> > tools/perf/arch/arm64/util/pmu.c | 4 +-
> > tools/perf/pmu-events/Build | 6 +-
> > .../arch/test/test_soc/cpu/metrics.json | 64 +++
> > tools/perf/pmu-events/empty-pmu-events.c | 204 +++++++-
> > tools/perf/pmu-events/jevents.py | 495 ++++++++++++++----
> > tools/perf/pmu-events/pmu-events.h | 40 +-
> > tools/perf/tests/expand-cgroup.c | 25 +-
> > tools/perf/tests/parse-metric.c | 77 +--
> > tools/perf/tests/pmu-events.c | 466 +++++++----------
> > tools/perf/util/metricgroup.c | 275 ++++++----
> > tools/perf/util/metricgroup.h | 5 +-
> > tools/perf/util/pmu.c | 139 ++---
> > tools/perf/util/pmu.h | 8 +-
> > tools/perf/util/s390-sample-raw.c | 50 +-
> > 14 files changed, 1140 insertions(+), 718 deletions(-)
> > create mode 100644 tools/perf/pmu-events/arch/test/test_soc/cpu/metrics.json
> >
> > --
> > 2.37.1.559.g78731f0fdb-goog
>
> --
>
> - Arnaldo
--
- Arnaldo
On Fri, Aug 5, 2022 at 5:31 AM John Garry <[email protected]> wrote:
>
> On 04/08/2022 23:18, Ian Rogers wrote:
> > Move usage of the table to pmu-events.c so it may be hidden. By
> > abstracting the table the implementation can later be changed.
> >
> > Signed-off-by: Ian Rogers <[email protected]>
> > ---
> > tools/perf/pmu-events/empty-pmu-events.c | 81 ++++++++-
> > tools/perf/pmu-events/jevents.py | 81 ++++++++-
> > tools/perf/pmu-events/pmu-events.h | 29 +--
> > tools/perf/tests/pmu-events.c | 218 +++++++++++------------
> > tools/perf/util/metricgroup.c | 15 +-
> > tools/perf/util/pmu.c | 34 +---
> > tools/perf/util/pmu.h | 2 +-
> > 7 files changed, 280 insertions(+), 180 deletions(-)
> >
> > diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c
> > index 216ea0482c37..8ef75aff996c 100644
> > --- a/tools/perf/pmu-events/empty-pmu-events.c
> > +++ b/tools/perf/pmu-events/empty-pmu-events.c
> > @@ -6,6 +6,8 @@
> > * The test cpu/soc is provided for testing.
> > */
> > #include "pmu-events/pmu-events.h"
> > +#include "util/header.h"
> > +#include "util/pmu.h"
> > #include <string.h>
> > #include <stddef.h>
> >
> > @@ -110,7 +112,26 @@ static const struct pmu_event pme_test_soc_cpu[] = {
> > },
> > };
> >
> > -const struct pmu_events_map pmu_events_map[] = {
> > +
> > +/*
> > + * Map a CPU to its table of PMU events. The CPU is identified by the
> > + * cpuid field, which is an arch-specific identifier for the CPU.
> > + * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
> > + * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
> > + *
> > + * The cpuid can contain any character other than the comma.
> > + */
> > +struct pmu_events_map {
> > + const char *arch;
> > + const char *cpuid;
> > + const struct pmu_event *table;
> > +};
> > +
> > +/*
> > + * Global table mapping each known CPU for the architecture to its
> > + * table of PMU events.
> > + */
> > +static const struct pmu_events_map pmu_events_map[] = {
> > {
> > .arch = "testarch",
> > .cpuid = "testcpu",
> > @@ -162,6 +183,62 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> > },
> > };
> >
> > +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> > +{
> > + const struct pmu_event *table = NULL;
> > + char *cpuid = perf_pmu__getcpuid(pmu);
> > + int i;
> > +
> > + /* on some platforms which uses cpus map, cpuid can be NULL for
> > + * PMUs other than CORE PMUs.
> > + */
> > + if (!cpuid)
> > + return NULL;
> > +
> > + i = 0;
> > + for (;;) {
> > + const struct pmu_events_map *map = &pmu_events_map[i++];
> > +
> > + if (!map->table)
> > + break;
> > +
> > + if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> > + table = map->table;
> > + break;
> > + }
> > + }
> > + free(cpuid);
> > + return table;
> > +}
> > +
> > +const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
> > +{
> > + for (const struct pmu_events_map *tables = &pmu_events_map[0];
> > + tables->table;
> > + tables++) {
> > + if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
> > + return tables->table;
> > + }
> > + return NULL;
> > +}
> > +
> > +int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
> > +{
> > + for (const struct pmu_events_map *tables = &pmu_events_map[0];
> > + tables->table;
> > + tables++) {
> > + for (const struct pmu_event *pe = &tables->table[0];
> > + pe->name || pe->metric_group || pe->metric_name;
> > + pe++) {
> > + int ret = fn(pe, &tables->table[0], data);
> > +
> > + if (ret)
> > + return ret;
> > + }
> > + }
> > + return 0;
> > +}
> > +
> > const struct pmu_event *find_sys_events_table(const char *name)
> > {
> > for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
> > @@ -181,7 +258,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
> > for (const struct pmu_event *pe = &tables->table[0];
> > pe->name || pe->metric_group || pe->metric_name;
> > pe++) {
> > - int ret = fn(pe, data);
> > + int ret = fn(pe, &tables->table[0], data);
> >
> > if (ret)
> > return ret;
> > diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> > index dd21bc9eeeed..e976c5e8e80b 100755
> > --- a/tools/perf/pmu-events/jevents.py
> > +++ b/tools/perf/pmu-events/jevents.py
> > @@ -333,7 +333,27 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> >
> > def print_mapping_table(archs: Sequence[str]) -> None:
> > """Read the mapfile and generate the struct from cpuid string to event table."""
> > - _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
> > + _args.output_file.write("""
> > +/*
> > + * Map a CPU to its table of PMU events. The CPU is identified by the
> > + * cpuid field, which is an arch-specific identifier for the CPU.
> > + * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
> > + * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
> > + *
> > + * The cpuid can contain any character other than the comma.
> > + */
> > +struct pmu_events_map {
> > + const char *arch;
> > + const char *cpuid;
> > + const struct pmu_event *table;
> > +};
> > +
> > +/*
> > + * Global table mapping each known CPU for the architecture to its
> > + * table of PMU events.
> > + */
> > +const struct pmu_events_map pmu_events_map[] = {
> > +""")
> > for arch in archs:
> > if arch == 'test':
> > _args.output_file.write("""{
> > @@ -389,6 +409,61 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> > \t},
> > };
> >
> > +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> > +{
> > + const struct pmu_event *table = NULL;
> > + char *cpuid = perf_pmu__getcpuid(pmu);
>
> This seems an identical implementation to that in empty-pmu-events.c -
> can we reduce this duplication? Maybe a seperate common c file which can
> be linked in
>
> The indentation seems different also - this version seems to use whitespaces
Agreed. Later on this will change, the empty version isn't compressed
and the jevents.py one is. Having a common C file would defeat the
goal of hiding the API, but ultimately we'd need to get rid of it in
later changes when the empty/compressed implementations diverge.
Thanks,
Ian
> > + int i;
> > +
> > + /* on some platforms which uses cpus map, cpuid can be NULL for
> > + * PMUs other than CORE PMUs.
> > + */
> > + if (!cpuid)
> > + return NULL;
> > +
> > + i = 0;
> > + for (;;) {
> > + const struct pmu_events_map *map = &pmu_events_map[i++];
> > + if (!map->table)
> > + break;
> > +
> > + if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> > + table = map->table;
> > + break;
> > + }
> > + }
> > + free(cpuid);
> > + return table;
> > +}
On Fri, Aug 5, 2022 at 7:02 AM John Garry <[email protected]> wrote:
>
> On 04/08/2022 23:18, Ian Rogers wrote:
> > The pmu_events array requires 15 pointers per entry which in position
> > independent code need relocating. Change the array to be an array of
> > offsets within a big C string. Only the offset of the first variable is
> > required, subsequent variables are stored in order after the \0
> > terminator (requiring a byte per variable rather than 4 bytes per
> > offset).
> >
> > The file size savings are:
> > no jevents - the same 19,788,464bytes
> > x86 jevents - ~16.7% file size saving 23,744,288bytes vs 28,502,632bytes
> > all jevents - ~19.5% file size saving 24,469,056bytes vs 30,379,920bytes
> > default build options plus NO_LIBBFD=1.
> >
> > For example, the x86 build savings come from .rela.dyn and
> > .data.rel.ro becoming smaller by 3,157,032bytes and 3,042,016bytes
> > respectively. .rodata increases by 1,432,448bytes, giving an overall
> > 4,766,600bytes saving.
> >
> > To make metric strings more shareable, the topic is changed from say
> > 'skx metrics' to just 'metrics'.
> >
> > To try to help with the memory layout the pmu_events are ordered as used
> > by perf qsort comparator functions.
> >
> > Signed-off-by: Ian Rogers <[email protected]>
> > ---
> > tools/perf/pmu-events/jevents.py | 207 ++++++++++++++++++++++++-------
> > 1 file changed, 162 insertions(+), 45 deletions(-)
> >
> > diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> > index aa8df649025a..a5e162558994 100755
> > --- a/tools/perf/pmu-events/jevents.py
> > +++ b/tools/perf/pmu-events/jevents.py
> > @@ -6,7 +6,8 @@ import csv
> > import json
> > import os
> > import sys
> > -from typing import (Callable, Optional, Sequence)
> > +from typing import (Callable, Dict, Optional, Sequence, Set, Tuple)
> > +import collections
> >
> > # Global command line arguments.
> > _args = None
> > @@ -20,6 +21,19 @@ _arch_std_events = {}
> > _close_table = False
> > # Events to write out when the table is closed
> > _pending_events = []
> > +# Global BigCString shared by all structures.
> > +_bcs = None
> > +# Order specific JsonEvent attributes will be visited.
> > +_json_event_attributes = [
> > + # cmp_sevent related attributes.
> > + 'name', 'pmu', 'topic', 'desc', 'metric_name', 'metric_group',
> > + # Seems useful, put it early.
> > + 'event',
> > + # Short things in alphabetical order.
> > + 'aggr_mode', 'compat', 'deprecated', 'perpkg', 'unit',
> > + # Longer things (the last won't be iterated over during decompress).
> > + 'metric_constraint', 'metric_expr', 'long_desc'
> > +]
> >
> >
> > def removesuffix(s: str, suffix: str) -> str:
> > @@ -39,6 +53,66 @@ def file_name_to_table_name(parents: Sequence[str], dirname: str) -> str:
> > tblname += '_' + dirname
> > return tblname.replace('-', '_')
> >
> > +def c_len(s: str) -> int:
> > + """Return the length of s a C string
> > +
> > + This doesn't handle all escape characters properly. It first assumes
> > + all \ are for escaping, it then adjusts as it will have over counted
> > + \\. The code uses \000 rather than \0 as a terminator as an adjacent
> > + number would be folded into a string of \0 (ie. "\0" + "5" doesn't
> > + equal a terminator followed by the number 5 but the escape of
> > + \05). The code adjusts for \000 but not properly for all octal, hex
> > + or unicode values.
> > + """
> > + try:
> > + utf = s.encode(encoding='utf-8',errors='strict')
> > + except:
> > + print(f'broken string {s}')
> > + raise
> > + return len(utf) - utf.count(b'\\') + utf.count(b'\\\\') - (utf.count(b'\\000') * 2)
> > +
> > +class BigCString:
> > + """A class to hold many strings concatenated together.
> > +
> > + Generating a large number of stand-alone C strings creates a large
> > + number of relocations in position independent code. The BigCString
> > + is a helper for this case. It builds a single string which within it
> > + are all the other C strings (to avoid memory issues the string
> > + itself is held as a list of strings). The offsets within the big
> > + string are recorded and when stored to disk these don't need
> > + relocation.
> > + """
> > + strings: Set[str]
> > + big_string: Sequence[str]
> > + offsets: Dict[str, int]
> > +
> > + def __init__(self):
> > + self.strings = set()
> > +
> > + def add(self, s: str) -> None:
> > + """Called to add to the big string."""
> > + self.strings.add(s)
> > +
> > + def compute(self) -> None:
> > + """Called once all strings are added to compute the string and offsets."""
> > +
> > + # big_string_offset is the current location within the C string
> > + # being appended to - comments, etc. don't count. big_string is
> > + # the string contents represented as a list. Strings are immutable
> > + # in Python and so appending to one causes memory issues, while
> > + # lists are mutable.
> > + big_string_offset = 0
> > + self.big_string = []
> > + self.offsets = {}
> > + # Emit all strings in a sorted manner.
> > + for s in sorted(self.strings):
> > + self.offsets[s] = big_string_offset
> > + self.big_string.append(f'/* offset={big_string_offset} */ "')
> > + self.big_string.append(s)
> > + self.big_string.append('"\n')
> > + big_string_offset += c_len(s)
> > +
> > +_bcs = BigCString()
> >
> > class JsonEvent:
> > """Representation of an event loaded from a json file dictionary."""
> > @@ -202,26 +276,18 @@ class JsonEvent:
> > s += f'\t{attr} = {value},\n'
> > return s + '}'
> >
> > + def build_c_string(self) -> str:
> > + s = ''
> > + for attr in _json_event_attributes:
> > + x = getattr(self, attr)
> > + s += f'{x}\\000' if x else '\\000'
> > + return s
> > +
> > def to_c_string(self) -> str:
> > """Representation of the event as a C struct initializer."""
> >
> > - def attr_string(attr: str, value: str) -> str:
> > - return f'\t.{attr} = \"{value}\",\n'
> > -
> > - def str_if_present(self, attr: str) -> str:
> > - if not getattr(self, attr):
> > - return ''
> > - return attr_string(attr, getattr(self, attr))
> > -
> > - s = '{\n'
> > - for attr in [
> > - 'aggr_mode', 'compat', 'deprecated', 'desc', 'event', 'long_desc',
> > - 'metric_constraint', 'metric_expr', 'metric_group', 'metric_name',
> > - 'name', 'perpkg', 'pmu', 'topic', 'unit'
> > - ]:
> > - s += str_if_present(self, attr)
> > - s += '},\n'
> > - return s
> > + s = self.build_c_string()
> > + return f'{{ { _bcs.offsets[s] } }}, /* {s} */\n'
> >
> >
> > def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
> > @@ -236,7 +302,6 @@ def read_json_events(path: str, topic: str) -> Sequence[JsonEvent]:
> > event.topic = topic
> > return result
> >
> > -
> > def preprocess_arch_std_files(archpath: str) -> None:
> > """Read in all architecture standard events."""
> > global _arch_std_events
> > @@ -252,7 +317,7 @@ def print_events_table_prefix(tblname: str) -> None:
> > global _close_table
> > if _close_table:
> > raise IOError('Printing table prefix but last table has no suffix')
> > - _args.output_file.write(f'static const struct pmu_event {tblname}[] = {{\n')
> > + _args.output_file.write(f'static const struct compact_pmu_event {tblname}[] = {{\n')
> > _close_table = True
> >
> >
> > @@ -267,13 +332,13 @@ def add_events_table_entries(item: os.DirEntry, topic: str) -> None:
> > def print_events_table_suffix() -> None:
> > """Optionally close events table."""
> >
> > - def event_cmp_key(j: JsonEvent):
> > - def fix_none(s: str):
> > + def event_cmp_key(j: JsonEvent) -> Tuple[bool, str, str, str, str]:
> > + def fix_none(s: Optional[str]) -> str:
> > if s is None:
> > return ''
> > return s
> >
> > - return (not j.desc is None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> > + return (j.desc is not None, fix_none(j.topic), fix_none(j.name), fix_none(j.pmu),
> > fix_none(j.metric_name))
> >
> > global _close_table
> > @@ -285,23 +350,37 @@ def print_events_table_suffix() -> None:
> > _args.output_file.write(event.to_c_string())
> > _pending_events = []
> >
> > - _args.output_file.write("""{
> > -\t.name = 0,
> > -\t.event = 0,
> > -\t.desc = 0,
> > -},
> > -};
> > -""")
> > + _args.output_file.write('};\n\n')
> > _close_table = False
> >
> > +def get_topic(topic: str) -> str:
> > + if topic.endswith('metrics.json'):
> > + return 'metrics'
> > + return removesuffix(topic, '.json').replace('-', ' ')
> > +
> > +def preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> > +
> > + if item.is_dir():
> > + return
> > +
> > + # base dir or too deep
> > + level = len(parents)
> > + if level == 0 or level > 4:
> > + return
> > +
> > + # Ignore other directories. If the file name does not have a .json
> > + # extension, ignore it. It could be a readme.txt for instance.
> > + if not item.is_file() or not item.name.endswith('.json'):
> > + return
> > +
> > + topic = get_topic(item.name)
> > + for event in read_json_events(item.path, topic):
> > + _bcs.add(event.build_c_string())
> >
> > def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
> > """Process a JSON file during the main walk."""
> > global _sys_event_tables
> >
> > - def get_topic(topic: str) -> str:
> > - return removesuffix(topic, '.json').replace('-', ' ')
> > -
> > def is_leaf_dir(path: str) -> bool:
> > for item in os.scandir(path):
> > if item.is_dir():
> > @@ -336,7 +415,8 @@ def print_mapping_table(archs: Sequence[str]) -> None:
> > _args.output_file.write("""
> > /* Struct used to make the PMU event table implementation opaque to callers. */
> > struct pmu_events_table {
> > - const struct pmu_event *entries;
> > + const struct compact_pmu_event *entries;
> > + size_t length;
> > };
> >
> > /*
> > @@ -364,7 +444,10 @@ const struct pmu_events_map pmu_events_map[] = {
> > _args.output_file.write("""{
> > \t.arch = "testarch",
> > \t.cpuid = "testcpu",
> > -\t.table = { pme_test_soc_cpu },
> > +\t.table = {
> > +\t.entries = pme_test_soc_cpu,
> > +\t.length = ARRAY_SIZE(pme_test_soc_cpu),
> > +\t}
> > },
> > """)
> > else:
> > @@ -379,7 +462,10 @@ const struct pmu_events_map pmu_events_map[] = {
> > _args.output_file.write(f"""{{
> > \t.arch = "{arch}",
> > \t.cpuid = "{cpuid}",
> > -\t.table = {{ {tblname} }}
> > +\t.table = {{
> > +\t\t.entries = {tblname},
> > +\t\t.length = ARRAY_SIZE({tblname})
> > +\t}}
> > }},
> > """)
> > first = False
> > @@ -387,7 +473,7 @@ const struct pmu_events_map pmu_events_map[] = {
> > _args.output_file.write("""{
> > \t.arch = 0,
> > \t.cpuid = 0,
> > -\t.table = { 0 },
> > +\t.table = { 0, 0 },
> > }
> > };
> > """)
> > @@ -405,23 +491,41 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
> > """)
> > for tblname in _sys_event_tables:
> > _args.output_file.write(f"""\t{{
> > -\t\t.table = {{ {tblname} }},
> > +\t\t.table = {{
> > +\t\t\t.entries = {tblname},
> > +\t\t\t.length = ARRAY_SIZE({tblname})
> > +\t\t}},
> > \t\t.name = \"{tblname}\",
> > \t}},
> > """)
> > _args.output_file.write("""\t{
> > -\t\t.table = { 0 }
> > +\t\t.table = { 0, 0 }
> > \t},
> > };
> >
> > -int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
> > +static void decompress(int offset, struct pmu_event *pe)
> > +{
> > +\tconst char *p = &big_c_string[offset];
> > +""")
> > + for attr in _json_event_attributes:
> > + _args.output_file.write(f"""
> > +\tpe->{attr} = (*p == '\\0' ? NULL : p);
> > +""")
> > + if attr == _json_event_attributes[-1]:
> > + continue
> > + _args.output_file.write('\twhile (*p++);')
> > + _args.output_file.write("""}
>
>
> I get this in generated pmu-events.c:
>
> static void decompress(int offset, struct pmu_event *pe)
> {
> const char *p = &big_c_string[offset];
>
> pe->name = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->pmu = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->topic = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->desc = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->metric_name = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->metric_group = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->event = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->aggr_mode = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->compat = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->deprecated = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->perpkg = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->unit = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->metric_constraint = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->metric_expr = (*p == '\0' ? NULL : p);
> while (*p++);
> pe->long_desc = (*p == '\0' ? NULL : p);
> }
>
> int pmu_events_table_for_each_event(const struct pmu_events_table *table,
> pmu_event_iter_fn fn,
> void *data)
> {
> for (size_t i = 0; i < table->length; i++) {
> struct pmu_event pe;
> int ret;
>
> decompress(table->entries[i].offset, &pe);
> ret = fn(&pe, table, data);
> if (ret)
> return ret;
> }
> return 0;
> }
>
> --->8---
>
> This seems a bit inefficient in terms of performance - if that really is
> a requirement, but I figure that it isn't really.
I think the main inefficiency is coming from the struct pmu_event
containing so many variables. I think we can modify that later, say by
separating metrics from events, I did look at performance and the
decompress function is hot but overall the performance was similar to
before the change for some hand crafted examples.
> Another observation is that although we compress and reduce size in this
> method, we are now losing out on some sharing of strings. For example,
> this is an extract from big_string:
>
> /* offset=3342573 */
> "unc_p_core0_transition_cycles\000uncore_pcu\000uncore power\000Core 0 C
> State Transition Cycles. Unit: uncore_pcu
> \000\000\000event=0x70\000\000\000\0001\000\000\000\000Number of cycles
> spent performing core C state transitions. There is one event per core\000"
> /* offset=3342789 */
> "unc_p_core0_transition_cycles\000uncore_pcu\000uncore power\000Core C
> State Transition Cycles. Unit: uncore_pcu
> \000\000\000event=0x103\000\000\000\0001\000\000\000\000Number of cycles
> spent performing core C state transitions. There is one event per core\000"
>
> These super-strings are not identical, but many sub-strings are, like
> "Number of cycles spent performing core C state transitions. There is
> one event per core", so we are losing out there on sharing strings there.
Agreed. I found that the savings by having a single offset were in
O(100kbs) and so had to give up string sharing for this.
Thanks,
Ian
> Thanks,
> John
> > +
> > +int pmu_events_table_for_each_event(const struct pmu_events_table *table,
> > + pmu_event_iter_fn fn,
> > void *data)
> > {
> > - for (const struct pmu_event *pe = &table->entries[0];
> > - pe->name || pe->metric_group || pe->metric_name;
> > - pe++) {
> > - int ret = fn(pe, table, data);
> > + for (size_t i = 0; i < table->length; i++) {
> > + struct pmu_event pe;
> > + int ret;
> >
> > + decompress(table->entries[i].offset, &pe);
> > + ret = fn(&pe, table, data);
> > if (ret)
> > return ret;
> > }
> > @@ -530,7 +634,7 @@ def main() -> None:
> > help='Root of tree containing architecture directories containing json files'
> > )
> > ap.add_argument(
> > - 'output_file', type=argparse.FileType('w'), nargs='?', default=sys.stdout)
> > + 'output_file', type=argparse.FileType('w', encoding='utf-8'), nargs='?', default=sys.stdout)
> > _args = ap.parse_args()
> >
> > _args.output_file.write("""
> > @@ -540,6 +644,10 @@ def main() -> None:
> > #include <string.h>
> > #include <stddef.h>
> >
> > +struct compact_pmu_event {
> > + int offset;
> > +};
> > +
> > """)
> > archs = []
> > for item in os.scandir(_args.starting_dir):
> > @@ -555,6 +663,15 @@ def main() -> None:
> > for arch in archs:
> > arch_path = f'{_args.starting_dir}/{arch}'
> > preprocess_arch_std_files(arch_path)
> > + ftw(arch_path, [], preprocess_one_file)
> > +
> > + _bcs.compute()
> > + _args.output_file.write('static const char *const big_c_string =\n')
> > + for s in _bcs.big_string:
> > + _args.output_file.write(s)
> > + _args.output_file.write(';\n\n')
> > + for arch in archs:
> > + arch_path = f'{_args.starting_dir}/{arch}'
> > ftw(arch_path, [], process_one_file)
> > print_events_table_suffix()
> >
>
On Fri, Aug 5, 2022 at 4:28 AM John Garry <[email protected]> wrote:
>
> On 04/08/2022 23:18, Ian Rogers wrote:
> > Preparation for hiding pmu_events_map as an implementation detail. While
> > the map is passed, the table of events is all that is normally wanted.
> >
> > Signed-off-by: Ian Rogers <[email protected]>
>
> Apart from comments on naming, below:
>
> Reviewed-by: John Garry <[email protected]>
>
> As an aside, I will mention that reviewing this series is not helped by
> limited description of the changes in the cover letter. A primer would
> be nice. As I go through the series, I am often assuming that the
> motivation for the change is sound.
Ack. I was hoping the compression motivation would be enough in the
cover letter, but yeah the refactoring to get to that is painful and
could do with more explaining. Thanks for the reviews!
> Thanks,
> John
>
> > ---
> > tools/perf/arch/arm64/util/pmu.c | 4 +-
> > tools/perf/tests/expand-cgroup.c | 6 +--
> > tools/perf/tests/parse-metric.c | 7 +--
> > tools/perf/tests/pmu-events.c | 63 +++++++++++-------------
> > tools/perf/util/metricgroup.c | 82 +++++++++++++++----------------
> > tools/perf/util/metricgroup.h | 4 +-
> > tools/perf/util/pmu.c | 33 +++++++------
> > tools/perf/util/pmu.h | 6 +--
> > tools/perf/util/s390-sample-raw.c | 12 ++---
> > 9 files changed, 99 insertions(+), 118 deletions(-)
> >
> > diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c
> > index 79124bba713e..646af8603227 100644
> > --- a/tools/perf/arch/arm64/util/pmu.c
> > +++ b/tools/perf/arch/arm64/util/pmu.c
> > @@ -3,7 +3,7 @@
> > #include "../../../util/cpumap.h"
> > #include "../../../util/pmu.h"
> >
> > -const struct pmu_events_map *pmu_events_map__find(void)
> > +const struct pmu_event *pmu_events_map__find(void)
>
> The function name is no longer appropriate
>
>
> > {
> > struct perf_pmu *pmu = NULL;
> >
> > @@ -18,7 +18,7 @@ const struct pmu_events_map *pmu_events_map__find(void)
> > if (pmu->cpus->nr != cpu__max_cpu().cpu)
> > return NULL;
> >
> > - return perf_pmu__find_map(pmu);
> > + return perf_pmu__find_table(pmu);
> > }
> >
> > return NULL;
> > diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
> > index dc4038f997d7..411fc578e5a4 100644
> > --- a/tools/perf/tests/expand-cgroup.c
> > +++ b/tools/perf/tests/expand-cgroup.c
> > @@ -195,16 +195,12 @@ static int expand_metric_events(void)
> > .metric_name = NULL,
> > },
> > };
> > - const struct pmu_events_map ev_map = {
> > - .cpuid = "test",
> > - .table = pme_test,
> > - };
> >
> > evlist = evlist__new();
> > TEST_ASSERT_VAL("failed to get evlist", evlist);
> >
> > rblist__init(&metric_events);
> > - ret = metricgroup__parse_groups_test(evlist, &ev_map, metric_str,
> > + ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str,
> > false, false, &metric_events);
> > if (ret < 0) {
> > pr_debug("failed to parse '%s' metric\n", metric_str);
> > diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> > index 1b811a26f4ee..7aebde7c37ec 100644
> > --- a/tools/perf/tests/parse-metric.c
> > +++ b/tools/perf/tests/parse-metric.c
> > @@ -79,11 +79,6 @@ static struct pmu_event pme_test[] = {
> > }
> > };
> >
> > -static const struct pmu_events_map map = {
> > - .cpuid = "test",
> > - .table = pme_test,
> > -};
> > -
> > struct value {
> > const char *event;
> > u64 val;
> > @@ -166,7 +161,7 @@ static int __compute_metric(const char *name, struct value *vals,
> > runtime_stat__init(&st);
> >
> > /* Parse the metric into metric_events list. */
> > - err = metricgroup__parse_groups_test(evlist, &map, name,
> > + err = metricgroup__parse_groups_test(evlist, pme_test, name,
> > false, false,
> > &metric_events);
> > if (err)
> > diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> > index a39a2c99ede6..b3cde5f98982 100644
> > --- a/tools/perf/tests/pmu-events.c
> > +++ b/tools/perf/tests/pmu-events.c
> > @@ -272,13 +272,11 @@ static bool is_same(const char *reference, const char *test)
> > return !strcmp(reference, test);
> > }
> >
> > -static const struct pmu_events_map *__test_pmu_get_events_map(void)
> > +static const struct pmu_event *__test_pmu_get_events_table(void)
> > {
> > - const struct pmu_events_map *map;
> > -
> > - for (map = &pmu_events_map[0]; map->cpuid; map++) {
> > + for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
> > if (!strcmp(map->cpuid, "testcpu"))
> > - return map;
> > + return map->table;
> > }
> >
> > pr_err("could not find test events map\n");
> > @@ -440,8 +438,7 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
> > int subtest __maybe_unused)
> > {
> > const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
> > - const struct pmu_events_map *map = __test_pmu_get_events_map();
> > - const struct pmu_event *table;
> > + const struct pmu_event *table = __test_pmu_get_events_table();
> > int map_events = 0, expected_events;
> >
> > /* ignore 3x sentinels */
> > @@ -449,10 +446,10 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
> > ARRAY_SIZE(uncore_events) +
> > ARRAY_SIZE(sys_events) - 3;
> >
> > - if (!map || !sys_event_tables)
> > + if (!table || !sys_event_tables)
> > return -1;
> >
> > - for (table = map->table; table->name; table++) {
> > + for (; table->name; table++) {
> > struct perf_pmu_test_event const **test_event_table;
> > bool found = false;
> >
> > @@ -537,10 +534,10 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
> > struct perf_pmu *pmu;
> > LIST_HEAD(aliases);
> > int res = 0;
> > - const struct pmu_events_map *map = __test_pmu_get_events_map();
> > + const struct pmu_event *table = __test_pmu_get_events_table();
> > struct perf_pmu_alias *a, *tmp;
> >
> > - if (!map)
> > + if (!table)
> > return -1;
> >
> > test_event_table = &core_events[0];
> > @@ -551,7 +548,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
> >
> > pmu->name = pmu_name;
> >
> > - pmu_add_cpu_aliases_map(&aliases, pmu, map);
> > + pmu_add_cpu_aliases_map(&aliases, pmu, table);
> >
> > for (; *test_event_table; test_event_table++) {
> > struct perf_pmu_test_event const *test_event = *test_event_table;
> > @@ -590,14 +587,14 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
> > struct perf_pmu *pmu = &test_pmu->pmu;
> > const char *pmu_name = pmu->name;
> > struct perf_pmu_alias *a, *tmp, *alias;
> > - const struct pmu_events_map *map;
> > + const struct pmu_event *events_table;
> > LIST_HEAD(aliases);
> > int res = 0;
> >
> > - map = __test_pmu_get_events_map();
> > - if (!map)
> > + events_table = __test_pmu_get_events_table();
> > + if (!events_table)
> > return -1;
> > - pmu_add_cpu_aliases_map(&aliases, pmu, map);
> > + pmu_add_cpu_aliases_map(&aliases, pmu, events_table);
> > pmu_add_sys_aliases(&aliases, pmu);
> >
> > /* Count how many aliases we generated */
> > @@ -848,13 +845,9 @@ static int check_parse_fake(const char *id)
> > return ret;
> > }
> >
> > -static void expr_failure(const char *msg,
> > - const struct pmu_events_map *map,
> > - const struct pmu_event *pe)
> > +static void expr_failure(const char *msg, const struct pmu_event *pe)
> > {
> > - pr_debug("%s for map %s %s\n", msg, map->arch, map->cpuid);
> > - pr_debug("On metric %s\n", pe->metric_name);
> > - pr_debug("On expression %s\n", pe->metric_expr);
> > + pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
> > }
> >
> > struct metric {
> > @@ -864,7 +857,7 @@ struct metric {
> >
> > static int resolve_metric_simple(struct expr_parse_ctx *pctx,
> > struct list_head *compound_list,
> > - const struct pmu_events_map *map,
> > + const struct pmu_event *map,
> > const char *metric_name)
> > {
> > struct hashmap_entry *cur, *cur_tmp;
> > @@ -925,8 +918,7 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx,
> > static int test__parsing(struct test_suite *test __maybe_unused,
> > int subtest __maybe_unused)
> > {
> > - const struct pmu_events_map *cpus_map = pmu_events_map__find();
> > - const struct pmu_events_map *map;
> > + const struct pmu_event *cpus_table = pmu_events_map__find();
> > const struct pmu_event *pe;
> > int i, j, k;
> > int ret = 0;
> > @@ -940,7 +932,8 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> > }
> > i = 0;
> > for (;;) {
> > - map = &pmu_events_map[i++];
> > + const struct pmu_events_map *map = &pmu_events_map[i++];
> > +
> > if (!map->table)
> > break;
> > j = 0;
> > @@ -957,14 +950,14 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> > continue;
> > expr__ctx_clear(ctx);
> > if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
> > - expr_failure("Parse find ids failed", map, pe);
> > + expr_failure("Parse find ids failed", pe);
> > ret++;
> > continue;
> > }
> >
> > - if (resolve_metric_simple(ctx, &compound_list, map,
> > + if (resolve_metric_simple(ctx, &compound_list, map->table,
> > pe->metric_name)) {
> > - expr_failure("Could not resolve metrics", map, pe);
> > + expr_failure("Could not resolve metrics", pe);
> > ret++;
> > goto exit; /* Don't tolerate errors due to severity */
> > }
> > @@ -979,7 +972,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> > expr__add_id_val(ctx, strdup(cur->key), k++);
> >
> > hashmap__for_each_entry(ctx->ids, cur, bkt) {
> > - if (check_parse_cpu(cur->key, map == cpus_map,
> > + if (check_parse_cpu(cur->key, map->table == cpus_table,
> > pe))
> > ret++;
> > }
> > @@ -999,7 +992,7 @@ static int test__parsing(struct test_suite *test __maybe_unused,
> > hashmap__for_each_entry(ctx->ids, cur, bkt)
> > expr__add_id_val(ctx, strdup(cur->key), k--);
> > if (expr__parse(&result, ctx, pe->metric_expr)) {
> > - expr_failure("Parse failed", map, pe);
> > + expr_failure("Parse failed", pe);
> > ret++;
> > }
> > }
> > @@ -1088,8 +1081,6 @@ static int metric_parse_fake(const char *str)
> > static int test__parsing_fake(struct test_suite *test __maybe_unused,
> > int subtest __maybe_unused)
> > {
> > - const struct pmu_events_map *map;
> > - const struct pmu_event *pe;
> > unsigned int i, j;
> > int err = 0;
> >
> > @@ -1101,12 +1092,14 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused,
> >
> > i = 0;
> > for (;;) {
> > - map = &pmu_events_map[i++];
> > + const struct pmu_events_map *map = &pmu_events_map[i++];
> > +
> > if (!map->table)
> > break;
> > j = 0;
> > for (;;) {
> > - pe = &map->table[j++];
> > + const struct pmu_event *pe = &map->table[j++];
> > +
> > if (!pe->name && !pe->metric_group && !pe->metric_name)
> > break;
> > if (!pe->metric_expr)
> > diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> > index 8f7baeabc5cf..4d32b4fbf67d 100644
> > --- a/tools/perf/util/metricgroup.c
> > +++ b/tools/perf/util/metricgroup.c
> > @@ -539,9 +539,6 @@ static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *d
> > void metricgroup__print(bool metrics, bool metricgroups, char *filter,
> > bool raw, bool details, const char *pmu_name)
> > {
> > - const struct pmu_events_map *map = pmu_events_map__find();
> > - const struct pmu_event *pe;
> > - int i;
> > struct rblist groups;
> > struct rb_node *node, *next;
> > struct strlist *metriclist = NULL;
> > @@ -556,8 +553,7 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
> > groups.node_new = mep_new;
> > groups.node_cmp = mep_cmp;
> > groups.node_delete = mep_delete;
> > - for (i = 0; map; i++) {
> > - pe = &map->table[i];
> > + for (const struct pmu_event *pe = pmu_events_map__find(); pe; pe++) {
> >
> > if (!pe->name && !pe->metric_group && !pe->metric_name)
> > break;
> > @@ -850,7 +846,7 @@ struct metricgroup_add_iter_data {
> > bool metric_no_group;
> > struct metric *root_metric;
> > const struct visited_metric *visited;
> > - const struct pmu_events_map *map;
> > + const struct pmu_event *table;
> > };
> >
> > static int add_metric(struct list_head *metric_list,
> > @@ -859,7 +855,7 @@ static int add_metric(struct list_head *metric_list,
> > bool metric_no_group,
> > struct metric *root_metric,
> > const struct visited_metric *visited,
> > - const struct pmu_events_map *map);
> > + const struct pmu_event *table);
> >
> > /**
> > * resolve_metric - Locate metrics within the root metric and recursively add
> > @@ -874,7 +870,7 @@ static int add_metric(struct list_head *metric_list,
> > * metrics. When adding a root this argument is NULL.
> > * @visited: A singly linked list of metric names being added that is used to
> > * detect recursion.
> > - * @map: The map that is searched for metrics, most commonly the table for the
> > + * @table: The table that is searched for metrics, most commonly the table for the
> > * architecture perf is running upon.
> > */
> > static int resolve_metric(struct list_head *metric_list,
> > @@ -882,7 +878,7 @@ static int resolve_metric(struct list_head *metric_list,
> > bool metric_no_group,
> > struct metric *root_metric,
> > const struct visited_metric *visited,
> > - const struct pmu_events_map *map)
> > + const struct pmu_event *table)
> > {
> > struct hashmap_entry *cur;
> > size_t bkt;
> > @@ -904,7 +900,7 @@ static int resolve_metric(struct list_head *metric_list,
> > hashmap__for_each_entry(root_metric->pctx->ids, cur, bkt) {
> > const struct pmu_event *pe;
> >
> > - pe = metricgroup__find_metric(cur->key, map);
> > + pe = metricgroup__find_metric(cur->key, table);
> > if (pe) {
> > pending = realloc(pending,
> > (pending_cnt + 1) * sizeof(struct to_resolve));
> > @@ -927,7 +923,7 @@ static int resolve_metric(struct list_head *metric_list,
> > */
> > for (i = 0; i < pending_cnt; i++) {
> > ret = add_metric(metric_list, pending[i].pe, modifier, metric_no_group,
> > - root_metric, visited, map);
> > + root_metric, visited, table);
> > if (ret)
> > break;
> > }
> > @@ -950,7 +946,7 @@ static int resolve_metric(struct list_head *metric_list,
> > * metrics. When adding a root this argument is NULL.
> > * @visited: A singly linked list of metric names being added that is used to
> > * detect recursion.
> > - * @map: The map that is searched for metrics, most commonly the table for the
> > + * @table: The table that is searched for metrics, most commonly the table for the
> > * architecture perf is running upon.
> > */
> > static int __add_metric(struct list_head *metric_list,
> > @@ -960,7 +956,7 @@ static int __add_metric(struct list_head *metric_list,
> > int runtime,
> > struct metric *root_metric,
> > const struct visited_metric *visited,
> > - const struct pmu_events_map *map)
> > + const struct pmu_event *table)
> > {
> > const struct visited_metric *vm;
> > int ret;
> > @@ -1032,7 +1028,7 @@ static int __add_metric(struct list_head *metric_list,
> > } else {
> > /* Resolve referenced metrics. */
> > ret = resolve_metric(metric_list, modifier, metric_no_group, root_metric,
> > - &visited_node, map);
> > + &visited_node, table);
> > }
> >
> > if (ret) {
> > @@ -1045,25 +1041,25 @@ static int __add_metric(struct list_head *metric_list,
> > return ret;
> > }
> >
> > -#define map_for_each_event(__pe, __idx, __map) \
> > - if (__map) \
> > - for (__idx = 0, __pe = &__map->table[__idx]; \
> > +#define table_for_each_event(__pe, __idx, __table) \
> > + if (__table) \
> > + for (__idx = 0, __pe = &__table[__idx]; \
> > __pe->name || __pe->metric_group || __pe->metric_name; \
> > - __pe = &__map->table[++__idx])
> > + __pe = &__table[++__idx])
> >
> > -#define map_for_each_metric(__pe, __idx, __map, __metric) \
> > - map_for_each_event(__pe, __idx, __map) \
> > +#define table_for_each_metric(__pe, __idx, __table, __metric) \
> > + table_for_each_event(__pe, __idx, __table) \
> > if (__pe->metric_expr && \
> > (match_metric(__pe->metric_group, __metric) || \
> > match_metric(__pe->metric_name, __metric)))
> >
> > const struct pmu_event *metricgroup__find_metric(const char *metric,
> > - const struct pmu_events_map *map)
> > + const struct pmu_event *table)
> > {
> > const struct pmu_event *pe;
> > int i;
> >
> > - map_for_each_event(pe, i, map) {
> > + table_for_each_event(pe, i, table) {
> > if (match_metric(pe->metric_name, metric))
> > return pe;
> > }
> > @@ -1077,7 +1073,7 @@ static int add_metric(struct list_head *metric_list,
> > bool metric_no_group,
> > struct metric *root_metric,
> > const struct visited_metric *visited,
> > - const struct pmu_events_map *map)
> > + const struct pmu_event *table)
> > {
> > int ret = 0;
> >
> > @@ -1085,7 +1081,7 @@ static int add_metric(struct list_head *metric_list,
> >
> > if (!strstr(pe->metric_expr, "?")) {
> > ret = __add_metric(metric_list, pe, modifier, metric_no_group, 0,
> > - root_metric, visited, map);
> > + root_metric, visited, table);
> > } else {
> > int j, count;
> >
> > @@ -1098,7 +1094,7 @@ static int add_metric(struct list_head *metric_list,
> >
> > for (j = 0; j < count && !ret; j++)
> > ret = __add_metric(metric_list, pe, modifier, metric_no_group, j,
> > - root_metric, visited, map);
> > + root_metric, visited, table);
> > }
> >
> > return ret;
> > @@ -1114,7 +1110,7 @@ static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
> > return 0;
> >
> > ret = add_metric(d->metric_list, pe, d->modifier, d->metric_no_group,
> > - d->root_metric, d->visited, d->map);
> > + d->root_metric, d->visited, d->table);
> > if (ret)
> > goto out;
> >
> > @@ -1162,13 +1158,13 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
> > * global. Grouping is the default but due to multiplexing the
> > * user may override.
> > * @metric_list: The list that the metric or metric group are added to.
> > - * @map: The map that is searched for metrics, most commonly the table for the
> > + * @table: The table that is searched for metrics, most commonly the table for the
> > * architecture perf is running upon.
> > */
> > static int metricgroup__add_metric(const char *metric_name, const char *modifier,
> > bool metric_no_group,
> > struct list_head *metric_list,
> > - const struct pmu_events_map *map)
> > + const struct pmu_event *table)
> > {
> > const struct pmu_event *pe;
> > LIST_HEAD(list);
> > @@ -1179,11 +1175,11 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
> > * Iterate over all metrics seeing if metric matches either the name or
> > * group. When it does add the metric to the list.
> > */
> > - map_for_each_metric(pe, i, map, metric_name) {
> > + table_for_each_metric(pe, i, table, metric_name) {
> > has_match = true;
> > ret = add_metric(&list, pe, modifier, metric_no_group,
> > /*root_metric=*/NULL,
> > - /*visited_metrics=*/NULL, map);
> > + /*visited_metrics=*/NULL, table);
> > if (ret)
> > goto out;
> > }
> > @@ -1198,7 +1194,7 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
> > .metric_no_group = metric_no_group,
> > .has_match = &has_match,
> > .ret = &ret,
> > - .map = map,
> > + .table = table,
> > },
> > };
> >
> > @@ -1227,12 +1223,12 @@ static int metricgroup__add_metric(const char *metric_name, const char *modifier
> > * global. Grouping is the default but due to multiplexing the
> > * user may override.
> > * @metric_list: The list that metrics are added to.
> > - * @map: The map that is searched for metrics, most commonly the table for the
> > + * @table: The table that is searched for metrics, most commonly the table for the
> > * architecture perf is running upon.
> > */
> > static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
> > struct list_head *metric_list,
> > - const struct pmu_events_map *map)
> > + const struct pmu_event *table)
> > {
> > char *list_itr, *list_copy, *metric_name, *modifier;
> > int ret, count = 0;
> > @@ -1249,7 +1245,7 @@ static int metricgroup__add_metric_list(const char *list, bool metric_no_group,
> >
> > ret = metricgroup__add_metric(metric_name, modifier,
> > metric_no_group, metric_list,
> > - map);
> > + table);
> > if (ret == -EINVAL)
> > pr_err("Cannot find metric or group `%s'\n", metric_name);
> >
> > @@ -1440,7 +1436,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
> > bool metric_no_merge,
> > struct perf_pmu *fake_pmu,
> > struct rblist *metric_events_list,
> > - const struct pmu_events_map *map)
> > + const struct pmu_event *table)
> > {
> > struct evlist *combined_evlist = NULL;
> > LIST_HEAD(metric_list);
> > @@ -1451,7 +1447,7 @@ static int parse_groups(struct evlist *perf_evlist, const char *str,
> > if (metric_events_list->nr_entries == 0)
> > metricgroup__rblist_init(metric_events_list);
> > ret = metricgroup__add_metric_list(str, metric_no_group,
> > - &metric_list, map);
> > + &metric_list, table);
> > if (ret)
> > goto out;
> >
> > @@ -1586,34 +1582,34 @@ int metricgroup__parse_groups(const struct option *opt,
> > struct rblist *metric_events)
> > {
> > struct evlist *perf_evlist = *(struct evlist **)opt->value;
> > - const struct pmu_events_map *map = pmu_events_map__find();
> > + const struct pmu_event *table = pmu_events_map__find();
> >
> > return parse_groups(perf_evlist, str, metric_no_group,
> > - metric_no_merge, NULL, metric_events, map);
> > + metric_no_merge, NULL, metric_events, table);
> > }
> >
> > int metricgroup__parse_groups_test(struct evlist *evlist,
> > - const struct pmu_events_map *map,
> > + const struct pmu_event *table,
> > const char *str,
> > bool metric_no_group,
> > bool metric_no_merge,
> > struct rblist *metric_events)
> > {
> > return parse_groups(evlist, str, metric_no_group,
> > - metric_no_merge, &perf_pmu__fake, metric_events, map);
> > + metric_no_merge, &perf_pmu__fake, metric_events, table);
> > }
> >
> > bool metricgroup__has_metric(const char *metric)
> > {
> > - const struct pmu_events_map *map = pmu_events_map__find();
> > + const struct pmu_event *table = pmu_events_map__find();
> > const struct pmu_event *pe;
> > int i;
> >
> > - if (!map)
> > + if (!table)
> > return false;
> >
> > for (i = 0; ; i++) {
> > - pe = &map->table[i];
> > + pe = &table[i];
> >
> > if (!pe->name && !pe->metric_group && !pe->metric_name)
> > break;
> > diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h
> > index 2b42b778d1bf..5a1390e73d25 100644
> > --- a/tools/perf/util/metricgroup.h
> > +++ b/tools/perf/util/metricgroup.h
> > @@ -71,9 +71,9 @@ int metricgroup__parse_groups(const struct option *opt,
> > bool metric_no_merge,
> > struct rblist *metric_events);
> > const struct pmu_event *metricgroup__find_metric(const char *metric,
> > - const struct pmu_events_map *map);
> > + const struct pmu_event *table);
> > int metricgroup__parse_groups_test(struct evlist *evlist,
> > - const struct pmu_events_map *map,
> > + const struct pmu_event *table,
> > const char *str,
> > bool metric_no_group,
> > bool metric_no_merge,
> > diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> > index d8717c4548a4..f3e3c4a147e9 100644
> > --- a/tools/perf/util/pmu.c
> > +++ b/tools/perf/util/pmu.c
> > @@ -710,9 +710,9 @@ static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
> > return cpuid;
> > }
> >
> > -const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
> > +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
> > {
> > - const struct pmu_events_map *map;
> > + const struct pmu_event *table = NULL;
> > char *cpuid = perf_pmu__getcpuid(pmu);
> > int i;
> >
> > @@ -724,22 +724,23 @@ const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)
> >
> > i = 0;
> > for (;;) {
> > - map = &pmu_events_map[i++];
> > - if (!map->table) {
> > - map = NULL;
> > + const struct pmu_events_map *map = &pmu_events_map[i++];
> > +
> > + if (!map->table)
> > break;
> > - }
> >
> > - if (!strcmp_cpuid_str(map->cpuid, cpuid))
> > + if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
> > + table = map->table;
> > break;
> > + }
> > }
> > free(cpuid);
> > - return map;
> > + return table;
> > }
> >
> > -const struct pmu_events_map *__weak pmu_events_map__find(void)
> > +__weak const struct pmu_event *pmu_events_map__find(void)
> > {
> > - return perf_pmu__find_map(NULL);
> > + return perf_pmu__find_table(NULL);
> > }
> >
> > /*
> > @@ -824,7 +825,7 @@ bool pmu_uncore_alias_match(const char *pmu_name, const char *name)
> > * as aliases.
> > */
> > void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
>
> Again, it seems that this name should be changed
Ack. I'll put this into the next version. The next patch (number 10
"perf pmu-events: Hide the pmu_events") changes things slightly:
-const struct pmu_event *pmu_events_map__find(void)
+const struct pmu_events_table *pmu_events_map__find(void)
So I'll try to minimize the churn in renaming.
Thanks,
Ian
> > - const struct pmu_events_map *map)
> > + const struct pmu_event *table)
> > {
> > int i;
> > const char *name = pmu->name;
> > @@ -834,7 +835,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
> > i = 0;
> > while (1) {
> > const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
> > - const struct pmu_event *pe = &map->table[i++];
> > + const struct pmu_event *pe = &table[i++];
> > const char *pname = pe->pmu ? pe->pmu : cpu_name;
> >
> > if (!pe->name) {
> > @@ -859,13 +860,13 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
> >
> > static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
> > {
> > - const struct pmu_events_map *map;
> > + const struct pmu_event *table;
> >
> > - map = perf_pmu__find_map(pmu);
> > - if (!map)
> > + table = perf_pmu__find_table(pmu);
> > + if (!table)
> > return;
> >
> > - pmu_add_cpu_aliases_map(head, pmu, map);
> > + pmu_add_cpu_aliases_map(head, pmu, table);
> > }
> >
> > struct pmu_sys_event_iter_data {
> > diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
> > index 7e667eec2a01..015242c83698 100644
> > --- a/tools/perf/util/pmu.h
> > +++ b/tools/perf/util/pmu.h
> > @@ -126,10 +126,10 @@ int perf_pmu__test(void);
> >
> > struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
> > void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
> > - const struct pmu_events_map *map);
> > + const struct pmu_event *map);
> >
> > -const struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu);
> > -const struct pmu_events_map *pmu_events_map__find(void);
> > +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
> > +const struct pmu_event *pmu_events_map__find(void);
> > bool pmu_uncore_alias_match(const char *pmu_name, const char *name);
> > void perf_pmu_free_alias(struct perf_pmu_alias *alias);
> >
> > diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
> > index cd3a34840389..1ecb718fc0eb 100644
> > --- a/tools/perf/util/s390-sample-raw.c
> > +++ b/tools/perf/util/s390-sample-raw.c
> > @@ -135,12 +135,12 @@ static int get_counterset_start(int setnr)
> > * the name of this counter.
> > * If no match is found a NULL pointer is returned.
> > */
> > -static const char *get_counter_name(int set, int nr, const struct pmu_events_map *map)
> > +static const char *get_counter_name(int set, int nr, const struct pmu_event *table)
> > {
> > int rc, event_nr, wanted = get_counterset_start(set) + nr;
> >
> > - if (map) {
> > - const struct pmu_event *evp = map->table;
> > + if (table) {
> > + const struct pmu_event *evp = table;
> >
> > for (; evp->name || evp->event || evp->desc; ++evp) {
> > if (evp->name == NULL || evp->event == NULL)
> > @@ -159,10 +159,10 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
> > unsigned char *buf = sample->raw_data;
> > const char *color = PERF_COLOR_BLUE;
> > struct cf_ctrset_entry *cep, ce;
> > - const struct pmu_events_map *map;
> > + const struct pmu_event *table;
> > u64 *p;
> >
> > - map = pmu_events_map__find();
> > + table = pmu_events_map__find();
> > while (offset < len) {
> > cep = (struct cf_ctrset_entry *)(buf + offset);
> >
> > @@ -180,7 +180,7 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
> > color_fprintf(stdout, color, " [%#08zx] Counterset:%d"
> > " Counters:%d\n", offset, ce.set, ce.ctr);
> > for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) {
> > - const char *ev_name = get_counter_name(ce.set, i, map);
> > + const char *ev_name = get_counter_name(ce.set, i, table);
> >
> > color_fprintf(stdout, color,
> > "\tCounter:%03d %s Value:%#018lx\n", i,
>
On 10/08/2022 15:29, Ian Rogers wrote:
>>> _args.output_file.write("""{
>>> @@ -389,6 +409,61 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
>>> \t},
>>> };
>>>
>>> +const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
>>> +{
>>> + const struct pmu_event *table = NULL;
>>> + char *cpuid = perf_pmu__getcpuid(pmu);
>> This seems an identical implementation to that in empty-pmu-events.c -
>> can we reduce this duplication? Maybe a seperate common c file which can
>> be linked in
>>
>> The indentation seems different also - this version seems to use whitespaces
> Agreed. Later on this will change, the empty version isn't compressed
> and the jevents.py one is. Having a common C file would defeat the
> goal of hiding the API, but ultimately we'd need to get rid of it in
> later changes when the empty/compressed implementations diverge.
ok, I suppose.. I have to say that this divergence is less then ideal
and I don't so like much all the difference in pmu-events/pmu-events.c
and pmu-events/empty-pmu-events.c
thanks,
John