#include "../../../util/debug.h"
#include "../../../util/evlist.h"
#include "../../../util/pmu.h"
+#include "../../../util/pmus.h"
#include "cs-etm.h"
#include "arm-spe.h"
#include "hisi-ptt.h"
return NULL;
}
- arm_spe_pmus[*nr_spes] = perf_pmu__find(arm_spe_pmu_name);
+ arm_spe_pmus[*nr_spes] = perf_pmus__find(arm_spe_pmu_name);
if (arm_spe_pmus[*nr_spes]) {
pr_debug2("%s %d: arm_spe_pmu %d type %d name %s\n",
__func__, __LINE__, *nr_spes,
rewinddir(dir);
while ((dent = readdir(dir))) {
if (strstr(dent->d_name, HISI_PTT_PMU_NAME) && idx < *nr_ptts) {
- hisi_ptt_pmus[idx] = perf_pmu__find(dent->d_name);
+ hisi_ptt_pmus[idx] = perf_pmus__find(dent->d_name);
if (hisi_ptt_pmus[idx])
idx++;
}
if (!evlist)
return NULL;
- cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
+ cs_etm_pmu = perf_pmus__find(CORESIGHT_ETM_PMU_NAME);
arm_spe_pmus = find_all_arm_spe_pmus(&nr_spes, err);
hisi_ptt_pmus = find_all_hisi_ptt_pmus(&nr_ptts, err);
#include "../../../util/evsel.h"
#include "../../../util/perf_api_probe.h"
#include "../../../util/evsel_config.h"
-#include "../../../util/pmu.h"
+#include "../../../util/pmus.h"
#include "../../../util/cs-etm.h"
#include <internal/lib.h> // page_size
#include "../../../util/session.h"
struct perf_pmu *cs_etm_pmu;
struct cs_etm_recording *ptr;
- cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
+ cs_etm_pmu = perf_pmus__find(CORESIGHT_ETM_PMU_NAME);
if (!cs_etm_pmu) {
*err = -EINVAL;
#include <internal/cpumap.h>
#include "../../../util/cpumap.h"
#include "../../../util/pmu.h"
+#include "../../../util/pmus.h"
#include <api/fs/fs.h>
#include <math.h>
{
struct perf_pmu *pmu = NULL;
- while ((pmu = perf_pmu__scan(pmu))) {
+ while ((pmu = perf_pmus__scan(pmu))) {
if (!is_pmu_core(pmu->name))
continue;
#include "evlist.h"
#include "evsel.h"
#include "pmu.h"
+#include "pmus.h"
#include "tests/tests.h"
static bool test_config(const struct evsel *evsel, __u64 expected_config)
struct perf_evsel *evsel;
perf_evlist__for_each_evsel(&evlist->core, evsel) {
- struct perf_pmu *pmu = perf_pmu__find_by_type(evsel->attr.type);
+ struct perf_pmu *pmu = perf_pmus__find_by_type(evsel->attr.type);
TEST_ASSERT_VAL("missing pmu", pmu);
TEST_ASSERT_VAL("unexpected pmu", !strncmp(pmu->name, "cpu_", 4));
int test__hybrid(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
{
- if (!perf_pmu__has_hybrid())
+ if (!perf_pmus__has_hybrid())
return TEST_SKIP;
return test_events(test__hybrid_events, ARRAY_SIZE(test__hybrid_events));
#include "../../../util/header.h"
#include "../../../util/debug.h"
#include "../../../util/pmu.h"
+#include "../../../util/pmus.h"
#include "../../../util/auxtrace.h"
#include "../../../util/intel-pt.h"
#include "../../../util/intel-bts.h"
bool found_pt = false;
bool found_bts = false;
- intel_pt_pmu = perf_pmu__find(INTEL_PT_PMU_NAME);
- intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME);
+ intel_pt_pmu = perf_pmus__find(INTEL_PT_PMU_NAME);
+ intel_bts_pmu = perf_pmus__find(INTEL_BTS_PMU_NAME);
evlist__for_each_entry(evlist, evsel) {
if (intel_pt_pmu && evsel->core.attr.type == intel_pt_pmu->type)
// SPDX-License-Identifier: GPL-2.0
#include <stdio.h>
#include "util/pmu.h"
+#include "util/pmus.h"
#include "util/evlist.h"
#include "util/parse-events.h"
#include "util/event.h"
for (i = 0; i < nr_attrs; i++)
event_attr_init(attrs + i);
- if (!perf_pmu__has_hybrid())
+ if (!perf_pmus__has_hybrid())
return evlist__add_attrs(evlist, attrs, nr_attrs);
for (i = 0; i < nr_attrs; i++) {
continue;
}
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
struct perf_cpu_map *cpus;
struct evsel *evsel;
#include "util/evsel.h"
#include "util/env.h"
#include "util/pmu.h"
+#include "util/pmus.h"
#include "linux/string.h"
#include "evsel.h"
#include "util/debug.h"
* should be good enough to detect the perf metrics feature.
*/
if ((evsel->core.attr.type == PERF_TYPE_RAW) &&
- pmu_have_event(pmu_name, "slots"))
+ perf_pmus__have_event(pmu_name, "slots"))
return true;
return false;
if (!evsel_pmu)
return;
- ibs_fetch_pmu = perf_pmu__find("ibs_fetch");
- ibs_op_pmu = perf_pmu__find("ibs_op");
+ ibs_fetch_pmu = perf_pmus__find("ibs_fetch");
+ ibs_op_pmu = perf_pmus__find("ibs_op");
if (ibs_fetch_pmu && ibs_fetch_pmu->type == evsel_pmu->type) {
if (attr->config & IBS_FETCH_L3MISSONLY) {
#include "../../../util/evlist.h"
#include "../../../util/mmap.h"
#include "../../../util/session.h"
-#include "../../../util/pmu.h"
+#include "../../../util/pmus.h"
#include "../../../util/debug.h"
#include "../../../util/record.h"
#include "../../../util/tsc.h"
struct auxtrace_record *intel_bts_recording_init(int *err)
{
- struct perf_pmu *intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME);
+ struct perf_pmu *intel_bts_pmu = perf_pmus__find(INTEL_BTS_PMU_NAME);
struct intel_bts_recording *btsr;
if (!intel_bts_pmu)
#include "../../../util/mmap.h"
#include <subcmd/parse-options.h>
#include "../../../util/parse-events.h"
-#include "../../../util/pmu.h"
+#include "../../../util/pmus.h"
#include "../../../util/debug.h"
#include "../../../util/auxtrace.h"
#include "../../../util/perf_api_probe.h"
struct auxtrace_record *intel_pt_recording_init(int *err)
{
- struct perf_pmu *intel_pt_pmu = perf_pmu__find(INTEL_PT_PMU_NAME);
+ struct perf_pmu *intel_pt_pmu = perf_pmus__find(INTEL_PT_PMU_NAME);
struct intel_pt_recording *ptr;
if (!intel_pt_pmu)
// SPDX-License-Identifier: GPL-2.0
#include "util/pmu.h"
+#include "util/pmus.h"
#include "util/env.h"
#include "map_symbol.h"
#include "mem-events.h"
bool is_mem_loads_aux_event(struct evsel *leader)
{
- struct perf_pmu *pmu = perf_pmu__find("cpu");
+ struct perf_pmu *pmu = perf_pmus__find("cpu");
if (!pmu)
- pmu = perf_pmu__find("cpu_core");
+ pmu = perf_pmus__find("cpu_core");
- if (pmu && !pmu_have_event(pmu->name, "mem-loads-aux"))
+ if (pmu && !perf_pmu__have_event(pmu, "mem-loads-aux"))
return false;
return leader->core.attr.config == MEM_LOADS_AUX;
pmu_name = (char *)"cpu";
}
- if (pmu_have_event(pmu_name, "mem-loads-aux")) {
+ if (perf_pmus__have_event(pmu_name, "mem-loads-aux")) {
scnprintf(mem_loads_name, sizeof(mem_loads_name),
MEM_LOADS_AUX_NAME, pmu_name, pmu_name,
perf_mem_events__loads_ldlat);
#include "../../../util/debug.h"
#include "../../../util/event.h"
#include "../../../util/pmu.h"
+#include "../../../util/pmus.h"
const struct sample_reg sample_reg_masks[] = {
SMPL_REG(AX, PERF_REG_X86_AX),
*/
attr.sample_period = 1;
- if (perf_pmu__has_hybrid()) {
+ if (perf_pmus__has_hybrid()) {
struct perf_pmu *pmu = NULL;
__u64 type = PERF_TYPE_RAW;
* The same register set is supported among different hybrid PMUs.
* Only check the first available one.
*/
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
if (pmu->is_core) {
type = pmu->type;
break;
#include "api/fs/fs.h"
#include "util/evsel.h"
#include "util/pmu.h"
+#include "util/pmus.h"
#include "util/topdown.h"
#include "topdown.h"
#include "evsel.h"
* The slots event is only available when the core PMU
* supports the perf metrics feature.
*/
- pmu = perf_pmu__find_by_type(PERF_TYPE_RAW);
- if (pmu && pmu_have_event(pmu->name, "slots"))
+ pmu = perf_pmus__find_by_type(PERF_TYPE_RAW);
+ if (pmu && perf_pmu__have_event(pmu, "slots"))
has_perf_metrics = true;
cached = true;
struct list_head *list;
struct pmu_scan_result *r;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
r = realloc(results, (nr_pmus + 1) * sizeof(*r));
if (r == NULL)
return -ENOMEM;
nr_pmus++;
}
- perf_pmu__destroy();
+ perf_pmus__destroy();
return 0;
}
for (int i = 0; i < nr_pmus; i++) {
r = &results[i];
- pmu = perf_pmu__find(r->name);
+ pmu = perf_pmus__find(r->name);
if (pmu == NULL) {
pr_err("Cannot find PMU %s\n", r->name);
return -1;
for (i = 0; i < iterations; i++) {
gettimeofday(&start, NULL);
- perf_pmu__scan(NULL);
+ perf_pmus__scan(NULL);
gettimeofday(&end, NULL);
timersub(&end, &start, &diff);
update_stats(&stats, runtime_us);
ret = check_result();
- perf_pmu__destroy();
+ perf_pmus__destroy();
if (ret < 0)
break;
}
#include "symbol.h"
#include "ui/ui.h"
#include "ui/progress.h"
-#include "pmu.h"
+#include "pmus.h"
#include "string2.h"
#include "util/util.h"
PARSE_OPT_KEEP_UNKNOWN);
/* Max number of arguments multiplied by number of PMUs that can support them. */
- rec_argc = argc + 11 * perf_pmu__num_mem_pmus();
+ rec_argc = argc + 11 * perf_pmus__num_mem_pmus();
rec_argv = calloc(rec_argc + 1, sizeof(char *));
if (!rec_argv)
strcmp(argv[i], "hwcache") == 0)
print_hwcache_events(&print_cb, ps);
else if (strcmp(argv[i], "pmu") == 0)
- print_pmu_events(&print_cb, ps);
+ perf_pmus__print_pmu_events(&print_cb, ps);
else if (strcmp(argv[i], "sdt") == 0)
print_sdt_events(&print_cb, ps);
else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0) {
event_symbols_sw, PERF_COUNT_SW_MAX);
print_tool_events(&print_cb, ps);
print_hwcache_events(&print_cb, ps);
- print_pmu_events(&print_cb, ps);
+ perf_pmus__print_pmu_events(&print_cb, ps);
print_tracepoint_events(&print_cb, ps);
print_sdt_events(&print_cb, ps);
default_ps.metrics = true;
#include "util/dso.h"
#include "util/map.h"
#include "util/symbol.h"
-#include "util/pmu.h"
+#include "util/pmus.h"
#include "util/sample.h"
#include "util/string2.h"
#include "util/util.h"
PARSE_OPT_KEEP_UNKNOWN);
/* Max number of arguments multiplied by number of PMUs that can support them. */
- rec_argc = argc + 9 * perf_pmu__num_mem_pmus();
+ rec_argc = argc + 9 * perf_pmus__num_mem_pmus();
if (mem->cpu_list)
rec_argc += 2;
#include "util/bpf-event.h"
#include "util/util.h"
#include "util/pfm.h"
+#include "util/pmu.h"
+#include "util/pmus.h"
#include "util/clockid.h"
#include "util/off_cpu.h"
#include "util/bpf-filter.h"
* of waiting or event synthesis.
*/
if (opts->target.initial_delay || target__has_cpu(&opts->target) ||
- perf_pmu__has_hybrid()) {
+ perf_pmus__has_hybrid()) {
pos = evlist__get_tracking_event(evlist);
if (!evsel__is_dummy_event(pos)) {
/* Set up dummy event. */
char *new_name;
int ret;
- if (!perf_pmu__has_hybrid())
+ if (!perf_pmus__has_hybrid())
return;
evlist__for_each_entry(evlist, pos) {
if (evlist__add_default_attrs(evsel_list, default_attrs0) < 0)
return -1;
- if (pmu_have_event("cpu", "stalled-cycles-frontend")) {
+ if (perf_pmus__have_event("cpu", "stalled-cycles-frontend")) {
if (evlist__add_default_attrs(evsel_list, frontend_attrs) < 0)
return -1;
}
- if (pmu_have_event("cpu", "stalled-cycles-backend")) {
+ if (perf_pmus__have_event("cpu", "stalled-cycles-backend")) {
if (evlist__add_default_attrs(evsel_list, backend_attrs) < 0)
return -1;
}
#include "event.h"
#include "util.h"
#include "tests.h"
-#include "pmu.h"
+#include "pmus.h"
#define ENV "PERF_TEST_ATTR"
char path_dir[PATH_MAX];
char *exec_path;
- if (perf_pmu__has_hybrid())
+ if (perf_pmus__has_hybrid())
return TEST_SKIP;
/* First try development tree tests. */
struct perf_pmu *pmu = NULL;
int i, fd;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
for (i = 0; i < NR_UNCORE_PMUS; i++) {
if (!strcmp(uncore_pmus[i].name, pmu->name)) {
pr_debug("Using %s for uncore pmu event\n", pmu->name);
bool type_matched = false;
TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, 0x1a));
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
if (pmu->type == evsel->attr.type) {
TEST_ASSERT_VAL("PMU type expected once", !type_matched);
type_matched = true;
static bool test__pmu_cpu_valid(void)
{
- return !!perf_pmu__find("cpu");
+ return !!perf_pmus__find("cpu");
}
static bool test__intel_pt_valid(void)
{
- return !!perf_pmu__find("intel_pt");
+ return !!perf_pmus__find("intel_pt");
}
static int test__intel_pt(struct evlist *evlist)
struct perf_pmu *pmu = NULL;
int ret = TEST_OK;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
struct stat st;
char path[PATH_MAX];
struct dirent *ent;
#include "debug.h"
#include "expr.h"
#include "stat.h"
-#include "pmu.h"
+#include "pmus.h"
struct value {
const char *event;
TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
TEST_ASSERT_VAL("Memory bandwidth", test_memory_bandwidth() == 0);
- if (!perf_pmu__has_hybrid()) {
+ if (!perf_pmus__has_hybrid()) {
TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
TEST_ASSERT_VAL("test metric group", test_metric_group() == 0);
}
#include "math.h"
#include "parse-events.h"
#include "pmu.h"
+#include "pmus.h"
#include "tests.h"
#include <errno.h>
#include <stdio.h>
struct perf_pmu *pmu = NULL;
unsigned long i;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
int count = 0;
if (!is_pmu_core(pmu->name))
#include "tests.h"
#include "util/mmap.h"
#include "util/sample.h"
-#include "pmu.h"
+#include "pmus.h"
static int spin_sleep(void)
{
cpu_clocks_evsel = evlist__last(evlist);
/* Second event */
- if (perf_pmu__has_hybrid()) {
+ if (perf_pmus__has_hybrid()) {
cycles = "cpu_core/cycles/u";
err = parse_event(evlist, cycles);
if (err) {
#include "session.h"
#include "evlist.h"
#include "debug.h"
-#include "pmu.h"
+#include "pmus.h"
#include <linux/err.h>
#define TEMPL "/tmp/perf-test-XXXXXX"
session = perf_session__new(&data, NULL);
TEST_ASSERT_VAL("can't get session", !IS_ERR(session));
- if (!perf_pmu__has_hybrid()) {
+ if (!perf_pmus__has_hybrid()) {
session->evlist = evlist__new_default();
TEST_ASSERT_VAL("can't get evlist", session->evlist);
} else {
#include "debug.h"
#include "env.h"
#include "pmu.h"
+#include "pmus.h"
#define PACKAGE_CPUS_FMT \
"%s/devices/system/cpu/cpu%d/topology/package_cpus_list"
struct hybrid_topology *tp = NULL;
u32 nr = 0, i = 0;
- if (!perf_pmu__has_hybrid())
+ if (!perf_pmus__has_hybrid())
return NULL;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
if (pmu->is_core)
nr++;
}
return NULL;
tp->nr = nr;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
if (!pmu->is_core)
continue;
#include <sys/utsname.h>
#include <stdlib.h>
#include <string.h>
+#include "pmus.h"
#include "strbuf.h"
struct perf_env perf_env;
u32 pmu_num = 0;
struct strbuf sb;
- while ((pmu = perf_pmu__scan(pmu))) {
+ while ((pmu = perf_pmus__scan(pmu))) {
if (!pmu->name)
continue;
pmu_num++;
if (strbuf_init(&sb, 128 * pmu_num) < 0)
return -ENOMEM;
- while ((pmu = perf_pmu__scan(pmu))) {
+ while ((pmu = perf_pmus__scan(pmu))) {
if (!pmu->name)
continue;
if (strbuf_addf(&sb, "%u:%s", pmu->type, pmu->name) < 0)
#include "util/hashmap.h"
#include "off_cpu.h"
#include "pmu.h"
+#include "pmus.h"
#include "../perf-sys.h"
#include "util/parse-branch-options.h"
#include "util/bpf-filter.h"
*/
bool evsel__is_hybrid(const struct evsel *evsel)
{
- if (!perf_pmu__has_hybrid())
+ if (!perf_pmus__has_hybrid())
return false;
return evsel->core.is_pmu_core;
#include "debug.h"
#include "cpumap.h"
#include "pmu.h"
+#include "pmus.h"
#include "vdso.h"
#include "strbuf.h"
#include "build-id.h"
* Do a first pass to count number of pmu to avoid lseek so this
* works in pipe mode as well.
*/
- while ((pmu = perf_pmu__scan(pmu))) {
+ while ((pmu = perf_pmus__scan(pmu))) {
if (!pmu->name)
continue;
pmu_num++;
if (ret < 0)
return ret;
- while ((pmu = perf_pmu__scan(pmu))) {
+ while ((pmu = perf_pmus__scan(pmu))) {
if (!pmu->name)
continue;
static int write_cpu_pmu_caps(struct feat_fd *ff,
struct evlist *evlist __maybe_unused)
{
- struct perf_pmu *cpu_pmu = perf_pmu__find("cpu");
+ struct perf_pmu *cpu_pmu = perf_pmus__find("cpu");
int ret;
if (!cpu_pmu)
int nr_pmu = 0;
int ret;
- while ((pmu = perf_pmu__scan(pmu))) {
+ while ((pmu = perf_pmus__scan(pmu))) {
if (!pmu->name || !strcmp(pmu->name, "cpu") ||
perf_pmu__caps_parse(pmu) <= 0)
continue;
* Write hybrid pmu caps first to maintain compatibility with
* older perf tool.
*/
- if (perf_pmu__has_hybrid()) {
+ if (perf_pmus__has_hybrid()) {
pmu = NULL;
- while ((pmu = perf_pmu__scan(pmu))) {
+ while ((pmu = perf_pmus__scan(pmu))) {
if (!pmu->is_core)
continue;
}
pmu = NULL;
- while ((pmu = perf_pmu__scan(pmu))) {
+ while ((pmu = perf_pmus__scan(pmu))) {
if (pmu->is_core || !pmu->nr_caps)
continue;
#include "debug.h"
#include "symbol.h"
#include "pmu.h"
+#include "pmus.h"
unsigned int perf_mem_events__loads_ldlat = 30;
if (!e->tag)
continue;
- if (!perf_pmu__has_hybrid()) {
+ if (!perf_pmus__has_hybrid()) {
scnprintf(sysfs_name, sizeof(sysfs_name),
e->sysfs_name, "cpu");
e->supported = perf_mem_event__supported(mnt, sysfs_name);
} else {
struct perf_pmu *pmu = NULL;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
if (!pmu->is_core)
continue;
char sysfs_name[100];
struct perf_pmu *pmu = NULL;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
if (!pmu->is_core)
continue;
if (!e->record)
continue;
- if (!perf_pmu__has_hybrid()) {
+ if (!perf_pmus__has_hybrid()) {
if (!e->supported) {
pr_err("failed: event '%s' not supported\n",
perf_mem_events__name(j, NULL));
return -1;
}
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
if (!pmu->is_core)
continue;
rec_argv[i++] = "-e";
#include "evsel.h"
#include "strbuf.h"
#include "pmu.h"
+#include "pmus.h"
#include "print-events.h"
#include "smt.h"
#include "expr.h"
const char *metric_id;
struct evsel *ev;
size_t ids_size, matched_events, i;
- bool all_pmus = !strcmp(pmu, "all") || !perf_pmu__has_hybrid() || !is_pmu_hybrid(pmu);
+ bool all_pmus = !strcmp(pmu, "all") || !perf_pmus__has_hybrid() || !is_pmu_hybrid(pmu);
*out_metric_events = NULL;
ids_size = hashmap__size(ids);
if (!pm->metric_expr || !pm->compat)
return 0;
- while ((pmu = perf_pmu__scan(pmu))) {
+ while ((pmu = perf_pmus__scan(pmu))) {
if (!pmu->id || strcmp(pmu->id, pm->compat))
continue;
#include "parse-events-bison.h"
#include "parse-events-flex.h"
#include "pmu.h"
+#include "pmus.h"
#include "asm/bug.h"
#include "util/parse-branch-options.h"
#include "util/evsel_config.h"
const char *config_name = get_config_name(head_config);
const char *metric_id = get_config_metric_id(head_config);
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
LIST_HEAD(config_terms);
struct perf_event_attr attr;
int ret;
struct parse_events_error *err)
{
if (term->type_term == PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE) {
- const struct perf_pmu *pmu = perf_pmu__find_by_type(attr->type);
+ const struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type);
if (perf_pmu__supports_legacy_cache(pmu)) {
attr->type = PERF_TYPE_HW_CACHE;
term->type_term = PARSE_EVENTS__TERM_TYPE_USER;
}
if (term->type_term == PARSE_EVENTS__TERM_TYPE_HARDWARE) {
- const struct perf_pmu *pmu = perf_pmu__find_by_type(attr->type);
+ const struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type);
if (!pmu) {
pr_debug("Failed to find PMU for type %d", attr->type);
return __parse_events_add_numeric(parse_state, list, /*pmu=*/NULL,
type, config, head_config);
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
int ret;
if (!perf_pmu__supports_wildcard_numeric(pmu))
struct parse_events_error *err = parse_state->error;
LIST_HEAD(config_terms);
- pmu = parse_state->fake_pmu ?: perf_pmu__find(name);
+ pmu = parse_state->fake_pmu ?: perf_pmus__find(name);
if (verbose > 1 && !(pmu && pmu->selectable)) {
fprintf(stderr, "Attempting to add event pmu '%s' with '",
INIT_LIST_HEAD(list);
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
struct perf_pmu_alias *alias;
bool auto_merge_stats;
return 0;
}
- while ((pmu = perf_pmu__scan(pmu)) != NULL)
+ while ((pmu = perf_pmus__scan(pmu)) != NULL)
if (pmu->type == evsel->core.attr.type) {
found = true;
break;
#include <linux/types.h>
#include <linux/zalloc.h>
#include "pmu.h"
+#include "pmus.h"
#include "evsel.h"
#include "parse-events.h"
#include "parse-events-bison.h"
if (asprintf(&pattern, "%s*", $1) < 0)
CLEANUP_YYABORT;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
char *name = pmu->name;
if (parse_events__filter_pmu(parse_state, pmu))
#include "util/evlist.h"
#include "util/evsel.h"
#include "util/parse-events.h"
-#include "util/pmu.h"
+#include "util/pmus.h"
#include "util/pfm.h"
#include "util/strbuf.h"
/*
* force loading of the PMU list
*/
- perf_pmu__scan(NULL);
+ perf_pmus__scan(NULL);
for (q = p; strsep(&p, ",{}"); q = p) {
sep = p ? str + (p - p_orig - 1) : "";
goto error;
}
- pmu = perf_pmu__find_by_type((unsigned int)attr.type);
+ pmu = perf_pmus__find_by_type((unsigned int)attr.type);
evsel = parse_events__add_event(evlist->core.nr_entries,
&attr, q, /*metric_id=*/NULL,
pmu);
#include <linux/string.h>
#include <linux/zalloc.h>
#include <linux/ctype.h>
-#include <subcmd/pager.h>
#include <sys/types.h>
-#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdbool.h>
-#include <stdarg.h>
#include <dirent.h>
#include <api/fs/fs.h>
#include <locale.h>
-#include <regex.h>
-#include <perf/cpumap.h>
#include <fnmatch.h>
#include <math.h>
#include "debug.h"
struct list_head list;
};
-static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name);
-
/*
* Parse & process all the sysfs attributes located under
* the directory specified in 'dir' parameter.
return 0;
}
-/* Add all pmus in sysfs to pmu list: */
-static void pmu_read_sysfs(void)
-{
- int fd;
- DIR *dir;
- struct dirent *dent;
-
- fd = perf_pmu__event_source_devices_fd();
- if (fd < 0)
- return;
-
- dir = fdopendir(fd);
- if (!dir)
- return;
-
- while ((dent = readdir(dir))) {
- if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
- continue;
- /* add to static LIST_HEAD(pmus): */
- perf_pmu__find2(fd, dent->d_name);
- }
-
- closedir(dir);
-}
-
/*
* Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64)
* may have a "cpus" file.
return max_precise;
}
-static struct perf_pmu *pmu_lookup(int dirfd, const char *lookup_name)
+struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *lookup_name)
{
struct perf_pmu *pmu;
LIST_HEAD(format);
INIT_LIST_HEAD(&pmu->caps);
list_splice(&format, &pmu->format);
list_splice(&aliases, &pmu->aliases);
- list_add_tail(&pmu->list, &pmus);
+ list_add_tail(&pmu->list, pmus);
pmu->default_config = perf_pmu__get_default_config(pmu);
}
}
-static struct perf_pmu *pmu_find(const char *name)
-{
- struct perf_pmu *pmu;
-
- list_for_each_entry(pmu, &pmus, list) {
- if (!strcmp(pmu->name, name) ||
- (pmu->alias_name && !strcmp(pmu->alias_name, name)))
- return pmu;
- }
-
- return NULL;
-}
-
-struct perf_pmu *perf_pmu__find_by_type(unsigned int type)
-{
- struct perf_pmu *pmu;
-
- list_for_each_entry(pmu, &pmus, list)
- if (pmu->type == type)
- return pmu;
-
- return NULL;
-}
-
-struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
-{
- /*
- * pmu iterator: If pmu is NULL, we start at the begin,
- * otherwise return the next pmu. Returns NULL on end.
- */
- if (!pmu) {
- pmu_read_sysfs();
- pmu = list_prepare_entry(pmu, &pmus, list);
- }
- list_for_each_entry_continue(pmu, &pmus, list)
- return pmu;
- return NULL;
-}
-
-struct perf_pmu *evsel__find_pmu(const struct evsel *evsel)
-{
- struct perf_pmu *pmu = NULL;
-
- if (evsel->pmu)
- return evsel->pmu;
-
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
- if (pmu->type == evsel->core.attr.type)
- break;
- }
-
- ((struct evsel *)evsel)->pmu = pmu;
- return pmu;
-}
-
bool evsel__is_aux_event(const struct evsel *evsel)
{
struct perf_pmu *pmu = evsel__find_pmu(evsel);
evsel->core.attr.config |= field_prep(bits, val);
}
-struct perf_pmu *perf_pmu__find(const char *name)
-{
- struct perf_pmu *pmu;
- int dirfd;
-
- /*
- * Once PMU is loaded it stays in the list,
- * so we keep us from multiple reading/parsing
- * the pmu format definitions.
- */
- pmu = pmu_find(name);
- if (pmu)
- return pmu;
-
- dirfd = perf_pmu__event_source_devices_fd();
- pmu = pmu_lookup(dirfd, name);
- close(dirfd);
-
- return pmu;
-}
-
-static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name)
-{
- struct perf_pmu *pmu;
-
- /*
- * Once PMU is loaded it stays in the list,
- * so we keep us from multiple reading/parsing
- * the pmu format definitions.
- */
- pmu = pmu_find(name);
- if (pmu)
- return pmu;
-
- return pmu_lookup(dirfd, name);
-}
-
static struct perf_pmu_format *
pmu_find_format(struct list_head *formats, const char *name)
{
}
}
-static int sub_non_neg(int a, int b)
-{
- if (b > a)
- return 0;
- return a - b;
-}
-
-static char *format_alias(char *buf, int len, const struct perf_pmu *pmu,
- const struct perf_pmu_alias *alias)
-{
- struct parse_events_term *term;
- int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name);
-
- list_for_each_entry(term, &alias->terms, list) {
- if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
- used += snprintf(buf + used, sub_non_neg(len, used),
- ",%s=%s", term->config,
- term->val.str);
- }
-
- if (sub_non_neg(len, used) > 0) {
- buf[used] = '/';
- used++;
- }
- if (sub_non_neg(len, used) > 0) {
- buf[used] = '\0';
- used++;
- } else
- buf[len - 1] = '\0';
-
- return buf;
-}
-
-/** Struct for ordering events as output in perf list. */
-struct sevent {
- /** PMU for event. */
- const struct perf_pmu *pmu;
- /**
- * Optional event for name, desc, etc. If not present then this is a
- * selectable PMU and the event name is shown as "//".
- */
- const struct perf_pmu_alias *event;
- /** Is the PMU for the CPU? */
- bool is_cpu;
-};
-
-static int cmp_sevent(const void *a, const void *b)
-{
- const struct sevent *as = a;
- const struct sevent *bs = b;
- const char *a_pmu_name = NULL, *b_pmu_name = NULL;
- const char *a_name = "//", *a_desc = NULL, *a_topic = "";
- const char *b_name = "//", *b_desc = NULL, *b_topic = "";
- int ret;
-
- if (as->event) {
- a_name = as->event->name;
- a_desc = as->event->desc;
- a_topic = as->event->topic ?: "";
- a_pmu_name = as->event->pmu_name;
- }
- if (bs->event) {
- b_name = bs->event->name;
- b_desc = bs->event->desc;
- b_topic = bs->event->topic ?: "";
- b_pmu_name = bs->event->pmu_name;
- }
- /* Put extra events last. */
- if (!!a_desc != !!b_desc)
- return !!a_desc - !!b_desc;
-
- /* Order by topics. */
- ret = strcmp(a_topic, b_topic);
- if (ret)
- return ret;
-
- /* Order CPU core events to be first */
- if (as->is_cpu != bs->is_cpu)
- return as->is_cpu ? -1 : 1;
-
- /* Order by PMU name. */
- if (as->pmu != bs->pmu) {
- a_pmu_name = a_pmu_name ?: (as->pmu->name ?: "");
- b_pmu_name = b_pmu_name ?: (bs->pmu->name ?: "");
- ret = strcmp(a_pmu_name, b_pmu_name);
- if (ret)
- return ret;
- }
-
- /* Order by event name. */
- return strcmp(a_name, b_name);
-}
-
bool is_pmu_core(const char *name)
{
return !strcmp(name, "cpu") || is_sysfs_pmu_core(name);
return !is_pmu_hybrid(pmu->name);
}
-static bool perf_pmu__is_mem_pmu(const struct perf_pmu *pmu)
+bool perf_pmu__is_mem_pmu(const struct perf_pmu *pmu)
{
return pmu->is_core;
}
-int perf_pmu__num_mem_pmus(void)
-{
- struct perf_pmu *pmu = NULL;
- int count = 0;
-
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
- if (perf_pmu__is_mem_pmu(pmu))
- count++;
- }
- return count;
-}
-
-static bool pmu_alias_is_duplicate(struct sevent *alias_a,
- struct sevent *alias_b)
-{
- const char *a_pmu_name = NULL, *b_pmu_name = NULL;
- const char *a_name = "//", *b_name = "//";
-
-
- if (alias_a->event) {
- a_name = alias_a->event->name;
- a_pmu_name = alias_a->event->pmu_name;
- }
- if (alias_b->event) {
- b_name = alias_b->event->name;
- b_pmu_name = alias_b->event->pmu_name;
- }
-
- /* Different names -> never duplicates */
- if (strcmp(a_name, b_name))
- return false;
-
- /* Don't remove duplicates for different PMUs */
- a_pmu_name = a_pmu_name ?: (alias_a->pmu->name ?: "");
- b_pmu_name = b_pmu_name ?: (alias_b->pmu->name ?: "");
- return strcmp(a_pmu_name, b_pmu_name) == 0;
-}
-
-void print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
-{
- struct perf_pmu *pmu;
- struct perf_pmu_alias *event;
- char buf[1024];
- int printed = 0;
- int len, j;
- struct sevent *aliases;
-
- pmu = NULL;
- len = 0;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
- list_for_each_entry(event, &pmu->aliases, list)
- len++;
- if (pmu->selectable)
- len++;
- }
- aliases = zalloc(sizeof(struct sevent) * len);
- if (!aliases) {
- pr_err("FATAL: not enough memory to print PMU events\n");
- return;
- }
- pmu = NULL;
- j = 0;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
- bool is_cpu = pmu->is_core;
-
- list_for_each_entry(event, &pmu->aliases, list) {
- aliases[j].event = event;
- aliases[j].pmu = pmu;
- aliases[j].is_cpu = is_cpu;
- j++;
- }
- if (pmu->selectable) {
- aliases[j].event = NULL;
- aliases[j].pmu = pmu;
- aliases[j].is_cpu = is_cpu;
- j++;
- }
- }
- len = j;
- qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
- for (j = 0; j < len; j++) {
- const char *name, *alias = NULL, *scale_unit = NULL,
- *desc = NULL, *long_desc = NULL,
- *encoding_desc = NULL, *topic = NULL,
- *pmu_name = NULL;
- bool deprecated = false;
- size_t buf_used;
-
- /* Skip duplicates */
- if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1]))
- continue;
-
- if (!aliases[j].event) {
- /* A selectable event. */
- pmu_name = aliases[j].pmu->name;
- buf_used = snprintf(buf, sizeof(buf), "%s//", pmu_name) + 1;
- name = buf;
- } else {
- if (aliases[j].event->desc) {
- name = aliases[j].event->name;
- buf_used = 0;
- } else {
- name = format_alias(buf, sizeof(buf), aliases[j].pmu,
- aliases[j].event);
- if (aliases[j].is_cpu) {
- alias = name;
- name = aliases[j].event->name;
- }
- buf_used = strlen(buf) + 1;
- }
- pmu_name = aliases[j].event->pmu_name ?: (aliases[j].pmu->name ?: "");
- if (strlen(aliases[j].event->unit) || aliases[j].event->scale != 1.0) {
- scale_unit = buf + buf_used;
- buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
- "%G%s", aliases[j].event->scale,
- aliases[j].event->unit) + 1;
- }
- desc = aliases[j].event->desc;
- long_desc = aliases[j].event->long_desc;
- topic = aliases[j].event->topic;
- encoding_desc = buf + buf_used;
- buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
- "%s/%s/", pmu_name, aliases[j].event->str) + 1;
- deprecated = aliases[j].event->deprecated;
- }
- print_cb->print_event(print_state,
- pmu_name,
- topic,
- name,
- alias,
- scale_unit,
- deprecated,
- "Kernel PMU event",
- desc,
- long_desc,
- encoding_desc);
- }
- if (printed && pager_in_use())
- printf("\n");
-
- zfree(&aliases);
- return;
-}
-
-bool pmu_have_event(const char *pname, const char *name)
+bool perf_pmu__have_event(const struct perf_pmu *pmu, const char *name)
{
- struct perf_pmu *pmu;
struct perf_pmu_alias *alias;
- pmu = NULL;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
- if (strcmp(pname, pmu->name))
- continue;
- list_for_each_entry(alias, &pmu->aliases, list)
- if (!strcmp(alias->name, name))
- return true;
+ list_for_each_entry(alias, &pmu->aliases, list) {
+ if (!strcmp(alias->name, name))
+ return true;
}
return false;
}
name ?: "N/A", buf, config);
}
-bool perf_pmu__has_hybrid(void)
-{
- static bool hybrid_scanned, has_hybrid;
-
- if (!hybrid_scanned) {
- struct perf_pmu *pmu = NULL;
-
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
- if (pmu->is_core && is_pmu_hybrid(pmu->name)) {
- has_hybrid = true;
- break;
- }
- }
- hybrid_scanned = true;
- }
- return has_hybrid;
-}
-
int perf_pmu__match(char *pattern, char *name, char *tok)
{
if (!name)
return openat(dirfd, path, flags);
}
-static void perf_pmu__delete(struct perf_pmu *pmu)
+void perf_pmu__delete(struct perf_pmu *pmu)
{
perf_pmu__del_formats(&pmu->format);
perf_pmu__del_aliases(pmu);
zfree(&pmu->alias_name);
free(pmu);
}
-
-void perf_pmu__destroy(void)
-{
- struct perf_pmu *pmu, *tmp;
-
- list_for_each_entry_safe(pmu, tmp, &pmus, list) {
- list_del(&pmu->list);
-
- perf_pmu__delete(pmu);
- }
-}
char *pmu_name;
};
-struct perf_pmu *perf_pmu__find(const char *name);
-struct perf_pmu *perf_pmu__find_by_type(unsigned int type);
void pmu_add_sys_aliases(struct list_head *head, struct perf_pmu *pmu);
int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
struct list_head *head_terms,
int perf_pmu__format_parse(int dirfd, struct list_head *head);
void perf_pmu__del_formats(struct list_head *formats);
-struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
-
bool is_pmu_core(const char *name);
bool is_pmu_hybrid(const char *name);
bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu);
bool perf_pmu__supports_wildcard_numeric(const struct perf_pmu *pmu);
bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu);
-int perf_pmu__num_mem_pmus(void);
-void print_pmu_events(const struct print_callbacks *print_cb, void *print_state);
-bool pmu_have_event(const char *pname, const char *name);
+bool perf_pmu__is_mem_pmu(const struct perf_pmu *pmu);
+bool perf_pmu__have_event(const struct perf_pmu *pmu, const char *name);
FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name);
FILE *perf_pmu__open_file_at(struct perf_pmu *pmu, int dirfd, const char *name);
const char *name);
void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu);
-bool perf_pmu__has_hybrid(void);
int perf_pmu__match(char *pattern, char *name, char *tok);
char *pmu_find_real_name(const char *name);
int perf_pmu__event_source_devices_fd(void);
int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename, int flags);
-void perf_pmu__destroy(void);
+struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *lookup_name);
+void perf_pmu__delete(struct perf_pmu *pmu);
#endif /* __PMU_H */
// SPDX-License-Identifier: GPL-2.0
#include <linux/list.h>
+#include <linux/zalloc.h>
+#include <subcmd/pager.h>
+#include <sys/types.h>
+#include <dirent.h>
#include <string.h>
+#include <unistd.h>
+#include "debug.h"
+#include "evsel.h"
#include "pmus.h"
#include "pmu.h"
+#include "print-events.h"
-LIST_HEAD(pmus);
+static LIST_HEAD(pmus);
+
+void perf_pmus__destroy(void)
+{
+ struct perf_pmu *pmu, *tmp;
+
+ list_for_each_entry_safe(pmu, tmp, &pmus, list) {
+ list_del(&pmu->list);
+
+ perf_pmu__delete(pmu);
+ }
+}
+
+static struct perf_pmu *pmu_find(const char *name)
+{
+ struct perf_pmu *pmu;
+
+ list_for_each_entry(pmu, &pmus, list) {
+ if (!strcmp(pmu->name, name) ||
+ (pmu->alias_name && !strcmp(pmu->alias_name, name)))
+ return pmu;
+ }
+
+ return NULL;
+}
+
+struct perf_pmu *perf_pmus__find(const char *name)
+{
+ struct perf_pmu *pmu;
+ int dirfd;
+
+ /*
+ * Once PMU is loaded it stays in the list,
+ * so we keep us from multiple reading/parsing
+ * the pmu format definitions.
+ */
+ pmu = pmu_find(name);
+ if (pmu)
+ return pmu;
+
+ dirfd = perf_pmu__event_source_devices_fd();
+ pmu = perf_pmu__lookup(&pmus, dirfd, name);
+ close(dirfd);
+
+ return pmu;
+}
+
+static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name)
+{
+ struct perf_pmu *pmu;
+
+ /*
+ * Once PMU is loaded it stays in the list,
+ * so we keep us from multiple reading/parsing
+ * the pmu format definitions.
+ */
+ pmu = pmu_find(name);
+ if (pmu)
+ return pmu;
+
+ return perf_pmu__lookup(&pmus, dirfd, name);
+}
+
+/* Add all pmus in sysfs to pmu list: */
+static void pmu_read_sysfs(void)
+{
+ int fd;
+ DIR *dir;
+ struct dirent *dent;
+
+ fd = perf_pmu__event_source_devices_fd();
+ if (fd < 0)
+ return;
+
+ dir = fdopendir(fd);
+ if (!dir)
+ return;
+
+ while ((dent = readdir(dir))) {
+ if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+ continue;
+ /* add to static LIST_HEAD(pmus): */
+ perf_pmu__find2(fd, dent->d_name);
+ }
+
+ closedir(dir);
+}
+
+struct perf_pmu *perf_pmus__find_by_type(unsigned int type)
+{
+ struct perf_pmu *pmu;
+
+ list_for_each_entry(pmu, &pmus, list)
+ if (pmu->type == type)
+ return pmu;
+
+ return NULL;
+}
+
+struct perf_pmu *perf_pmus__scan(struct perf_pmu *pmu)
+{
+ /*
+ * pmu iterator: If pmu is NULL, we start at the begin,
+ * otherwise return the next pmu. Returns NULL on end.
+ */
+ if (!pmu) {
+ pmu_read_sysfs();
+ pmu = list_prepare_entry(pmu, &pmus, list);
+ }
+ list_for_each_entry_continue(pmu, &pmus, list)
+ return pmu;
+ return NULL;
+}
const struct perf_pmu *perf_pmus__pmu_for_pmu_filter(const char *str)
{
struct perf_pmu *pmu = NULL;
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
if (!strcmp(pmu->name, str))
return pmu;
/* Ignore "uncore_" prefix. */
}
return NULL;
}
+
+int perf_pmus__num_mem_pmus(void)
+{
+ struct perf_pmu *pmu = NULL;
+ int count = 0;
+
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
+ if (perf_pmu__is_mem_pmu(pmu))
+ count++;
+ }
+ return count;
+}
+
+/** Struct for ordering events as output in perf list. */
+struct sevent {
+ /** PMU for event. */
+ const struct perf_pmu *pmu;
+ /**
+ * Optional event for name, desc, etc. If not present then this is a
+ * selectable PMU and the event name is shown as "//".
+ */
+ const struct perf_pmu_alias *event;
+ /** Is the PMU for the CPU? */
+ bool is_cpu;
+};
+
+static int cmp_sevent(const void *a, const void *b)
+{
+ const struct sevent *as = a;
+ const struct sevent *bs = b;
+ const char *a_pmu_name = NULL, *b_pmu_name = NULL;
+ const char *a_name = "//", *a_desc = NULL, *a_topic = "";
+ const char *b_name = "//", *b_desc = NULL, *b_topic = "";
+ int ret;
+
+ if (as->event) {
+ a_name = as->event->name;
+ a_desc = as->event->desc;
+ a_topic = as->event->topic ?: "";
+ a_pmu_name = as->event->pmu_name;
+ }
+ if (bs->event) {
+ b_name = bs->event->name;
+ b_desc = bs->event->desc;
+ b_topic = bs->event->topic ?: "";
+ b_pmu_name = bs->event->pmu_name;
+ }
+ /* Put extra events last. */
+ if (!!a_desc != !!b_desc)
+ return !!a_desc - !!b_desc;
+
+ /* Order by topics. */
+ ret = strcmp(a_topic, b_topic);
+ if (ret)
+ return ret;
+
+ /* Order CPU core events to be first */
+ if (as->is_cpu != bs->is_cpu)
+ return as->is_cpu ? -1 : 1;
+
+ /* Order by PMU name. */
+ if (as->pmu != bs->pmu) {
+ a_pmu_name = a_pmu_name ?: (as->pmu->name ?: "");
+ b_pmu_name = b_pmu_name ?: (bs->pmu->name ?: "");
+ ret = strcmp(a_pmu_name, b_pmu_name);
+ if (ret)
+ return ret;
+ }
+
+ /* Order by event name. */
+ return strcmp(a_name, b_name);
+}
+
+static bool pmu_alias_is_duplicate(struct sevent *alias_a,
+ struct sevent *alias_b)
+{
+ const char *a_pmu_name = NULL, *b_pmu_name = NULL;
+ const char *a_name = "//", *b_name = "//";
+
+
+ if (alias_a->event) {
+ a_name = alias_a->event->name;
+ a_pmu_name = alias_a->event->pmu_name;
+ }
+ if (alias_b->event) {
+ b_name = alias_b->event->name;
+ b_pmu_name = alias_b->event->pmu_name;
+ }
+
+ /* Different names -> never duplicates */
+ if (strcmp(a_name, b_name))
+ return false;
+
+ /* Don't remove duplicates for different PMUs */
+ a_pmu_name = a_pmu_name ?: (alias_a->pmu->name ?: "");
+ b_pmu_name = b_pmu_name ?: (alias_b->pmu->name ?: "");
+ return strcmp(a_pmu_name, b_pmu_name) == 0;
+}
+
+static int sub_non_neg(int a, int b)
+{
+ if (b > a)
+ return 0;
+ return a - b;
+}
+
+static char *format_alias(char *buf, int len, const struct perf_pmu *pmu,
+ const struct perf_pmu_alias *alias)
+{
+ struct parse_events_term *term;
+ int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name);
+
+ list_for_each_entry(term, &alias->terms, list) {
+ if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
+ used += snprintf(buf + used, sub_non_neg(len, used),
+ ",%s=%s", term->config,
+ term->val.str);
+ }
+
+ if (sub_non_neg(len, used) > 0) {
+ buf[used] = '/';
+ used++;
+ }
+ if (sub_non_neg(len, used) > 0) {
+ buf[used] = '\0';
+ used++;
+ } else
+ buf[len - 1] = '\0';
+
+ return buf;
+}
+
+void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *print_state)
+{
+ struct perf_pmu *pmu;
+ struct perf_pmu_alias *event;
+ char buf[1024];
+ int printed = 0;
+ int len, j;
+ struct sevent *aliases;
+
+ pmu = NULL;
+ len = 0;
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
+ list_for_each_entry(event, &pmu->aliases, list)
+ len++;
+ if (pmu->selectable)
+ len++;
+ }
+ aliases = zalloc(sizeof(struct sevent) * len);
+ if (!aliases) {
+ pr_err("FATAL: not enough memory to print PMU events\n");
+ return;
+ }
+ pmu = NULL;
+ j = 0;
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
+ bool is_cpu = pmu->is_core;
+
+ list_for_each_entry(event, &pmu->aliases, list) {
+ aliases[j].event = event;
+ aliases[j].pmu = pmu;
+ aliases[j].is_cpu = is_cpu;
+ j++;
+ }
+ if (pmu->selectable) {
+ aliases[j].event = NULL;
+ aliases[j].pmu = pmu;
+ aliases[j].is_cpu = is_cpu;
+ j++;
+ }
+ }
+ len = j;
+ qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
+ for (j = 0; j < len; j++) {
+ const char *name, *alias = NULL, *scale_unit = NULL,
+ *desc = NULL, *long_desc = NULL,
+ *encoding_desc = NULL, *topic = NULL,
+ *pmu_name = NULL;
+ bool deprecated = false;
+ size_t buf_used;
+
+ /* Skip duplicates */
+ if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1]))
+ continue;
+
+ if (!aliases[j].event) {
+ /* A selectable event. */
+ pmu_name = aliases[j].pmu->name;
+ buf_used = snprintf(buf, sizeof(buf), "%s//", pmu_name) + 1;
+ name = buf;
+ } else {
+ if (aliases[j].event->desc) {
+ name = aliases[j].event->name;
+ buf_used = 0;
+ } else {
+ name = format_alias(buf, sizeof(buf), aliases[j].pmu,
+ aliases[j].event);
+ if (aliases[j].is_cpu) {
+ alias = name;
+ name = aliases[j].event->name;
+ }
+ buf_used = strlen(buf) + 1;
+ }
+ pmu_name = aliases[j].event->pmu_name ?: (aliases[j].pmu->name ?: "");
+ if (strlen(aliases[j].event->unit) || aliases[j].event->scale != 1.0) {
+ scale_unit = buf + buf_used;
+ buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
+ "%G%s", aliases[j].event->scale,
+ aliases[j].event->unit) + 1;
+ }
+ desc = aliases[j].event->desc;
+ long_desc = aliases[j].event->long_desc;
+ topic = aliases[j].event->topic;
+ encoding_desc = buf + buf_used;
+ buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
+ "%s/%s/", pmu_name, aliases[j].event->str) + 1;
+ deprecated = aliases[j].event->deprecated;
+ }
+ print_cb->print_event(print_state,
+ pmu_name,
+ topic,
+ name,
+ alias,
+ scale_unit,
+ deprecated,
+ "Kernel PMU event",
+ desc,
+ long_desc,
+ encoding_desc);
+ }
+ if (printed && pager_in_use())
+ printf("\n");
+
+ zfree(&aliases);
+}
+
+bool perf_pmus__have_event(const char *pname, const char *name)
+{
+ struct perf_pmu *pmu = perf_pmus__find(pname);
+
+ return pmu && perf_pmu__have_event(pmu, name);
+}
+
+bool perf_pmus__has_hybrid(void)
+{
+ static bool hybrid_scanned, has_hybrid;
+
+ if (!hybrid_scanned) {
+ struct perf_pmu *pmu = NULL;
+
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
+ if (pmu->is_core && is_pmu_hybrid(pmu->name)) {
+ has_hybrid = true;
+ break;
+ }
+ }
+ hybrid_scanned = true;
+ }
+ return has_hybrid;
+}
+
+struct perf_pmu *evsel__find_pmu(const struct evsel *evsel)
+{
+ struct perf_pmu *pmu = evsel->pmu;
+
+ if (!pmu) {
+ pmu = perf_pmus__find_by_type(evsel->core.attr.type);
+ ((struct evsel *)evsel)->pmu = pmu;
+ }
+ return pmu;
+}
#ifndef __PMUS_H
#define __PMUS_H
-extern struct list_head pmus;
struct perf_pmu;
+struct print_callbacks;
+
+void perf_pmus__destroy(void);
+
+struct perf_pmu *perf_pmus__find(const char *name);
+struct perf_pmu *perf_pmus__find_by_type(unsigned int type);
+
+struct perf_pmu *perf_pmus__scan(struct perf_pmu *pmu);
const struct perf_pmu *perf_pmus__pmu_for_pmu_filter(const char *str);
+int perf_pmus__num_mem_pmus(void);
+void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *print_state);
+bool perf_pmus__have_event(const char *pname, const char *name);
+bool perf_pmus__has_hybrid(void);
+
#endif /* __PMUS_H */
#include "metricgroup.h"
#include "parse-events.h"
#include "pmu.h"
+#include "pmus.h"
#include "print-events.h"
#include "probe-file.h"
#include "string2.h"
struct perf_pmu *pmu = NULL;
const char *event_type_descriptor = event_type_descriptors[PERF_TYPE_HW_CACHE];
- while ((pmu = perf_pmu__scan(pmu)) != NULL) {
+ while ((pmu = perf_pmus__scan(pmu)) != NULL) {
/*
* Skip uncore PMUs for performance. PERF_TYPE_HW_CACHE type
* attributes can accept software PMUs in the extended type, so
print_hwcache_events(print_cb, print_state);
- print_pmu_events(print_cb, print_state);
+ perf_pmus__print_pmu_events(print_cb, print_state);
print_cb->print_event(print_state,
/*topic=*/NULL,
#include "util/bpf-filter.h"
#include "util/env.h"
#include "util/pmu.h"
+#include "util/pmus.h"
#include <internal/lib.h>
#include "util.h"
return EOF;
}
-bool perf_pmu__has_hybrid(void)
+bool perf_pmus__has_hybrid(void)
{
return false;
}
#include "util.h"
#include "iostat.h"
#include "pmu.h"
+#include "pmus.h"
#define CNTR_NOT_SUPPORTED "<not supported>"
#define CNTR_NOT_COUNTED "<not counted>"
{
struct evsel *evsel;
- if (!perf_pmu__has_hybrid())
+ if (!perf_pmus__has_hybrid())
return false;
evlist__for_each_entry(evlist, evsel) {