xref: /linux/tools/perf/arch/x86/util/evlist.c (revision 1dc707e647bc919834eff9636c8d00b78c782545)
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 	 *
43 	 * If slots event and topdown metrics events are not in same group, the
44 	 * topdown metrics events must be first event after the slots event group,
45 	 * otherwise topdown metrics events can't be regrouped correctly, e.g.
46 	 *
47 	 * a. perf stat -e "{instructions,slots},cycles,topdown-retiring" -C0 sleep 1
48 	 *    WARNING: events were regrouped to match PMUs
49 	 *     Performance counter stats for 'CPU(s) 0':
50 	 *         17,923,134      slots
51 	 *          2,154,855      instructions
52 	 *          3,015,058      cycles
53 	 *    <not supported>      topdown-retiring
54 	 *
55 	 * If slots event and topdown metrics events are in two groups, the group which
56 	 * has topdown metrics events must contain only the topdown metrics event,
57 	 * otherwise topdown metrics event can't be regrouped correctly as well, e.g.
58 	 *
59 	 * a. perf stat -e "{instructions,slots},{topdown-retiring,cycles}" -C0 sleep 1
60 	 *    WARNING: events were regrouped to match PMUs
61 	 *    Error:
62 	 *    The sys_perf_event_open() syscall returned with 22 (Invalid argument) for
63 	 *    event (topdown-retiring)
64 	 */
65 	if (topdown_sys_has_perf_metrics() &&
66 	    (arch_evsel__must_be_in_group(lhs) || arch_evsel__must_be_in_group(rhs))) {
67 		/* Ensure the topdown slots comes first. */
68 		if (arch_is_topdown_slots(lhs))
69 			return -1;
70 		if (arch_is_topdown_slots(rhs))
71 			return 1;
72 
73 		/*
74 		 * Move topdown metrics events forward only when topdown metrics
75 		 * events are not in same group with previous slots event. If
76 		 * topdown metrics events are already in same group with slots
77 		 * event, do nothing.
78 		 */
79 		if (arch_is_topdown_metrics(lhs) && !arch_is_topdown_metrics(rhs) &&
80 		    lhs->core.leader != rhs->core.leader)
81 			return -1;
82 		if (!arch_is_topdown_metrics(lhs) && arch_is_topdown_metrics(rhs) &&
83 		    lhs->core.leader != rhs->core.leader)
84 			return 1;
85 	}
86 
87 	/* Retire latency event should not be group leader*/
88 	if (lhs->retire_lat && !rhs->retire_lat)
89 		return 1;
90 	if (!lhs->retire_lat && rhs->retire_lat)
91 		return -1;
92 
93 	/* Default ordering by insertion index. */
94 	return lhs->core.idx - rhs->core.idx;
95 }
96