xref: /openbmc/linux/tools/lib/perf/tests/test-evlist.c (revision 1fe3a33b)
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, tmp;
338 	struct perf_cpu cpu;
339 	union perf_event *event;
340 	int count = 0;
341 
342 	snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id",
343 		 sysfs__mountpoint());
344 
345 	if (filename__read_int(path, &id)) {
346 		fprintf(stderr, "error: failed to get tracepoint id: %s\n", path);
347 		return -1;
348 	}
349 
350 	attr.config = id;
351 
352 	cpus = perf_cpu_map__new(NULL);
353 	__T("failed to create cpus", cpus);
354 
355 	evlist = perf_evlist__new();
356 	__T("failed to create evlist", evlist);
357 
358 	evsel = perf_evsel__new(&attr);
359 	__T("failed to create evsel1", evsel);
360 	__T("failed to set leader", evsel->leader == evsel);
361 
362 	perf_evlist__add(evlist, evsel);
363 
364 	perf_evlist__set_maps(evlist, cpus, NULL);
365 
366 	err = perf_evlist__open(evlist);
367 	__T("failed to open evlist", err == 0);
368 
369 	err = perf_evlist__mmap(evlist, 4);
370 	__T("failed to mmap evlist", err == 0);
371 
372 	perf_evlist__enable(evlist);
373 
374 	err = sched_getaffinity(0, sizeof(saved_mask), &saved_mask);
375 	__T("sched_getaffinity failed", err == 0);
376 
377 	perf_cpu_map__for_each_cpu(cpu, tmp, cpus) {
378 		cpu_set_t mask;
379 
380 		CPU_ZERO(&mask);
381 		CPU_SET(cpu.cpu, &mask);
382 
383 		err = sched_setaffinity(0, sizeof(mask), &mask);
384 		__T("sched_setaffinity failed", err == 0);
385 
386 		prctl(0, 0, 0, 0, 0);
387 	}
388 
389 	err = sched_setaffinity(0, sizeof(saved_mask), &saved_mask);
390 	__T("sched_setaffinity failed", err == 0);
391 
392 	perf_evlist__disable(evlist);
393 
394 	perf_evlist__for_each_mmap(evlist, map, false) {
395 		if (perf_mmap__read_init(map) < 0)
396 			continue;
397 
398 		while ((event = perf_mmap__read_event(map)) != NULL) {
399 			count++;
400 			perf_mmap__consume(map);
401 		}
402 
403 		perf_mmap__read_done(map);
404 	}
405 
406 	/* calls perf_evlist__munmap/perf_evlist__close */
407 	perf_evlist__delete(evlist);
408 
409 	/*
410 	 * The generated prctl events should match the
411 	 * number of cpus or be bigger (we are system-wide).
412 	 */
413 	__T("failed count", count >= perf_cpu_map__nr(cpus));
414 
415 	perf_cpu_map__put(cpus);
416 
417 	return 0;
418 }
419 
420 static double display_error(long long average,
421 			    long long high,
422 			    long long low,
423 			    long long expected)
424 {
425 	double error;
426 
427 	error = (((double)average - expected) / expected) * 100.0;
428 
429 	__T_VERBOSE("   Expected: %lld\n", expected);
430 	__T_VERBOSE("   High: %lld   Low:  %lld   Average:  %lld\n",
431 		    high, low, average);
432 
433 	__T_VERBOSE("   Average Error = %.2f%%\n", error);
434 
435 	return error;
436 }
437 
438 static int test_stat_multiplexing(void)
439 {
440 	struct perf_counts_values expected_counts = { .val = 0 };
441 	struct perf_counts_values counts[EVENT_NUM] = {{ .val = 0 },};
442 	struct perf_thread_map *threads;
443 	struct perf_evlist *evlist;
444 	struct perf_evsel *evsel;
445 	struct perf_event_attr attr = {
446 		.type	     = PERF_TYPE_HARDWARE,
447 		.config	     = PERF_COUNT_HW_INSTRUCTIONS,
448 		.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
449 			       PERF_FORMAT_TOTAL_TIME_RUNNING,
450 		.disabled    = 1,
451 	};
452 	int err, i, nonzero = 0;
453 	unsigned long count;
454 	long long max = 0, min = 0, avg = 0;
455 	double error = 0.0;
456 	s8 scaled = 0;
457 
458 	/* read for non-multiplexing event count */
459 	threads = perf_thread_map__new_dummy();
460 	__T("failed to create threads", threads);
461 
462 	perf_thread_map__set_pid(threads, 0, 0);
463 
464 	evsel = perf_evsel__new(&attr);
465 	__T("failed to create evsel", evsel);
466 
467 	err = perf_evsel__open(evsel, NULL, threads);
468 	__T("failed to open evsel", err == 0);
469 
470 	err = perf_evsel__enable(evsel);
471 	__T("failed to enable evsel", err == 0);
472 
473 	/* wait loop */
474 	count = WAIT_COUNT;
475 	while (count--)
476 		;
477 
478 	perf_evsel__read(evsel, 0, 0, &expected_counts);
479 	__T("failed to read value for evsel", expected_counts.val != 0);
480 	__T("failed to read non-multiplexing event count",
481 	    expected_counts.ena == expected_counts.run);
482 
483 	err = perf_evsel__disable(evsel);
484 	__T("failed to enable evsel", err == 0);
485 
486 	perf_evsel__close(evsel);
487 	perf_evsel__delete(evsel);
488 
489 	perf_thread_map__put(threads);
490 
491 	/* read for multiplexing event count */
492 	threads = perf_thread_map__new_dummy();
493 	__T("failed to create threads", threads);
494 
495 	perf_thread_map__set_pid(threads, 0, 0);
496 
497 	evlist = perf_evlist__new();
498 	__T("failed to create evlist", evlist);
499 
500 	for (i = 0; i < EVENT_NUM; i++) {
501 		evsel = perf_evsel__new(&attr);
502 		__T("failed to create evsel", evsel);
503 
504 		perf_evlist__add(evlist, evsel);
505 	}
506 	perf_evlist__set_maps(evlist, NULL, threads);
507 
508 	err = perf_evlist__open(evlist);
509 	__T("failed to open evsel", err == 0);
510 
511 	perf_evlist__enable(evlist);
512 
513 	/* wait loop */
514 	count = WAIT_COUNT;
515 	while (count--)
516 		;
517 
518 	i = 0;
519 	perf_evlist__for_each_evsel(evlist, evsel) {
520 		perf_evsel__read(evsel, 0, 0, &counts[i]);
521 		__T("failed to read value for evsel", counts[i].val != 0);
522 		i++;
523 	}
524 
525 	perf_evlist__disable(evlist);
526 
527 	min = counts[0].val;
528 	for (i = 0; i < EVENT_NUM; i++) {
529 		__T_VERBOSE("Event %2d -- Raw count = %lu, run = %lu, enable = %lu\n",
530 			    i, counts[i].val, counts[i].run, counts[i].ena);
531 
532 		perf_counts_values__scale(&counts[i], true, &scaled);
533 		if (scaled == 1) {
534 			__T_VERBOSE("\t Scaled count = %lu (%.2lf%%, %lu/%lu)\n",
535 				    counts[i].val,
536 				    (double)counts[i].run / (double)counts[i].ena * 100.0,
537 				    counts[i].run, counts[i].ena);
538 		} else if (scaled == -1) {
539 			__T_VERBOSE("\t Not Running\n");
540 		} else {
541 			__T_VERBOSE("\t Not Scaling\n");
542 		}
543 
544 		if (counts[i].val > max)
545 			max = counts[i].val;
546 
547 		if (counts[i].val < min)
548 			min = counts[i].val;
549 
550 		avg += counts[i].val;
551 
552 		if (counts[i].val != 0)
553 			nonzero++;
554 	}
555 
556 	if (nonzero != 0)
557 		avg = avg / nonzero;
558 	else
559 		avg = 0;
560 
561 	error = display_error(avg, max, min, expected_counts.val);
562 
563 	__T("Error out of range!", ((error <= 1.0) && (error >= -1.0)));
564 
565 	perf_evlist__close(evlist);
566 	perf_evlist__delete(evlist);
567 
568 	perf_thread_map__put(threads);
569 
570 	return 0;
571 }
572 
573 int test_evlist(int argc, char **argv)
574 {
575 	__T_START;
576 
577 	libperf_init(libperf_print);
578 
579 	test_stat_cpu();
580 	test_stat_thread();
581 	test_stat_thread_enable();
582 	test_mmap_thread();
583 	test_mmap_cpus();
584 	test_stat_multiplexing();
585 
586 	__T_END;
587 	return tests_failed == 0 ? 0 : -1;
588 }
589