xref: /openbmc/linux/tools/lib/perf/tests/test-evlist.c (revision 808643ea)
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 static int libperf_print(enum libperf_print_level level,
25 			 const char *fmt, va_list ap)
26 {
27 	return vfprintf(stderr, fmt, ap);
28 }
29 
30 static int test_stat_cpu(void)
31 {
32 	struct perf_cpu_map *cpus;
33 	struct perf_evlist *evlist;
34 	struct perf_evsel *evsel, *leader;
35 	struct perf_event_attr attr1 = {
36 		.type	= PERF_TYPE_SOFTWARE,
37 		.config	= PERF_COUNT_SW_CPU_CLOCK,
38 	};
39 	struct perf_event_attr attr2 = {
40 		.type	= PERF_TYPE_SOFTWARE,
41 		.config	= PERF_COUNT_SW_TASK_CLOCK,
42 	};
43 	int err, cpu, tmp;
44 
45 	cpus = perf_cpu_map__new(NULL);
46 	__T("failed to create cpus", cpus);
47 
48 	evlist = perf_evlist__new();
49 	__T("failed to create evlist", evlist);
50 
51 	evsel = leader = perf_evsel__new(&attr1);
52 	__T("failed to create evsel1", evsel);
53 
54 	perf_evlist__add(evlist, evsel);
55 
56 	evsel = perf_evsel__new(&attr2);
57 	__T("failed to create evsel2", evsel);
58 
59 	perf_evlist__add(evlist, evsel);
60 
61 	perf_evlist__set_leader(evlist);
62 	__T("failed to set leader", leader->leader == leader);
63 	__T("failed to set leader", evsel->leader  == leader);
64 
65 	perf_evlist__set_maps(evlist, cpus, NULL);
66 
67 	err = perf_evlist__open(evlist);
68 	__T("failed to open evsel", err == 0);
69 
70 	perf_evlist__for_each_evsel(evlist, evsel) {
71 		cpus = perf_evsel__cpus(evsel);
72 
73 		perf_cpu_map__for_each_cpu(cpu, tmp, cpus) {
74 			struct perf_counts_values counts = { .val = 0 };
75 
76 			perf_evsel__read(evsel, cpu, 0, &counts);
77 			__T("failed to read value for evsel", counts.val != 0);
78 		}
79 	}
80 
81 	perf_evlist__close(evlist);
82 	perf_evlist__delete(evlist);
83 
84 	perf_cpu_map__put(cpus);
85 	return 0;
86 }
87 
88 static int test_stat_thread(void)
89 {
90 	struct perf_counts_values counts = { .val = 0 };
91 	struct perf_thread_map *threads;
92 	struct perf_evlist *evlist;
93 	struct perf_evsel *evsel, *leader;
94 	struct perf_event_attr attr1 = {
95 		.type	= PERF_TYPE_SOFTWARE,
96 		.config	= PERF_COUNT_SW_CPU_CLOCK,
97 	};
98 	struct perf_event_attr attr2 = {
99 		.type	= PERF_TYPE_SOFTWARE,
100 		.config	= PERF_COUNT_SW_TASK_CLOCK,
101 	};
102 	int err;
103 
104 	threads = perf_thread_map__new_dummy();
105 	__T("failed to create threads", threads);
106 
107 	perf_thread_map__set_pid(threads, 0, 0);
108 
109 	evlist = perf_evlist__new();
110 	__T("failed to create evlist", evlist);
111 
112 	evsel = leader = perf_evsel__new(&attr1);
113 	__T("failed to create evsel1", evsel);
114 
115 	perf_evlist__add(evlist, evsel);
116 
117 	evsel = perf_evsel__new(&attr2);
118 	__T("failed to create evsel2", evsel);
119 
120 	perf_evlist__add(evlist, evsel);
121 
122 	perf_evlist__set_leader(evlist);
123 	__T("failed to set leader", leader->leader == leader);
124 	__T("failed to set leader", evsel->leader  == leader);
125 
126 	perf_evlist__set_maps(evlist, NULL, threads);
127 
128 	err = perf_evlist__open(evlist);
129 	__T("failed to open evsel", err == 0);
130 
131 	perf_evlist__for_each_evsel(evlist, evsel) {
132 		perf_evsel__read(evsel, 0, 0, &counts);
133 		__T("failed to read value for evsel", counts.val != 0);
134 	}
135 
136 	perf_evlist__close(evlist);
137 	perf_evlist__delete(evlist);
138 
139 	perf_thread_map__put(threads);
140 	return 0;
141 }
142 
143 static int test_stat_thread_enable(void)
144 {
145 	struct perf_counts_values counts = { .val = 0 };
146 	struct perf_thread_map *threads;
147 	struct perf_evlist *evlist;
148 	struct perf_evsel *evsel, *leader;
149 	struct perf_event_attr attr1 = {
150 		.type	  = PERF_TYPE_SOFTWARE,
151 		.config	  = PERF_COUNT_SW_CPU_CLOCK,
152 		.disabled = 1,
153 	};
154 	struct perf_event_attr attr2 = {
155 		.type	  = PERF_TYPE_SOFTWARE,
156 		.config	  = PERF_COUNT_SW_TASK_CLOCK,
157 		.disabled = 1,
158 	};
159 	int err;
160 
161 	threads = perf_thread_map__new_dummy();
162 	__T("failed to create threads", threads);
163 
164 	perf_thread_map__set_pid(threads, 0, 0);
165 
166 	evlist = perf_evlist__new();
167 	__T("failed to create evlist", evlist);
168 
169 	evsel = leader = perf_evsel__new(&attr1);
170 	__T("failed to create evsel1", evsel);
171 
172 	perf_evlist__add(evlist, evsel);
173 
174 	evsel = perf_evsel__new(&attr2);
175 	__T("failed to create evsel2", evsel);
176 
177 	perf_evlist__add(evlist, evsel);
178 
179 	perf_evlist__set_leader(evlist);
180 	__T("failed to set leader", leader->leader == leader);
181 	__T("failed to set leader", evsel->leader  == leader);
182 
183 	perf_evlist__set_maps(evlist, NULL, threads);
184 
185 	err = perf_evlist__open(evlist);
186 	__T("failed to open evsel", err == 0);
187 
188 	perf_evlist__for_each_evsel(evlist, evsel) {
189 		perf_evsel__read(evsel, 0, 0, &counts);
190 		__T("failed to read value for evsel", counts.val == 0);
191 	}
192 
193 	perf_evlist__enable(evlist);
194 
195 	perf_evlist__for_each_evsel(evlist, evsel) {
196 		perf_evsel__read(evsel, 0, 0, &counts);
197 		__T("failed to read value for evsel", counts.val != 0);
198 	}
199 
200 	perf_evlist__disable(evlist);
201 
202 	perf_evlist__close(evlist);
203 	perf_evlist__delete(evlist);
204 
205 	perf_thread_map__put(threads);
206 	return 0;
207 }
208 
209 static int test_mmap_thread(void)
210 {
211 	struct perf_evlist *evlist;
212 	struct perf_evsel *evsel;
213 	struct perf_mmap *map;
214 	struct perf_cpu_map *cpus;
215 	struct perf_thread_map *threads;
216 	struct perf_event_attr attr = {
217 		.type             = PERF_TYPE_TRACEPOINT,
218 		.sample_period    = 1,
219 		.wakeup_watermark = 1,
220 		.disabled         = 1,
221 	};
222 	char path[PATH_MAX];
223 	int id, err, pid, go_pipe[2];
224 	union perf_event *event;
225 	int count = 0;
226 
227 	snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id",
228 		 sysfs__mountpoint());
229 
230 	if (filename__read_int(path, &id)) {
231 		tests_failed++;
232 		fprintf(stderr, "error: failed to get tracepoint id: %s\n", path);
233 		return -1;
234 	}
235 
236 	attr.config = id;
237 
238 	err = pipe(go_pipe);
239 	__T("failed to create pipe", err == 0);
240 
241 	fflush(NULL);
242 
243 	pid = fork();
244 	if (!pid) {
245 		int i;
246 		char bf;
247 
248 		read(go_pipe[0], &bf, 1);
249 
250 		/* Generate 100 prctl calls. */
251 		for (i = 0; i < 100; i++)
252 			prctl(0, 0, 0, 0, 0);
253 
254 		exit(0);
255 	}
256 
257 	threads = perf_thread_map__new_dummy();
258 	__T("failed to create threads", threads);
259 
260 	cpus = perf_cpu_map__dummy_new();
261 	__T("failed to create cpus", cpus);
262 
263 	perf_thread_map__set_pid(threads, 0, pid);
264 
265 	evlist = perf_evlist__new();
266 	__T("failed to create evlist", evlist);
267 
268 	evsel = perf_evsel__new(&attr);
269 	__T("failed to create evsel1", evsel);
270 	__T("failed to set leader", evsel->leader == evsel);
271 
272 	perf_evlist__add(evlist, evsel);
273 
274 	perf_evlist__set_maps(evlist, cpus, threads);
275 
276 	err = perf_evlist__open(evlist);
277 	__T("failed to open evlist", err == 0);
278 
279 	err = perf_evlist__mmap(evlist, 4);
280 	__T("failed to mmap evlist", err == 0);
281 
282 	perf_evlist__enable(evlist);
283 
284 	/* kick the child and wait for it to finish */
285 	write(go_pipe[1], "A", 1);
286 	waitpid(pid, NULL, 0);
287 
288 	/*
289 	 * There's no need to call perf_evlist__disable,
290 	 * monitored process is dead now.
291 	 */
292 
293 	perf_evlist__for_each_mmap(evlist, map, false) {
294 		if (perf_mmap__read_init(map) < 0)
295 			continue;
296 
297 		while ((event = perf_mmap__read_event(map)) != NULL) {
298 			count++;
299 			perf_mmap__consume(map);
300 		}
301 
302 		perf_mmap__read_done(map);
303 	}
304 
305 	/* calls perf_evlist__munmap/perf_evlist__close */
306 	perf_evlist__delete(evlist);
307 
308 	perf_thread_map__put(threads);
309 	perf_cpu_map__put(cpus);
310 
311 	/*
312 	 * The generated prctl calls should match the
313 	 * number of events in the buffer.
314 	 */
315 	__T("failed count", count == 100);
316 
317 	return 0;
318 }
319 
320 static int test_mmap_cpus(void)
321 {
322 	struct perf_evlist *evlist;
323 	struct perf_evsel *evsel;
324 	struct perf_mmap *map;
325 	struct perf_cpu_map *cpus;
326 	struct perf_event_attr attr = {
327 		.type             = PERF_TYPE_TRACEPOINT,
328 		.sample_period    = 1,
329 		.wakeup_watermark = 1,
330 		.disabled         = 1,
331 	};
332 	cpu_set_t saved_mask;
333 	char path[PATH_MAX];
334 	int id, err, cpu, tmp;
335 	union perf_event *event;
336 	int count = 0;
337 
338 	snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id",
339 		 sysfs__mountpoint());
340 
341 	if (filename__read_int(path, &id)) {
342 		fprintf(stderr, "error: failed to get tracepoint id: %s\n", path);
343 		return -1;
344 	}
345 
346 	attr.config = id;
347 
348 	cpus = perf_cpu_map__new(NULL);
349 	__T("failed to create cpus", cpus);
350 
351 	evlist = perf_evlist__new();
352 	__T("failed to create evlist", evlist);
353 
354 	evsel = perf_evsel__new(&attr);
355 	__T("failed to create evsel1", evsel);
356 	__T("failed to set leader", evsel->leader == evsel);
357 
358 	perf_evlist__add(evlist, evsel);
359 
360 	perf_evlist__set_maps(evlist, cpus, NULL);
361 
362 	err = perf_evlist__open(evlist);
363 	__T("failed to open evlist", err == 0);
364 
365 	err = perf_evlist__mmap(evlist, 4);
366 	__T("failed to mmap evlist", err == 0);
367 
368 	perf_evlist__enable(evlist);
369 
370 	err = sched_getaffinity(0, sizeof(saved_mask), &saved_mask);
371 	__T("sched_getaffinity failed", err == 0);
372 
373 	perf_cpu_map__for_each_cpu(cpu, tmp, cpus) {
374 		cpu_set_t mask;
375 
376 		CPU_ZERO(&mask);
377 		CPU_SET(cpu, &mask);
378 
379 		err = sched_setaffinity(0, sizeof(mask), &mask);
380 		__T("sched_setaffinity failed", err == 0);
381 
382 		prctl(0, 0, 0, 0, 0);
383 	}
384 
385 	err = sched_setaffinity(0, sizeof(saved_mask), &saved_mask);
386 	__T("sched_setaffinity failed", err == 0);
387 
388 	perf_evlist__disable(evlist);
389 
390 	perf_evlist__for_each_mmap(evlist, map, false) {
391 		if (perf_mmap__read_init(map) < 0)
392 			continue;
393 
394 		while ((event = perf_mmap__read_event(map)) != NULL) {
395 			count++;
396 			perf_mmap__consume(map);
397 		}
398 
399 		perf_mmap__read_done(map);
400 	}
401 
402 	/* calls perf_evlist__munmap/perf_evlist__close */
403 	perf_evlist__delete(evlist);
404 
405 	/*
406 	 * The generated prctl events should match the
407 	 * number of cpus or be bigger (we are system-wide).
408 	 */
409 	__T("failed count", count >= perf_cpu_map__nr(cpus));
410 
411 	perf_cpu_map__put(cpus);
412 
413 	return 0;
414 }
415 
416 int test_evlist(int argc, char **argv)
417 {
418 	__T_START;
419 
420 	libperf_init(libperf_print);
421 
422 	test_stat_cpu();
423 	test_stat_thread();
424 	test_stat_thread_enable();
425 	test_mmap_thread();
426 	test_mmap_cpus();
427 
428 	__T_END;
429 	return tests_failed == 0 ? 0 : -1;
430 }
431