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