xref: /linux/tools/perf/tests/mmap-basic.c (revision 390d5ea26622f794c2d29cefd5a01ef116b4fe1d)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <inttypes.h>
5 #include <stdlib.h>
6 #include <perf/cpumap.h>
7 
8 #include "cpumap.h"
9 #include "debug.h"
10 #include "event.h"
11 #include "evlist.h"
12 #include "evsel.h"
13 #include "thread_map.h"
14 #include "tests.h"
15 #include "util/affinity.h"
16 #include "util/mmap.h"
17 #include "util/sample.h"
18 #include <linux/err.h>
19 #include <linux/kernel.h>
20 #include <linux/string.h>
21 #include <perf/evlist.h>
22 #include <perf/mmap.h>
23 
24 /*
25  * This test will generate random numbers of calls to some getpid syscalls,
26  * then establish an mmap for a group of events that are created to monitor
27  * the syscalls.
28  *
29  * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
30  * sample.id field to map back to its respective perf_evsel instance.
31  *
32  * Then it checks if the number of syscalls reported as perf events by
33  * the kernel corresponds to the number of syscalls made.
34  */
35 static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
36 {
37 	int err = TEST_FAIL;
38 	union perf_event *event;
39 	struct perf_thread_map *threads;
40 	struct perf_cpu_map *cpus;
41 	struct evlist *evlist;
42 	cpu_set_t cpu_set;
43 	const char *syscall_names[] = { "getsid", "getppid", "getpgid", };
44 	pid_t (*syscalls[])(void) = { (void *)getsid, getppid, (void*)getpgid };
45 #define nsyscalls ARRAY_SIZE(syscall_names)
46 	unsigned int nr_events[nsyscalls],
47 		     expected_nr_events[nsyscalls], i, j;
48 	struct evsel *evsels[nsyscalls], *evsel;
49 	char sbuf[STRERR_BUFSIZE];
50 	struct mmap *md;
51 
52 	threads = thread_map__new_by_tid(getpid());
53 	if (threads == NULL) {
54 		pr_debug("thread_map__new\n");
55 		return -1;
56 	}
57 
58 	cpus = perf_cpu_map__new_online_cpus();
59 	if (cpus == NULL) {
60 		pr_debug("perf_cpu_map__new\n");
61 		goto out_free_threads;
62 	}
63 
64 	CPU_ZERO(&cpu_set);
65 	CPU_SET(perf_cpu_map__cpu(cpus, 0).cpu, &cpu_set);
66 	sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
67 	if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
68 		pr_debug("sched_setaffinity() failed on CPU %d: %s ",
69 			 perf_cpu_map__cpu(cpus, 0).cpu,
70 			 str_error_r(errno, sbuf, sizeof(sbuf)));
71 		goto out_free_cpus;
72 	}
73 
74 	evlist = evlist__new();
75 	if (evlist == NULL) {
76 		pr_debug("evlist__new\n");
77 		goto out_free_cpus;
78 	}
79 
80 	perf_evlist__set_maps(&evlist->core, cpus, threads);
81 
82 	for (i = 0; i < nsyscalls; ++i) {
83 		char name[64];
84 
85 		snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
86 		evsels[i] = evsel__newtp("syscalls", name);
87 		if (IS_ERR(evsels[i])) {
88 			pr_debug("evsel__new(%s)\n", name);
89 			if (PTR_ERR(evsels[i]) == -EACCES) {
90 				/* Permissions failure, flag the failure as a skip. */
91 				err = TEST_SKIP;
92 			}
93 			goto out_delete_evlist;
94 		}
95 
96 		evsels[i]->core.attr.wakeup_events = 1;
97 		evsel__set_sample_id(evsels[i], false);
98 
99 		evlist__add(evlist, evsels[i]);
100 
101 		if (evsel__open(evsels[i], cpus, threads) < 0) {
102 			pr_debug("failed to open counter: %s, "
103 				 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
104 				 str_error_r(errno, sbuf, sizeof(sbuf)));
105 			goto out_delete_evlist;
106 		}
107 
108 		nr_events[i] = 0;
109 		expected_nr_events[i] = 1 + rand() % 127;
110 	}
111 
112 	if (evlist__mmap(evlist, 128) < 0) {
113 		pr_debug("failed to mmap events: %d (%s)\n", errno,
114 			 str_error_r(errno, sbuf, sizeof(sbuf)));
115 		goto out_delete_evlist;
116 	}
117 
118 	for (i = 0; i < nsyscalls; ++i)
119 		for (j = 0; j < expected_nr_events[i]; ++j) {
120 			syscalls[i]();
121 		}
122 
123 	md = &evlist->mmap[0];
124 	if (perf_mmap__read_init(&md->core) < 0)
125 		goto out_init;
126 
127 	while ((event = perf_mmap__read_event(&md->core)) != NULL) {
128 		struct perf_sample sample;
129 
130 		if (event->header.type != PERF_RECORD_SAMPLE) {
131 			pr_debug("unexpected %s event\n",
132 				 perf_event__name(event->header.type));
133 			goto out_delete_evlist;
134 		}
135 
136 		perf_sample__init(&sample, /*all=*/false);
137 		err = evlist__parse_sample(evlist, event, &sample);
138 		if (err) {
139 			pr_err("Can't parse sample, err = %d\n", err);
140 			perf_sample__exit(&sample);
141 			goto out_delete_evlist;
142 		}
143 
144 		err = -1;
145 		evsel = sample.evsel;
146 		if (!evsel)
147 			evsel = evlist__id2evsel(evlist, sample.id);
148 		perf_sample__exit(&sample);
149 		if (evsel == NULL) {
150 			pr_debug("event with id %" PRIu64
151 				 " doesn't map to an evsel\n", sample.id);
152 			goto out_delete_evlist;
153 		}
154 		nr_events[evsel->core.idx]++;
155 		perf_mmap__consume(&md->core);
156 	}
157 	perf_mmap__read_done(&md->core);
158 
159 out_init:
160 	err = 0;
161 	evlist__for_each_entry(evlist, evsel) {
162 		if (nr_events[evsel->core.idx] != expected_nr_events[evsel->core.idx]) {
163 			pr_debug("expected %d %s events, got %d\n",
164 				 expected_nr_events[evsel->core.idx],
165 				 evsel__name(evsel), nr_events[evsel->core.idx]);
166 			err = -1;
167 			goto out_delete_evlist;
168 		}
169 	}
170 
171 out_delete_evlist:
172 	evlist__delete(evlist);
173 out_free_cpus:
174 	perf_cpu_map__put(cpus);
175 out_free_threads:
176 	perf_thread_map__put(threads);
177 	return err;
178 }
179 
180 enum user_read_state {
181 	USER_READ_ENABLED,
182 	USER_READ_DISABLED,
183 	USER_READ_UNKNOWN,
184 };
185 
186 static enum user_read_state set_user_read(struct perf_pmu *pmu, enum user_read_state enabled)
187 {
188 	char buf[2] = {0, '\n'};
189 	ssize_t len;
190 	int events_fd, rdpmc_fd;
191 	enum user_read_state old_user_read = USER_READ_UNKNOWN;
192 
193 	if (enabled == USER_READ_UNKNOWN)
194 		return USER_READ_UNKNOWN;
195 
196 	events_fd = perf_pmu__event_source_devices_fd();
197 	if (events_fd < 0)
198 		return USER_READ_UNKNOWN;
199 
200 	rdpmc_fd = perf_pmu__pathname_fd(events_fd, pmu->name, "rdpmc", O_RDWR);
201 	if (rdpmc_fd < 0) {
202 		close(events_fd);
203 		return USER_READ_UNKNOWN;
204 	}
205 
206 	len = read(rdpmc_fd, buf, sizeof(buf));
207 	if (len != sizeof(buf))
208 		pr_debug("%s read failed\n", __func__);
209 
210 	// Note, on Intel hybrid disabling on 1 PMU will implicitly disable on
211 	// all the core PMUs.
212 	old_user_read = (buf[0] == '1') ? USER_READ_ENABLED : USER_READ_DISABLED;
213 
214 	if (enabled != old_user_read) {
215 		buf[0] = (enabled == USER_READ_ENABLED) ? '1' : '0';
216 		len = write(rdpmc_fd, buf, sizeof(buf));
217 		if (len != sizeof(buf))
218 			pr_debug("%s write failed\n", __func__);
219 	}
220 	close(rdpmc_fd);
221 	close(events_fd);
222 	return old_user_read;
223 }
224 
225 static int test_stat_user_read(u64 event, enum user_read_state enabled)
226 {
227 	struct perf_pmu *pmu = NULL;
228 	struct perf_thread_map *threads = perf_thread_map__new_dummy();
229 	int ret = TEST_OK;
230 
231 	pr_err("User space counter reading %" PRIu64 "\n", event);
232 	if (!threads) {
233 		pr_err("User space counter reading [Failed to create threads]\n");
234 		return TEST_FAIL;
235 	}
236 	perf_thread_map__set_pid(threads, 0, 0);
237 
238 	while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
239 		enum user_read_state saved_user_read_state = set_user_read(pmu, enabled);
240 		struct perf_event_attr attr = {
241 			.type	= PERF_TYPE_HARDWARE,
242 			.config	= perf_pmus__supports_extended_type()
243 			? event | ((u64)pmu->type << PERF_PMU_TYPE_SHIFT)
244 				: event,
245 #ifdef __aarch64__
246 			.config1 = 0x2,		/* Request user access */
247 #endif
248 		};
249 		struct perf_evsel *evsel = NULL;
250 		int err;
251 		struct perf_event_mmap_page *pc;
252 		bool mapped = false, opened = false, rdpmc_supported;
253 		struct perf_counts_values counts = { .val = 0 };
254 
255 
256 		pr_debug("User space counter reading for PMU %s\n", pmu->name);
257 		/*
258 		 * Restrict scheduling to only use the rdpmc on the CPUs the
259 		 * event can be on. If the test doesn't run on the CPU of the
260 		 * event then the event will be disabled and the pc->index test
261 		 * will fail.
262 		 */
263 		if (pmu->cpus != NULL)
264 			cpu_map__set_affinity(pmu->cpus);
265 
266 		/* Make the evsel. */
267 		evsel = perf_evsel__new(&attr);
268 		if (!evsel) {
269 			pr_err("User space counter reading for PMU %s [Failed to allocate evsel]\n",
270 				pmu->name);
271 			ret = TEST_FAIL;
272 			goto cleanup;
273 		}
274 
275 		err = perf_evsel__open(evsel, NULL, threads);
276 		if (err) {
277 			pr_err("User space counter reading for PMU %s [Failed to open evsel]\n",
278 				pmu->name);
279 			ret = TEST_SKIP;
280 			goto cleanup;
281 		}
282 		opened = true;
283 		err = perf_evsel__mmap(evsel, 0);
284 		if (err) {
285 			pr_err("User space counter reading for PMU %s [Failed to mmap evsel]\n",
286 				pmu->name);
287 			ret = TEST_FAIL;
288 			goto cleanup;
289 		}
290 		mapped = true;
291 
292 		pc = perf_evsel__mmap_base(evsel, 0, 0);
293 		if (!pc) {
294 			pr_err("User space counter reading for PMU %s [Failed to get mmaped address]\n",
295 				pmu->name);
296 			ret = TEST_FAIL;
297 			goto cleanup;
298 		}
299 
300 		if (saved_user_read_state == USER_READ_UNKNOWN)
301 			rdpmc_supported = pc->cap_user_rdpmc && pc->index;
302 		else
303 			rdpmc_supported = (enabled == USER_READ_ENABLED);
304 
305 		if (rdpmc_supported && (!pc->cap_user_rdpmc || !pc->index)) {
306 			pr_err("User space counter reading for PMU %s [Failed unexpected supported counter access %d %d]\n",
307 				pmu->name, pc->cap_user_rdpmc, pc->index);
308 			ret = TEST_FAIL;
309 			goto cleanup;
310 		}
311 
312 		if (!rdpmc_supported && pc->cap_user_rdpmc) {
313 			pr_err("User space counter reading for PMU %s [Failed unexpected unsupported counter access %d]\n",
314 				pmu->name, pc->cap_user_rdpmc);
315 			ret = TEST_FAIL;
316 			goto cleanup;
317 		}
318 
319 		if (rdpmc_supported && pc->pmc_width < 32) {
320 			pr_err("User space counter reading for PMU %s [Failed width not set %d]\n",
321 				pmu->name, pc->pmc_width);
322 			ret = TEST_FAIL;
323 			goto cleanup;
324 		}
325 
326 		perf_evsel__read(evsel, 0, 0, &counts);
327 		if (rdpmc_supported && counts.val == 0) {
328 			pr_err("User space counter reading for PMU %s [Failed read]\n", pmu->name);
329 			ret = TEST_FAIL;
330 			goto cleanup;
331 		}
332 
333 		for (int i = 0; i < 5; i++) {
334 			volatile int count = 0x10000 << i;
335 			__u64 start, end, last = 0;
336 
337 			pr_debug("\tloop = %u, ", count);
338 
339 			perf_evsel__read(evsel, 0, 0, &counts);
340 			start = counts.val;
341 
342 			while (count--) ;
343 
344 			perf_evsel__read(evsel, 0, 0, &counts);
345 			end = counts.val;
346 
347 			if ((end - start) < last) {
348 				pr_err("User space counter reading for PMU %s [Failed invalid counter data: end=%llu start=%llu last= %llu]\n",
349 					pmu->name, end, start, last);
350 				ret = TEST_FAIL;
351 				goto cleanup;
352 			}
353 			last = end - start;
354 			pr_debug("count = %llu\n", last);
355 		}
356 		pr_debug("User space counter reading for PMU %s [Success]\n", pmu->name);
357 cleanup:
358 		if (mapped)
359 			perf_evsel__munmap(evsel);
360 		if (opened)
361 			perf_evsel__close(evsel);
362 		perf_evsel__delete(evsel);
363 
364 		/* If the affinity was changed, then put it back to all CPUs. */
365 		if (pmu->cpus != NULL) {
366 			struct perf_cpu_map *cpus = cpu_map__online();
367 
368 			cpu_map__set_affinity(cpus);
369 			perf_cpu_map__put(cpus);
370 		}
371 		set_user_read(pmu, saved_user_read_state);
372 	}
373 	perf_thread_map__put(threads);
374 	return ret;
375 }
376 
377 static int test__mmap_user_read_instr(struct test_suite *test __maybe_unused,
378 				      int subtest __maybe_unused)
379 {
380 	return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS, USER_READ_ENABLED);
381 }
382 
383 static int test__mmap_user_read_cycles(struct test_suite *test __maybe_unused,
384 				       int subtest __maybe_unused)
385 {
386 	return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES, USER_READ_ENABLED);
387 }
388 
389 static int test__mmap_user_read_instr_disabled(struct test_suite *test __maybe_unused,
390 					       int subtest __maybe_unused)
391 {
392 	return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS, USER_READ_DISABLED);
393 }
394 
395 static int test__mmap_user_read_cycles_disabled(struct test_suite *test __maybe_unused,
396 						int subtest __maybe_unused)
397 {
398 	return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES, USER_READ_DISABLED);
399 }
400 
401 static struct test_case tests__basic_mmap[] = {
402 	TEST_CASE_REASON("Read samples using the mmap interface",
403 			 basic_mmap,
404 			 "permissions"),
405 	TEST_CASE_REASON_EXCLUSIVE("User space counter reading of instructions",
406 			 mmap_user_read_instr,
407 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
408 			 (defined(__riscv) && __riscv_xlen == 64)
409 			 "permissions"
410 #else
411 			 "unsupported"
412 #endif
413 		),
414 	TEST_CASE_REASON_EXCLUSIVE("User space counter reading of cycles",
415 			 mmap_user_read_cycles,
416 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
417 			 (defined(__riscv) && __riscv_xlen == 64)
418 			 "permissions"
419 #else
420 			 "unsupported"
421 #endif
422 		),
423 	TEST_CASE_REASON_EXCLUSIVE("User space counter disabling instructions",
424 			 mmap_user_read_instr_disabled,
425 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
426 			 (defined(__riscv) && __riscv_xlen == 64)
427 			 "permissions"
428 #else
429 			 "unsupported"
430 #endif
431 		),
432 	TEST_CASE_REASON_EXCLUSIVE("User space counter disabling cycles",
433 			 mmap_user_read_cycles_disabled,
434 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
435 			 (defined(__riscv) && __riscv_xlen == 64)
436 			 "permissions"
437 #else
438 			 "unsupported"
439 #endif
440 		),
441 	{	.name = NULL, }
442 };
443 
444 struct test_suite suite__basic_mmap = {
445 	.desc = "mmap interface tests",
446 	.test_cases = tests__basic_mmap,
447 };
448