mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
perf pmu: Change aliases from list to hashmap
Finding an alias for things like perf_pmu__have_event() would need to search the aliases list, whilst this happens relatively infrequently it can be a significant overhead in testing. Switch to using a hashmap. Move common initialization code to perf_pmu__init(). Refactor the test 'struct perf_pmu_test_pmu' to not have perf pmu within it to better support the perf_pmu__init() function. Before: ``` $ time perf test "Parsing of PMU event table metrics" 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok real 0m13.287s user 0m13.026s sys 0m0.532s ``` After: ``` $ time perf test "Parsing of PMU event table metrics" 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok real 0m13.011s user 0m12.885s sys 0m0.485s ``` Committer testing: root@number:~# grep -m1 'model name' /proc/cpuinfo model name : AMD Ryzen 9 9950X3D 16-Core Processor root@number:~# Before: root@number:~# time perf test "Parsing of PMU event table metrics" 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok real 0m9.296s user 0m9.361s sys 0m0.063s root@number:~# After: root@number:~# time perf test "Parsing of PMU event table metrics" 10.3: Parsing of PMU event table metrics : Ok 10.4: Parsing of PMU event table metrics with fake PMUs : Ok real 0m9.286s user 0m9.354s sys 0m0.062s root@number:~# Signed-off-by: Ian Rogers <irogers@google.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Tested-by: Namhyung Kim <namhyung@kernel.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@linaro.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ravi Bangoria <ravi.bangoria@amd.com> Cc: Thomas Richter <tmricht@linux.ibm.com> Cc: Xu Yang <xu.yang_2@nxp.com> Link: https://lore.kernel.org/r/20250512194622.33258-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
375368a961
commit
754baf426e
5 changed files with 199 additions and 161 deletions
|
@ -38,7 +38,9 @@ struct perf_pmu_test_event {
|
|||
};
|
||||
|
||||
struct perf_pmu_test_pmu {
|
||||
struct perf_pmu pmu;
|
||||
const char *pmu_name;
|
||||
bool pmu_is_uncore;
|
||||
const char *pmu_id;
|
||||
struct perf_pmu_test_event const *aliases[10];
|
||||
};
|
||||
|
||||
|
@ -553,11 +555,10 @@ static int __test_core_pmu_event_aliases(const char *pmu_name, int *count)
|
|||
if (!pmu)
|
||||
return -1;
|
||||
|
||||
INIT_LIST_HEAD(&pmu->format);
|
||||
INIT_LIST_HEAD(&pmu->aliases);
|
||||
INIT_LIST_HEAD(&pmu->caps);
|
||||
INIT_LIST_HEAD(&pmu->list);
|
||||
pmu->name = strdup(pmu_name);
|
||||
if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, pmu_name) != 0) {
|
||||
perf_pmu__delete(pmu);
|
||||
return -1;
|
||||
}
|
||||
pmu->is_core = true;
|
||||
|
||||
pmu->events_table = table;
|
||||
|
@ -594,14 +595,30 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
|
|||
{
|
||||
int alias_count = 0, to_match_count = 0, matched_count = 0;
|
||||
struct perf_pmu_test_event const **table;
|
||||
struct perf_pmu *pmu = &test_pmu->pmu;
|
||||
const char *pmu_name = pmu->name;
|
||||
struct perf_pmu *pmu;
|
||||
const struct pmu_events_table *events_table;
|
||||
int res = 0;
|
||||
|
||||
events_table = find_core_events_table("testarch", "testcpu");
|
||||
if (!events_table)
|
||||
return -1;
|
||||
|
||||
pmu = zalloc(sizeof(*pmu));
|
||||
if (!pmu)
|
||||
return -1;
|
||||
|
||||
if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, test_pmu->pmu_name) != 0) {
|
||||
perf_pmu__delete(pmu);
|
||||
return -1;
|
||||
}
|
||||
pmu->is_uncore = test_pmu->pmu_is_uncore;
|
||||
if (test_pmu->pmu_id) {
|
||||
pmu->id = strdup(test_pmu->pmu_id);
|
||||
if (!pmu->id) {
|
||||
perf_pmu__delete(pmu);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
pmu->events_table = events_table;
|
||||
pmu_add_cpu_aliases_table(pmu, events_table);
|
||||
pmu->cpu_aliases_added = true;
|
||||
|
@ -617,7 +634,8 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
|
|||
|
||||
if (alias_count != to_match_count) {
|
||||
pr_debug("testing aliases uncore PMU %s: mismatch expected aliases (%d) vs found (%d)\n",
|
||||
pmu_name, to_match_count, alias_count);
|
||||
pmu->name, to_match_count, alias_count);
|
||||
perf_pmu__delete(pmu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -630,9 +648,10 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
|
|||
.count = &matched_count,
|
||||
};
|
||||
|
||||
if (strcmp(pmu_name, test_event.matching_pmu)) {
|
||||
if (strcmp(pmu->name, test_event.matching_pmu)) {
|
||||
pr_debug("testing aliases uncore PMU %s: mismatched matching_pmu, %s vs %s\n",
|
||||
pmu_name, test_event.matching_pmu, pmu_name);
|
||||
pmu->name, test_event.matching_pmu, pmu->name);
|
||||
perf_pmu__delete(pmu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -641,34 +660,32 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
|
|||
if (err) {
|
||||
res = err;
|
||||
pr_debug("testing aliases uncore PMU %s: could not match alias %s\n",
|
||||
pmu_name, event->name);
|
||||
pmu->name, event->name);
|
||||
perf_pmu__delete(pmu);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (alias_count != matched_count) {
|
||||
pr_debug("testing aliases uncore PMU %s: mismatch found aliases (%d) vs matched (%d)\n",
|
||||
pmu_name, matched_count, alias_count);
|
||||
pmu->name, matched_count, alias_count);
|
||||
res = -1;
|
||||
}
|
||||
perf_pmu__delete(pmu);
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct perf_pmu_test_pmu test_pmus[] = {
|
||||
{
|
||||
.pmu = {
|
||||
.name = "hisi_sccl1_ddrc2",
|
||||
.is_uncore = 1,
|
||||
},
|
||||
.pmu_name = "hisi_sccl1_ddrc2",
|
||||
.pmu_is_uncore = 1,
|
||||
.aliases = {
|
||||
&uncore_hisi_ddrc_flux_wcmd,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pmu = {
|
||||
.name = "uncore_cbox_0",
|
||||
.is_uncore = 1,
|
||||
},
|
||||
.pmu_name = "uncore_cbox_0",
|
||||
.pmu_is_uncore = 1,
|
||||
.aliases = {
|
||||
&unc_cbo_xsnp_response_miss_eviction,
|
||||
&uncore_hyphen,
|
||||
|
@ -676,88 +693,70 @@ static struct perf_pmu_test_pmu test_pmus[] = {
|
|||
},
|
||||
},
|
||||
{
|
||||
.pmu = {
|
||||
.name = "hisi_sccl3_l3c7",
|
||||
.is_uncore = 1,
|
||||
},
|
||||
.pmu_name = "hisi_sccl3_l3c7",
|
||||
.pmu_is_uncore = 1,
|
||||
.aliases = {
|
||||
&uncore_hisi_l3c_rd_hit_cpipe,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pmu = {
|
||||
.name = "uncore_imc_free_running_0",
|
||||
.is_uncore = 1,
|
||||
},
|
||||
.pmu_name = "uncore_imc_free_running_0",
|
||||
.pmu_is_uncore = 1,
|
||||
.aliases = {
|
||||
&uncore_imc_free_running_cache_miss,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pmu = {
|
||||
.name = "uncore_imc_0",
|
||||
.is_uncore = 1,
|
||||
},
|
||||
.pmu_name = "uncore_imc_0",
|
||||
.pmu_is_uncore = 1,
|
||||
.aliases = {
|
||||
&uncore_imc_cache_hits,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pmu = {
|
||||
.name = "uncore_sys_ddr_pmu0",
|
||||
.is_uncore = 1,
|
||||
.id = "v8",
|
||||
},
|
||||
.pmu_name = "uncore_sys_ddr_pmu0",
|
||||
.pmu_is_uncore = 1,
|
||||
.pmu_id = "v8",
|
||||
.aliases = {
|
||||
&sys_ddr_pmu_write_cycles,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pmu = {
|
||||
.name = "uncore_sys_ccn_pmu4",
|
||||
.is_uncore = 1,
|
||||
.id = "0x01",
|
||||
},
|
||||
.pmu_name = "uncore_sys_ccn_pmu4",
|
||||
.pmu_is_uncore = 1,
|
||||
.pmu_id = "0x01",
|
||||
.aliases = {
|
||||
&sys_ccn_pmu_read_cycles,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pmu = {
|
||||
.name = (char *)"uncore_sys_cmn_pmu0",
|
||||
.is_uncore = 1,
|
||||
.id = (char *)"43401",
|
||||
},
|
||||
.pmu_name = "uncore_sys_cmn_pmu0",
|
||||
.pmu_is_uncore = 1,
|
||||
.pmu_id = "43401",
|
||||
.aliases = {
|
||||
&sys_cmn_pmu_hnf_cache_miss,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pmu = {
|
||||
.name = (char *)"uncore_sys_cmn_pmu0",
|
||||
.is_uncore = 1,
|
||||
.id = (char *)"43602",
|
||||
},
|
||||
.pmu_name = "uncore_sys_cmn_pmu0",
|
||||
.pmu_is_uncore = 1,
|
||||
.pmu_id = "43602",
|
||||
.aliases = {
|
||||
&sys_cmn_pmu_hnf_cache_miss,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pmu = {
|
||||
.name = (char *)"uncore_sys_cmn_pmu0",
|
||||
.is_uncore = 1,
|
||||
.id = (char *)"43c03",
|
||||
},
|
||||
.pmu_name = "uncore_sys_cmn_pmu0",
|
||||
.pmu_is_uncore = 1,
|
||||
.pmu_id = "43c03",
|
||||
.aliases = {
|
||||
&sys_cmn_pmu_hnf_cache_miss,
|
||||
},
|
||||
},
|
||||
{
|
||||
.pmu = {
|
||||
.name = (char *)"uncore_sys_cmn_pmu0",
|
||||
.is_uncore = 1,
|
||||
.id = (char *)"43a01",
|
||||
},
|
||||
.pmu_name = "uncore_sys_cmn_pmu0",
|
||||
.pmu_is_uncore = 1,
|
||||
.pmu_id = "43a01",
|
||||
.aliases = {
|
||||
&sys_cmn_pmu_hnf_cache_miss,
|
||||
},
|
||||
|
@ -796,10 +795,6 @@ static int test__aliases(struct test_suite *test __maybe_unused,
|
|||
for (i = 0; i < ARRAY_SIZE(test_pmus); i++) {
|
||||
int res;
|
||||
|
||||
INIT_LIST_HEAD(&test_pmus[i].pmu.format);
|
||||
INIT_LIST_HEAD(&test_pmus[i].pmu.aliases);
|
||||
INIT_LIST_HEAD(&test_pmus[i].pmu.caps);
|
||||
|
||||
res = __test_uncore_pmu_event_aliases(&test_pmus[i]);
|
||||
if (res)
|
||||
return res;
|
||||
|
|
|
@ -346,42 +346,43 @@ struct perf_pmu *hwmon_pmu__new(struct list_head *pmus, int hwmon_dir, const cha
|
|||
{
|
||||
char buf[32];
|
||||
struct hwmon_pmu *hwm;
|
||||
__u32 type = PERF_PMU_TYPE_HWMON_START + strtoul(sysfs_name + 5, NULL, 10);
|
||||
|
||||
if (type > PERF_PMU_TYPE_HWMON_END) {
|
||||
pr_err("Unable to encode hwmon type from %s in valid PMU type\n", sysfs_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "hwmon_%s", name);
|
||||
fix_name(buf + 6);
|
||||
|
||||
hwm = zalloc(sizeof(*hwm));
|
||||
if (!hwm)
|
||||
return NULL;
|
||||
|
||||
hwm->hwmon_dir_fd = hwmon_dir;
|
||||
hwm->pmu.type = PERF_PMU_TYPE_HWMON_START + strtoul(sysfs_name + 5, NULL, 10);
|
||||
if (hwm->pmu.type > PERF_PMU_TYPE_HWMON_END) {
|
||||
pr_err("Unable to encode hwmon type from %s in valid PMU type\n", sysfs_name);
|
||||
goto err_out;
|
||||
if (perf_pmu__init(&hwm->pmu, type, buf) != 0) {
|
||||
perf_pmu__delete(&hwm->pmu);
|
||||
return NULL;
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "hwmon_%s", name);
|
||||
fix_name(buf + 6);
|
||||
hwm->pmu.name = strdup(buf);
|
||||
if (!hwm->pmu.name)
|
||||
goto err_out;
|
||||
|
||||
hwm->hwmon_dir_fd = hwmon_dir;
|
||||
hwm->pmu.alias_name = strdup(sysfs_name);
|
||||
if (!hwm->pmu.alias_name)
|
||||
goto err_out;
|
||||
if (!hwm->pmu.alias_name) {
|
||||
perf_pmu__delete(&hwm->pmu);
|
||||
return NULL;
|
||||
}
|
||||
hwm->pmu.cpus = perf_cpu_map__new("0");
|
||||
if (!hwm->pmu.cpus)
|
||||
goto err_out;
|
||||
if (!hwm->pmu.cpus) {
|
||||
perf_pmu__delete(&hwm->pmu);
|
||||
return NULL;
|
||||
}
|
||||
INIT_LIST_HEAD(&hwm->pmu.format);
|
||||
INIT_LIST_HEAD(&hwm->pmu.aliases);
|
||||
INIT_LIST_HEAD(&hwm->pmu.caps);
|
||||
hashmap__init(&hwm->events, hwmon_pmu__event_hashmap_hash,
|
||||
hwmon_pmu__event_hashmap_equal, /*ctx=*/NULL);
|
||||
|
||||
list_add_tail(&hwm->pmu.list, pmus);
|
||||
return &hwm->pmu;
|
||||
err_out:
|
||||
free((char *)hwm->pmu.name);
|
||||
free(hwm->pmu.alias_name);
|
||||
free(hwm);
|
||||
close(hwmon_dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hwmon_pmu__exit(struct perf_pmu *pmu)
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <util/pmu-flex.h>
|
||||
#include "parse-events.h"
|
||||
#include "print-events.h"
|
||||
#include "hashmap.h"
|
||||
#include "header.h"
|
||||
#include "string2.h"
|
||||
#include "strbuf.h"
|
||||
|
@ -66,8 +67,6 @@ struct perf_pmu_alias {
|
|||
char *topic;
|
||||
/** @terms: Owned list of the original parsed parameters. */
|
||||
struct parse_events_terms terms;
|
||||
/** @list: List element of struct perf_pmu aliases. */
|
||||
struct list_head list;
|
||||
/**
|
||||
* @pmu_name: The name copied from the json struct pmu_event. This can
|
||||
* differ from the PMU name as it won't have suffixes.
|
||||
|
@ -418,25 +417,33 @@ static void perf_pmu__parse_snapshot(struct perf_pmu *pmu, struct perf_pmu_alias
|
|||
}
|
||||
|
||||
/* Delete an alias entry. */
|
||||
static void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
|
||||
static void perf_pmu_free_alias(struct perf_pmu_alias *alias)
|
||||
{
|
||||
zfree(&newalias->name);
|
||||
zfree(&newalias->desc);
|
||||
zfree(&newalias->long_desc);
|
||||
zfree(&newalias->topic);
|
||||
zfree(&newalias->pmu_name);
|
||||
parse_events_terms__exit(&newalias->terms);
|
||||
free(newalias);
|
||||
if (!alias)
|
||||
return;
|
||||
|
||||
zfree(&alias->name);
|
||||
zfree(&alias->desc);
|
||||
zfree(&alias->long_desc);
|
||||
zfree(&alias->topic);
|
||||
zfree(&alias->pmu_name);
|
||||
parse_events_terms__exit(&alias->terms);
|
||||
free(alias);
|
||||
}
|
||||
|
||||
static void perf_pmu__del_aliases(struct perf_pmu *pmu)
|
||||
{
|
||||
struct perf_pmu_alias *alias, *tmp;
|
||||
struct hashmap_entry *entry;
|
||||
size_t bkt;
|
||||
|
||||
list_for_each_entry_safe(alias, tmp, &pmu->aliases, list) {
|
||||
list_del(&alias->list);
|
||||
perf_pmu_free_alias(alias);
|
||||
}
|
||||
if (!pmu->aliases)
|
||||
return;
|
||||
|
||||
hashmap__for_each_entry(pmu->aliases, entry, bkt)
|
||||
perf_pmu_free_alias(entry->pvalue);
|
||||
|
||||
hashmap__free(pmu->aliases);
|
||||
pmu->aliases = NULL;
|
||||
}
|
||||
|
||||
static struct perf_pmu_alias *perf_pmu__find_alias(struct perf_pmu *pmu,
|
||||
|
@ -444,35 +451,37 @@ static struct perf_pmu_alias *perf_pmu__find_alias(struct perf_pmu *pmu,
|
|||
bool load)
|
||||
{
|
||||
struct perf_pmu_alias *alias;
|
||||
bool has_sysfs_event;
|
||||
char event_file_name[FILENAME_MAX + 8];
|
||||
|
||||
if (load && !pmu->sysfs_aliases_loaded) {
|
||||
bool has_sysfs_event;
|
||||
char event_file_name[FILENAME_MAX + 8];
|
||||
if (hashmap__find(pmu->aliases, name, &alias))
|
||||
return alias;
|
||||
|
||||
/*
|
||||
* Test if alias/event 'name' exists in the PMU's sysfs/events
|
||||
* directory. If not skip parsing the sysfs aliases. Sysfs event
|
||||
* name must be all lower or all upper case.
|
||||
*/
|
||||
scnprintf(event_file_name, sizeof(event_file_name), "events/%s", name);
|
||||
if (!load || pmu->sysfs_aliases_loaded)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Test if alias/event 'name' exists in the PMU's sysfs/events
|
||||
* directory. If not skip parsing the sysfs aliases. Sysfs event
|
||||
* name must be all lower or all upper case.
|
||||
*/
|
||||
scnprintf(event_file_name, sizeof(event_file_name), "events/%s", name);
|
||||
for (size_t i = 7, n = 7 + strlen(name); i < n; i++)
|
||||
event_file_name[i] = tolower(event_file_name[i]);
|
||||
|
||||
has_sysfs_event = perf_pmu__file_exists(pmu, event_file_name);
|
||||
if (!has_sysfs_event) {
|
||||
for (size_t i = 7, n = 7 + strlen(name); i < n; i++)
|
||||
event_file_name[i] = tolower(event_file_name[i]);
|
||||
event_file_name[i] = toupper(event_file_name[i]);
|
||||
|
||||
has_sysfs_event = perf_pmu__file_exists(pmu, event_file_name);
|
||||
if (!has_sysfs_event) {
|
||||
for (size_t i = 7, n = 7 + strlen(name); i < n; i++)
|
||||
event_file_name[i] = toupper(event_file_name[i]);
|
||||
|
||||
has_sysfs_event = perf_pmu__file_exists(pmu, event_file_name);
|
||||
}
|
||||
if (has_sysfs_event)
|
||||
pmu_aliases_parse(pmu);
|
||||
|
||||
}
|
||||
list_for_each_entry(alias, &pmu->aliases, list) {
|
||||
if (!strcasecmp(alias->name, name))
|
||||
if (has_sysfs_event) {
|
||||
pmu_aliases_parse(pmu);
|
||||
if (hashmap__find(pmu->aliases, name, &alias))
|
||||
return alias;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -555,7 +564,7 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
|
|||
const char *desc, const char *val, FILE *val_fd,
|
||||
const struct pmu_event *pe, enum event_source src)
|
||||
{
|
||||
struct perf_pmu_alias *alias;
|
||||
struct perf_pmu_alias *alias, *old_alias;
|
||||
int ret = 0;
|
||||
const char *long_desc = NULL, *topic = NULL, *unit = NULL, *pmu_name = NULL;
|
||||
bool deprecated = false, perpkg = false;
|
||||
|
@ -648,7 +657,8 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
|
|||
break;
|
||||
|
||||
}
|
||||
list_add_tail(&alias->list, &pmu->aliases);
|
||||
hashmap__set(pmu->aliases, alias->name, alias, /*old_key=*/ NULL, &old_alias);
|
||||
perf_pmu_free_alias(old_alias);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1136,43 +1146,77 @@ perf_pmu__arch_init(struct perf_pmu *pmu)
|
|||
pmu->mem_events = perf_mem_events;
|
||||
}
|
||||
|
||||
/* Variant of str_hash that does tolower on each character. */
|
||||
static size_t aliases__hash(long key, void *ctx __maybe_unused)
|
||||
{
|
||||
const char *s = (const char *)key;
|
||||
size_t h = 0;
|
||||
|
||||
while (*s) {
|
||||
h = h * 31 + tolower(*s);
|
||||
s++;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static bool aliases__equal(long key1, long key2, void *ctx __maybe_unused)
|
||||
{
|
||||
return strcasecmp((const char *)key1, (const char *)key2) == 0;
|
||||
}
|
||||
|
||||
int perf_pmu__init(struct perf_pmu *pmu, __u32 type, const char *name)
|
||||
{
|
||||
pmu->type = type;
|
||||
INIT_LIST_HEAD(&pmu->format);
|
||||
INIT_LIST_HEAD(&pmu->caps);
|
||||
|
||||
pmu->name = strdup(name);
|
||||
if (!pmu->name)
|
||||
return -ENOMEM;
|
||||
|
||||
pmu->aliases = hashmap__new(aliases__hash, aliases__equal, /*ctx=*/ NULL);
|
||||
if (!pmu->aliases)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *name,
|
||||
bool eager_load)
|
||||
{
|
||||
struct perf_pmu *pmu;
|
||||
__u32 type;
|
||||
|
||||
pmu = zalloc(sizeof(*pmu));
|
||||
if (!pmu)
|
||||
return NULL;
|
||||
|
||||
pmu->name = strdup(name);
|
||||
if (!pmu->name)
|
||||
goto err;
|
||||
if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, name) != 0) {
|
||||
perf_pmu__delete(pmu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read type early to fail fast if a lookup name isn't a PMU. Ensure
|
||||
* that type value is successfully assigned (return 1).
|
||||
*/
|
||||
if (perf_pmu__scan_file_at(pmu, dirfd, "type", "%u", &type) != 1)
|
||||
goto err;
|
||||
|
||||
INIT_LIST_HEAD(&pmu->format);
|
||||
INIT_LIST_HEAD(&pmu->aliases);
|
||||
INIT_LIST_HEAD(&pmu->caps);
|
||||
if (perf_pmu__scan_file_at(pmu, dirfd, "type", "%u", &pmu->type) != 1) {
|
||||
perf_pmu__delete(pmu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The pmu data we store & need consists of the pmu
|
||||
* type value and format definitions. Load both right
|
||||
* now.
|
||||
*/
|
||||
if (pmu_format(pmu, dirfd, name, eager_load))
|
||||
goto err;
|
||||
if (pmu_format(pmu, dirfd, name, eager_load)) {
|
||||
perf_pmu__delete(pmu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pmu->is_core = is_pmu_core(name);
|
||||
pmu->cpus = pmu_cpumask(dirfd, name, pmu->is_core);
|
||||
|
||||
pmu->type = type;
|
||||
pmu->is_uncore = pmu_is_uncore(dirfd, name);
|
||||
if (pmu->is_uncore)
|
||||
pmu->id = pmu_id(name);
|
||||
|
@ -1194,10 +1238,6 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char
|
|||
pmu_aliases_parse_eager(pmu, dirfd);
|
||||
|
||||
return pmu;
|
||||
err:
|
||||
zfree(&pmu->name);
|
||||
free(pmu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Creates the PMU when sysfs scanning fails. */
|
||||
|
@ -1219,7 +1259,7 @@ struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pm
|
|||
pmu->cpus = cpu_map__online();
|
||||
|
||||
INIT_LIST_HEAD(&pmu->format);
|
||||
INIT_LIST_HEAD(&pmu->aliases);
|
||||
pmu->aliases = hashmap__new(aliases__hash, aliases__equal, /*ctx=*/ NULL);
|
||||
INIT_LIST_HEAD(&pmu->caps);
|
||||
list_add_tail(&pmu->list, core_pmus);
|
||||
return pmu;
|
||||
|
@ -1979,13 +2019,14 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
|
|||
void *state, pmu_event_callback cb)
|
||||
{
|
||||
char buf[1024];
|
||||
struct perf_pmu_alias *event;
|
||||
struct pmu_event_info info = {
|
||||
.pmu = pmu,
|
||||
.event_type_desc = "Kernel PMU event",
|
||||
};
|
||||
int ret = 0;
|
||||
struct strbuf sb;
|
||||
struct hashmap_entry *entry;
|
||||
size_t bkt;
|
||||
|
||||
if (perf_pmu__is_hwmon(pmu))
|
||||
return hwmon_pmu__for_each_event(pmu, state, cb);
|
||||
|
@ -1993,7 +2034,8 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
|
|||
strbuf_init(&sb, /*hint=*/ 0);
|
||||
pmu_aliases_parse(pmu);
|
||||
pmu_add_cpu_aliases(pmu);
|
||||
list_for_each_entry(event, &pmu->aliases, list) {
|
||||
hashmap__for_each_entry(pmu->aliases, entry, bkt) {
|
||||
struct perf_pmu_alias *event = entry->pvalue;
|
||||
size_t buf_used, pmu_name_len;
|
||||
|
||||
if (perf_pmu__is_tool(pmu) && tool_pmu__skip_event(event->name))
|
||||
|
@ -2461,6 +2503,9 @@ int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename,
|
|||
|
||||
void perf_pmu__delete(struct perf_pmu *pmu)
|
||||
{
|
||||
if (!pmu)
|
||||
return;
|
||||
|
||||
if (perf_pmu__is_hwmon(pmu))
|
||||
hwmon_pmu__exit(pmu);
|
||||
|
||||
|
@ -2478,14 +2523,16 @@ void perf_pmu__delete(struct perf_pmu *pmu)
|
|||
|
||||
const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config)
|
||||
{
|
||||
struct perf_pmu_alias *event;
|
||||
struct hashmap_entry *entry;
|
||||
size_t bkt;
|
||||
|
||||
if (!pmu)
|
||||
return NULL;
|
||||
|
||||
pmu_aliases_parse(pmu);
|
||||
pmu_add_cpu_aliases(pmu);
|
||||
list_for_each_entry(event, &pmu->aliases, list) {
|
||||
hashmap__for_each_entry(pmu->aliases, entry, bkt) {
|
||||
struct perf_pmu_alias *event = entry->pvalue;
|
||||
struct perf_event_attr attr = {.config = 0,};
|
||||
|
||||
int ret = perf_pmu__config(pmu, &attr, &event->terms, /*apply_hardcoded=*/true,
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "mem-events.h"
|
||||
|
||||
struct evsel_config_term;
|
||||
struct hashmap;
|
||||
struct perf_cpu_map;
|
||||
struct print_callbacks;
|
||||
|
||||
|
@ -125,7 +126,7 @@ struct perf_pmu {
|
|||
* event read from <sysfs>/bus/event_source/devices/<name>/events/ or
|
||||
* from json events in pmu-events.c.
|
||||
*/
|
||||
struct list_head aliases;
|
||||
struct hashmap *aliases;
|
||||
/**
|
||||
* @events_table: The events table for json events in pmu-events.c.
|
||||
*/
|
||||
|
@ -294,6 +295,7 @@ int perf_pmu__pathname_scnprintf(char *buf, size_t size,
|
|||
int perf_pmu__event_source_devices_fd(void);
|
||||
int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename, int flags);
|
||||
|
||||
int perf_pmu__init(struct perf_pmu *pmu, __u32 type, const char *name);
|
||||
struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *lookup_name,
|
||||
bool eager_load);
|
||||
struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pmus);
|
||||
|
|
|
@ -502,19 +502,12 @@ struct perf_pmu *tool_pmu__new(void)
|
|||
struct perf_pmu *tool = zalloc(sizeof(struct perf_pmu));
|
||||
|
||||
if (!tool)
|
||||
goto out;
|
||||
tool->name = strdup("tool");
|
||||
if (!tool->name) {
|
||||
zfree(&tool);
|
||||
goto out;
|
||||
return NULL;
|
||||
|
||||
if (perf_pmu__init(tool, PERF_PMU_TYPE_TOOL, "tool") != 0) {
|
||||
perf_pmu__delete(tool);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tool->type = PERF_PMU_TYPE_TOOL;
|
||||
INIT_LIST_HEAD(&tool->aliases);
|
||||
INIT_LIST_HEAD(&tool->caps);
|
||||
INIT_LIST_HEAD(&tool->format);
|
||||
tool->events_table = find_core_events_table("common", "common");
|
||||
|
||||
out:
|
||||
return tool;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue