1 // SPDX-License-Identifier: GPL-2.0 2 #include "api/fs/fs.h" 3 #include "util/evsel.h" 4 #include "util/evlist.h" 5 #include "util/pmu.h" 6 #include "util/pmus.h" 7 #include "util/topdown.h" 8 #include "topdown.h" 9 #include "evsel.h" 10 11 /* Check whether there is a PMU which supports the perf metrics. */ 12 bool topdown_sys_has_perf_metrics(void) 13 { 14 static bool has_perf_metrics; 15 static bool cached; 16 struct perf_pmu *pmu; 17 18 if (cached) 19 return has_perf_metrics; 20 21 /* 22 * The perf metrics feature is a core PMU feature. 23 * The PERF_TYPE_RAW type is the type of a core PMU. 24 * The slots event is only available when the core PMU 25 * supports the perf metrics feature. 26 */ 27 pmu = perf_pmus__find_by_type(PERF_TYPE_RAW); 28 if (pmu && perf_pmu__have_event(pmu, "slots")) 29 has_perf_metrics = true; 30 31 cached = true; 32 return has_perf_metrics; 33 } 34 35 #define TOPDOWN_SLOTS 0x0400 36 bool arch_is_topdown_slots(const struct evsel *evsel) 37 { 38 if (evsel->core.attr.config == TOPDOWN_SLOTS) 39 return true; 40 41 return false; 42 } 43 44 static int compare_topdown_event(void *vstate, struct pmu_event_info *info) 45 { 46 int *config = vstate; 47 int event = 0; 48 int umask = 0; 49 char *str; 50 51 if (!strcasestr(info->name, "topdown")) 52 return 0; 53 54 str = strcasestr(info->str, "event="); 55 if (str) 56 sscanf(str, "event=%x", &event); 57 58 str = strcasestr(info->str, "umask="); 59 if (str) 60 sscanf(str, "umask=%x", &umask); 61 62 if (event == 0 && *config == (event | umask << 8)) 63 return 1; 64 65 return 0; 66 } 67 68 bool arch_is_topdown_metrics(const struct evsel *evsel) 69 { 70 struct perf_pmu *pmu = evsel__find_pmu(evsel); 71 int config = evsel->core.attr.config; 72 73 if (!pmu || !pmu->is_core) 74 return false; 75 76 if (perf_pmu__for_each_event(pmu, false, &config, 77 compare_topdown_event)) 78 return true; 79 80 return false; 81 } 82 83 /* 84 * Check whether a topdown group supports sample-read. 85 * 86 * Only Topdown metric supports sample-read. The slots 87 * event must be the leader of the topdown group. 88 */ 89 bool arch_topdown_sample_read(struct evsel *leader) 90 { 91 struct evsel *evsel; 92 93 if (!evsel__sys_has_perf_metrics(leader)) 94 return false; 95 96 if (!arch_is_topdown_slots(leader)) 97 return false; 98 99 /* 100 * If slots event as leader event but no topdown metric events 101 * in group, slots event should still sample as leader. 102 */ 103 evlist__for_each_entry(leader->evlist, evsel) { 104 if (evsel->core.leader != leader->core.leader) 105 return false; 106 if (evsel != leader && arch_is_topdown_metrics(evsel)) 107 return true; 108 } 109 110 return false; 111 } 112