xref: /openbmc/linux/tools/lib/perf/tests/test-evlist.c (revision dfc66bef)
1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE // needed for sched.h to get sched_[gs]etaffinity and CPU_(ZERO,SET)
3 #include <sched.h>
4 #include <stdio.h>
5 #include <stdarg.h>
6 #include <unistd.h>
7 #include <stdlib.h>
8 #include <linux/perf_event.h>
9 #include <linux/limits.h>
10 #include <sys/types.h>
11 #include <sys/wait.h>
12 #include <sys/prctl.h>
13 #include <perf/cpumap.h>
14 #include <perf/threadmap.h>
15 #include <perf/evlist.h>
16 #include <perf/evsel.h>
17 #include <perf/mmap.h>
18 #include <perf/event.h>
19 #include <internal/tests.h>
20 #include <api/fs/fs.h>
21 #include "tests.h"
22 #include <internal/evsel.h>
23 
24 #define EVENT_NUM 15
25 #define WAIT_COUNT 100000000UL
26 
27 static int libperf_print(enum libperf_print_level level,
28 			 const char *fmt, va_list ap)
29 {
30 	return vfprintf(stderr, fmt, ap);
31 }
32 
33 static int test_stat_cpu(void)
34 {
35 	struct perf_cpu_map *cpus;
36 	struct perf_evlist *evlist;
37 	struct perf_evsel *evsel, *leader;
38 	struct perf_event_attr attr1 = {
39 		.type	= PERF_TYPE_SOFTWARE,
40 		.config	= PERF_COUNT_SW_CPU_CLOCK,
41 	};
42 	struct perf_event_attr attr2 = {
43 		.type	= PERF_TYPE_SOFTWARE,
44 		.config	= PERF_COUNT_SW_TASK_CLOCK,
45 	};
46 	int err, idx;
47 
48 	cpus = perf_cpu_map__new(NULL);
49 	__T("failed to create cpus", cpus);
50 
51 	evlist = perf_evlist__new();
52 	__T("failed to create evlist", evlist);
53 
54 	evsel = leader = perf_evsel__new(&attr1);
55 	__T("failed to create evsel1", evsel);
56 
57 	perf_evlist__add(evlist, evsel);
58 
59 	evsel = perf_evsel__new(&attr2);
60 	__T("failed to create evsel2", evsel);
61 
62 	perf_evlist__add(evlist, evsel);
63 
64 	perf_evlist__set_leader(evlist);
65 	__T("failed to set leader", leader->leader == leader);
66 	__T("failed to set leader", evsel->leader  == leader);
67 
68 	perf_evlist__set_maps(evlist, cpus, NULL);
69 
70 	err = perf_evlist__open(evlist);
71 	__T("failed to open evsel", err == 0);
72 
73 	perf_evlist__for_each_evsel(evlist, evsel) {
74 		cpus = perf_evsel__cpus(evsel);
75 
76 		for (idx = 0; idx < perf_cpu_map__nr(cpus); idx++) {
77 			struct perf_counts_values counts = { .val = 0 };
78 
79 			perf_evsel__read(evsel, idx, 0, &counts);
80 			__T("failed to read value for evsel", counts.val != 0);
81 		}
82 	}
83 
84 	perf_evlist__close(evlist);
85 	perf_evlist__delete(evlist);
86 
87 	perf_cpu_map__put(cpus);
88 	return 0;
89 }
90 
91 static int test_stat_thread(void)
92 {
93 	struct perf_counts_values counts = { .val = 0 };
94 	struct perf_thread_map *threads;
95 	struct perf_evlist *evlist;
96 	struct perf_evsel *evsel, *leader;
97 	struct perf_event_attr attr1 = {
98 		.type	= PERF_TYPE_SOFTWARE,
99 		.config	= PERF_COUNT_SW_CPU_CLOCK,
100 	};
101 	struct perf_event_attr attr2 = {
102 		.type	= PERF_TYPE_SOFTWARE,
103 		.config	= PERF_COUNT_SW_TASK_CLOCK,
104 	};
105 	int err;
106 
107 	threads = perf_thread_map__new_dummy();
108 	__T("failed to create threads", threads);
109 
110 	perf_thread_map__set_pid(threads, 0, 0);
111 
112 	evlist = perf_evlist__new();
113 	__T("failed to create evlist", evlist);
114 
115 	evsel = leader = perf_evsel__new(&attr1);
116 	__T("failed to create evsel1", evsel);
117 
118 	perf_evlist__add(evlist, evsel);
119 
120 	evsel = perf_evsel__new(&attr2);
121 	__T("failed to create evsel2", evsel);
122 
123 	perf_evlist__add(evlist, evsel);
124 
125 	perf_evlist__set_leader(evlist);
126 	__T("failed to set leader", leader->leader == leader);
127 	__T("failed to set leader", evsel->leader  == leader);
128 
129 	perf_evlist__set_maps(evlist, NULL, threads);
130 
131 	err = perf_evlist__open(evlist);
132 	__T("failed to open evsel", err == 0);
133 
134 	perf_evlist__for_each_evsel(evlist, evsel) {
135 		perf_evsel__read(evsel, 0, 0, &counts);
136 		__T("failed to read value for evsel", counts.val != 0);
137 	}
138 
139 	perf_evlist__close(evlist);
140 	perf_evlist__delete(evlist);
141 
142 	perf_thread_map__put(threads);
143 	return 0;
144 }
145 
146 static int test_stat_thread_enable(void)
147 {
148 	struct perf_counts_values counts = { .val = 0 };
149 	struct perf_thread_map *threads;
150 	struct perf_evlist *evlist;
151 	struct perf_evsel *evsel, *leader;
152 	struct perf_event_attr attr1 = {
153 		.type	  = PERF_TYPE_SOFTWARE,
154 		.config	  = PERF_COUNT_SW_CPU_CLOCK,
155 		.disabled = 1,
156 	};
157 	struct perf_event_attr attr2 = {
158 		.type	  = PERF_TYPE_SOFTWARE,
159 		.config	  = PERF_COUNT_SW_TASK_CLOCK,
160 		.disabled = 1,
161 	};
162 	int err;
163 
164 	threads = perf_thread_map__new_dummy();
165 	__T("failed to create threads", threads);
166 
167 	perf_thread_map__set_pid(threads, 0, 0);
168 
169 	evlist = perf_evlist__new();
170 	__T("failed to create evlist", evlist);
171 
172 	evsel = leader = perf_evsel__new(&attr1);
173 	__T("failed to create evsel1", evsel);
174 
175 	perf_evlist__add(evlist, evsel);
176 
177 	evsel = perf_evsel__new(&attr2);
178 	__T("failed to create evsel2", evsel);
179 
180 	perf_evlist__add(evlist, evsel);
181 
182 	perf_evlist__set_leader(evlist);
183 	__T("failed to set leader", leader->leader == leader);
184 	__T("failed to set leader", evsel->leader  == leader);
185 
186 	perf_evlist__set_maps(evlist, NULL, threads);
187 
188 	err = perf_evlist__open(evlist);
189 	__T("failed to open evsel", err == 0);
190 
191 	perf_evlist__for_each_evsel(evlist, evsel) {
192 		perf_evsel__read(evsel, 0, 0, &counts);
193 		__T("failed to read value for evsel", counts.val == 0);
194 	}
195 
196 	perf_evlist__enable(evlist);
197 
198 	perf_evlist__for_each_evsel(evlist, evsel) {
199 		perf_evsel__read(evsel, 0, 0, &counts);
200 		__T("failed to read value for evsel", counts.val != 0);
201 	}
202 
203 	perf_evlist__disable(evlist);
204 
205 	perf_evlist__close(evlist);
206 	perf_evlist__delete(evlist);
207 
208 	perf_thread_map__put(threads);
209 	return 0;
210 }
211 
212 static int test_mmap_thread(void)
213 {
214 	struct perf_evlist *evlist;
215 	struct perf_evsel *evsel;
216 	struct perf_mmap *map;
217 	struct perf_cpu_map *cpus;
218 	struct perf_thread_map *threads;
219 	struct perf_event_attr attr = {
220 		.type             = PERF_TYPE_TRACEPOINT,
221 		.sample_period    = 1,
222 		.wakeup_watermark = 1,
223 		.disabled         = 1,
224 	};
225 	char path[PATH_MAX];
226 	int id, err, pid, go_pipe[2];
227 	union perf_event *event;
228 	int count = 0;
229 
230 	snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id",
231 		 sysfs__mountpoint());
232 
233 	if (filename__read_int(path, &id)) {
234 		tests_failed++;
235 		fprintf(stderr, "error: failed to get tracepoint id: %s\n", path);
236 		return -1;
237 	}
238 
239 	attr.config = id;
240 
241 	err = pipe(go_pipe);
242 	__T("failed to create pipe", err == 0);
243 
244 	fflush(NULL);
245 
246 	pid = fork();
247 	if (!pid) {
248 		int i;
249 		char bf;
250 
251 		read(go_pipe[0], &bf, 1);
252 
253 		/* Generate 100 prctl calls. */
254 		for (i = 0; i < 100; i++)
255 			prctl(0, 0, 0, 0, 0);
256 
257 		exit(0);
258 	}
259 
260 	threads = perf_thread_map__new_dummy();
261 	__T("failed to create threads", threads);
262 
263 	cpus = perf_cpu_map__dummy_new();
264 	__T("failed to create cpus", cpus);
265 
266 	perf_thread_map__set_pid(threads, 0, pid);
267 
268 	evlist = perf_evlist__new();
269 	__T("failed to create evlist", evlist);
270 
271 	evsel = perf_evsel__new(&attr);
272 	__T("failed to create evsel1", evsel);
273 	__T("failed to set leader", evsel->leader == evsel);
274 
275 	perf_evlist__add(evlist, evsel);
276 
277 	perf_evlist__set_maps(evlist, cpus, threads);
278 
279 	err = perf_evlist__open(evlist);
280 	__T("failed to open evlist", err == 0);
281 
282 	err = perf_evlist__mmap(evlist, 4);
283 	__T("failed to mmap evlist", err == 0);
284 
285 	perf_evlist__enable(evlist);
286 
287 	/* kick the child and wait for it to finish */
288 	write(go_pipe[1], "A", 1);
289 	waitpid(pid, NULL, 0);
290 
291 	/*
292 	 * There's no need to call perf_evlist__disable,
293 	 * monitored process is dead now.
294 	 */
295 
296 	perf_evlist__for_each_mmap(evlist, map, false) {
297 		if (perf_mmap__read_init(map) < 0)
298 			continue;
299 
300 		while ((event = perf_mmap__read_event(map)) != NULL) {
301 			count++;
302 			perf_mmap__consume(map);
303 		}
304 
305 		perf_mmap__read_done(map);
306 	}
307 
308 	/* calls perf_evlist__munmap/perf_evlist__close */
309 	perf_evlist__delete(evlist);
310 
311 	perf_thread_map__put(threads);
312 	perf_cpu_map__put(cpus);
313 
314 	/*
315 	 * The generated prctl calls should match the
316 	 * number of events in the buffer.
317 	 */
318 	__T("failed count", count == 100);
319 
320 	return 0;
321 }
322 
323 static int test_mmap_cpus(void)
324 {
325 	struct perf_evlist *evlist;
326 	struct perf_evsel *evsel;
327 	struct perf_mmap *map;
328 	struct perf_cpu_map *cpus;
329 	struct perf_event_attr attr = {
330 		.type             = PERF_TYPE_TRACEPOINT,
331 		.sample_period    = 1,
332 		.wakeup_watermark = 1,
333 		.disabled         = 1,
334 	};
335 	cpu_set_t saved_mask;
336 	char path[PATH_MAX];
337 	int id, err, cpu, tmp;
338 	union perf_event *event;
339 	int count = 0;
340 
341 	snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id",
342 		 sysfs__mountpoint());
343 
344 	if (filename__read_int(path, &id)) {
345 		fprintf(stderr, "error: failed to get tracepoint id: %s\n", path);
346 		return -1;
347 	}
348 
349 	attr.config = id;
350 
351 	cpus = perf_cpu_map__new(NULL);
352 	__T("failed to create cpus", cpus);
353 
354 	evlist = perf_evlist__new();
355 	__T("failed to create evlist", evlist);
356 
357 	evsel = perf_evsel__new(&attr);
358 	__T("failed to create evsel1", evsel);
359 	__T("failed to set leader", evsel->leader == evsel);
360 
361 	perf_evlist__add(evlist, evsel);
362 
363 	perf_evlist__set_maps(evlist, cpus, NULL);
364 
365 	err = perf_evlist__open(evlist);
366 	__T("failed to open evlist", err == 0);
367 
368 	err = perf_evlist__mmap(evlist, 4);
369 	__T("failed to mmap evlist", err == 0);
370 
371 	perf_evlist__enable(evlist);
372 
373 	err = sched_getaffinity(0, sizeof(saved_mask), &saved_mask);
374 	__T("sched_getaffinity failed", err == 0);
375 
376 	perf_cpu_map__for_each_cpu(cpu, tmp, cpus) {
377 		cpu_set_t mask;
378 
379 		CPU_ZERO(&mask);
380 		CPU_SET(cpu, &mask);
381 
382 		err = sched_setaffinity(0, sizeof(mask), &mask);
383 		__T("sched_setaffinity failed", err == 0);
384 
385 		prctl(0, 0, 0, 0, 0);
386 	}
387 
388 	err = sched_setaffinity(0, sizeof(saved_mask), &saved_mask);
389 	__T("sched_setaffinity failed", err == 0);
390 
391 	perf_evlist__disable(evlist);
392 
393 	perf_evlist__for_each_mmap(evlist, map, false) {
394 		if (perf_mmap__read_init(map) < 0)
395 			continue;
396 
397 		while ((event = perf_mmap__read_event(map)) != NULL) {
398 			count++;
399 			perf_mmap__consume(map);
400 		}
401 
402 		perf_mmap__read_done(map);
403 	}
404 
405 	/* calls perf_evlist__munmap/perf_evlist__close */
406 	perf_evlist__delete(evlist);
407 
408 	/*
409 	 * The generated prctl events should match the
410 	 * number of cpus or be bigger (we are system-wide).
411 	 */
412 	__T("failed count", count >= perf_cpu_map__nr(cpus));
413 
414 	perf_cpu_map__put(cpus);
415 
416 	return 0;
417 }
418 
419 static double display_error(long long average,
420 			    long long high,
421 			    long long low,
422 			    long long expected)
423 {
424 	double error;
425 
426 	error = (((double)average - expected) / expected) * 100.0;
427 
428 	__T_VERBOSE("   Expected: %lld\n", expected);
429 	__T_VERBOSE("   High: %lld   Low:  %lld   Average:  %lld\n",
430 		    high, low, average);
431 
432 	__T_VERBOSE("   Average Error = %.2f%%\n", error);
433 
434 	return error;
435 }
436 
437 static int test_stat_multiplexing(void)
438 {
439 	struct perf_counts_values expected_counts = { .val = 0 };
440 	struct perf_counts_values counts[EVENT_NUM] = {{ .val = 0 },};
441 	struct perf_thread_map *threads;
442 	struct perf_evlist *evlist;
443 	struct perf_evsel *evsel;
444 	struct perf_event_attr attr = {
445 		.type	     = PERF_TYPE_HARDWARE,
446 		.config	     = PERF_COUNT_HW_INSTRUCTIONS,
447 		.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
448 			       PERF_FORMAT_TOTAL_TIME_RUNNING,
449 		.disabled    = 1,
450 	};
451 	int err, i, nonzero = 0;
452 	unsigned long count;
453 	long long max = 0, min = 0, avg = 0;
454 	double error = 0.0;
455 	s8 scaled = 0;
456 
457 	/* read for non-multiplexing event count */
458 	threads = perf_thread_map__new_dummy();
459 	__T("failed to create threads", threads);
460 
461 	perf_thread_map__set_pid(threads, 0, 0);
462 
463 	evsel = perf_evsel__new(&attr);
464 	__T("failed to create evsel", evsel);
465 
466 	err = perf_evsel__open(evsel, NULL, threads);
467 	__T("failed to open evsel", err == 0);
468 
469 	err = perf_evsel__enable(evsel);
470 	__T("failed to enable evsel", err == 0);
471 
472 	/* wait loop */
473 	count = WAIT_COUNT;
474 	while (count--)
475 		;
476 
477 	perf_evsel__read(evsel, 0, 0, &expected_counts);
478 	__T("failed to read value for evsel", expected_counts.val != 0);
479 	__T("failed to read non-multiplexing event count",
480 	    expected_counts.ena == expected_counts.run);
481 
482 	err = perf_evsel__disable(evsel);
483 	__T("failed to enable evsel", err == 0);
484 
485 	perf_evsel__close(evsel);
486 	perf_evsel__delete(evsel);
487 
488 	perf_thread_map__put(threads);
489 
490 	/* read for multiplexing event count */
491 	threads = perf_thread_map__new_dummy();
492 	__T("failed to create threads", threads);
493 
494 	perf_thread_map__set_pid(threads, 0, 0);
495 
496 	evlist = perf_evlist__new();
497 	__T("failed to create evlist", evlist);
498 
499 	for (i = 0; i < EVENT_NUM; i++) {
500 		evsel = perf_evsel__new(&attr);
501 		__T("failed to create evsel", evsel);
502 
503 		perf_evlist__add(evlist, evsel);
504 	}
505 	perf_evlist__set_maps(evlist, NULL, threads);
506 
507 	err = perf_evlist__open(evlist);
508 	__T("failed to open evsel", err == 0);
509 
510 	perf_evlist__enable(evlist);
511 
512 	/* wait loop */
513 	count = WAIT_COUNT;
514 	while (count--)
515 		;
516 
517 	i = 0;
518 	perf_evlist__for_each_evsel(evlist, evsel) {
519 		perf_evsel__read(evsel, 0, 0, &counts[i]);
520 		__T("failed to read value for evsel", counts[i].val != 0);
521 		i++;
522 	}
523 
524 	perf_evlist__disable(evlist);
525 
526 	min = counts[0].val;
527 	for (i = 0; i < EVENT_NUM; i++) {
528 		__T_VERBOSE("Event %2d -- Raw count = %lu, run = %lu, enable = %lu\n",
529 			    i, counts[i].val, counts[i].run, counts[i].ena);
530 
531 		perf_counts_values__scale(&counts[i], true, &scaled);
532 		if (scaled == 1) {
533 			__T_VERBOSE("\t Scaled count = %lu (%.2lf%%, %lu/%lu)\n",
534 				    counts[i].val,
535 				    (double)counts[i].run / (double)counts[i].ena * 100.0,
536 				    counts[i].run, counts[i].ena);
537 		} else if (scaled == -1) {
538 			__T_VERBOSE("\t Not Running\n");
539 		} else {
540 			__T_VERBOSE("\t Not Scaling\n");
541 		}
542 
543 		if (counts[i].val > max)
544 			max = counts[i].val;
545 
546 		if (counts[i].val < min)
547 			min = counts[i].val;
548 
549 		avg += counts[i].val;
550 
551 		if (counts[i].val != 0)
552 			nonzero++;
553 	}
554 
555 	if (nonzero != 0)
556 		avg = avg / nonzero;
557 	else
558 		avg = 0;
559 
560 	error = display_error(avg, max, min, expected_counts.val);
561 
562 	__T("Error out of range!", ((error <= 1.0) && (error >= -1.0)));
563 
564 	perf_evlist__close(evlist);
565 	perf_evlist__delete(evlist);
566 
567 	perf_thread_map__put(threads);
568 
569 	return 0;
570 }
571 
572 int test_evlist(int argc, char **argv)
573 {
574 	__T_START;
575 
576 	libperf_init(libperf_print);
577 
578 	test_stat_cpu();
579 	test_stat_thread();
580 	test_stat_thread_enable();
581 	test_mmap_thread();
582 	test_mmap_cpus();
583 	test_stat_multiplexing();
584 
585 	__T_END;
586 	return tests_failed == 0 ? 0 : -1;
587 }
588