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 
libperf_print(enum libperf_print_level level,const char * fmt,va_list ap)14 static int libperf_print(enum libperf_print_level level,
15 			 const char *fmt, va_list ap)
16 {
17 	return vfprintf(stderr, fmt, ap);
18 }
19 
test_stat_cpu(void)20 static 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(NULL);
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 
test_stat_thread(void)53 static 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 
test_stat_thread_enable(void)85 static 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 
test_stat_user_read(int event)127 static 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 
test_stat_read_format_single(struct perf_event_attr * attr,struct perf_thread_map * threads)195 static 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 
test_stat_read_format_group(struct perf_event_attr * attr,struct perf_thread_map * threads)230 static 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 
test_stat_read_format(void)291 static 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 
test_evsel(int argc,char ** argv)352 int 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