1 // SPDX-License-Identifier: GPL-2.0
2 #include "arch-tests.h"
3 #include "debug.h"
4 #include "evlist.h"
5 #include "evsel.h"
6 #include "pmu.h"
7 #include "pmus.h"
8 #include "tests/tests.h"
9
test_config(const struct evsel * evsel,__u64 expected_config)10 static bool test_config(const struct evsel *evsel, __u64 expected_config)
11 {
12 return (evsel->core.attr.config & PERF_HW_EVENT_MASK) == expected_config;
13 }
14
test_perf_config(const struct perf_evsel * evsel,__u64 expected_config)15 static bool test_perf_config(const struct perf_evsel *evsel, __u64 expected_config)
16 {
17 return (evsel->attr.config & PERF_HW_EVENT_MASK) == expected_config;
18 }
19
test_hybrid_type(const struct evsel * evsel,__u64 expected_config)20 static bool test_hybrid_type(const struct evsel *evsel, __u64 expected_config)
21 {
22 return (evsel->core.attr.config >> PERF_PMU_TYPE_SHIFT) == expected_config;
23 }
24
test__hybrid_hw_event_with_pmu(struct evlist * evlist)25 static int test__hybrid_hw_event_with_pmu(struct evlist *evlist)
26 {
27 struct evsel *evsel = evlist__first(evlist);
28
29 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
30 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
31 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
32 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
33 return TEST_OK;
34 }
35
test__hybrid_hw_group_event(struct evlist * evlist)36 static int test__hybrid_hw_group_event(struct evlist *evlist)
37 {
38 struct evsel *evsel, *leader;
39
40 evsel = leader = evlist__first(evlist);
41 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
42 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
43 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
44 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
45 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
46
47 evsel = evsel__next(evsel);
48 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
49 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
50 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_INSTRUCTIONS));
51 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
52 return TEST_OK;
53 }
54
test__hybrid_sw_hw_group_event(struct evlist * evlist)55 static int test__hybrid_sw_hw_group_event(struct evlist *evlist)
56 {
57 struct evsel *evsel, *leader;
58
59 evsel = leader = evlist__first(evlist);
60 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
61 TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type);
62 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
63
64 evsel = evsel__next(evsel);
65 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
66 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
67 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
68 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
69 return TEST_OK;
70 }
71
test__hybrid_hw_sw_group_event(struct evlist * evlist)72 static int test__hybrid_hw_sw_group_event(struct evlist *evlist)
73 {
74 struct evsel *evsel, *leader;
75
76 evsel = leader = evlist__first(evlist);
77 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
78 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
79 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
80 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
81 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
82
83 evsel = evsel__next(evsel);
84 TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type);
85 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
86 return TEST_OK;
87 }
88
test__hybrid_group_modifier1(struct evlist * evlist)89 static int test__hybrid_group_modifier1(struct evlist *evlist)
90 {
91 struct evsel *evsel, *leader;
92
93 evsel = leader = evlist__first(evlist);
94 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
95 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
96 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
97 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
98 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
99 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);
100 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
101
102 evsel = evsel__next(evsel);
103 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
104 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
105 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_INSTRUCTIONS));
106 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
107 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
108 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
109 return TEST_OK;
110 }
111
test__hybrid_raw1(struct evlist * evlist)112 static int test__hybrid_raw1(struct evlist *evlist)
113 {
114 struct perf_evsel *evsel;
115
116 perf_evlist__for_each_evsel(&evlist->core, evsel) {
117 struct perf_pmu *pmu = perf_pmus__find_by_type(evsel->attr.type);
118
119 TEST_ASSERT_VAL("missing pmu", pmu);
120 TEST_ASSERT_VAL("unexpected pmu", !strncmp(pmu->name, "cpu_", 4));
121 TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, 0x1a));
122 }
123 return TEST_OK;
124 }
125
test__hybrid_raw2(struct evlist * evlist)126 static int test__hybrid_raw2(struct evlist *evlist)
127 {
128 struct evsel *evsel = evlist__first(evlist);
129
130 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
131 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
132 TEST_ASSERT_VAL("wrong config", test_config(evsel, 0x1a));
133 return TEST_OK;
134 }
135
test__hybrid_cache_event(struct evlist * evlist)136 static int test__hybrid_cache_event(struct evlist *evlist)
137 {
138 struct evsel *evsel = evlist__first(evlist);
139
140 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
141 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->core.attr.type);
142 TEST_ASSERT_VAL("wrong config", 0x2 == (evsel->core.attr.config & 0xffffffff));
143 return TEST_OK;
144 }
145
test__checkevent_pmu(struct evlist * evlist)146 static int test__checkevent_pmu(struct evlist *evlist)
147 {
148
149 struct evsel *evsel = evlist__first(evlist);
150
151 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
152 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
153 TEST_ASSERT_VAL("wrong config", 10 == evsel->core.attr.config);
154 TEST_ASSERT_VAL("wrong config1", 1 == evsel->core.attr.config1);
155 TEST_ASSERT_VAL("wrong config2", 3 == evsel->core.attr.config2);
156 TEST_ASSERT_VAL("wrong config3", 0 == evsel->core.attr.config3);
157 /*
158 * The period value gets configured within evlist__config,
159 * while this test executes only parse events method.
160 */
161 TEST_ASSERT_VAL("wrong period", 0 == evsel->core.attr.sample_period);
162
163 return TEST_OK;
164 }
165
test__hybrid_hw_group_event_2(struct evlist * evlist)166 static int test__hybrid_hw_group_event_2(struct evlist *evlist)
167 {
168 struct evsel *evsel, *leader;
169
170 evsel = leader = evlist__first(evlist);
171 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
172 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
173 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
174 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
175 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
176
177 evsel = evsel__next(evsel);
178 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
179 TEST_ASSERT_VAL("wrong config", evsel->core.attr.config == 0x3c);
180 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
181 return TEST_OK;
182 }
183
184 struct evlist_test {
185 const char *name;
186 bool (*valid)(void);
187 int (*check)(struct evlist *evlist);
188 };
189
190 static const struct evlist_test test__hybrid_events[] = {
191 {
192 .name = "cpu_core/cycles/",
193 .check = test__hybrid_hw_event_with_pmu,
194 /* 0 */
195 },
196 {
197 .name = "{cpu_core/cycles/,cpu_core/branches/}",
198 .check = test__hybrid_hw_group_event,
199 /* 1 */
200 },
201 {
202 .name = "{cpu-clock,cpu_core/cycles/}",
203 .check = test__hybrid_sw_hw_group_event,
204 /* 2 */
205 },
206 {
207 .name = "{cpu_core/cycles/,cpu-clock}",
208 .check = test__hybrid_hw_sw_group_event,
209 /* 3 */
210 },
211 {
212 .name = "{cpu_core/cycles/k,cpu_core/branches/u}",
213 .check = test__hybrid_group_modifier1,
214 /* 4 */
215 },
216 {
217 .name = "r1a",
218 .check = test__hybrid_raw1,
219 /* 5 */
220 },
221 {
222 .name = "cpu_core/r1a/",
223 .check = test__hybrid_raw2,
224 /* 6 */
225 },
226 {
227 .name = "cpu_core/config=10,config1,config2=3,period=1000/u",
228 .check = test__checkevent_pmu,
229 /* 7 */
230 },
231 {
232 .name = "cpu_core/LLC-loads/",
233 .check = test__hybrid_cache_event,
234 /* 8 */
235 },
236 {
237 .name = "{cpu_core/cycles/,cpu_core/cpu-cycles/}",
238 .check = test__hybrid_hw_group_event_2,
239 /* 9 */
240 },
241 };
242
test_event(const struct evlist_test * e)243 static int test_event(const struct evlist_test *e)
244 {
245 struct parse_events_error err;
246 struct evlist *evlist;
247 int ret;
248
249 if (e->valid && !e->valid()) {
250 pr_debug("... SKIP\n");
251 return TEST_OK;
252 }
253
254 evlist = evlist__new();
255 if (evlist == NULL) {
256 pr_err("Failed allocation");
257 return TEST_FAIL;
258 }
259 parse_events_error__init(&err);
260 ret = parse_events(evlist, e->name, &err);
261 if (ret) {
262 pr_debug("failed to parse event '%s', err %d\n", e->name, ret);
263 parse_events_error__print(&err, e->name);
264 ret = TEST_FAIL;
265 if (parse_events_error__contains(&err, "can't access trace events"))
266 ret = TEST_SKIP;
267 } else {
268 ret = e->check(evlist);
269 }
270 parse_events_error__exit(&err);
271 evlist__delete(evlist);
272
273 return ret;
274 }
275
combine_test_results(int existing,int latest)276 static int combine_test_results(int existing, int latest)
277 {
278 if (existing == TEST_FAIL)
279 return TEST_FAIL;
280 if (existing == TEST_SKIP)
281 return latest == TEST_OK ? TEST_SKIP : latest;
282 return latest;
283 }
284
test_events(const struct evlist_test * events,int cnt)285 static int test_events(const struct evlist_test *events, int cnt)
286 {
287 int ret = TEST_OK;
288
289 for (int i = 0; i < cnt; i++) {
290 const struct evlist_test *e = &events[i];
291 int test_ret;
292
293 pr_debug("running test %d '%s'\n", i, e->name);
294 test_ret = test_event(e);
295 if (test_ret != TEST_OK) {
296 pr_debug("Event test failure: test %d '%s'", i, e->name);
297 ret = combine_test_results(ret, test_ret);
298 }
299 }
300
301 return ret;
302 }
303
test__hybrid(struct test_suite * test __maybe_unused,int subtest __maybe_unused)304 int test__hybrid(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
305 {
306 if (perf_pmus__num_core_pmus() == 1)
307 return TEST_SKIP;
308
309 return test_events(test__hybrid_events, ARRAY_SIZE(test__hybrid_events));
310 }
311