Commit e6ff1eed authored by Ian Rogers's avatar Ian Rogers Committed by Arnaldo Carvalho de Melo

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: default avatarIan Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Gaosheng Cui <cuigaosheng1@huawei.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jing Zhang <renyu.zj@linux.alibaba.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20230824041330.266337-14-irogers@google.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 7c52f10c
...@@ -298,6 +298,20 @@ int pmu_events_table__find_event(const struct pmu_events_table *table, ...@@ -298,6 +298,20 @@ int pmu_events_table__find_event(const struct pmu_events_table *table,
return -1000; 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, int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn,
void *data) void *data)
{ {
......
...@@ -909,6 +909,21 @@ int pmu_events_table__find_event(const struct pmu_events_table *table, ...@@ -909,6 +909,21 @@ int pmu_events_table__find_event(const struct pmu_events_table *table,
return -1000; 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, static int pmu_metrics_table__for_each_metric_pmu(const struct pmu_metrics_table *table,
const struct pmu_table_entry *pmu, const struct pmu_table_entry *pmu,
pmu_metric_iter_fn fn, pmu_metric_iter_fn fn,
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#define PMU_EVENTS_H #define PMU_EVENTS_H
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
struct perf_pmu; struct perf_pmu;
...@@ -86,6 +87,9 @@ int pmu_events_table__find_event(const struct pmu_events_table *table, ...@@ -86,6 +87,9 @@ int pmu_events_table__find_event(const struct pmu_events_table *table,
const char *name, const char *name,
pmu_event_iter_fn fn, pmu_event_iter_fn fn,
void *data); 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, int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn,
void *data); void *data);
......
...@@ -546,6 +546,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count) ...@@ -546,6 +546,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
pmu->events_table = table; pmu->events_table = table;
pmu_add_cpu_aliases_table(pmu, 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); res = pmu_events_table__find_event(table, pmu, "bp_l1_btb_correct", NULL, NULL);
if (res != 0) { if (res != 0) {
...@@ -586,6 +587,7 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu) ...@@ -586,6 +587,7 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
return -1; return -1;
pmu->events_table = events_table; pmu->events_table = events_table;
pmu_add_cpu_aliases_table(pmu, events_table); pmu_add_cpu_aliases_table(pmu, events_table);
pmu->cpu_aliases_added = true;
pmu_add_sys_aliases(pmu); pmu_add_sys_aliases(pmu);
/* Count how many aliases we generated */ /* Count how many aliases we generated */
......
...@@ -523,8 +523,9 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, int dirfd, const char *name ...@@ -523,8 +523,9 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, int dirfd, const char *name
if (!pe) { if (!pe) {
/* Update an event from sysfs with json data. */ /* Update an event from sysfs with json data. */
if (pmu->events_table) { if (pmu->events_table) {
pmu_events_table__find_event(pmu->events_table, pmu, name, if (pmu_events_table__find_event(pmu->events_table, pmu, name,
update_alias, alias); 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 ...@@ -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); "%s=%s", term->config, term->val.str);
} }
alias->str = strdup(newval); alias->str = strdup(newval);
if (!pe)
pmu->sysfs_aliases++;
else
pmu->loaded_json_aliases++;
list_add_tail(&alias->list, &pmu->aliases); list_add_tail(&alias->list, &pmu->aliases);
return 0; return 0;
} }
...@@ -878,7 +883,11 @@ static void pmu_add_cpu_aliases(struct perf_pmu *pmu) ...@@ -878,7 +883,11 @@ static void pmu_add_cpu_aliases(struct perf_pmu *pmu)
if (!pmu->events_table) if (!pmu->events_table)
return; return;
if (pmu->cpu_aliases_added)
return;
pmu_add_cpu_aliases_table(pmu, pmu->events_table); 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, 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 ...@@ -990,7 +999,6 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char
pmu->id = pmu_id(name); pmu->id = pmu_id(name);
pmu->max_precise = pmu_max_precise(dirfd, pmu); pmu->max_precise = pmu_max_precise(dirfd, pmu);
pmu->events_table = perf_pmu__find_events_table(pmu); pmu->events_table = perf_pmu__find_events_table(pmu);
pmu_add_cpu_aliases(pmu);
pmu_add_sys_aliases(pmu); pmu_add_sys_aliases(pmu);
list_add_tail(&pmu->list, pmus); list_add_tail(&pmu->list, pmus);
...@@ -1368,6 +1376,7 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, ...@@ -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, static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
struct parse_events_term *term) struct parse_events_term *term)
{ {
struct perf_pmu_alias *alias;
char *name; char *name;
if (parse_events__is_hardcoded_term(term)) if (parse_events__is_hardcoded_term(term))
...@@ -1388,7 +1397,18 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, ...@@ -1388,7 +1397,18 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
return NULL; 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) ...@@ -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; 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 = pmu->sysfs_aliases;
size_t nr = 0;
list_for_each(list, &pmu->aliases) if (pmu->cpu_aliases_added)
nr++; 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; return pmu->selectable ? nr + 1 : nr;
} }
...@@ -1604,7 +1629,7 @@ static char *format_alias(char *buf, int len, const struct perf_pmu *pmu, ...@@ -1604,7 +1629,7 @@ static char *format_alias(char *buf, int len, const struct perf_pmu *pmu,
return buf; 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]; char buf[1024];
struct perf_pmu_alias *event; struct perf_pmu_alias *event;
...@@ -1613,6 +1638,7 @@ int perf_pmu__for_each_event(const struct perf_pmu *pmu, void *state, pmu_event_ ...@@ -1613,6 +1638,7 @@ int perf_pmu__for_each_event(const struct perf_pmu *pmu, void *state, pmu_event_
}; };
int ret = 0; int ret = 0;
pmu_add_cpu_aliases(pmu);
list_for_each_entry(event, &pmu->aliases, list) { list_for_each_entry(event, &pmu->aliases, list) {
size_t buf_used; size_t buf_used;
......
...@@ -118,6 +118,15 @@ struct perf_pmu { ...@@ -118,6 +118,15 @@ struct perf_pmu {
* @events_table: The events table for json events in pmu-events.c. * @events_table: The events table for json events in pmu-events.c.
*/ */
const struct pmu_events_table *events_table; 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? */ /** @caps_initialized: Has the list caps been initialized? */
bool caps_initialized; bool caps_initialized;
/** @nr_caps: The length of the list caps. */ /** @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); ...@@ -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 is_pmu_core(const char *name);
bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu); 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__auto_merge_stats(const struct perf_pmu *pmu);
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);
size_t perf_pmu__num_events(const struct perf_pmu *pmu); size_t perf_pmu__num_events(struct perf_pmu *pmu);
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);
bool pmu__name_match(const struct perf_pmu *pmu, const char *pmu_name); bool pmu__name_match(const struct perf_pmu *pmu, const char *pmu_name);
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment