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