xref: /openbmc/linux/tools/lib/perf/tests/test-evlist.c (revision 9bd5910d)
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 	char bf;
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 		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 
233 		read(go_pipe[0], &bf, 1);
234 
235 		/* Generate 100 prctl calls. */
236 		for (i = 0; i < 100; i++)
237 			prctl(0, 0, 0, 0, 0);
238 
239 		exit(0);
240 	}
241 
242 	threads = perf_thread_map__new_dummy();
243 	__T("failed to create threads", threads);
244 
245 	cpus = perf_cpu_map__dummy_new();
246 	__T("failed to create cpus", cpus);
247 
248 	perf_thread_map__set_pid(threads, 0, pid);
249 
250 	evlist = perf_evlist__new();
251 	__T("failed to create evlist", evlist);
252 
253 	evsel = perf_evsel__new(&attr);
254 	__T("failed to create evsel1", evsel);
255 
256 	perf_evlist__add(evlist, evsel);
257 
258 	perf_evlist__set_maps(evlist, cpus, threads);
259 
260 	err = perf_evlist__open(evlist);
261 	__T("failed to open evlist", err == 0);
262 
263 	err = perf_evlist__mmap(evlist, 4);
264 	__T("failed to mmap evlist", err == 0);
265 
266 	perf_evlist__enable(evlist);
267 
268 	/* kick the child and wait for it to finish */
269 	write(go_pipe[1], &bf, 1);
270 	waitpid(pid, NULL, 0);
271 
272 	/*
273 	 * There's no need to call perf_evlist__disable,
274 	 * monitored process is dead now.
275 	 */
276 
277 	perf_evlist__for_each_mmap(evlist, map, false) {
278 		if (perf_mmap__read_init(map) < 0)
279 			continue;
280 
281 		while ((event = perf_mmap__read_event(map)) != NULL) {
282 			count++;
283 			perf_mmap__consume(map);
284 		}
285 
286 		perf_mmap__read_done(map);
287 	}
288 
289 	/* calls perf_evlist__munmap/perf_evlist__close */
290 	perf_evlist__delete(evlist);
291 
292 	perf_thread_map__put(threads);
293 	perf_cpu_map__put(cpus);
294 
295 	/*
296 	 * The generated prctl calls should match the
297 	 * number of events in the buffer.
298 	 */
299 	__T("failed count", count == 100);
300 
301 	return 0;
302 }
303 
304 static int test_mmap_cpus(void)
305 {
306 	struct perf_evlist *evlist;
307 	struct perf_evsel *evsel;
308 	struct perf_mmap *map;
309 	struct perf_cpu_map *cpus;
310 	struct perf_event_attr attr = {
311 		.type             = PERF_TYPE_TRACEPOINT,
312 		.sample_period    = 1,
313 		.wakeup_watermark = 1,
314 		.disabled         = 1,
315 	};
316 	cpu_set_t saved_mask;
317 	char path[PATH_MAX];
318 	int id, err, cpu, tmp;
319 	union perf_event *event;
320 	int count = 0;
321 
322 	snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id",
323 		 sysfs__mountpoint());
324 
325 	if (filename__read_int(path, &id)) {
326 		fprintf(stderr, "error: failed to get tracepoint id: %s\n", path);
327 		return -1;
328 	}
329 
330 	attr.config = id;
331 
332 	cpus = perf_cpu_map__new(NULL);
333 	__T("failed to create cpus", cpus);
334 
335 	evlist = perf_evlist__new();
336 	__T("failed to create evlist", evlist);
337 
338 	evsel = perf_evsel__new(&attr);
339 	__T("failed to create evsel1", evsel);
340 
341 	perf_evlist__add(evlist, evsel);
342 
343 	perf_evlist__set_maps(evlist, cpus, NULL);
344 
345 	err = perf_evlist__open(evlist);
346 	__T("failed to open evlist", err == 0);
347 
348 	err = perf_evlist__mmap(evlist, 4);
349 	__T("failed to mmap evlist", err == 0);
350 
351 	perf_evlist__enable(evlist);
352 
353 	err = sched_getaffinity(0, sizeof(saved_mask), &saved_mask);
354 	__T("sched_getaffinity failed", err == 0);
355 
356 	perf_cpu_map__for_each_cpu(cpu, tmp, cpus) {
357 		cpu_set_t mask;
358 
359 		CPU_ZERO(&mask);
360 		CPU_SET(cpu, &mask);
361 
362 		err = sched_setaffinity(0, sizeof(mask), &mask);
363 		__T("sched_setaffinity failed", err == 0);
364 
365 		prctl(0, 0, 0, 0, 0);
366 	}
367 
368 	err = sched_setaffinity(0, sizeof(saved_mask), &saved_mask);
369 	__T("sched_setaffinity failed", err == 0);
370 
371 	perf_evlist__disable(evlist);
372 
373 	perf_evlist__for_each_mmap(evlist, map, false) {
374 		if (perf_mmap__read_init(map) < 0)
375 			continue;
376 
377 		while ((event = perf_mmap__read_event(map)) != NULL) {
378 			count++;
379 			perf_mmap__consume(map);
380 		}
381 
382 		perf_mmap__read_done(map);
383 	}
384 
385 	/* calls perf_evlist__munmap/perf_evlist__close */
386 	perf_evlist__delete(evlist);
387 
388 	/*
389 	 * The generated prctl events should match the
390 	 * number of cpus or be bigger (we are system-wide).
391 	 */
392 	__T("failed count", count >= perf_cpu_map__nr(cpus));
393 
394 	perf_cpu_map__put(cpus);
395 
396 	return 0;
397 }
398 
399 int main(int argc, char **argv)
400 {
401 	__T_START;
402 
403 	libperf_init(libperf_print);
404 
405 	test_stat_cpu();
406 	test_stat_thread();
407 	test_stat_thread_enable();
408 	test_mmap_thread();
409 	test_mmap_cpus();
410 
411 	__T_END;
412 	return 0;
413 }
414