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_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_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
166 struct evlist_test {
167 const char *name;
168 bool (*valid)(void);
169 int (*check)(struct evlist *evlist);
170 };
171
172 static const struct evlist_test test__hybrid_events[] = {
173 {
174 .name = "cpu_core/cpu-cycles/",
175 .check = test__hybrid_hw_event_with_pmu,
176 /* 0 */
177 },
178 {
179 .name = "{cpu_core/cpu-cycles/,cpu_core/instructions/}",
180 .check = test__hybrid_hw_group_event,
181 /* 1 */
182 },
183 {
184 .name = "{cpu-clock,cpu_core/cpu-cycles/}",
185 .check = test__hybrid_sw_hw_group_event,
186 /* 2 */
187 },
188 {
189 .name = "{cpu_core/cpu-cycles/,cpu-clock}",
190 .check = test__hybrid_hw_sw_group_event,
191 /* 3 */
192 },
193 {
194 .name = "{cpu_core/cpu-cycles/k,cpu_core/instructions/u}",
195 .check = test__hybrid_group_modifier1,
196 /* 4 */
197 },
198 {
199 .name = "r1a",
200 .check = test__hybrid_raw1,
201 /* 5 */
202 },
203 {
204 .name = "cpu_core/r1a/",
205 .check = test__hybrid_raw2,
206 /* 6 */
207 },
208 {
209 .name = "cpu_core/config=10,config1,config2=3,period=1000/u",
210 .check = test__checkevent_pmu,
211 /* 7 */
212 },
213 {
214 .name = "cpu_core/LLC-loads/",
215 .check = test__hybrid_cache_event,
216 /* 8 */
217 },
218 };
219
test_event(const struct evlist_test * e)220 static int test_event(const struct evlist_test *e)
221 {
222 struct parse_events_error err;
223 struct evlist *evlist;
224 int ret;
225
226 if (e->valid && !e->valid()) {
227 pr_debug("... SKIP\n");
228 return TEST_OK;
229 }
230
231 evlist = evlist__new();
232 if (evlist == NULL) {
233 pr_err("Failed allocation");
234 return TEST_FAIL;
235 }
236 parse_events_error__init(&err);
237 ret = parse_events(evlist, e->name, &err);
238 if (ret) {
239 pr_debug("failed to parse event '%s', err %d, str '%s'\n",
240 e->name, ret, err.str);
241 parse_events_error__print(&err, e->name);
242 ret = TEST_FAIL;
243 if (strstr(err.str, "can't access trace events"))
244 ret = TEST_SKIP;
245 } else {
246 ret = e->check(evlist);
247 }
248 parse_events_error__exit(&err);
249 evlist__delete(evlist);
250
251 return ret;
252 }
253
combine_test_results(int existing,int latest)254 static int combine_test_results(int existing, int latest)
255 {
256 if (existing == TEST_FAIL)
257 return TEST_FAIL;
258 if (existing == TEST_SKIP)
259 return latest == TEST_OK ? TEST_SKIP : latest;
260 return latest;
261 }
262
test_events(const struct evlist_test * events,int cnt)263 static int test_events(const struct evlist_test *events, int cnt)
264 {
265 int ret = TEST_OK;
266
267 for (int i = 0; i < cnt; i++) {
268 const struct evlist_test *e = &events[i];
269 int test_ret;
270
271 pr_debug("running test %d '%s'\n", i, e->name);
272 test_ret = test_event(e);
273 if (test_ret != TEST_OK) {
274 pr_debug("Event test failure: test %d '%s'", i, e->name);
275 ret = combine_test_results(ret, test_ret);
276 }
277 }
278
279 return ret;
280 }
281
test__hybrid(struct test_suite * test __maybe_unused,int subtest __maybe_unused)282 int test__hybrid(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
283 {
284 if (perf_pmus__num_core_pmus() == 1)
285 return TEST_SKIP;
286
287 return test_events(test__hybrid_events, ARRAY_SIZE(test__hybrid_events));
288 }
289