From e6ff1eed3584362dcf5ffb6b9daf497183b4d3a8 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 23 Aug 2023 21:13:25 -0700 Subject: perf pmu: Lazily add JSON events Rather than scanning all JSON events and adding them when a PMU is created, add the alias when the JSON event is needed. Average core PMU scanning run time reduced by 60.2%. Average PMU scanning run time reduced by 15%. Page faults with no events reduced by 74 page faults, 4% of total. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Gaosheng Cui Cc: Ingo Molnar Cc: James Clark Cc: Jing Zhang Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Rob Herring Link: https://lore.kernel.org/r/20230824041330.266337-14-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/empty-pmu-events.c | 14 +++++++++ tools/perf/pmu-events/jevents.py | 15 ++++++++++ tools/perf/pmu-events/pmu-events.h | 4 +++ tools/perf/tests/pmu-events.c | 2 ++ tools/perf/util/pmu.c | 50 ++++++++++++++++++++++++-------- tools/perf/util/pmu.h | 15 ++++++++-- 6 files changed, 85 insertions(+), 15 deletions(-) (limited to 'tools') diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c index ef18d403f25f..12bd043a05e3 100644 --- a/tools/perf/pmu-events/empty-pmu-events.c +++ b/tools/perf/pmu-events/empty-pmu-events.c @@ -298,6 +298,20 @@ int pmu_events_table__find_event(const struct pmu_events_table *table, return -1000; } +size_t pmu_events_table__num_events(const struct pmu_events_table *table, + struct perf_pmu *pmu) +{ + size_t count = 0; + + for (const struct pmu_event *pe = &table->entries[0]; pe->name; pe++) { + if (pmu && !pmu__name_match(pmu, pe->pmu)) + continue; + + count++; + } + return count; +} + int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn, void *data) { diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py index f07864fabd54..01335a452e70 100755 --- a/tools/perf/pmu-events/jevents.py +++ b/tools/perf/pmu-events/jevents.py @@ -909,6 +909,21 @@ int pmu_events_table__find_event(const struct pmu_events_table *table, return -1000; } +size_t pmu_events_table__num_events(const struct pmu_events_table *table, + struct perf_pmu *pmu) +{ + size_t count = 0; + + for (size_t i = 0; i < table->num_pmus; i++) { + const struct pmu_table_entry *table_pmu = &table->pmus[i]; + const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset]; + + if (pmu__name_match(pmu, pmu_name)) + count += table_pmu->num_entries; + } + return count; +} + static int pmu_metrics_table__for_each_metric_pmu(const struct pmu_metrics_table *table, const struct pmu_table_entry *pmu, pmu_metric_iter_fn fn, diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h index 9882b7125761..f5aa96f1685c 100644 --- a/tools/perf/pmu-events/pmu-events.h +++ b/tools/perf/pmu-events/pmu-events.h @@ -3,6 +3,7 @@ #define PMU_EVENTS_H #include +#include struct perf_pmu; @@ -86,6 +87,9 @@ int pmu_events_table__find_event(const struct pmu_events_table *table, const char *name, pmu_event_iter_fn fn, void *data); +size_t pmu_events_table__num_events(const struct pmu_events_table *table, + struct perf_pmu *pmu); + int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn, void *data); diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index 4fcb84fd1f65..9ac893ae5f0d 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -546,6 +546,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count) pmu->events_table = table; pmu_add_cpu_aliases_table(pmu, table); + pmu->cpu_aliases_added = true; res = pmu_events_table__find_event(table, pmu, "bp_l1_btb_correct", NULL, NULL); if (res != 0) { @@ -586,6 +587,7 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu) return -1; pmu->events_table = events_table; pmu_add_cpu_aliases_table(pmu, events_table); + pmu->cpu_aliases_added = true; pmu_add_sys_aliases(pmu); /* Count how many aliases we generated */ diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 685903c1970b..b6a118226541 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -523,8 +523,9 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, int dirfd, const char *name if (!pe) { /* Update an event from sysfs with json data. */ if (pmu->events_table) { - pmu_events_table__find_event(pmu->events_table, pmu, name, - update_alias, alias); + if (pmu_events_table__find_event(pmu->events_table, pmu, name, + update_alias, alias) == 0) + pmu->loaded_json_aliases++; } } @@ -548,6 +549,10 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, int dirfd, const char *name "%s=%s", term->config, term->val.str); } alias->str = strdup(newval); + if (!pe) + pmu->sysfs_aliases++; + else + pmu->loaded_json_aliases++; list_add_tail(&alias->list, &pmu->aliases); return 0; } @@ -878,7 +883,11 @@ static void pmu_add_cpu_aliases(struct perf_pmu *pmu) if (!pmu->events_table) return; + if (pmu->cpu_aliases_added) + return; + pmu_add_cpu_aliases_table(pmu, pmu->events_table); + pmu->cpu_aliases_added = true; } static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe, @@ -990,7 +999,6 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char pmu->id = pmu_id(name); pmu->max_precise = pmu_max_precise(dirfd, pmu); pmu->events_table = perf_pmu__find_events_table(pmu); - pmu_add_cpu_aliases(pmu); pmu_add_sys_aliases(pmu); list_add_tail(&pmu->list, pmus); @@ -1368,6 +1376,7 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, struct parse_events_term *term) { + struct perf_pmu_alias *alias; char *name; if (parse_events__is_hardcoded_term(term)) @@ -1388,7 +1397,18 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, return NULL; } - return perf_pmu__find_alias(pmu, name); + alias = perf_pmu__find_alias(pmu, name); + if (alias || pmu->cpu_aliases_added) + return alias; + + /* Alias doesn't exist, try to get it from the json events. */ + if (pmu->events_table && + pmu_events_table__find_event(pmu->events_table, pmu, name, + pmu_add_cpu_aliases_map_callback, + pmu) == 0) { + alias = perf_pmu__find_alias(pmu, name); + } + return alias; } @@ -1555,18 +1575,23 @@ bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu) return !pmu->is_core || perf_pmus__num_core_pmus() == 1; } -bool perf_pmu__have_event(const struct perf_pmu *pmu, const char *name) +bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name) { - return perf_pmu__find_alias(pmu, name) != NULL; + if (perf_pmu__find_alias(pmu, name) != NULL) + return true; + if (pmu->cpu_aliases_added || !pmu->events_table) + return false; + return pmu_events_table__find_event(pmu->events_table, pmu, name, NULL, NULL) == 0; } -size_t perf_pmu__num_events(const struct perf_pmu *pmu) +size_t perf_pmu__num_events(struct perf_pmu *pmu) { - struct list_head *list; - size_t nr = 0; + size_t nr = pmu->sysfs_aliases; - list_for_each(list, &pmu->aliases) - nr++; + if (pmu->cpu_aliases_added) + nr += pmu->loaded_json_aliases; + else if (pmu->events_table) + nr += pmu_events_table__num_events(pmu->events_table, pmu) - pmu->loaded_json_aliases; return pmu->selectable ? nr + 1 : nr; } @@ -1604,7 +1629,7 @@ static char *format_alias(char *buf, int len, const struct perf_pmu *pmu, return buf; } -int perf_pmu__for_each_event(const struct perf_pmu *pmu, void *state, pmu_event_callback cb) +int perf_pmu__for_each_event(struct perf_pmu *pmu, void *state, pmu_event_callback cb) { char buf[1024]; struct perf_pmu_alias *event; @@ -1613,6 +1638,7 @@ int perf_pmu__for_each_event(const struct perf_pmu *pmu, void *state, pmu_event_ }; int ret = 0; + pmu_add_cpu_aliases(pmu); list_for_each_entry(event, &pmu->aliases, list) { size_t buf_used; diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 6bf0fbde4e85..288d2908382a 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -118,6 +118,15 @@ struct perf_pmu { * @events_table: The events table for json events in pmu-events.c. */ const struct pmu_events_table *events_table; + /** @sysfs_aliases: Number of sysfs aliases loaded. */ + uint32_t sysfs_aliases; + /** @sysfs_aliases: Number of json event aliases loaded. */ + uint32_t loaded_json_aliases; + /** + * @cpu_aliases_added: Have all json events table entries for the PMU + * been added? + */ + bool cpu_aliases_added; /** @caps_initialized: Has the list caps been initialized? */ bool caps_initialized; /** @nr_caps: The length of the list caps. */ @@ -199,9 +208,9 @@ bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name); bool is_pmu_core(const char *name); bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu); bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu); -bool perf_pmu__have_event(const struct perf_pmu *pmu, const char *name); -size_t perf_pmu__num_events(const struct perf_pmu *pmu); -int perf_pmu__for_each_event(const struct perf_pmu *pmu, void *state, pmu_event_callback cb); +bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name); +size_t perf_pmu__num_events(struct perf_pmu *pmu); +int perf_pmu__for_each_event(struct perf_pmu *pmu, void *state, pmu_event_callback cb); bool pmu__name_match(const struct perf_pmu *pmu, const char *pmu_name); /** -- cgit v1.2.3