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