1 // SPDX-License-Identifier: GPL-2.0 2 #include <string.h> 3 #include "../../../util/evlist.h" 4 #include "../../../util/evsel.h" 5 #include "topdown.h" 6 #include "evsel.h" 7 8 int arch_evlist__cmp(const struct evsel *lhs, const struct evsel *rhs) 9 { 10 /* 11 * Currently the following topdown events sequence are supported to 12 * move and regroup correctly. 13 * 14 * a. all events in a group 15 * perf stat -e "{instructions,topdown-retiring,slots}" -C0 sleep 1 16 * WARNING: events were regrouped to match PMUs 17 * Performance counter stats for 'CPU(s) 0': 18 * 15,066,240 slots 19 * 1,899,760 instructions 20 * 2,126,998 topdown-retiring 21 * b. all events not in a group 22 * perf stat -e "instructions,topdown-retiring,slots" -C0 sleep 1 23 * WARNING: events were regrouped to match PMUs 24 * Performance counter stats for 'CPU(s) 0': 25 * 2,045,561 instructions 26 * 17,108,370 slots 27 * 2,281,116 topdown-retiring 28 * c. slots event in a group but topdown metrics events outside the group 29 * perf stat -e "{instructions,slots},topdown-retiring" -C0 sleep 1 30 * WARNING: events were regrouped to match PMUs 31 * Performance counter stats for 'CPU(s) 0': 32 * 20,323,878 slots 33 * 2,634,884 instructions 34 * 3,028,656 topdown-retiring 35 * d. slots event and topdown metrics events in two groups 36 * perf stat -e "{instructions,slots},{topdown-retiring}" -C0 sleep 1 37 * WARNING: events were regrouped to match PMUs 38 * Performance counter stats for 'CPU(s) 0': 39 * 26,319,024 slots 40 * 2,427,791 instructions 41 * 2,683,508 topdown-retiring 42 * e. slots event and metrics event are not in a group and not adjacent 43 * perf stat -e "{instructions,slots},cycles,topdown-retiring" -C0 sleep 1 44 * WARNING: events were regrouped to match PMUs 45 * 68,433,522 slots 46 * 8,856,102 topdown-retiring 47 * 7,791,494 instructions 48 * 11,469,513 cycles 49 */ 50 if (topdown_sys_has_perf_metrics() && 51 (arch_evsel__must_be_in_group(lhs) || arch_evsel__must_be_in_group(rhs))) { 52 /* Ensure the topdown slots comes first. */ 53 if (arch_is_topdown_slots(lhs)) 54 return -1; 55 if (arch_is_topdown_slots(rhs)) 56 return 1; 57 58 /* 59 * Move topdown metrics events forward only when topdown metrics 60 * events are not in same group with previous slots event. If 61 * topdown metrics events are already in same group with slots 62 * event, do nothing. 63 */ 64 if (lhs->core.leader != rhs->core.leader) { 65 bool lhs_topdown = arch_is_topdown_metrics(lhs); 66 bool rhs_topdown = arch_is_topdown_metrics(rhs); 67 68 if (lhs_topdown && !rhs_topdown) 69 return -1; 70 if (!lhs_topdown && rhs_topdown) 71 return 1; 72 } 73 } 74 75 /* Retire latency event should not be group leader*/ 76 if (lhs->retire_lat && !rhs->retire_lat) 77 return 1; 78 if (!lhs->retire_lat && rhs->retire_lat) 79 return -1; 80 81 /* Default ordering by insertion index. */ 82 return lhs->core.idx - rhs->core.idx; 83 } 84 85 int arch_evlist__add_required_events(struct list_head *list) 86 { 87 struct evsel *pos, *metric_event = NULL; 88 int idx = 0; 89 90 if (!topdown_sys_has_perf_metrics()) 91 return 0; 92 93 list_for_each_entry(pos, list, core.node) { 94 if (arch_is_topdown_slots(pos)) { 95 /* Slots event already present, nothing to do. */ 96 return 0; 97 } 98 if (metric_event == NULL && arch_is_topdown_metrics(pos)) 99 metric_event = pos; 100 idx++; 101 } 102 if (metric_event == NULL) { 103 /* No topdown metric events, nothing to do. */ 104 return 0; 105 } 106 return topdown_insert_slots_event(list, idx + 1, metric_event); 107 } 108