perf pmu: Separate pmu and pmus
Separate and hide the pmus list in pmus.[ch]. Move pmus functionality out of pmu.[ch] into pmus.[ch] renaming pmus functions which were prefixed perf_pmu__ to perf_pmus__. Reviewed-by: Kan Liang <kan.liang@linux.intel.com> Signed-off-by: Ian Rogers <irogers@google.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Ali Saidi <alisaidi@amazon.com> Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com> Cc: Dmitrii Dolgov <9erthalion6@gmail.com> Cc: Huacai Chen <chenhuacai@kernel.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@arm.com> Cc: Jing Zhang <renyu.zj@linux.alibaba.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: John Garry <john.g.garry@oracle.com> Cc: Kajol Jain <kjain@linux.ibm.com> Cc: Kang Minchul <tegongkang@gmail.com> Cc: Leo Yan <leo.yan@linaro.org> Cc: Madhavan Srinivasan <maddy@linux.ibm.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Mike Leach <mike.leach@linaro.org> Cc: Ming Wang <wangming01@loongson.cn> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ravi Bangoria <ravi.bangoria@amd.com> Cc: Rob Herring <robh@kernel.org> Cc: Sandipan Das <sandipan.das@amd.com> Cc: Sean Christopherson <seanjc@google.com> Cc: Suzuki Poulouse <suzuki.poulose@arm.com> Cc: Thomas Richter <tmricht@linux.ibm.com> Cc: Will Deacon <will@kernel.org> Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com> Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20230527072210.2900565-28-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
875375ea91
commit
1eaf496ed3
41 changed files with 533 additions and 506 deletions
|
@ -14,6 +14,7 @@
|
||||||
#include "../../../util/debug.h"
|
#include "../../../util/debug.h"
|
||||||
#include "../../../util/evlist.h"
|
#include "../../../util/evlist.h"
|
||||||
#include "../../../util/pmu.h"
|
#include "../../../util/pmu.h"
|
||||||
|
#include "../../../util/pmus.h"
|
||||||
#include "cs-etm.h"
|
#include "cs-etm.h"
|
||||||
#include "arm-spe.h"
|
#include "arm-spe.h"
|
||||||
#include "hisi-ptt.h"
|
#include "hisi-ptt.h"
|
||||||
|
@ -40,7 +41,7 @@ static struct perf_pmu **find_all_arm_spe_pmus(int *nr_spes, int *err)
|
||||||
return NULL;
|
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]) {
|
if (arm_spe_pmus[*nr_spes]) {
|
||||||
pr_debug2("%s %d: arm_spe_pmu %d type %d name %s\n",
|
pr_debug2("%s %d: arm_spe_pmu %d type %d name %s\n",
|
||||||
__func__, __LINE__, *nr_spes,
|
__func__, __LINE__, *nr_spes,
|
||||||
|
@ -87,7 +88,7 @@ static struct perf_pmu **find_all_hisi_ptt_pmus(int *nr_ptts, int *err)
|
||||||
rewinddir(dir);
|
rewinddir(dir);
|
||||||
while ((dent = readdir(dir))) {
|
while ((dent = readdir(dir))) {
|
||||||
if (strstr(dent->d_name, HISI_PTT_PMU_NAME) && idx < *nr_ptts) {
|
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])
|
if (hisi_ptt_pmus[idx])
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
@ -131,7 +132,7 @@ struct auxtrace_record
|
||||||
if (!evlist)
|
if (!evlist)
|
||||||
return NULL;
|
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);
|
arm_spe_pmus = find_all_arm_spe_pmus(&nr_spes, err);
|
||||||
hisi_ptt_pmus = find_all_hisi_ptt_pmus(&nr_ptts, err);
|
hisi_ptt_pmus = find_all_hisi_ptt_pmus(&nr_ptts, err);
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include "../../../util/evsel.h"
|
#include "../../../util/evsel.h"
|
||||||
#include "../../../util/perf_api_probe.h"
|
#include "../../../util/perf_api_probe.h"
|
||||||
#include "../../../util/evsel_config.h"
|
#include "../../../util/evsel_config.h"
|
||||||
#include "../../../util/pmu.h"
|
#include "../../../util/pmus.h"
|
||||||
#include "../../../util/cs-etm.h"
|
#include "../../../util/cs-etm.h"
|
||||||
#include <internal/lib.h> // page_size
|
#include <internal/lib.h> // page_size
|
||||||
#include "../../../util/session.h"
|
#include "../../../util/session.h"
|
||||||
|
@ -881,7 +881,7 @@ struct auxtrace_record *cs_etm_record_init(int *err)
|
||||||
struct perf_pmu *cs_etm_pmu;
|
struct perf_pmu *cs_etm_pmu;
|
||||||
struct cs_etm_recording *ptr;
|
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) {
|
if (!cs_etm_pmu) {
|
||||||
*err = -EINVAL;
|
*err = -EINVAL;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <internal/cpumap.h>
|
#include <internal/cpumap.h>
|
||||||
#include "../../../util/cpumap.h"
|
#include "../../../util/cpumap.h"
|
||||||
#include "../../../util/pmu.h"
|
#include "../../../util/pmu.h"
|
||||||
|
#include "../../../util/pmus.h"
|
||||||
#include <api/fs/fs.h>
|
#include <api/fs/fs.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
@ -10,7 +11,7 @@ static struct perf_pmu *pmu__find_core_pmu(void)
|
||||||
{
|
{
|
||||||
struct perf_pmu *pmu = NULL;
|
struct perf_pmu *pmu = NULL;
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu))) {
|
while ((pmu = perf_pmus__scan(pmu))) {
|
||||||
if (!is_pmu_core(pmu->name))
|
if (!is_pmu_core(pmu->name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "evlist.h"
|
#include "evlist.h"
|
||||||
#include "evsel.h"
|
#include "evsel.h"
|
||||||
#include "pmu.h"
|
#include "pmu.h"
|
||||||
|
#include "pmus.h"
|
||||||
#include "tests/tests.h"
|
#include "tests/tests.h"
|
||||||
|
|
||||||
static bool test_config(const struct evsel *evsel, __u64 expected_config)
|
static bool test_config(const struct evsel *evsel, __u64 expected_config)
|
||||||
|
@ -113,7 +114,7 @@ static int test__hybrid_raw1(struct evlist *evlist)
|
||||||
struct perf_evsel *evsel;
|
struct perf_evsel *evsel;
|
||||||
|
|
||||||
perf_evlist__for_each_evsel(&evlist->core, 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("missing pmu", pmu);
|
||||||
TEST_ASSERT_VAL("unexpected pmu", !strncmp(pmu->name, "cpu_", 4));
|
TEST_ASSERT_VAL("unexpected pmu", !strncmp(pmu->name, "cpu_", 4));
|
||||||
|
@ -280,7 +281,7 @@ static int test_events(const struct evlist_test *events, int cnt)
|
||||||
|
|
||||||
int test__hybrid(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
|
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_SKIP;
|
||||||
|
|
||||||
return test_events(test__hybrid_events, ARRAY_SIZE(test__hybrid_events));
|
return test_events(test__hybrid_events, ARRAY_SIZE(test__hybrid_events));
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "../../../util/header.h"
|
#include "../../../util/header.h"
|
||||||
#include "../../../util/debug.h"
|
#include "../../../util/debug.h"
|
||||||
#include "../../../util/pmu.h"
|
#include "../../../util/pmu.h"
|
||||||
|
#include "../../../util/pmus.h"
|
||||||
#include "../../../util/auxtrace.h"
|
#include "../../../util/auxtrace.h"
|
||||||
#include "../../../util/intel-pt.h"
|
#include "../../../util/intel-pt.h"
|
||||||
#include "../../../util/intel-bts.h"
|
#include "../../../util/intel-bts.h"
|
||||||
|
@ -25,8 +26,8 @@ struct auxtrace_record *auxtrace_record__init_intel(struct evlist *evlist,
|
||||||
bool found_pt = false;
|
bool found_pt = false;
|
||||||
bool found_bts = false;
|
bool found_bts = false;
|
||||||
|
|
||||||
intel_pt_pmu = perf_pmu__find(INTEL_PT_PMU_NAME);
|
intel_pt_pmu = perf_pmus__find(INTEL_PT_PMU_NAME);
|
||||||
intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME);
|
intel_bts_pmu = perf_pmus__find(INTEL_BTS_PMU_NAME);
|
||||||
|
|
||||||
evlist__for_each_entry(evlist, evsel) {
|
evlist__for_each_entry(evlist, evsel) {
|
||||||
if (intel_pt_pmu && evsel->core.attr.type == intel_pt_pmu->type)
|
if (intel_pt_pmu && evsel->core.attr.type == intel_pt_pmu->type)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "util/pmu.h"
|
#include "util/pmu.h"
|
||||||
|
#include "util/pmus.h"
|
||||||
#include "util/evlist.h"
|
#include "util/evlist.h"
|
||||||
#include "util/parse-events.h"
|
#include "util/parse-events.h"
|
||||||
#include "util/event.h"
|
#include "util/event.h"
|
||||||
|
@ -17,7 +18,7 @@ static int ___evlist__add_default_attrs(struct evlist *evlist,
|
||||||
for (i = 0; i < nr_attrs; i++)
|
for (i = 0; i < nr_attrs; i++)
|
||||||
event_attr_init(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);
|
return evlist__add_attrs(evlist, attrs, nr_attrs);
|
||||||
|
|
||||||
for (i = 0; i < nr_attrs; i++) {
|
for (i = 0; i < nr_attrs; i++) {
|
||||||
|
@ -32,7 +33,7 @@ static int ___evlist__add_default_attrs(struct evlist *evlist,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||||
struct perf_cpu_map *cpus;
|
struct perf_cpu_map *cpus;
|
||||||
struct evsel *evsel;
|
struct evsel *evsel;
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "util/evsel.h"
|
#include "util/evsel.h"
|
||||||
#include "util/env.h"
|
#include "util/env.h"
|
||||||
#include "util/pmu.h"
|
#include "util/pmu.h"
|
||||||
|
#include "util/pmus.h"
|
||||||
#include "linux/string.h"
|
#include "linux/string.h"
|
||||||
#include "evsel.h"
|
#include "evsel.h"
|
||||||
#include "util/debug.h"
|
#include "util/debug.h"
|
||||||
|
@ -30,7 +31,7 @@ bool evsel__sys_has_perf_metrics(const struct evsel *evsel)
|
||||||
* should be good enough to detect the perf metrics feature.
|
* should be good enough to detect the perf metrics feature.
|
||||||
*/
|
*/
|
||||||
if ((evsel->core.attr.type == PERF_TYPE_RAW) &&
|
if ((evsel->core.attr.type == PERF_TYPE_RAW) &&
|
||||||
pmu_have_event(pmu_name, "slots"))
|
perf_pmus__have_event(pmu_name, "slots"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -98,8 +99,8 @@ void arch__post_evsel_config(struct evsel *evsel, struct perf_event_attr *attr)
|
||||||
if (!evsel_pmu)
|
if (!evsel_pmu)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ibs_fetch_pmu = perf_pmu__find("ibs_fetch");
|
ibs_fetch_pmu = perf_pmus__find("ibs_fetch");
|
||||||
ibs_op_pmu = perf_pmu__find("ibs_op");
|
ibs_op_pmu = perf_pmus__find("ibs_op");
|
||||||
|
|
||||||
if (ibs_fetch_pmu && ibs_fetch_pmu->type == evsel_pmu->type) {
|
if (ibs_fetch_pmu && ibs_fetch_pmu->type == evsel_pmu->type) {
|
||||||
if (attr->config & IBS_FETCH_L3MISSONLY) {
|
if (attr->config & IBS_FETCH_L3MISSONLY) {
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include "../../../util/evlist.h"
|
#include "../../../util/evlist.h"
|
||||||
#include "../../../util/mmap.h"
|
#include "../../../util/mmap.h"
|
||||||
#include "../../../util/session.h"
|
#include "../../../util/session.h"
|
||||||
#include "../../../util/pmu.h"
|
#include "../../../util/pmus.h"
|
||||||
#include "../../../util/debug.h"
|
#include "../../../util/debug.h"
|
||||||
#include "../../../util/record.h"
|
#include "../../../util/record.h"
|
||||||
#include "../../../util/tsc.h"
|
#include "../../../util/tsc.h"
|
||||||
|
@ -416,7 +416,7 @@ out_err:
|
||||||
|
|
||||||
struct auxtrace_record *intel_bts_recording_init(int *err)
|
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;
|
struct intel_bts_recording *btsr;
|
||||||
|
|
||||||
if (!intel_bts_pmu)
|
if (!intel_bts_pmu)
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "../../../util/mmap.h"
|
#include "../../../util/mmap.h"
|
||||||
#include <subcmd/parse-options.h>
|
#include <subcmd/parse-options.h>
|
||||||
#include "../../../util/parse-events.h"
|
#include "../../../util/parse-events.h"
|
||||||
#include "../../../util/pmu.h"
|
#include "../../../util/pmus.h"
|
||||||
#include "../../../util/debug.h"
|
#include "../../../util/debug.h"
|
||||||
#include "../../../util/auxtrace.h"
|
#include "../../../util/auxtrace.h"
|
||||||
#include "../../../util/perf_api_probe.h"
|
#include "../../../util/perf_api_probe.h"
|
||||||
|
@ -1185,7 +1185,7 @@ static u64 intel_pt_reference(struct auxtrace_record *itr __maybe_unused)
|
||||||
|
|
||||||
struct auxtrace_record *intel_pt_recording_init(int *err)
|
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;
|
struct intel_pt_recording *ptr;
|
||||||
|
|
||||||
if (!intel_pt_pmu)
|
if (!intel_pt_pmu)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include "util/pmu.h"
|
#include "util/pmu.h"
|
||||||
|
#include "util/pmus.h"
|
||||||
#include "util/env.h"
|
#include "util/env.h"
|
||||||
#include "map_symbol.h"
|
#include "map_symbol.h"
|
||||||
#include "mem-events.h"
|
#include "mem-events.h"
|
||||||
|
@ -55,12 +56,12 @@ struct perf_mem_event *perf_mem_events__ptr(int i)
|
||||||
|
|
||||||
bool is_mem_loads_aux_event(struct evsel *leader)
|
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)
|
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 false;
|
||||||
|
|
||||||
return leader->core.attr.config == MEM_LOADS_AUX;
|
return leader->core.attr.config == MEM_LOADS_AUX;
|
||||||
|
@ -82,7 +83,7 @@ char *perf_mem_events__name(int i, char *pmu_name)
|
||||||
pmu_name = (char *)"cpu";
|
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),
|
scnprintf(mem_loads_name, sizeof(mem_loads_name),
|
||||||
MEM_LOADS_AUX_NAME, pmu_name, pmu_name,
|
MEM_LOADS_AUX_NAME, pmu_name, pmu_name,
|
||||||
perf_mem_events__loads_ldlat);
|
perf_mem_events__loads_ldlat);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "../../../util/debug.h"
|
#include "../../../util/debug.h"
|
||||||
#include "../../../util/event.h"
|
#include "../../../util/event.h"
|
||||||
#include "../../../util/pmu.h"
|
#include "../../../util/pmu.h"
|
||||||
|
#include "../../../util/pmus.h"
|
||||||
|
|
||||||
const struct sample_reg sample_reg_masks[] = {
|
const struct sample_reg sample_reg_masks[] = {
|
||||||
SMPL_REG(AX, PERF_REG_X86_AX),
|
SMPL_REG(AX, PERF_REG_X86_AX),
|
||||||
|
@ -291,7 +292,7 @@ uint64_t arch__intr_reg_mask(void)
|
||||||
*/
|
*/
|
||||||
attr.sample_period = 1;
|
attr.sample_period = 1;
|
||||||
|
|
||||||
if (perf_pmu__has_hybrid()) {
|
if (perf_pmus__has_hybrid()) {
|
||||||
struct perf_pmu *pmu = NULL;
|
struct perf_pmu *pmu = NULL;
|
||||||
__u64 type = PERF_TYPE_RAW;
|
__u64 type = PERF_TYPE_RAW;
|
||||||
|
|
||||||
|
@ -299,7 +300,7 @@ uint64_t arch__intr_reg_mask(void)
|
||||||
* The same register set is supported among different hybrid PMUs.
|
* The same register set is supported among different hybrid PMUs.
|
||||||
* Only check the first available one.
|
* Only check the first available one.
|
||||||
*/
|
*/
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||||
if (pmu->is_core) {
|
if (pmu->is_core) {
|
||||||
type = pmu->type;
|
type = pmu->type;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "api/fs/fs.h"
|
#include "api/fs/fs.h"
|
||||||
#include "util/evsel.h"
|
#include "util/evsel.h"
|
||||||
#include "util/pmu.h"
|
#include "util/pmu.h"
|
||||||
|
#include "util/pmus.h"
|
||||||
#include "util/topdown.h"
|
#include "util/topdown.h"
|
||||||
#include "topdown.h"
|
#include "topdown.h"
|
||||||
#include "evsel.h"
|
#include "evsel.h"
|
||||||
|
@ -22,8 +23,8 @@ bool topdown_sys_has_perf_metrics(void)
|
||||||
* The slots event is only available when the core PMU
|
* The slots event is only available when the core PMU
|
||||||
* supports the perf metrics feature.
|
* supports the perf metrics feature.
|
||||||
*/
|
*/
|
||||||
pmu = perf_pmu__find_by_type(PERF_TYPE_RAW);
|
pmu = perf_pmus__find_by_type(PERF_TYPE_RAW);
|
||||||
if (pmu && pmu_have_event(pmu->name, "slots"))
|
if (pmu && perf_pmu__have_event(pmu, "slots"))
|
||||||
has_perf_metrics = true;
|
has_perf_metrics = true;
|
||||||
|
|
||||||
cached = true;
|
cached = true;
|
||||||
|
|
|
@ -44,7 +44,7 @@ static int save_result(void)
|
||||||
struct list_head *list;
|
struct list_head *list;
|
||||||
struct pmu_scan_result *r;
|
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));
|
r = realloc(results, (nr_pmus + 1) * sizeof(*r));
|
||||||
if (r == NULL)
|
if (r == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -68,7 +68,7 @@ static int save_result(void)
|
||||||
nr_pmus++;
|
nr_pmus++;
|
||||||
}
|
}
|
||||||
|
|
||||||
perf_pmu__destroy();
|
perf_pmus__destroy();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ static int check_result(void)
|
||||||
|
|
||||||
for (int i = 0; i < nr_pmus; i++) {
|
for (int i = 0; i < nr_pmus; i++) {
|
||||||
r = &results[i];
|
r = &results[i];
|
||||||
pmu = perf_pmu__find(r->name);
|
pmu = perf_pmus__find(r->name);
|
||||||
if (pmu == NULL) {
|
if (pmu == NULL) {
|
||||||
pr_err("Cannot find PMU %s\n", r->name);
|
pr_err("Cannot find PMU %s\n", r->name);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -144,7 +144,7 @@ static int run_pmu_scan(void)
|
||||||
|
|
||||||
for (i = 0; i < iterations; i++) {
|
for (i = 0; i < iterations; i++) {
|
||||||
gettimeofday(&start, NULL);
|
gettimeofday(&start, NULL);
|
||||||
perf_pmu__scan(NULL);
|
perf_pmus__scan(NULL);
|
||||||
gettimeofday(&end, NULL);
|
gettimeofday(&end, NULL);
|
||||||
|
|
||||||
timersub(&end, &start, &diff);
|
timersub(&end, &start, &diff);
|
||||||
|
@ -152,7 +152,7 @@ static int run_pmu_scan(void)
|
||||||
update_stats(&stats, runtime_us);
|
update_stats(&stats, runtime_us);
|
||||||
|
|
||||||
ret = check_result();
|
ret = check_result();
|
||||||
perf_pmu__destroy();
|
perf_pmus__destroy();
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
#include "ui/ui.h"
|
#include "ui/ui.h"
|
||||||
#include "ui/progress.h"
|
#include "ui/progress.h"
|
||||||
#include "pmu.h"
|
#include "pmus.h"
|
||||||
#include "string2.h"
|
#include "string2.h"
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
|
|
||||||
|
@ -3259,7 +3259,7 @@ static int perf_c2c__record(int argc, const char **argv)
|
||||||
PARSE_OPT_KEEP_UNKNOWN);
|
PARSE_OPT_KEEP_UNKNOWN);
|
||||||
|
|
||||||
/* Max number of arguments multiplied by number of PMUs that can support them. */
|
/* 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 *));
|
rec_argv = calloc(rec_argc + 1, sizeof(char *));
|
||||||
if (!rec_argv)
|
if (!rec_argv)
|
||||||
|
|
|
@ -527,7 +527,7 @@ int cmd_list(int argc, const char **argv)
|
||||||
strcmp(argv[i], "hwcache") == 0)
|
strcmp(argv[i], "hwcache") == 0)
|
||||||
print_hwcache_events(&print_cb, ps);
|
print_hwcache_events(&print_cb, ps);
|
||||||
else if (strcmp(argv[i], "pmu") == 0)
|
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)
|
else if (strcmp(argv[i], "sdt") == 0)
|
||||||
print_sdt_events(&print_cb, ps);
|
print_sdt_events(&print_cb, ps);
|
||||||
else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0) {
|
else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0) {
|
||||||
|
@ -567,7 +567,7 @@ int cmd_list(int argc, const char **argv)
|
||||||
event_symbols_sw, PERF_COUNT_SW_MAX);
|
event_symbols_sw, PERF_COUNT_SW_MAX);
|
||||||
print_tool_events(&print_cb, ps);
|
print_tool_events(&print_cb, ps);
|
||||||
print_hwcache_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_tracepoint_events(&print_cb, ps);
|
||||||
print_sdt_events(&print_cb, ps);
|
print_sdt_events(&print_cb, ps);
|
||||||
default_ps.metrics = true;
|
default_ps.metrics = true;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include "util/dso.h"
|
#include "util/dso.h"
|
||||||
#include "util/map.h"
|
#include "util/map.h"
|
||||||
#include "util/symbol.h"
|
#include "util/symbol.h"
|
||||||
#include "util/pmu.h"
|
#include "util/pmus.h"
|
||||||
#include "util/sample.h"
|
#include "util/sample.h"
|
||||||
#include "util/string2.h"
|
#include "util/string2.h"
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
|
@ -93,7 +93,7 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
|
||||||
PARSE_OPT_KEEP_UNKNOWN);
|
PARSE_OPT_KEEP_UNKNOWN);
|
||||||
|
|
||||||
/* Max number of arguments multiplied by number of PMUs that can support them. */
|
/* 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)
|
if (mem->cpu_list)
|
||||||
rec_argc += 2;
|
rec_argc += 2;
|
||||||
|
|
|
@ -48,6 +48,8 @@
|
||||||
#include "util/bpf-event.h"
|
#include "util/bpf-event.h"
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
#include "util/pfm.h"
|
#include "util/pfm.h"
|
||||||
|
#include "util/pmu.h"
|
||||||
|
#include "util/pmus.h"
|
||||||
#include "util/clockid.h"
|
#include "util/clockid.h"
|
||||||
#include "util/off_cpu.h"
|
#include "util/off_cpu.h"
|
||||||
#include "util/bpf-filter.h"
|
#include "util/bpf-filter.h"
|
||||||
|
@ -1292,7 +1294,7 @@ static int record__open(struct record *rec)
|
||||||
* of waiting or event synthesis.
|
* of waiting or event synthesis.
|
||||||
*/
|
*/
|
||||||
if (opts->target.initial_delay || target__has_cpu(&opts->target) ||
|
if (opts->target.initial_delay || target__has_cpu(&opts->target) ||
|
||||||
perf_pmu__has_hybrid()) {
|
perf_pmus__has_hybrid()) {
|
||||||
pos = evlist__get_tracking_event(evlist);
|
pos = evlist__get_tracking_event(evlist);
|
||||||
if (!evsel__is_dummy_event(pos)) {
|
if (!evsel__is_dummy_event(pos)) {
|
||||||
/* Set up dummy event. */
|
/* Set up dummy event. */
|
||||||
|
@ -2191,7 +2193,7 @@ static void record__uniquify_name(struct record *rec)
|
||||||
char *new_name;
|
char *new_name;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!perf_pmu__has_hybrid())
|
if (!perf_pmus__has_hybrid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
evlist__for_each_entry(evlist, pos) {
|
evlist__for_each_entry(evlist, pos) {
|
||||||
|
|
|
@ -2140,11 +2140,11 @@ static int add_default_attributes(void)
|
||||||
|
|
||||||
if (evlist__add_default_attrs(evsel_list, default_attrs0) < 0)
|
if (evlist__add_default_attrs(evsel_list, default_attrs0) < 0)
|
||||||
return -1;
|
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)
|
if (evlist__add_default_attrs(evsel_list, frontend_attrs) < 0)
|
||||||
return -1;
|
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)
|
if (evlist__add_default_attrs(evsel_list, backend_attrs) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "pmu.h"
|
#include "pmus.h"
|
||||||
|
|
||||||
#define ENV "PERF_TEST_ATTR"
|
#define ENV "PERF_TEST_ATTR"
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ static int test__attr(struct test_suite *test __maybe_unused, int subtest __mayb
|
||||||
char path_dir[PATH_MAX];
|
char path_dir[PATH_MAX];
|
||||||
char *exec_path;
|
char *exec_path;
|
||||||
|
|
||||||
if (perf_pmu__has_hybrid())
|
if (perf_pmus__has_hybrid())
|
||||||
return TEST_SKIP;
|
return TEST_SKIP;
|
||||||
|
|
||||||
/* First try development tree tests. */
|
/* First try development tree tests. */
|
||||||
|
|
|
@ -53,7 +53,7 @@ static int setup_uncore_event(void)
|
||||||
struct perf_pmu *pmu = NULL;
|
struct perf_pmu *pmu = NULL;
|
||||||
int i, fd;
|
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++) {
|
for (i = 0; i < NR_UNCORE_PMUS; i++) {
|
||||||
if (!strcmp(uncore_pmus[i].name, pmu->name)) {
|
if (!strcmp(uncore_pmus[i].name, pmu->name)) {
|
||||||
pr_debug("Using %s for uncore pmu event\n", pmu->name);
|
pr_debug("Using %s for uncore pmu event\n", pmu->name);
|
||||||
|
|
|
@ -112,7 +112,7 @@ static int test__checkevent_raw(struct evlist *evlist)
|
||||||
bool type_matched = false;
|
bool type_matched = false;
|
||||||
|
|
||||||
TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, 0x1a));
|
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) {
|
if (pmu->type == evsel->attr.type) {
|
||||||
TEST_ASSERT_VAL("PMU type expected once", !type_matched);
|
TEST_ASSERT_VAL("PMU type expected once", !type_matched);
|
||||||
type_matched = true;
|
type_matched = true;
|
||||||
|
@ -1443,12 +1443,12 @@ static int test__checkevent_config_cache(struct evlist *evlist)
|
||||||
|
|
||||||
static bool test__pmu_cpu_valid(void)
|
static bool test__pmu_cpu_valid(void)
|
||||||
{
|
{
|
||||||
return !!perf_pmu__find("cpu");
|
return !!perf_pmus__find("cpu");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool test__intel_pt_valid(void)
|
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)
|
static int test__intel_pt(struct evlist *evlist)
|
||||||
|
@ -2246,7 +2246,7 @@ static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest
|
||||||
struct perf_pmu *pmu = NULL;
|
struct perf_pmu *pmu = NULL;
|
||||||
int ret = TEST_OK;
|
int ret = TEST_OK;
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "stat.h"
|
#include "stat.h"
|
||||||
#include "pmu.h"
|
#include "pmus.h"
|
||||||
|
|
||||||
struct value {
|
struct value {
|
||||||
const char *event;
|
const char *event;
|
||||||
|
@ -303,7 +303,7 @@ static int test__parse_metric(struct test_suite *test __maybe_unused, int subtes
|
||||||
TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
|
TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
|
||||||
TEST_ASSERT_VAL("Memory bandwidth", test_memory_bandwidth() == 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("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
|
||||||
TEST_ASSERT_VAL("test metric group", test_metric_group() == 0);
|
TEST_ASSERT_VAL("test metric group", test_metric_group() == 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
#include "parse-events.h"
|
#include "parse-events.h"
|
||||||
#include "pmu.h"
|
#include "pmu.h"
|
||||||
|
#include "pmus.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -708,7 +709,7 @@ static int test__aliases(struct test_suite *test __maybe_unused,
|
||||||
struct perf_pmu *pmu = NULL;
|
struct perf_pmu *pmu = NULL;
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
if (!is_pmu_core(pmu->name))
|
if (!is_pmu_core(pmu->name))
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "util/mmap.h"
|
#include "util/mmap.h"
|
||||||
#include "util/sample.h"
|
#include "util/sample.h"
|
||||||
#include "pmu.h"
|
#include "pmus.h"
|
||||||
|
|
||||||
static int spin_sleep(void)
|
static int spin_sleep(void)
|
||||||
{
|
{
|
||||||
|
@ -375,7 +375,7 @@ static int test__switch_tracking(struct test_suite *test __maybe_unused, int sub
|
||||||
cpu_clocks_evsel = evlist__last(evlist);
|
cpu_clocks_evsel = evlist__last(evlist);
|
||||||
|
|
||||||
/* Second event */
|
/* Second event */
|
||||||
if (perf_pmu__has_hybrid()) {
|
if (perf_pmus__has_hybrid()) {
|
||||||
cycles = "cpu_core/cycles/u";
|
cycles = "cpu_core/cycles/u";
|
||||||
err = parse_event(evlist, cycles);
|
err = parse_event(evlist, cycles);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
#include "evlist.h"
|
#include "evlist.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "pmu.h"
|
#include "pmus.h"
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
|
||||||
#define TEMPL "/tmp/perf-test-XXXXXX"
|
#define TEMPL "/tmp/perf-test-XXXXXX"
|
||||||
|
@ -41,7 +41,7 @@ static int session_write_header(char *path)
|
||||||
session = perf_session__new(&data, NULL);
|
session = perf_session__new(&data, NULL);
|
||||||
TEST_ASSERT_VAL("can't get session", !IS_ERR(session));
|
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();
|
session->evlist = evlist__new_default();
|
||||||
TEST_ASSERT_VAL("can't get evlist", session->evlist);
|
TEST_ASSERT_VAL("can't get evlist", session->evlist);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "env.h"
|
#include "env.h"
|
||||||
#include "pmu.h"
|
#include "pmu.h"
|
||||||
|
#include "pmus.h"
|
||||||
|
|
||||||
#define PACKAGE_CPUS_FMT \
|
#define PACKAGE_CPUS_FMT \
|
||||||
"%s/devices/system/cpu/cpu%d/topology/package_cpus_list"
|
"%s/devices/system/cpu/cpu%d/topology/package_cpus_list"
|
||||||
|
@ -473,10 +474,10 @@ struct hybrid_topology *hybrid_topology__new(void)
|
||||||
struct hybrid_topology *tp = NULL;
|
struct hybrid_topology *tp = NULL;
|
||||||
u32 nr = 0, i = 0;
|
u32 nr = 0, i = 0;
|
||||||
|
|
||||||
if (!perf_pmu__has_hybrid())
|
if (!perf_pmus__has_hybrid())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||||
if (pmu->is_core)
|
if (pmu->is_core)
|
||||||
nr++;
|
nr++;
|
||||||
}
|
}
|
||||||
|
@ -488,7 +489,7 @@ struct hybrid_topology *hybrid_topology__new(void)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
tp->nr = nr;
|
tp->nr = nr;
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||||
if (!pmu->is_core)
|
if (!pmu->is_core)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "pmus.h"
|
||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
|
|
||||||
struct perf_env perf_env;
|
struct perf_env perf_env;
|
||||||
|
@ -323,7 +324,7 @@ int perf_env__read_pmu_mappings(struct perf_env *env)
|
||||||
u32 pmu_num = 0;
|
u32 pmu_num = 0;
|
||||||
struct strbuf sb;
|
struct strbuf sb;
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu))) {
|
while ((pmu = perf_pmus__scan(pmu))) {
|
||||||
if (!pmu->name)
|
if (!pmu->name)
|
||||||
continue;
|
continue;
|
||||||
pmu_num++;
|
pmu_num++;
|
||||||
|
@ -337,7 +338,7 @@ int perf_env__read_pmu_mappings(struct perf_env *env)
|
||||||
if (strbuf_init(&sb, 128 * pmu_num) < 0)
|
if (strbuf_init(&sb, 128 * pmu_num) < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu))) {
|
while ((pmu = perf_pmus__scan(pmu))) {
|
||||||
if (!pmu->name)
|
if (!pmu->name)
|
||||||
continue;
|
continue;
|
||||||
if (strbuf_addf(&sb, "%u:%s", pmu->type, pmu->name) < 0)
|
if (strbuf_addf(&sb, "%u:%s", pmu->type, pmu->name) < 0)
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "util/hashmap.h"
|
#include "util/hashmap.h"
|
||||||
#include "off_cpu.h"
|
#include "off_cpu.h"
|
||||||
#include "pmu.h"
|
#include "pmu.h"
|
||||||
|
#include "pmus.h"
|
||||||
#include "../perf-sys.h"
|
#include "../perf-sys.h"
|
||||||
#include "util/parse-branch-options.h"
|
#include "util/parse-branch-options.h"
|
||||||
#include "util/bpf-filter.h"
|
#include "util/bpf-filter.h"
|
||||||
|
@ -3139,7 +3140,7 @@ void evsel__zero_per_pkg(struct evsel *evsel)
|
||||||
*/
|
*/
|
||||||
bool evsel__is_hybrid(const struct evsel *evsel)
|
bool evsel__is_hybrid(const struct evsel *evsel)
|
||||||
{
|
{
|
||||||
if (!perf_pmu__has_hybrid())
|
if (!perf_pmus__has_hybrid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return evsel->core.is_pmu_core;
|
return evsel->core.is_pmu_core;
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "cpumap.h"
|
#include "cpumap.h"
|
||||||
#include "pmu.h"
|
#include "pmu.h"
|
||||||
|
#include "pmus.h"
|
||||||
#include "vdso.h"
|
#include "vdso.h"
|
||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
#include "build-id.h"
|
#include "build-id.h"
|
||||||
|
@ -744,7 +745,7 @@ static int write_pmu_mappings(struct feat_fd *ff,
|
||||||
* Do a first pass to count number of pmu to avoid lseek so this
|
* Do a first pass to count number of pmu to avoid lseek so this
|
||||||
* works in pipe mode as well.
|
* works in pipe mode as well.
|
||||||
*/
|
*/
|
||||||
while ((pmu = perf_pmu__scan(pmu))) {
|
while ((pmu = perf_pmus__scan(pmu))) {
|
||||||
if (!pmu->name)
|
if (!pmu->name)
|
||||||
continue;
|
continue;
|
||||||
pmu_num++;
|
pmu_num++;
|
||||||
|
@ -754,7 +755,7 @@ static int write_pmu_mappings(struct feat_fd *ff,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu))) {
|
while ((pmu = perf_pmus__scan(pmu))) {
|
||||||
if (!pmu->name)
|
if (!pmu->name)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1566,7 +1567,7 @@ static int __write_pmu_caps(struct feat_fd *ff, struct perf_pmu *pmu,
|
||||||
static int write_cpu_pmu_caps(struct feat_fd *ff,
|
static int write_cpu_pmu_caps(struct feat_fd *ff,
|
||||||
struct evlist *evlist __maybe_unused)
|
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;
|
int ret;
|
||||||
|
|
||||||
if (!cpu_pmu)
|
if (!cpu_pmu)
|
||||||
|
@ -1586,7 +1587,7 @@ static int write_pmu_caps(struct feat_fd *ff,
|
||||||
int nr_pmu = 0;
|
int nr_pmu = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu))) {
|
while ((pmu = perf_pmus__scan(pmu))) {
|
||||||
if (!pmu->name || !strcmp(pmu->name, "cpu") ||
|
if (!pmu->name || !strcmp(pmu->name, "cpu") ||
|
||||||
perf_pmu__caps_parse(pmu) <= 0)
|
perf_pmu__caps_parse(pmu) <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -1604,9 +1605,9 @@ static int write_pmu_caps(struct feat_fd *ff,
|
||||||
* Write hybrid pmu caps first to maintain compatibility with
|
* Write hybrid pmu caps first to maintain compatibility with
|
||||||
* older perf tool.
|
* older perf tool.
|
||||||
*/
|
*/
|
||||||
if (perf_pmu__has_hybrid()) {
|
if (perf_pmus__has_hybrid()) {
|
||||||
pmu = NULL;
|
pmu = NULL;
|
||||||
while ((pmu = perf_pmu__scan(pmu))) {
|
while ((pmu = perf_pmus__scan(pmu))) {
|
||||||
if (!pmu->is_core)
|
if (!pmu->is_core)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1617,7 +1618,7 @@ static int write_pmu_caps(struct feat_fd *ff,
|
||||||
}
|
}
|
||||||
|
|
||||||
pmu = NULL;
|
pmu = NULL;
|
||||||
while ((pmu = perf_pmu__scan(pmu))) {
|
while ((pmu = perf_pmus__scan(pmu))) {
|
||||||
if (pmu->is_core || !pmu->nr_caps)
|
if (pmu->is_core || !pmu->nr_caps)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
#include "pmu.h"
|
#include "pmu.h"
|
||||||
|
#include "pmus.h"
|
||||||
|
|
||||||
unsigned int perf_mem_events__loads_ldlat = 30;
|
unsigned int perf_mem_events__loads_ldlat = 30;
|
||||||
|
|
||||||
|
@ -128,14 +129,14 @@ int perf_mem_events__init(void)
|
||||||
if (!e->tag)
|
if (!e->tag)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!perf_pmu__has_hybrid()) {
|
if (!perf_pmus__has_hybrid()) {
|
||||||
scnprintf(sysfs_name, sizeof(sysfs_name),
|
scnprintf(sysfs_name, sizeof(sysfs_name),
|
||||||
e->sysfs_name, "cpu");
|
e->sysfs_name, "cpu");
|
||||||
e->supported = perf_mem_event__supported(mnt, sysfs_name);
|
e->supported = perf_mem_event__supported(mnt, sysfs_name);
|
||||||
} else {
|
} else {
|
||||||
struct perf_pmu *pmu = NULL;
|
struct perf_pmu *pmu = NULL;
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||||
if (!pmu->is_core)
|
if (!pmu->is_core)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -175,7 +176,7 @@ static void perf_mem_events__print_unsupport_hybrid(struct perf_mem_event *e,
|
||||||
char sysfs_name[100];
|
char sysfs_name[100];
|
||||||
struct perf_pmu *pmu = NULL;
|
struct perf_pmu *pmu = NULL;
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||||
if (!pmu->is_core)
|
if (!pmu->is_core)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -201,7 +202,7 @@ int perf_mem_events__record_args(const char **rec_argv, int *argv_nr,
|
||||||
if (!e->record)
|
if (!e->record)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!perf_pmu__has_hybrid()) {
|
if (!perf_pmus__has_hybrid()) {
|
||||||
if (!e->supported) {
|
if (!e->supported) {
|
||||||
pr_err("failed: event '%s' not supported\n",
|
pr_err("failed: event '%s' not supported\n",
|
||||||
perf_mem_events__name(j, NULL));
|
perf_mem_events__name(j, NULL));
|
||||||
|
@ -216,7 +217,7 @@ int perf_mem_events__record_args(const char **rec_argv, int *argv_nr,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||||
if (!pmu->is_core)
|
if (!pmu->is_core)
|
||||||
continue;
|
continue;
|
||||||
rec_argv[i++] = "-e";
|
rec_argv[i++] = "-e";
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "evsel.h"
|
#include "evsel.h"
|
||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
#include "pmu.h"
|
#include "pmu.h"
|
||||||
|
#include "pmus.h"
|
||||||
#include "print-events.h"
|
#include "print-events.h"
|
||||||
#include "smt.h"
|
#include "smt.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
|
@ -273,7 +274,7 @@ static int setup_metric_events(const char *pmu, struct hashmap *ids,
|
||||||
const char *metric_id;
|
const char *metric_id;
|
||||||
struct evsel *ev;
|
struct evsel *ev;
|
||||||
size_t ids_size, matched_events, i;
|
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;
|
*out_metric_events = NULL;
|
||||||
ids_size = hashmap__size(ids);
|
ids_size = hashmap__size(ids);
|
||||||
|
@ -488,7 +489,7 @@ static int metricgroup__sys_event_iter(const struct pmu_metric *pm,
|
||||||
if (!pm->metric_expr || !pm->compat)
|
if (!pm->metric_expr || !pm->compat)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu))) {
|
while ((pmu = perf_pmus__scan(pmu))) {
|
||||||
|
|
||||||
if (!pmu->id || strcmp(pmu->id, pm->compat))
|
if (!pmu->id || strcmp(pmu->id, pm->compat))
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "parse-events-bison.h"
|
#include "parse-events-bison.h"
|
||||||
#include "parse-events-flex.h"
|
#include "parse-events-flex.h"
|
||||||
#include "pmu.h"
|
#include "pmu.h"
|
||||||
|
#include "pmus.h"
|
||||||
#include "asm/bug.h"
|
#include "asm/bug.h"
|
||||||
#include "util/parse-branch-options.h"
|
#include "util/parse-branch-options.h"
|
||||||
#include "util/evsel_config.h"
|
#include "util/evsel_config.h"
|
||||||
|
@ -452,7 +453,7 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name,
|
||||||
const char *config_name = get_config_name(head_config);
|
const char *config_name = get_config_name(head_config);
|
||||||
const char *metric_id = get_config_metric_id(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);
|
LIST_HEAD(config_terms);
|
||||||
struct perf_event_attr attr;
|
struct perf_event_attr attr;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1193,7 +1194,7 @@ static int config_term_pmu(struct perf_event_attr *attr,
|
||||||
struct parse_events_error *err)
|
struct parse_events_error *err)
|
||||||
{
|
{
|
||||||
if (term->type_term == PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE) {
|
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)) {
|
if (perf_pmu__supports_legacy_cache(pmu)) {
|
||||||
attr->type = PERF_TYPE_HW_CACHE;
|
attr->type = PERF_TYPE_HW_CACHE;
|
||||||
|
@ -1203,7 +1204,7 @@ static int config_term_pmu(struct perf_event_attr *attr,
|
||||||
term->type_term = PARSE_EVENTS__TERM_TYPE_USER;
|
term->type_term = PARSE_EVENTS__TERM_TYPE_USER;
|
||||||
}
|
}
|
||||||
if (term->type_term == PARSE_EVENTS__TERM_TYPE_HARDWARE) {
|
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) {
|
if (!pmu) {
|
||||||
pr_debug("Failed to find PMU for type %d", attr->type);
|
pr_debug("Failed to find PMU for type %d", attr->type);
|
||||||
|
@ -1480,7 +1481,7 @@ int parse_events_add_numeric(struct parse_events_state *parse_state,
|
||||||
return __parse_events_add_numeric(parse_state, list, /*pmu=*/NULL,
|
return __parse_events_add_numeric(parse_state, list, /*pmu=*/NULL,
|
||||||
type, config, head_config);
|
type, config, head_config);
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!perf_pmu__supports_wildcard_numeric(pmu))
|
if (!perf_pmu__supports_wildcard_numeric(pmu))
|
||||||
|
@ -1529,7 +1530,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state,
|
||||||
struct parse_events_error *err = parse_state->error;
|
struct parse_events_error *err = parse_state->error;
|
||||||
LIST_HEAD(config_terms);
|
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)) {
|
if (verbose > 1 && !(pmu && pmu->selectable)) {
|
||||||
fprintf(stderr, "Attempting to add event pmu '%s' with '",
|
fprintf(stderr, "Attempting to add event pmu '%s' with '",
|
||||||
|
@ -1674,7 +1675,7 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
|
||||||
|
|
||||||
INIT_LIST_HEAD(list);
|
INIT_LIST_HEAD(list);
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||||
struct perf_pmu_alias *alias;
|
struct perf_pmu_alias *alias;
|
||||||
bool auto_merge_stats;
|
bool auto_merge_stats;
|
||||||
|
|
||||||
|
@ -2410,7 +2411,7 @@ static int set_filter(struct evsel *evsel, const void *arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL)
|
while ((pmu = perf_pmus__scan(pmu)) != NULL)
|
||||||
if (pmu->type == evsel->core.attr.type) {
|
if (pmu->type == evsel->core.attr.type) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/zalloc.h>
|
#include <linux/zalloc.h>
|
||||||
#include "pmu.h"
|
#include "pmu.h"
|
||||||
|
#include "pmus.h"
|
||||||
#include "evsel.h"
|
#include "evsel.h"
|
||||||
#include "parse-events.h"
|
#include "parse-events.h"
|
||||||
#include "parse-events-bison.h"
|
#include "parse-events-bison.h"
|
||||||
|
@ -316,7 +317,7 @@ PE_NAME opt_pmu_config
|
||||||
if (asprintf(&pattern, "%s*", $1) < 0)
|
if (asprintf(&pattern, "%s*", $1) < 0)
|
||||||
CLEANUP_YYABORT;
|
CLEANUP_YYABORT;
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||||
char *name = pmu->name;
|
char *name = pmu->name;
|
||||||
|
|
||||||
if (parse_events__filter_pmu(parse_state, pmu))
|
if (parse_events__filter_pmu(parse_state, pmu))
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include "util/evlist.h"
|
#include "util/evlist.h"
|
||||||
#include "util/evsel.h"
|
#include "util/evsel.h"
|
||||||
#include "util/parse-events.h"
|
#include "util/parse-events.h"
|
||||||
#include "util/pmu.h"
|
#include "util/pmus.h"
|
||||||
#include "util/pfm.h"
|
#include "util/pfm.h"
|
||||||
#include "util/strbuf.h"
|
#include "util/strbuf.h"
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ int parse_libpfm_events_option(const struct option *opt, const char *str,
|
||||||
/*
|
/*
|
||||||
* force loading of the PMU list
|
* force loading of the PMU list
|
||||||
*/
|
*/
|
||||||
perf_pmu__scan(NULL);
|
perf_pmus__scan(NULL);
|
||||||
|
|
||||||
for (q = p; strsep(&p, ",{}"); q = p) {
|
for (q = p; strsep(&p, ",{}"); q = p) {
|
||||||
sep = p ? str + (p - p_orig - 1) : "";
|
sep = p ? str + (p - p_orig - 1) : "";
|
||||||
|
@ -86,7 +86,7 @@ int parse_libpfm_events_option(const struct option *opt, const char *str,
|
||||||
goto error;
|
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,
|
evsel = parse_events__add_event(evlist->core.nr_entries,
|
||||||
&attr, q, /*metric_id=*/NULL,
|
&attr, q, /*metric_id=*/NULL,
|
||||||
pmu);
|
pmu);
|
||||||
|
|
|
@ -4,20 +4,15 @@
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/zalloc.h>
|
#include <linux/zalloc.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <subcmd/pager.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <api/fs/fs.h>
|
#include <api/fs/fs.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <regex.h>
|
|
||||||
#include <perf/cpumap.h>
|
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
@ -59,8 +54,6 @@ struct perf_pmu_format {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse & process all the sysfs attributes located under
|
* Parse & process all the sysfs attributes located under
|
||||||
* the directory specified in 'dir' parameter.
|
* the directory specified in 'dir' parameter.
|
||||||
|
@ -554,31 +547,6 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias,
|
||||||
return 0;
|
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)
|
* Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64)
|
||||||
* may have a "cpus" file.
|
* may have a "cpus" file.
|
||||||
|
@ -894,7 +862,7 @@ static int pmu_max_precise(int dirfd, struct perf_pmu *pmu)
|
||||||
return max_precise;
|
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;
|
struct perf_pmu *pmu;
|
||||||
LIST_HEAD(format);
|
LIST_HEAD(format);
|
||||||
|
@ -951,7 +919,7 @@ static struct perf_pmu *pmu_lookup(int dirfd, const char *lookup_name)
|
||||||
INIT_LIST_HEAD(&pmu->caps);
|
INIT_LIST_HEAD(&pmu->caps);
|
||||||
list_splice(&format, &pmu->format);
|
list_splice(&format, &pmu->format);
|
||||||
list_splice(&aliases, &pmu->aliases);
|
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);
|
pmu->default_config = perf_pmu__get_default_config(pmu);
|
||||||
|
|
||||||
|
@ -979,61 +947,6 @@ void perf_pmu__warn_invalid_formats(struct perf_pmu *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)
|
bool evsel__is_aux_event(const struct evsel *evsel)
|
||||||
{
|
{
|
||||||
struct perf_pmu *pmu = evsel__find_pmu(evsel);
|
struct perf_pmu *pmu = evsel__find_pmu(evsel);
|
||||||
|
@ -1070,43 +983,6 @@ void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel,
|
||||||
evsel->core.attr.config |= field_prep(bits, val);
|
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 *
|
static struct perf_pmu_format *
|
||||||
pmu_find_format(struct list_head *formats, const char *name)
|
pmu_find_format(struct list_head *formats, const char *name)
|
||||||
{
|
{
|
||||||
|
@ -1536,99 +1412,6 @@ void perf_pmu__del_formats(struct list_head *formats)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
bool is_pmu_core(const char *name)
|
||||||
{
|
{
|
||||||
return !strcmp(name, "cpu") || is_sysfs_pmu_core(name);
|
return !strcmp(name, "cpu") || is_sysfs_pmu_core(name);
|
||||||
|
@ -1654,167 +1437,18 @@ bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu)
|
||||||
return !is_pmu_hybrid(pmu->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;
|
return pmu->is_core;
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_pmu__num_mem_pmus(void)
|
bool perf_pmu__have_event(const struct perf_pmu *pmu, const char *name)
|
||||||
{
|
{
|
||||||
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)
|
|
||||||
{
|
|
||||||
struct perf_pmu *pmu;
|
|
||||||
struct perf_pmu_alias *alias;
|
struct perf_pmu_alias *alias;
|
||||||
|
|
||||||
pmu = NULL;
|
list_for_each_entry(alias, &pmu->aliases, list) {
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
if (!strcmp(alias->name, name))
|
||||||
if (strcmp(pname, pmu->name))
|
return true;
|
||||||
continue;
|
|
||||||
list_for_each_entry(alias, &pmu->aliases, list)
|
|
||||||
if (!strcmp(alias->name, name))
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2020,24 +1654,6 @@ void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
|
||||||
name ?: "N/A", buf, config);
|
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)
|
int perf_pmu__match(char *pattern, char *name, char *tok)
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!name)
|
||||||
|
@ -2105,7 +1721,7 @@ int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename,
|
||||||
return openat(dirfd, path, flags);
|
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_formats(&pmu->format);
|
||||||
perf_pmu__del_aliases(pmu);
|
perf_pmu__del_aliases(pmu);
|
||||||
|
@ -2118,14 +1734,3 @@ static void perf_pmu__delete(struct perf_pmu *pmu)
|
||||||
zfree(&pmu->alias_name);
|
zfree(&pmu->alias_name);
|
||||||
free(pmu);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -198,8 +198,6 @@ struct perf_pmu_alias {
|
||||||
char *pmu_name;
|
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);
|
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,
|
int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
|
||||||
struct list_head *head_terms,
|
struct list_head *head_terms,
|
||||||
|
@ -222,16 +220,13 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to);
|
||||||
int perf_pmu__format_parse(int dirfd, struct list_head *head);
|
int perf_pmu__format_parse(int dirfd, struct list_head *head);
|
||||||
void perf_pmu__del_formats(struct list_head *formats);
|
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_core(const char *name);
|
||||||
bool is_pmu_hybrid(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_legacy_cache(const struct perf_pmu *pmu);
|
||||||
bool perf_pmu__supports_wildcard_numeric(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);
|
bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu);
|
||||||
int perf_pmu__num_mem_pmus(void);
|
bool perf_pmu__is_mem_pmu(const struct perf_pmu *pmu);
|
||||||
void print_pmu_events(const struct print_callbacks *print_cb, void *print_state);
|
bool perf_pmu__have_event(const struct perf_pmu *pmu, const char *name);
|
||||||
bool pmu_have_event(const char *pname, const char *name);
|
|
||||||
|
|
||||||
FILE *perf_pmu__open_file(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);
|
FILE *perf_pmu__open_file_at(struct perf_pmu *pmu, int dirfd, const char *name);
|
||||||
|
@ -261,7 +256,6 @@ void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
|
||||||
const char *name);
|
const char *name);
|
||||||
void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu);
|
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);
|
int perf_pmu__match(char *pattern, char *name, char *tok);
|
||||||
|
|
||||||
char *pmu_find_real_name(const char *name);
|
char *pmu_find_real_name(const char *name);
|
||||||
|
@ -273,6 +267,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);
|
||||||
|
|
||||||
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 */
|
#endif /* __PMU_H */
|
||||||
|
|
|
@ -1,16 +1,136 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/zalloc.h>
|
||||||
|
#include <subcmd/pager.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <dirent.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "debug.h"
|
||||||
|
#include "evsel.h"
|
||||||
#include "pmus.h"
|
#include "pmus.h"
|
||||||
#include "pmu.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)
|
const struct perf_pmu *perf_pmus__pmu_for_pmu_filter(const char *str)
|
||||||
{
|
{
|
||||||
struct perf_pmu *pmu = NULL;
|
struct perf_pmu *pmu = NULL;
|
||||||
|
|
||||||
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
|
while ((pmu = perf_pmus__scan(pmu)) != NULL) {
|
||||||
if (!strcmp(pmu->name, str))
|
if (!strcmp(pmu->name, str))
|
||||||
return pmu;
|
return pmu;
|
||||||
/* Ignore "uncore_" prefix. */
|
/* Ignore "uncore_" prefix. */
|
||||||
|
@ -26,3 +146,275 @@ const struct perf_pmu *perf_pmus__pmu_for_pmu_filter(const char *str)
|
||||||
}
|
}
|
||||||
return NULL;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -2,9 +2,21 @@
|
||||||
#ifndef __PMUS_H
|
#ifndef __PMUS_H
|
||||||
#define __PMUS_H
|
#define __PMUS_H
|
||||||
|
|
||||||
extern struct list_head pmus;
|
|
||||||
struct perf_pmu;
|
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);
|
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 */
|
#endif /* __PMUS_H */
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "metricgroup.h"
|
#include "metricgroup.h"
|
||||||
#include "parse-events.h"
|
#include "parse-events.h"
|
||||||
#include "pmu.h"
|
#include "pmu.h"
|
||||||
|
#include "pmus.h"
|
||||||
#include "print-events.h"
|
#include "print-events.h"
|
||||||
#include "probe-file.h"
|
#include "probe-file.h"
|
||||||
#include "string2.h"
|
#include "string2.h"
|
||||||
|
@ -271,7 +272,7 @@ int print_hwcache_events(const struct print_callbacks *print_cb, void *print_sta
|
||||||
struct perf_pmu *pmu = NULL;
|
struct perf_pmu *pmu = NULL;
|
||||||
const char *event_type_descriptor = event_type_descriptors[PERF_TYPE_HW_CACHE];
|
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
|
* Skip uncore PMUs for performance. PERF_TYPE_HW_CACHE type
|
||||||
* attributes can accept software PMUs in the extended type, so
|
* attributes can accept software PMUs in the extended type, so
|
||||||
|
@ -404,7 +405,7 @@ void print_events(const struct print_callbacks *print_cb, void *print_state)
|
||||||
|
|
||||||
print_hwcache_events(print_cb, print_state);
|
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,
|
print_cb->print_event(print_state,
|
||||||
/*topic=*/NULL,
|
/*topic=*/NULL,
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "util/bpf-filter.h"
|
#include "util/bpf-filter.h"
|
||||||
#include "util/env.h"
|
#include "util/env.h"
|
||||||
#include "util/pmu.h"
|
#include "util/pmu.h"
|
||||||
|
#include "util/pmus.h"
|
||||||
#include <internal/lib.h>
|
#include <internal/lib.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -102,7 +103,7 @@ int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool perf_pmu__has_hybrid(void)
|
bool perf_pmus__has_hybrid(void)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "iostat.h"
|
#include "iostat.h"
|
||||||
#include "pmu.h"
|
#include "pmu.h"
|
||||||
|
#include "pmus.h"
|
||||||
|
|
||||||
#define CNTR_NOT_SUPPORTED "<not supported>"
|
#define CNTR_NOT_SUPPORTED "<not supported>"
|
||||||
#define CNTR_NOT_COUNTED "<not counted>"
|
#define CNTR_NOT_COUNTED "<not counted>"
|
||||||
|
@ -695,7 +696,7 @@ static bool evlist__has_hybrid(struct evlist *evlist)
|
||||||
{
|
{
|
||||||
struct evsel *evsel;
|
struct evsel *evsel;
|
||||||
|
|
||||||
if (!perf_pmu__has_hybrid())
|
if (!perf_pmus__has_hybrid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
evlist__for_each_entry(evlist, evsel) {
|
evlist__for_each_entry(evlist, evsel) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue