1// SPDX-License-Identifier: GPL-2.0
2#include <stdarg.h>
3#include <stdio.h>
4#include <string.h>
5#include <linux/perf_event.h>
6#include <linux/kernel.h>
7#include <perf/cpumap.h>
8#include <perf/threadmap.h>
9#include <perf/evsel.h>
10#include <internal/evsel.h>
11#include <internal/tests.h>
12#include "tests.h"
13
14static int libperf_print(enum libperf_print_level level,
15			 const char *fmt, va_list ap)
16{
17	return vfprintf(stderr, fmt, ap);
18}
19
20static int test_stat_cpu(void)
21{
22	struct perf_cpu_map *cpus;
23	struct perf_evsel *evsel;
24	struct perf_event_attr attr = {
25		.type	= PERF_TYPE_SOFTWARE,
26		.config	= PERF_COUNT_SW_CPU_CLOCK,
27	};
28	int err, idx;
29
30	cpus = perf_cpu_map__new_online_cpus();
31	__T("failed to create cpus", cpus);
32
33	evsel = perf_evsel__new(&attr);
34	__T("failed to create evsel", evsel);
35
36	err = perf_evsel__open(evsel, cpus, NULL);
37	__T("failed to open evsel", err == 0);
38
39	for (idx = 0; idx < perf_cpu_map__nr(cpus); idx++) {
40		struct perf_counts_values counts = { .val = 0 };
41
42		perf_evsel__read(evsel, idx, 0, &counts);
43		__T("failed to read value for evsel", counts.val != 0);
44	}
45
46	perf_evsel__close(evsel);
47	perf_evsel__delete(evsel);
48
49	perf_cpu_map__put(cpus);
50	return 0;
51}
52
53static int test_stat_thread(void)
54{
55	struct perf_counts_values counts = { .val = 0 };
56	struct perf_thread_map *threads;
57	struct perf_evsel *evsel;
58	struct perf_event_attr attr = {
59		.type	= PERF_TYPE_SOFTWARE,
60		.config	= PERF_COUNT_SW_TASK_CLOCK,
61	};
62	int err;
63
64	threads = perf_thread_map__new_dummy();
65	__T("failed to create threads", threads);
66
67	perf_thread_map__set_pid(threads, 0, 0);
68
69	evsel = perf_evsel__new(&attr);
70	__T("failed to create evsel", evsel);
71
72	err = perf_evsel__open(evsel, NULL, threads);
73	__T("failed to open evsel", err == 0);
74
75	perf_evsel__read(evsel, 0, 0, &counts);
76	__T("failed to read value for evsel", counts.val != 0);
77
78	perf_evsel__close(evsel);
79	perf_evsel__delete(evsel);
80
81	perf_thread_map__put(threads);
82	return 0;
83}
84
85static int test_stat_thread_enable(void)
86{
87	struct perf_counts_values counts = { .val = 0 };
88	struct perf_thread_map *threads;
89	struct perf_evsel *evsel;
90	struct perf_event_attr attr = {
91		.type	  = PERF_TYPE_SOFTWARE,
92		.config	  = PERF_COUNT_SW_TASK_CLOCK,
93		.disabled = 1,
94	};
95	int err;
96
97	threads = perf_thread_map__new_dummy();
98	__T("failed to create threads", threads);
99
100	perf_thread_map__set_pid(threads, 0, 0);
101
102	evsel = perf_evsel__new(&attr);
103	__T("failed to create evsel", evsel);
104
105	err = perf_evsel__open(evsel, NULL, threads);
106	__T("failed to open evsel", err == 0);
107
108	perf_evsel__read(evsel, 0, 0, &counts);
109	__T("failed to read value for evsel", counts.val == 0);
110
111	err = perf_evsel__enable(evsel);
112	__T("failed to enable evsel", err == 0);
113
114	perf_evsel__read(evsel, 0, 0, &counts);
115	__T("failed to read value for evsel", counts.val != 0);
116
117	err = perf_evsel__disable(evsel);
118	__T("failed to enable evsel", err == 0);
119
120	perf_evsel__close(evsel);
121	perf_evsel__delete(evsel);
122
123	perf_thread_map__put(threads);
124	return 0;
125}
126
127static int test_stat_user_read(int event)
128{
129	struct perf_counts_values counts = { .val = 0 };
130	struct perf_thread_map *threads;
131	struct perf_evsel *evsel;
132	struct perf_event_mmap_page *pc;
133	struct perf_event_attr attr = {
134		.type	= PERF_TYPE_HARDWARE,
135		.config	= event,
136#ifdef __aarch64__
137		.config1 = 0x2,		/* Request user access */
138#endif
139	};
140	int err, i;
141
142	threads = perf_thread_map__new_dummy();
143	__T("failed to create threads", threads);
144
145	perf_thread_map__set_pid(threads, 0, 0);
146
147	evsel = perf_evsel__new(&attr);
148	__T("failed to create evsel", evsel);
149
150	err = perf_evsel__open(evsel, NULL, threads);
151	__T("failed to open evsel", err == 0);
152
153	err = perf_evsel__mmap(evsel, 0);
154	__T("failed to mmap evsel", err == 0);
155
156	pc = perf_evsel__mmap_base(evsel, 0, 0);
157	__T("failed to get mmapped address", pc);
158
159#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
160	__T("userspace counter access not supported", pc->cap_user_rdpmc);
161	__T("userspace counter access not enabled", pc->index);
162	__T("userspace counter width not set", pc->pmc_width >= 32);
163#endif
164
165	perf_evsel__read(evsel, 0, 0, &counts);
166	__T("failed to read value for evsel", counts.val != 0);
167
168	for (i = 0; i < 5; i++) {
169		volatile int count = 0x10000 << i;
170		__u64 start, end, last = 0;
171
172		__T_VERBOSE("\tloop = %u, ", count);
173
174		perf_evsel__read(evsel, 0, 0, &counts);
175		start = counts.val;
176
177		while (count--) ;
178
179		perf_evsel__read(evsel, 0, 0, &counts);
180		end = counts.val;
181
182		__T("invalid counter data", (end - start) > last);
183		last = end - start;
184		__T_VERBOSE("count = %llu\n", end - start);
185	}
186
187	perf_evsel__munmap(evsel);
188	perf_evsel__close(evsel);
189	perf_evsel__delete(evsel);
190
191	perf_thread_map__put(threads);
192	return 0;
193}
194
195static int test_stat_read_format_single(struct perf_event_attr *attr, struct perf_thread_map *threads)
196{
197	struct perf_evsel *evsel;
198	struct perf_counts_values counts;
199	volatile int count = 0x100000;
200	int err;
201
202	evsel = perf_evsel__new(attr);
203	__T("failed to create evsel", evsel);
204
205	/* skip old kernels that don't support the format */
206	err = perf_evsel__open(evsel, NULL, threads);
207	if (err < 0)
208		return 0;
209
210	while (count--) ;
211
212	memset(&counts, -1, sizeof(counts));
213	perf_evsel__read(evsel, 0, 0, &counts);
214
215	__T("failed to read value", counts.val);
216	if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
217		__T("failed to read TOTAL_TIME_ENABLED", counts.ena);
218	if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
219		__T("failed to read TOTAL_TIME_RUNNING", counts.run);
220	if (attr->read_format & PERF_FORMAT_ID)
221		__T("failed to read ID", counts.id);
222	if (attr->read_format & PERF_FORMAT_LOST)
223		__T("failed to read LOST", counts.lost == 0);
224
225	perf_evsel__close(evsel);
226	perf_evsel__delete(evsel);
227	return 0;
228}
229
230static int test_stat_read_format_group(struct perf_event_attr *attr, struct perf_thread_map *threads)
231{
232	struct perf_evsel *leader, *member;
233	struct perf_counts_values counts;
234	volatile int count = 0x100000;
235	int err;
236
237	attr->read_format |= PERF_FORMAT_GROUP;
238	leader = perf_evsel__new(attr);
239	__T("failed to create leader", leader);
240
241	attr->read_format &= ~PERF_FORMAT_GROUP;
242	member = perf_evsel__new(attr);
243	__T("failed to create member", member);
244
245	member->leader = leader;
246	leader->nr_members = 2;
247
248	/* skip old kernels that don't support the format */
249	err = perf_evsel__open(leader, NULL, threads);
250	if (err < 0)
251		return 0;
252	err = perf_evsel__open(member, NULL, threads);
253	if (err < 0)
254		return 0;
255
256	while (count--) ;
257
258	memset(&counts, -1, sizeof(counts));
259	perf_evsel__read(leader, 0, 0, &counts);
260
261	__T("failed to read leader value", counts.val);
262	if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
263		__T("failed to read leader TOTAL_TIME_ENABLED", counts.ena);
264	if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
265		__T("failed to read leader TOTAL_TIME_RUNNING", counts.run);
266	if (attr->read_format & PERF_FORMAT_ID)
267		__T("failed to read leader ID", counts.id);
268	if (attr->read_format & PERF_FORMAT_LOST)
269		__T("failed to read leader LOST", counts.lost == 0);
270
271	memset(&counts, -1, sizeof(counts));
272	perf_evsel__read(member, 0, 0, &counts);
273
274	__T("failed to read member value", counts.val);
275	if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
276		__T("failed to read member TOTAL_TIME_ENABLED", counts.ena);
277	if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
278		__T("failed to read member TOTAL_TIME_RUNNING", counts.run);
279	if (attr->read_format & PERF_FORMAT_ID)
280		__T("failed to read member ID", counts.id);
281	if (attr->read_format & PERF_FORMAT_LOST)
282		__T("failed to read member LOST", counts.lost == 0);
283
284	perf_evsel__close(member);
285	perf_evsel__close(leader);
286	perf_evsel__delete(member);
287	perf_evsel__delete(leader);
288	return 0;
289}
290
291static int test_stat_read_format(void)
292{
293	struct perf_thread_map *threads;
294	struct perf_event_attr attr = {
295		.type	= PERF_TYPE_SOFTWARE,
296		.config	= PERF_COUNT_SW_TASK_CLOCK,
297	};
298	int err, i;
299
300#define FMT(_fmt)  PERF_FORMAT_ ## _fmt
301#define FMT_TIME  (FMT(TOTAL_TIME_ENABLED) | FMT(TOTAL_TIME_RUNNING))
302
303	uint64_t test_formats [] = {
304		0,
305		FMT_TIME,
306		FMT(ID),
307		FMT(LOST),
308		FMT_TIME | FMT(ID),
309		FMT_TIME | FMT(LOST),
310		FMT_TIME | FMT(ID) | FMT(LOST),
311		FMT(ID) | FMT(LOST),
312	};
313
314#undef FMT
315#undef FMT_TIME
316
317	threads = perf_thread_map__new_dummy();
318	__T("failed to create threads", threads);
319
320	perf_thread_map__set_pid(threads, 0, 0);
321
322	for (i = 0; i < (int)ARRAY_SIZE(test_formats); i++) {
323		attr.read_format = test_formats[i];
324		__T_VERBOSE("testing single read with read_format: %lx\n",
325			    (unsigned long)test_formats[i]);
326
327		err = test_stat_read_format_single(&attr, threads);
328		__T("failed to read single format", err == 0);
329	}
330
331	perf_thread_map__put(threads);
332
333	threads = perf_thread_map__new_array(2, NULL);
334	__T("failed to create threads", threads);
335
336	perf_thread_map__set_pid(threads, 0, 0);
337	perf_thread_map__set_pid(threads, 1, 0);
338
339	for (i = 0; i < (int)ARRAY_SIZE(test_formats); i++) {
340		attr.read_format = test_formats[i];
341		__T_VERBOSE("testing group read with read_format: %lx\n",
342			    (unsigned long)test_formats[i]);
343
344		err = test_stat_read_format_group(&attr, threads);
345		__T("failed to read group format", err == 0);
346	}
347
348	perf_thread_map__put(threads);
349	return 0;
350}
351
352int test_evsel(int argc, char **argv)
353{
354	__T_START;
355
356	libperf_init(libperf_print);
357
358	test_stat_cpu();
359	test_stat_thread();
360	test_stat_thread_enable();
361	test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS);
362	test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES);
363	test_stat_read_format();
364
365	__T_END;
366	return tests_failed == 0 ? 0 : -1;
367}
368