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_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];
|
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)
|
if (!pmu)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&pmu->format);
|
if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, pmu_name) != 0) {
|
||||||
INIT_LIST_HEAD(&pmu->aliases);
|
perf_pmu__delete(pmu);
|
||||||
INIT_LIST_HEAD(&pmu->caps);
|
return -1;
|
||||||
INIT_LIST_HEAD(&pmu->list);
|
}
|
||||||
pmu->name = strdup(pmu_name);
|
|
||||||
pmu->is_core = true;
|
pmu->is_core = true;
|
||||||
|
|
||||||
pmu->events_table = table;
|
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;
|
int alias_count = 0, to_match_count = 0, matched_count = 0;
|
||||||
struct perf_pmu_test_event const **table;
|
struct perf_pmu_test_event const **table;
|
||||||
struct perf_pmu *pmu = &test_pmu->pmu;
|
struct perf_pmu *pmu;
|
||||||
const char *pmu_name = pmu->name;
|
|
||||||
const struct pmu_events_table *events_table;
|
const struct pmu_events_table *events_table;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
events_table = find_core_events_table("testarch", "testcpu");
|
events_table = find_core_events_table("testarch", "testcpu");
|
||||||
if (!events_table)
|
if (!events_table)
|
||||||
return -1;
|
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->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->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) {
|
if (alias_count != to_match_count) {
|
||||||
pr_debug("testing aliases uncore PMU %s: mismatch expected aliases (%d) vs found (%d)\n",
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,9 +648,10 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
|
||||||
.count = &matched_count,
|
.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",
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -641,34 +660,32 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
|
||||||
if (err) {
|
if (err) {
|
||||||
res = err;
|
res = err;
|
||||||
pr_debug("testing aliases uncore PMU %s: could not match alias %s\n",
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alias_count != matched_count) {
|
if (alias_count != matched_count) {
|
||||||
pr_debug("testing aliases uncore PMU %s: mismatch found aliases (%d) vs matched (%d)\n",
|
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;
|
res = -1;
|
||||||
}
|
}
|
||||||
|
perf_pmu__delete(pmu);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct perf_pmu_test_pmu test_pmus[] = {
|
static struct perf_pmu_test_pmu test_pmus[] = {
|
||||||
{
|
{
|
||||||
.pmu = {
|
.pmu_name = "hisi_sccl1_ddrc2",
|
||||||
.name = "hisi_sccl1_ddrc2",
|
.pmu_is_uncore = 1,
|
||||||
.is_uncore = 1,
|
|
||||||
},
|
|
||||||
.aliases = {
|
.aliases = {
|
||||||
&uncore_hisi_ddrc_flux_wcmd,
|
&uncore_hisi_ddrc_flux_wcmd,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.pmu = {
|
.pmu_name = "uncore_cbox_0",
|
||||||
.name = "uncore_cbox_0",
|
.pmu_is_uncore = 1,
|
||||||
.is_uncore = 1,
|
|
||||||
},
|
|
||||||
.aliases = {
|
.aliases = {
|
||||||
&unc_cbo_xsnp_response_miss_eviction,
|
&unc_cbo_xsnp_response_miss_eviction,
|
||||||
&uncore_hyphen,
|
&uncore_hyphen,
|
||||||
|
@ -676,88 +693,70 @@ static struct perf_pmu_test_pmu test_pmus[] = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.pmu = {
|
.pmu_name = "hisi_sccl3_l3c7",
|
||||||
.name = "hisi_sccl3_l3c7",
|
.pmu_is_uncore = 1,
|
||||||
.is_uncore = 1,
|
|
||||||
},
|
|
||||||
.aliases = {
|
.aliases = {
|
||||||
&uncore_hisi_l3c_rd_hit_cpipe,
|
&uncore_hisi_l3c_rd_hit_cpipe,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.pmu = {
|
.pmu_name = "uncore_imc_free_running_0",
|
||||||
.name = "uncore_imc_free_running_0",
|
.pmu_is_uncore = 1,
|
||||||
.is_uncore = 1,
|
|
||||||
},
|
|
||||||
.aliases = {
|
.aliases = {
|
||||||
&uncore_imc_free_running_cache_miss,
|
&uncore_imc_free_running_cache_miss,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.pmu = {
|
.pmu_name = "uncore_imc_0",
|
||||||
.name = "uncore_imc_0",
|
.pmu_is_uncore = 1,
|
||||||
.is_uncore = 1,
|
|
||||||
},
|
|
||||||
.aliases = {
|
.aliases = {
|
||||||
&uncore_imc_cache_hits,
|
&uncore_imc_cache_hits,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.pmu = {
|
.pmu_name = "uncore_sys_ddr_pmu0",
|
||||||
.name = "uncore_sys_ddr_pmu0",
|
.pmu_is_uncore = 1,
|
||||||
.is_uncore = 1,
|
.pmu_id = "v8",
|
||||||
.id = "v8",
|
|
||||||
},
|
|
||||||
.aliases = {
|
.aliases = {
|
||||||
&sys_ddr_pmu_write_cycles,
|
&sys_ddr_pmu_write_cycles,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.pmu = {
|
.pmu_name = "uncore_sys_ccn_pmu4",
|
||||||
.name = "uncore_sys_ccn_pmu4",
|
.pmu_is_uncore = 1,
|
||||||
.is_uncore = 1,
|
.pmu_id = "0x01",
|
||||||
.id = "0x01",
|
|
||||||
},
|
|
||||||
.aliases = {
|
.aliases = {
|
||||||
&sys_ccn_pmu_read_cycles,
|
&sys_ccn_pmu_read_cycles,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.pmu = {
|
.pmu_name = "uncore_sys_cmn_pmu0",
|
||||||
.name = (char *)"uncore_sys_cmn_pmu0",
|
.pmu_is_uncore = 1,
|
||||||
.is_uncore = 1,
|
.pmu_id = "43401",
|
||||||
.id = (char *)"43401",
|
|
||||||
},
|
|
||||||
.aliases = {
|
.aliases = {
|
||||||
&sys_cmn_pmu_hnf_cache_miss,
|
&sys_cmn_pmu_hnf_cache_miss,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.pmu = {
|
.pmu_name = "uncore_sys_cmn_pmu0",
|
||||||
.name = (char *)"uncore_sys_cmn_pmu0",
|
.pmu_is_uncore = 1,
|
||||||
.is_uncore = 1,
|
.pmu_id = "43602",
|
||||||
.id = (char *)"43602",
|
|
||||||
},
|
|
||||||
.aliases = {
|
.aliases = {
|
||||||
&sys_cmn_pmu_hnf_cache_miss,
|
&sys_cmn_pmu_hnf_cache_miss,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.pmu = {
|
.pmu_name = "uncore_sys_cmn_pmu0",
|
||||||
.name = (char *)"uncore_sys_cmn_pmu0",
|
.pmu_is_uncore = 1,
|
||||||
.is_uncore = 1,
|
.pmu_id = "43c03",
|
||||||
.id = (char *)"43c03",
|
|
||||||
},
|
|
||||||
.aliases = {
|
.aliases = {
|
||||||
&sys_cmn_pmu_hnf_cache_miss,
|
&sys_cmn_pmu_hnf_cache_miss,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.pmu = {
|
.pmu_name = "uncore_sys_cmn_pmu0",
|
||||||
.name = (char *)"uncore_sys_cmn_pmu0",
|
.pmu_is_uncore = 1,
|
||||||
.is_uncore = 1,
|
.pmu_id = "43a01",
|
||||||
.id = (char *)"43a01",
|
|
||||||
},
|
|
||||||
.aliases = {
|
.aliases = {
|
||||||
&sys_cmn_pmu_hnf_cache_miss,
|
&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++) {
|
for (i = 0; i < ARRAY_SIZE(test_pmus); i++) {
|
||||||
int res;
|
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]);
|
res = __test_uncore_pmu_event_aliases(&test_pmus[i]);
|
||||||
if (res)
|
if (res)
|
||||||
return 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];
|
char buf[32];
|
||||||
struct hwmon_pmu *hwm;
|
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));
|
hwm = zalloc(sizeof(*hwm));
|
||||||
if (!hwm)
|
if (!hwm)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
hwm->hwmon_dir_fd = hwmon_dir;
|
if (perf_pmu__init(&hwm->pmu, type, buf) != 0) {
|
||||||
hwm->pmu.type = PERF_PMU_TYPE_HWMON_START + strtoul(sysfs_name + 5, NULL, 10);
|
perf_pmu__delete(&hwm->pmu);
|
||||||
if (hwm->pmu.type > PERF_PMU_TYPE_HWMON_END) {
|
return NULL;
|
||||||
pr_err("Unable to encode hwmon type from %s in valid PMU type\n", sysfs_name);
|
|
||||||
goto err_out;
|
|
||||||
}
|
}
|
||||||
snprintf(buf, sizeof(buf), "hwmon_%s", name);
|
|
||||||
fix_name(buf + 6);
|
hwm->hwmon_dir_fd = hwmon_dir;
|
||||||
hwm->pmu.name = strdup(buf);
|
|
||||||
if (!hwm->pmu.name)
|
|
||||||
goto err_out;
|
|
||||||
hwm->pmu.alias_name = strdup(sysfs_name);
|
hwm->pmu.alias_name = strdup(sysfs_name);
|
||||||
if (!hwm->pmu.alias_name)
|
if (!hwm->pmu.alias_name) {
|
||||||
goto err_out;
|
perf_pmu__delete(&hwm->pmu);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
hwm->pmu.cpus = perf_cpu_map__new("0");
|
hwm->pmu.cpus = perf_cpu_map__new("0");
|
||||||
if (!hwm->pmu.cpus)
|
if (!hwm->pmu.cpus) {
|
||||||
goto err_out;
|
perf_pmu__delete(&hwm->pmu);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
INIT_LIST_HEAD(&hwm->pmu.format);
|
INIT_LIST_HEAD(&hwm->pmu.format);
|
||||||
INIT_LIST_HEAD(&hwm->pmu.aliases);
|
|
||||||
INIT_LIST_HEAD(&hwm->pmu.caps);
|
INIT_LIST_HEAD(&hwm->pmu.caps);
|
||||||
hashmap__init(&hwm->events, hwmon_pmu__event_hashmap_hash,
|
hashmap__init(&hwm->events, hwmon_pmu__event_hashmap_hash,
|
||||||
hwmon_pmu__event_hashmap_equal, /*ctx=*/NULL);
|
hwmon_pmu__event_hashmap_equal, /*ctx=*/NULL);
|
||||||
|
|
||||||
list_add_tail(&hwm->pmu.list, pmus);
|
list_add_tail(&hwm->pmu.list, pmus);
|
||||||
return &hwm->pmu;
|
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)
|
void hwmon_pmu__exit(struct perf_pmu *pmu)
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <util/pmu-flex.h>
|
#include <util/pmu-flex.h>
|
||||||
#include "parse-events.h"
|
#include "parse-events.h"
|
||||||
#include "print-events.h"
|
#include "print-events.h"
|
||||||
|
#include "hashmap.h"
|
||||||
#include "header.h"
|
#include "header.h"
|
||||||
#include "string2.h"
|
#include "string2.h"
|
||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
|
@ -66,8 +67,6 @@ struct perf_pmu_alias {
|
||||||
char *topic;
|
char *topic;
|
||||||
/** @terms: Owned list of the original parsed parameters. */
|
/** @terms: Owned list of the original parsed parameters. */
|
||||||
struct parse_events_terms terms;
|
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
|
* @pmu_name: The name copied from the json struct pmu_event. This can
|
||||||
* differ from the PMU name as it won't have suffixes.
|
* 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. */
|
/* 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);
|
if (!alias)
|
||||||
zfree(&newalias->desc);
|
return;
|
||||||
zfree(&newalias->long_desc);
|
|
||||||
zfree(&newalias->topic);
|
zfree(&alias->name);
|
||||||
zfree(&newalias->pmu_name);
|
zfree(&alias->desc);
|
||||||
parse_events_terms__exit(&newalias->terms);
|
zfree(&alias->long_desc);
|
||||||
free(newalias);
|
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)
|
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) {
|
if (!pmu->aliases)
|
||||||
list_del(&alias->list);
|
return;
|
||||||
perf_pmu_free_alias(alias);
|
|
||||||
}
|
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,
|
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)
|
bool load)
|
||||||
{
|
{
|
||||||
struct perf_pmu_alias *alias;
|
struct perf_pmu_alias *alias;
|
||||||
|
bool has_sysfs_event;
|
||||||
|
char event_file_name[FILENAME_MAX + 8];
|
||||||
|
|
||||||
if (load && !pmu->sysfs_aliases_loaded) {
|
if (hashmap__find(pmu->aliases, name, &alias))
|
||||||
bool has_sysfs_event;
|
return alias;
|
||||||
char event_file_name[FILENAME_MAX + 8];
|
|
||||||
|
|
||||||
/*
|
if (!load || pmu->sysfs_aliases_loaded)
|
||||||
* Test if alias/event 'name' exists in the PMU's sysfs/events
|
return NULL;
|
||||||
* directory. If not skip parsing the sysfs aliases. Sysfs event
|
|
||||||
* name must be all lower or all upper case.
|
/*
|
||||||
*/
|
* Test if alias/event 'name' exists in the PMU's sysfs/events
|
||||||
scnprintf(event_file_name, sizeof(event_file_name), "events/%s", name);
|
* 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++)
|
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);
|
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 (has_sysfs_event) {
|
||||||
if (!strcasecmp(alias->name, name))
|
pmu_aliases_parse(pmu);
|
||||||
|
if (hashmap__find(pmu->aliases, name, &alias))
|
||||||
return alias;
|
return alias;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
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 char *desc, const char *val, FILE *val_fd,
|
||||||
const struct pmu_event *pe, enum event_source src)
|
const struct pmu_event *pe, enum event_source src)
|
||||||
{
|
{
|
||||||
struct perf_pmu_alias *alias;
|
struct perf_pmu_alias *alias, *old_alias;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
const char *long_desc = NULL, *topic = NULL, *unit = NULL, *pmu_name = NULL;
|
const char *long_desc = NULL, *topic = NULL, *unit = NULL, *pmu_name = NULL;
|
||||||
bool deprecated = false, perpkg = false;
|
bool deprecated = false, perpkg = false;
|
||||||
|
@ -648,7 +657,8 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
|
||||||
break;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1136,43 +1146,77 @@ perf_pmu__arch_init(struct perf_pmu *pmu)
|
||||||
pmu->mem_events = perf_mem_events;
|
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,
|
struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *name,
|
||||||
bool eager_load)
|
bool eager_load)
|
||||||
{
|
{
|
||||||
struct perf_pmu *pmu;
|
struct perf_pmu *pmu;
|
||||||
__u32 type;
|
|
||||||
|
|
||||||
pmu = zalloc(sizeof(*pmu));
|
pmu = zalloc(sizeof(*pmu));
|
||||||
if (!pmu)
|
if (!pmu)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
pmu->name = strdup(name);
|
if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, name) != 0) {
|
||||||
if (!pmu->name)
|
perf_pmu__delete(pmu);
|
||||||
goto err;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read type early to fail fast if a lookup name isn't a PMU. Ensure
|
* Read type early to fail fast if a lookup name isn't a PMU. Ensure
|
||||||
* that type value is successfully assigned (return 1).
|
* that type value is successfully assigned (return 1).
|
||||||
*/
|
*/
|
||||||
if (perf_pmu__scan_file_at(pmu, dirfd, "type", "%u", &type) != 1)
|
if (perf_pmu__scan_file_at(pmu, dirfd, "type", "%u", &pmu->type) != 1) {
|
||||||
goto err;
|
perf_pmu__delete(pmu);
|
||||||
|
return NULL;
|
||||||
INIT_LIST_HEAD(&pmu->format);
|
}
|
||||||
INIT_LIST_HEAD(&pmu->aliases);
|
|
||||||
INIT_LIST_HEAD(&pmu->caps);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The pmu data we store & need consists of the pmu
|
* The pmu data we store & need consists of the pmu
|
||||||
* type value and format definitions. Load both right
|
* type value and format definitions. Load both right
|
||||||
* now.
|
* now.
|
||||||
*/
|
*/
|
||||||
if (pmu_format(pmu, dirfd, name, eager_load))
|
if (pmu_format(pmu, dirfd, name, eager_load)) {
|
||||||
goto err;
|
perf_pmu__delete(pmu);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
pmu->is_core = is_pmu_core(name);
|
pmu->is_core = is_pmu_core(name);
|
||||||
pmu->cpus = pmu_cpumask(dirfd, name, pmu->is_core);
|
pmu->cpus = pmu_cpumask(dirfd, name, pmu->is_core);
|
||||||
|
|
||||||
pmu->type = type;
|
|
||||||
pmu->is_uncore = pmu_is_uncore(dirfd, name);
|
pmu->is_uncore = pmu_is_uncore(dirfd, name);
|
||||||
if (pmu->is_uncore)
|
if (pmu->is_uncore)
|
||||||
pmu->id = pmu_id(name);
|
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);
|
pmu_aliases_parse_eager(pmu, dirfd);
|
||||||
|
|
||||||
return pmu;
|
return pmu;
|
||||||
err:
|
|
||||||
zfree(&pmu->name);
|
|
||||||
free(pmu);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Creates the PMU when sysfs scanning fails. */
|
/* 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();
|
pmu->cpus = cpu_map__online();
|
||||||
|
|
||||||
INIT_LIST_HEAD(&pmu->format);
|
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);
|
INIT_LIST_HEAD(&pmu->caps);
|
||||||
list_add_tail(&pmu->list, core_pmus);
|
list_add_tail(&pmu->list, core_pmus);
|
||||||
return pmu;
|
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)
|
void *state, pmu_event_callback cb)
|
||||||
{
|
{
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
struct perf_pmu_alias *event;
|
|
||||||
struct pmu_event_info info = {
|
struct pmu_event_info info = {
|
||||||
.pmu = pmu,
|
.pmu = pmu,
|
||||||
.event_type_desc = "Kernel PMU event",
|
.event_type_desc = "Kernel PMU event",
|
||||||
};
|
};
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct strbuf sb;
|
struct strbuf sb;
|
||||||
|
struct hashmap_entry *entry;
|
||||||
|
size_t bkt;
|
||||||
|
|
||||||
if (perf_pmu__is_hwmon(pmu))
|
if (perf_pmu__is_hwmon(pmu))
|
||||||
return hwmon_pmu__for_each_event(pmu, state, cb);
|
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);
|
strbuf_init(&sb, /*hint=*/ 0);
|
||||||
pmu_aliases_parse(pmu);
|
pmu_aliases_parse(pmu);
|
||||||
pmu_add_cpu_aliases(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;
|
size_t buf_used, pmu_name_len;
|
||||||
|
|
||||||
if (perf_pmu__is_tool(pmu) && tool_pmu__skip_event(event->name))
|
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)
|
void perf_pmu__delete(struct perf_pmu *pmu)
|
||||||
{
|
{
|
||||||
|
if (!pmu)
|
||||||
|
return;
|
||||||
|
|
||||||
if (perf_pmu__is_hwmon(pmu))
|
if (perf_pmu__is_hwmon(pmu))
|
||||||
hwmon_pmu__exit(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)
|
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)
|
if (!pmu)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
pmu_aliases_parse(pmu);
|
pmu_aliases_parse(pmu);
|
||||||
pmu_add_cpu_aliases(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,};
|
struct perf_event_attr attr = {.config = 0,};
|
||||||
|
|
||||||
int ret = perf_pmu__config(pmu, &attr, &event->terms, /*apply_hardcoded=*/true,
|
int ret = perf_pmu__config(pmu, &attr, &event->terms, /*apply_hardcoded=*/true,
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "mem-events.h"
|
#include "mem-events.h"
|
||||||
|
|
||||||
struct evsel_config_term;
|
struct evsel_config_term;
|
||||||
|
struct hashmap;
|
||||||
struct perf_cpu_map;
|
struct perf_cpu_map;
|
||||||
struct print_callbacks;
|
struct print_callbacks;
|
||||||
|
|
||||||
|
@ -125,7 +126,7 @@ struct perf_pmu {
|
||||||
* event read from <sysfs>/bus/event_source/devices/<name>/events/ or
|
* event read from <sysfs>/bus/event_source/devices/<name>/events/ or
|
||||||
* from json events in pmu-events.c.
|
* 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.
|
* @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__event_source_devices_fd(void);
|
||||||
int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename, int flags);
|
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,
|
struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *lookup_name,
|
||||||
bool eager_load);
|
bool eager_load);
|
||||||
struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pmus);
|
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));
|
struct perf_pmu *tool = zalloc(sizeof(struct perf_pmu));
|
||||||
|
|
||||||
if (!tool)
|
if (!tool)
|
||||||
goto out;
|
return NULL;
|
||||||
tool->name = strdup("tool");
|
|
||||||
if (!tool->name) {
|
if (perf_pmu__init(tool, PERF_PMU_TYPE_TOOL, "tool") != 0) {
|
||||||
zfree(&tool);
|
perf_pmu__delete(tool);
|
||||||
goto out;
|
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");
|
tool->events_table = find_core_events_table("common", "common");
|
||||||
|
|
||||||
out:
|
|
||||||
return tool;
|
return tool;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue