1241675Suqs// SPDX-License-Identifier: GPL-2.0
2241675Suqs#include <stdarg.h>
3241675Suqs#include <stdio.h>
4241675Suqs#include <string.h>
5241675Suqs#include <linux/perf_event.h>
6241675Suqs#include <linux/kernel.h>
7241675Suqs#include <perf/cpumap.h>
8241675Suqs#include <perf/threadmap.h>
9241675Suqs#include <perf/evsel.h>
10241675Suqs#include <internal/evsel.h>
11241675Suqs#include <internal/tests.h>
12241675Suqs#include "tests.h"
13241675Suqs
14241675Suqsstatic int libperf_print(enum libperf_print_level level,
15241675Suqs			 const char *fmt, va_list ap)
16241675Suqs{
17241675Suqs	return vfprintf(stderr, fmt, ap);
18241675Suqs}
19241675Suqs
20241675Suqsstatic int test_stat_cpu(void)
21241675Suqs{
22241675Suqs	struct perf_cpu_map *cpus;
23241675Suqs	struct perf_evsel *evsel;
24241675Suqs	struct perf_event_attr attr = {
25241675Suqs		.type	= PERF_TYPE_SOFTWARE,
26241675Suqs		.config	= PERF_COUNT_SW_CPU_CLOCK,
27241675Suqs	};
28241675Suqs	int err, idx;
29241675Suqs
30241675Suqs	cpus = perf_cpu_map__new_online_cpus();
31241675Suqs	__T("failed to create cpus", cpus);
32241675Suqs
33241675Suqs	evsel = perf_evsel__new(&attr);
34241675Suqs	__T("failed to create evsel", evsel);
35241675Suqs
36241675Suqs	err = perf_evsel__open(evsel, cpus, NULL);
37241675Suqs	__T("failed to open evsel", err == 0);
38241675Suqs
39241675Suqs	for (idx = 0; idx < perf_cpu_map__nr(cpus); idx++) {
40241675Suqs		struct perf_counts_values counts = { .val = 0 };
41241675Suqs
42241675Suqs		perf_evsel__read(evsel, idx, 0, &counts);
43241675Suqs		__T("failed to read value for evsel", counts.val != 0);
44241675Suqs	}
45241675Suqs
46241675Suqs	perf_evsel__close(evsel);
47241675Suqs	perf_evsel__delete(evsel);
48241675Suqs
49241675Suqs	perf_cpu_map__put(cpus);
50241675Suqs	return 0;
51241675Suqs}
52241675Suqs
53241675Suqsstatic int test_stat_thread(void)
54241675Suqs{
55241675Suqs	struct perf_counts_values counts = { .val = 0 };
56241675Suqs	struct perf_thread_map *threads;
57241675Suqs	struct perf_evsel *evsel;
58241675Suqs	struct perf_event_attr attr = {
59241675Suqs		.type	= PERF_TYPE_SOFTWARE,
60241675Suqs		.config	= PERF_COUNT_SW_TASK_CLOCK,
61241675Suqs	};
62241675Suqs	int err;
63241675Suqs
64241675Suqs	threads = perf_thread_map__new_dummy();
65241675Suqs	__T("failed to create threads", threads);
66241675Suqs
67241675Suqs	perf_thread_map__set_pid(threads, 0, 0);
68241675Suqs
69241675Suqs	evsel = perf_evsel__new(&attr);
70241675Suqs	__T("failed to create evsel", evsel);
71241675Suqs
72241675Suqs	err = perf_evsel__open(evsel, NULL, threads);
73241675Suqs	__T("failed to open evsel", err == 0);
74241675Suqs
75241675Suqs	perf_evsel__read(evsel, 0, 0, &counts);
76241675Suqs	__T("failed to read value for evsel", counts.val != 0);
77241675Suqs
78241675Suqs	perf_evsel__close(evsel);
79241675Suqs	perf_evsel__delete(evsel);
80241675Suqs
81241675Suqs	perf_thread_map__put(threads);
82241675Suqs	return 0;
83241675Suqs}
84241675Suqs
85241675Suqsstatic int test_stat_thread_enable(void)
86241675Suqs{
87241675Suqs	struct perf_counts_values counts = { .val = 0 };
88241675Suqs	struct perf_thread_map *threads;
89241675Suqs	struct perf_evsel *evsel;
90241675Suqs	struct perf_event_attr attr = {
91241675Suqs		.type	  = PERF_TYPE_SOFTWARE,
92241675Suqs		.config	  = PERF_COUNT_SW_TASK_CLOCK,
93241675Suqs		.disabled = 1,
94241675Suqs	};
95241675Suqs	int err;
96241675Suqs
97241675Suqs	threads = perf_thread_map__new_dummy();
98241675Suqs	__T("failed to create threads", threads);
99241675Suqs
100241675Suqs	perf_thread_map__set_pid(threads, 0, 0);
101241675Suqs
102241675Suqs	evsel = perf_evsel__new(&attr);
103241675Suqs	__T("failed to create evsel", evsel);
104241675Suqs
105241675Suqs	err = perf_evsel__open(evsel, NULL, threads);
106241675Suqs	__T("failed to open evsel", err == 0);
107241675Suqs
108241675Suqs	perf_evsel__read(evsel, 0, 0, &counts);
109241675Suqs	__T("failed to read value for evsel", counts.val == 0);
110241675Suqs
111241675Suqs	err = perf_evsel__enable(evsel);
112241675Suqs	__T("failed to enable evsel", err == 0);
113241675Suqs
114241675Suqs	perf_evsel__read(evsel, 0, 0, &counts);
115241675Suqs	__T("failed to read value for evsel", counts.val != 0);
116241675Suqs
117241675Suqs	err = perf_evsel__disable(evsel);
118241675Suqs	__T("failed to enable evsel", err == 0);
119241675Suqs
120241675Suqs	perf_evsel__close(evsel);
121241675Suqs	perf_evsel__delete(evsel);
122241675Suqs
123241675Suqs	perf_thread_map__put(threads);
124241675Suqs	return 0;
125241675Suqs}
126241675Suqs
127241675Suqsstatic int test_stat_user_read(int event)
128241675Suqs{
129241675Suqs	struct perf_counts_values counts = { .val = 0 };
130241675Suqs	struct perf_thread_map *threads;
131241675Suqs	struct perf_evsel *evsel;
132241675Suqs	struct perf_event_mmap_page *pc;
133241675Suqs	struct perf_event_attr attr = {
134241675Suqs		.type	= PERF_TYPE_HARDWARE,
135241675Suqs		.config	= event,
136241675Suqs#ifdef __aarch64__
137241675Suqs		.config1 = 0x2,		/* Request user access */
138241675Suqs#endif
139241675Suqs	};
140241675Suqs	int err, i;
141241675Suqs
142241675Suqs	threads = perf_thread_map__new_dummy();
143241675Suqs	__T("failed to create threads", threads);
144241675Suqs
145241675Suqs	perf_thread_map__set_pid(threads, 0, 0);
146241675Suqs
147241675Suqs	evsel = perf_evsel__new(&attr);
148241675Suqs	__T("failed to create evsel", evsel);
149241675Suqs
150241675Suqs	err = perf_evsel__open(evsel, NULL, threads);
151241675Suqs	__T("failed to open evsel", err == 0);
152241675Suqs
153241675Suqs	err = perf_evsel__mmap(evsel, 0);
154241675Suqs	__T("failed to mmap evsel", err == 0);
155241675Suqs
156241675Suqs	pc = perf_evsel__mmap_base(evsel, 0, 0);
157241675Suqs	__T("failed to get mmapped address", pc);
158241675Suqs
159241675Suqs#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
160241675Suqs	__T("userspace counter access not supported", pc->cap_user_rdpmc);
161241675Suqs	__T("userspace counter access not enabled", pc->index);
162241675Suqs	__T("userspace counter width not set", pc->pmc_width >= 32);
163241675Suqs#endif
164241675Suqs
165241675Suqs	perf_evsel__read(evsel, 0, 0, &counts);
166241675Suqs	__T("failed to read value for evsel", counts.val != 0);
167241675Suqs
168241675Suqs	for (i = 0; i < 5; i++) {
169241675Suqs		volatile int count = 0x10000 << i;
170241675Suqs		__u64 start, end, last = 0;
171241675Suqs
172241675Suqs		__T_VERBOSE("\tloop = %u, ", count);
173241675Suqs
174241675Suqs		perf_evsel__read(evsel, 0, 0, &counts);
175241675Suqs		start = counts.val;
176241675Suqs
177241675Suqs		while (count--) ;
178241675Suqs
179241675Suqs		perf_evsel__read(evsel, 0, 0, &counts);
180241675Suqs		end = counts.val;
181241675Suqs
182241675Suqs		__T("invalid counter data", (end - start) > last);
183241675Suqs		last = end - start;
184241675Suqs		__T_VERBOSE("count = %llu\n", end - start);
185241675Suqs	}
186241675Suqs
187241675Suqs	perf_evsel__munmap(evsel);
188241675Suqs	perf_evsel__close(evsel);
189241675Suqs	perf_evsel__delete(evsel);
190241675Suqs
191241675Suqs	perf_thread_map__put(threads);
192241675Suqs	return 0;
193241675Suqs}
194241675Suqs
195241675Suqsstatic int test_stat_read_format_single(struct perf_event_attr *attr, struct perf_thread_map *threads)
196241675Suqs{
197241675Suqs	struct perf_evsel *evsel;
198241675Suqs	struct perf_counts_values counts;
199241675Suqs	volatile int count = 0x100000;
200241675Suqs	int err;
201241675Suqs
202241675Suqs	evsel = perf_evsel__new(attr);
203241675Suqs	__T("failed to create evsel", evsel);
204241675Suqs
205241675Suqs	/* skip old kernels that don't support the format */
206241675Suqs	err = perf_evsel__open(evsel, NULL, threads);
207241675Suqs	if (err < 0)
208241675Suqs		return 0;
209241675Suqs
210241675Suqs	while (count--) ;
211241675Suqs
212241675Suqs	memset(&counts, -1, sizeof(counts));
213241675Suqs	perf_evsel__read(evsel, 0, 0, &counts);
214241675Suqs
215241675Suqs	__T("failed to read value", counts.val);
216241675Suqs	if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
217241675Suqs		__T("failed to read TOTAL_TIME_ENABLED", counts.ena);
218241675Suqs	if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
219241675Suqs		__T("failed to read TOTAL_TIME_RUNNING", counts.run);
220241675Suqs	if (attr->read_format & PERF_FORMAT_ID)
221241675Suqs		__T("failed to read ID", counts.id);
222241675Suqs	if (attr->read_format & PERF_FORMAT_LOST)
223241675Suqs		__T("failed to read LOST", counts.lost == 0);
224241675Suqs
225241675Suqs	perf_evsel__close(evsel);
226241675Suqs	perf_evsel__delete(evsel);
227241675Suqs	return 0;
228241675Suqs}
229241675Suqs
230241675Suqsstatic int test_stat_read_format_group(struct perf_event_attr *attr, struct perf_thread_map *threads)
231241675Suqs{
232241675Suqs	struct perf_evsel *leader, *member;
233241675Suqs	struct perf_counts_values counts;
234241675Suqs	volatile int count = 0x100000;
235241675Suqs	int err;
236241675Suqs
237241675Suqs	attr->read_format |= PERF_FORMAT_GROUP;
238241675Suqs	leader = perf_evsel__new(attr);
239241675Suqs	__T("failed to create leader", leader);
240241675Suqs
241241675Suqs	attr->read_format &= ~PERF_FORMAT_GROUP;
242241675Suqs	member = perf_evsel__new(attr);
243241675Suqs	__T("failed to create member", member);
244241675Suqs
245241675Suqs	member->leader = leader;
246241675Suqs	leader->nr_members = 2;
247241675Suqs
248241675Suqs	/* skip old kernels that don't support the format */
249241675Suqs	err = perf_evsel__open(leader, NULL, threads);
250241675Suqs	if (err < 0)
251241675Suqs		return 0;
252241675Suqs	err = perf_evsel__open(member, NULL, threads);
253241675Suqs	if (err < 0)
254241675Suqs		return 0;
255241675Suqs
256241675Suqs	while (count--) ;
257241675Suqs
258241675Suqs	memset(&counts, -1, sizeof(counts));
259241675Suqs	perf_evsel__read(leader, 0, 0, &counts);
260241675Suqs
261241675Suqs	__T("failed to read leader value", counts.val);
262241675Suqs	if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
263241675Suqs		__T("failed to read leader TOTAL_TIME_ENABLED", counts.ena);
264241675Suqs	if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
265241675Suqs		__T("failed to read leader TOTAL_TIME_RUNNING", counts.run);
266241675Suqs	if (attr->read_format & PERF_FORMAT_ID)
267241675Suqs		__T("failed to read leader ID", counts.id);
268241675Suqs	if (attr->read_format & PERF_FORMAT_LOST)
269241675Suqs		__T("failed to read leader LOST", counts.lost == 0);
270241675Suqs
271241675Suqs	memset(&counts, -1, sizeof(counts));
272241675Suqs	perf_evsel__read(member, 0, 0, &counts);
273241675Suqs
274241675Suqs	__T("failed to read member value", counts.val);
275241675Suqs	if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
276241675Suqs		__T("failed to read member TOTAL_TIME_ENABLED", counts.ena);
277241675Suqs	if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
278241675Suqs		__T("failed to read member TOTAL_TIME_RUNNING", counts.run);
279241675Suqs	if (attr->read_format & PERF_FORMAT_ID)
280241675Suqs		__T("failed to read member ID", counts.id);
281241675Suqs	if (attr->read_format & PERF_FORMAT_LOST)
282241675Suqs		__T("failed to read member LOST", counts.lost == 0);
283241675Suqs
284241675Suqs	perf_evsel__close(member);
285241675Suqs	perf_evsel__close(leader);
286241675Suqs	perf_evsel__delete(member);
287241675Suqs	perf_evsel__delete(leader);
288241675Suqs	return 0;
289241675Suqs}
290241675Suqs
291241675Suqsstatic int test_stat_read_format(void)
292241675Suqs{
293241675Suqs	struct perf_thread_map *threads;
294241675Suqs	struct perf_event_attr attr = {
295241675Suqs		.type	= PERF_TYPE_SOFTWARE,
296241675Suqs		.config	= PERF_COUNT_SW_TASK_CLOCK,
297241675Suqs	};
298241675Suqs	int err, i;
299241675Suqs
300241675Suqs#define FMT(_fmt)  PERF_FORMAT_ ## _fmt
301241675Suqs#define FMT_TIME  (FMT(TOTAL_TIME_ENABLED) | FMT(TOTAL_TIME_RUNNING))
302241675Suqs
303241675Suqs	uint64_t test_formats [] = {
304241675Suqs		0,
305241675Suqs		FMT_TIME,
306241675Suqs		FMT(ID),
307241675Suqs		FMT(LOST),
308241675Suqs		FMT_TIME | FMT(ID),
309241675Suqs		FMT_TIME | FMT(LOST),
310241675Suqs		FMT_TIME | FMT(ID) | FMT(LOST),
311241675Suqs		FMT(ID) | FMT(LOST),
312241675Suqs	};
313241675Suqs
314241675Suqs#undef FMT
315241675Suqs#undef FMT_TIME
316241675Suqs
317241675Suqs	threads = perf_thread_map__new_dummy();
318241675Suqs	__T("failed to create threads", threads);
319241675Suqs
320241675Suqs	perf_thread_map__set_pid(threads, 0, 0);
321241675Suqs
322241675Suqs	for (i = 0; i < (int)ARRAY_SIZE(test_formats); i++) {
323241675Suqs		attr.read_format = test_formats[i];
324241675Suqs		__T_VERBOSE("testing single read with read_format: %lx\n",
325241675Suqs			    (unsigned long)test_formats[i]);
326241675Suqs
327241675Suqs		err = test_stat_read_format_single(&attr, threads);
328241675Suqs		__T("failed to read single format", err == 0);
329241675Suqs	}
330241675Suqs
331241675Suqs	perf_thread_map__put(threads);
332241675Suqs
333241675Suqs	threads = perf_thread_map__new_array(2, NULL);
334241675Suqs	__T("failed to create threads", threads);
335241675Suqs
336241675Suqs	perf_thread_map__set_pid(threads, 0, 0);
337241675Suqs	perf_thread_map__set_pid(threads, 1, 0);
338241675Suqs
339241675Suqs	for (i = 0; i < (int)ARRAY_SIZE(test_formats); i++) {
340241675Suqs		attr.read_format = test_formats[i];
341241675Suqs		__T_VERBOSE("testing group read with read_format: %lx\n",
342241675Suqs			    (unsigned long)test_formats[i]);
343241675Suqs
344241675Suqs		err = test_stat_read_format_group(&attr, threads);
345241675Suqs		__T("failed to read group format", err == 0);
346241675Suqs	}
347241675Suqs
348241675Suqs	perf_thread_map__put(threads);
349241675Suqs	return 0;
350241675Suqs}
351241675Suqs
352241675Suqsint test_evsel(int argc, char **argv)
353241675Suqs{
354241675Suqs	__T_START;
355241675Suqs
356241675Suqs	libperf_init(libperf_print);
357241675Suqs
358241675Suqs	test_stat_cpu();
359241675Suqs	test_stat_thread();
360241675Suqs	test_stat_thread_enable();
361241675Suqs	test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS);
362241675Suqs	test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES);
363241675Suqs	test_stat_read_format();
364241675Suqs
365241675Suqs	__T_END;
366241675Suqs	return tests_failed == 0 ? 0 : -1;
367241675Suqs}
368241675Suqs