Skip to content

Commit

Permalink
perf pmu-events: Remember the perf_events_map for a PMU
Browse files Browse the repository at this point in the history
strcmp_cpuid_str performs regular expression comparisons and so per
CPUID linear searches over the perf_events_map are expensive. Add a
helper function called map_for_pmu that does the search but also
caches the map specific to a PMU. As the PMU may differ, also cache
the CPUID string so that PMUs with the same CPUID string don't require
the linear search and regular expression comparisons. This speeds
loading PMUs as the search is done once per PMU to find the
appropriate tables.

Signed-off-by: Ian Rogers <[email protected]>
Tested-by: Yang Jihong <[email protected]>
Cc: Ravi Bangoria <[email protected]>
Cc: James Clark <[email protected]>
Cc: Suzuki K Poulose <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Leo Yan <[email protected]>
Cc: Mike Leach <[email protected]>
Cc: Jing Zhang <[email protected]>
Cc: Kajol Jain <[email protected]>
Cc: Thomas Richter <[email protected]>
Cc: Kan Liang <[email protected]>
Cc: John Garry <[email protected]>
Cc: [email protected]
Cc: [email protected]
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Namhyung Kim <[email protected]>
  • Loading branch information
captain5050 authored and namhyung committed Oct 17, 2023
1 parent 63883cb commit f20c15d
Showing 1 changed file with 70 additions and 39 deletions.
109 changes: 70 additions & 39 deletions tools/perf/pmu-events/jevents.py
Original file line number Diff line number Diff line change
Expand Up @@ -976,68 +976,99 @@ def print_system_mapping_table() -> None:
return 0;
}
const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu)
static const struct pmu_events_map *map_for_pmu(struct perf_pmu *pmu)
{
const struct pmu_events_table *table = NULL;
char *cpuid = perf_pmu__getcpuid(pmu);
static struct {
const struct pmu_events_map *map;
struct perf_pmu *pmu;
} last_result;
static struct {
const struct pmu_events_map *map;
char *cpuid;
} last_map_search;
static bool has_last_result, has_last_map_search;
const struct pmu_events_map *map = NULL;
char *cpuid = NULL;
size_t i;
/* on some platforms which uses cpus map, cpuid can be NULL for
if (has_last_result && last_result.pmu == pmu)
return last_result.map;
cpuid = perf_pmu__getcpuid(pmu);
/*
* On some platforms which uses cpus map, cpuid can be NULL for
* PMUs other than CORE PMUs.
*/
if (!cpuid)
return NULL;
goto out_update_last_result;
if (has_last_map_search && !strcmp(last_map_search.cpuid, cpuid)) {
map = last_map_search.map;
free(cpuid);
} else {
i = 0;
for (;;) {
map = &pmu_events_map[i++];
if (!map->arch) {
map = NULL;
break;
}
if (!strcmp_cpuid_str(map->cpuid, cpuid))
break;
}
free(last_map_search.cpuid);
last_map_search.cpuid = cpuid;
last_map_search.map = map;
has_last_map_search = true;
}
out_update_last_result:
last_result.pmu = pmu;
last_result.map = map;
has_last_result = true;
return map;
}
i = 0;
for (;;) {
const struct pmu_events_map *map = &pmu_events_map[i++];
if (!map->arch)
break;
const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu)
{
const struct pmu_events_map *map = map_for_pmu(pmu);
if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
table = &map->event_table;
break;
}
}
free(cpuid);
if (!pmu || !table)
return table;
if (!map)
return NULL;
for (i = 0; i < table->num_pmus; i++) {
const struct pmu_table_entry *table_pmu = &table->pmus[i];
if (!pmu)
return &map->event_table;
for (size_t i = 0; i < map->event_table.num_pmus; i++) {
const struct pmu_table_entry *table_pmu = &map->event_table.pmus[i];
const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
if (pmu__name_match(pmu, pmu_name))
return table;
return &map->event_table;
}
return NULL;
}
const struct pmu_metrics_table *perf_pmu__find_metrics_table(struct perf_pmu *pmu)
{
const struct pmu_metrics_table *table = NULL;
char *cpuid = perf_pmu__getcpuid(pmu);
int i;
const struct pmu_events_map *map = map_for_pmu(pmu);
/* on some platforms which uses cpus map, cpuid can be NULL for
* PMUs other than CORE PMUs.
*/
if (!cpuid)
if (!map)
return NULL;
i = 0;
for (;;) {
const struct pmu_events_map *map = &pmu_events_map[i++];
if (!map->arch)
break;
if (!pmu)
return &map->metric_table;
if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
table = &map->metric_table;
break;
}
for (size_t i = 0; i < map->metric_table.num_pmus; i++) {
const struct pmu_table_entry *table_pmu = &map->metric_table.pmus[i];
const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
if (pmu__name_match(pmu, pmu_name))
return &map->metric_table;
}
free(cpuid);
return table;
return NULL;
}
const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid)
Expand Down

0 comments on commit f20c15d

Please sign in to comment.