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