diff options
Diffstat (limited to 'tools/perf/arch/x86/util/topdown.c')
-rw-r--r-- | tools/perf/arch/x86/util/topdown.c | 97 |
1 files changed, 80 insertions, 17 deletions
diff --git a/tools/perf/arch/x86/util/topdown.c b/tools/perf/arch/x86/util/topdown.c index 2f3d96aa92a5..54810f9acd6f 100644 --- a/tools/perf/arch/x86/util/topdown.c +++ b/tools/perf/arch/x86/util/topdown.c @@ -3,6 +3,40 @@ #include "api/fs/fs.h" #include "util/pmu.h" #include "util/topdown.h" +#include "util/evlist.h" +#include "util/debug.h" +#include "util/pmu-hybrid.h" +#include "topdown.h" +#include "evsel.h" + +#define TOPDOWN_L1_EVENTS "{slots,topdown-retiring,topdown-bad-spec,topdown-fe-bound,topdown-be-bound}" +#define TOPDOWN_L1_EVENTS_CORE "{slots,cpu_core/topdown-retiring/,cpu_core/topdown-bad-spec/,cpu_core/topdown-fe-bound/,cpu_core/topdown-be-bound/}" +#define TOPDOWN_L2_EVENTS "{slots,topdown-retiring,topdown-bad-spec,topdown-fe-bound,topdown-be-bound,topdown-heavy-ops,topdown-br-mispredict,topdown-fetch-lat,topdown-mem-bound}" +#define TOPDOWN_L2_EVENTS_CORE "{slots,cpu_core/topdown-retiring/,cpu_core/topdown-bad-spec/,cpu_core/topdown-fe-bound/,cpu_core/topdown-be-bound/,cpu_core/topdown-heavy-ops/,cpu_core/topdown-br-mispredict/,cpu_core/topdown-fetch-lat/,cpu_core/topdown-mem-bound/}" + +/* Check whether there is a PMU which supports the perf metrics. */ +bool topdown_sys_has_perf_metrics(void) +{ + static bool has_perf_metrics; + static bool cached; + struct perf_pmu *pmu; + + if (cached) + return has_perf_metrics; + + /* + * The perf metrics feature is a core PMU feature. + * The PERF_TYPE_RAW type is the type of a core PMU. + * 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")) + has_perf_metrics = true; + + cached = true; + return has_perf_metrics; +} /* * Check whether we can use a group for top down. @@ -30,34 +64,63 @@ void arch_topdown_group_warn(void) #define TOPDOWN_SLOTS 0x0400 -static bool is_topdown_slots_event(struct evsel *counter) -{ - if (!counter->pmu_name) - return false; - - if (strcmp(counter->pmu_name, "cpu")) - return false; - - if (counter->core.attr.config == TOPDOWN_SLOTS) - return true; - - return false; -} - /* * Check whether a topdown group supports sample-read. * - * Only Topdown metic supports sample-read. The slots + * Only Topdown metric supports sample-read. The slots * event must be the leader of the topdown group. */ bool arch_topdown_sample_read(struct evsel *leader) { - if (!pmu_have_event("cpu", "slots")) + if (!evsel__sys_has_perf_metrics(leader)) return false; - if (is_topdown_slots_event(leader)) + if (leader->core.attr.config == TOPDOWN_SLOTS) return true; return false; } + +const char *arch_get_topdown_pmu_name(struct evlist *evlist, bool warn) +{ + const char *pmu_name; + + if (!perf_pmu__has_hybrid()) + return "cpu"; + + if (!evlist->hybrid_pmu_name) { + if (warn) + pr_warning("WARNING: default to use cpu_core topdown events\n"); + evlist->hybrid_pmu_name = perf_pmu__hybrid_type_to_pmu("core"); + } + + pmu_name = evlist->hybrid_pmu_name; + + return pmu_name; +} + +int topdown_parse_events(struct evlist *evlist) +{ + const char *topdown_events; + const char *pmu_name; + + if (!topdown_sys_has_perf_metrics()) + return 0; + + pmu_name = arch_get_topdown_pmu_name(evlist, false); + + if (pmu_have_event(pmu_name, "topdown-heavy-ops")) { + if (!strcmp(pmu_name, "cpu_core")) + topdown_events = TOPDOWN_L2_EVENTS_CORE; + else + topdown_events = TOPDOWN_L2_EVENTS; + } else { + if (!strcmp(pmu_name, "cpu_core")) + topdown_events = TOPDOWN_L1_EVENTS_CORE; + else + topdown_events = TOPDOWN_L1_EVENTS; + } + + return parse_event(evlist, topdown_events); +} |