xref: /linux-6.15/tools/perf/tests/mmap-basic.c (revision dc6d2bc2)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2a43783aeSArnaldo Carvalho de Melo #include <errno.h>
3fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
4f2a39fe8SArnaldo Carvalho de Melo #include <stdlib.h>
59c3516d1SJiri Olsa #include <perf/cpumap.h>
61fbe7df8SArnaldo Carvalho de Melo 
7b4209025SArnaldo Carvalho de Melo #include "debug.h"
8fd8d5a3bSArnaldo Carvalho de Melo #include "event.h"
9a65b9c62SJiri Olsa #include "evlist.h"
10a65b9c62SJiri Olsa #include "evsel.h"
11a65b9c62SJiri Olsa #include "thread_map.h"
12a65b9c62SJiri Olsa #include "tests.h"
13e0fcfb08SArnaldo Carvalho de Melo #include "util/mmap.h"
149823147dSArnaldo Carvalho de Melo #include "util/sample.h"
158dd2a131SJiri Olsa #include <linux/err.h>
16877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h>
178520a98dSArnaldo Carvalho de Melo #include <linux/string.h>
18453fa030SJiri Olsa #include <perf/evlist.h>
197728fa0cSJiri Olsa #include <perf/mmap.h>
20a65b9c62SJiri Olsa 
21a65b9c62SJiri Olsa /*
22a65b9c62SJiri Olsa  * This test will generate random numbers of calls to some getpid syscalls,
23a65b9c62SJiri Olsa  * then establish an mmap for a group of events that are created to monitor
24a65b9c62SJiri Olsa  * the syscalls.
25a65b9c62SJiri Olsa  *
26a65b9c62SJiri Olsa  * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
27a65b9c62SJiri Olsa  * sample.id field to map back to its respective perf_evsel instance.
28a65b9c62SJiri Olsa  *
29a65b9c62SJiri Olsa  * Then it checks if the number of syscalls reported as perf events by
30a65b9c62SJiri Olsa  * the kernel corresponds to the number of syscalls made.
31a65b9c62SJiri Olsa  */
test__basic_mmap(struct test_suite * test __maybe_unused,int subtest __maybe_unused)3233f44bfdSIan Rogers static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
33a65b9c62SJiri Olsa {
347312c36cSIan Rogers 	int err = TEST_FAIL;
35a65b9c62SJiri Olsa 	union perf_event *event;
369749b90eSJiri Olsa 	struct perf_thread_map *threads;
37f854839bSJiri Olsa 	struct perf_cpu_map *cpus;
3863503dbaSJiri Olsa 	struct evlist *evlist;
39a65b9c62SJiri Olsa 	cpu_set_t cpu_set;
40cec83938SRiku Voipio 	const char *syscall_names[] = { "getsid", "getppid", "getpgid", };
41cec83938SRiku Voipio 	pid_t (*syscalls[])(void) = { (void *)getsid, getppid, (void*)getpgid };
42a65b9c62SJiri Olsa #define nsyscalls ARRAY_SIZE(syscall_names)
43a65b9c62SJiri Olsa 	unsigned int nr_events[nsyscalls],
44a65b9c62SJiri Olsa 		     expected_nr_events[nsyscalls], i, j;
4532dcd021SJiri Olsa 	struct evsel *evsels[nsyscalls], *evsel;
46ba3dfff8SMasami Hiramatsu 	char sbuf[STRERR_BUFSIZE];
47a5830532SJiri Olsa 	struct mmap *md;
48a65b9c62SJiri Olsa 
49a65b9c62SJiri Olsa 	threads = thread_map__new(-1, getpid(), UINT_MAX);
50a65b9c62SJiri Olsa 	if (threads == NULL) {
51a65b9c62SJiri Olsa 		pr_debug("thread_map__new\n");
52a65b9c62SJiri Olsa 		return -1;
53a65b9c62SJiri Olsa 	}
54a65b9c62SJiri Olsa 
55effe957cSIan Rogers 	cpus = perf_cpu_map__new_online_cpus();
56a65b9c62SJiri Olsa 	if (cpus == NULL) {
5787ffb6c6SArnaldo Carvalho de Melo 		pr_debug("perf_cpu_map__new\n");
58a65b9c62SJiri Olsa 		goto out_free_threads;
59a65b9c62SJiri Olsa 	}
60a65b9c62SJiri Olsa 
61a65b9c62SJiri Olsa 	CPU_ZERO(&cpu_set);
6244028699SIan Rogers 	CPU_SET(perf_cpu_map__cpu(cpus, 0).cpu, &cpu_set);
63a65b9c62SJiri Olsa 	sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
64a65b9c62SJiri Olsa 	if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
65a65b9c62SJiri Olsa 		pr_debug("sched_setaffinity() failed on CPU %d: %s ",
6644028699SIan Rogers 			 perf_cpu_map__cpu(cpus, 0).cpu,
6744028699SIan Rogers 			 str_error_r(errno, sbuf, sizeof(sbuf)));
68a65b9c62SJiri Olsa 		goto out_free_cpus;
69a65b9c62SJiri Olsa 	}
70a65b9c62SJiri Olsa 
710f98b11cSJiri Olsa 	evlist = evlist__new();
72a65b9c62SJiri Olsa 	if (evlist == NULL) {
73606e2c29SArnaldo Carvalho de Melo 		pr_debug("evlist__new\n");
74a65b9c62SJiri Olsa 		goto out_free_cpus;
75a65b9c62SJiri Olsa 	}
76a65b9c62SJiri Olsa 
77453fa030SJiri Olsa 	perf_evlist__set_maps(&evlist->core, cpus, threads);
78334fe7a3SNamhyung Kim 
79a65b9c62SJiri Olsa 	for (i = 0; i < nsyscalls; ++i) {
80a60d7953SArnaldo Carvalho de Melo 		char name[64];
81a60d7953SArnaldo Carvalho de Melo 
82a60d7953SArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
838f6725a2SArnaldo Carvalho de Melo 		evsels[i] = evsel__newtp("syscalls", name);
848dd2a131SJiri Olsa 		if (IS_ERR(evsels[i])) {
858f6725a2SArnaldo Carvalho de Melo 			pr_debug("evsel__new(%s)\n", name);
867312c36cSIan Rogers 			if (PTR_ERR(evsels[i]) == -EACCES) {
877312c36cSIan Rogers 				/* Permissions failure, flag the failure as a skip. */
887312c36cSIan Rogers 				err = TEST_SKIP;
897312c36cSIan Rogers 			}
90f26e1c7cSArnaldo Carvalho de Melo 			goto out_delete_evlist;
91a65b9c62SJiri Olsa 		}
92a65b9c62SJiri Olsa 
931fc632ceSJiri Olsa 		evsels[i]->core.attr.wakeup_events = 1;
94862b2f8fSArnaldo Carvalho de Melo 		evsel__set_sample_id(evsels[i], false);
95a60d7953SArnaldo Carvalho de Melo 
96a1cf3a75SJiri Olsa 		evlist__add(evlist, evsels[i]);
97a65b9c62SJiri Olsa 
985972d1e0SJiri Olsa 		if (evsel__open(evsels[i], cpus, threads) < 0) {
99a65b9c62SJiri Olsa 			pr_debug("failed to open counter: %s, "
100a65b9c62SJiri Olsa 				 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
101c8b5f2c9SArnaldo Carvalho de Melo 				 str_error_r(errno, sbuf, sizeof(sbuf)));
102f26e1c7cSArnaldo Carvalho de Melo 			goto out_delete_evlist;
103a65b9c62SJiri Olsa 		}
104a60d7953SArnaldo Carvalho de Melo 
105a60d7953SArnaldo Carvalho de Melo 		nr_events[i] = 0;
106a60d7953SArnaldo Carvalho de Melo 		expected_nr_events[i] = 1 + rand() % 127;
107a65b9c62SJiri Olsa 	}
108a65b9c62SJiri Olsa 
1099521b5f2SJiri Olsa 	if (evlist__mmap(evlist, 128) < 0) {
110a65b9c62SJiri Olsa 		pr_debug("failed to mmap events: %d (%s)\n", errno,
111c8b5f2c9SArnaldo Carvalho de Melo 			 str_error_r(errno, sbuf, sizeof(sbuf)));
112f26e1c7cSArnaldo Carvalho de Melo 		goto out_delete_evlist;
113a65b9c62SJiri Olsa 	}
114a65b9c62SJiri Olsa 
115a65b9c62SJiri Olsa 	for (i = 0; i < nsyscalls; ++i)
116a65b9c62SJiri Olsa 		for (j = 0; j < expected_nr_events[i]; ++j) {
1175551717bSJiri Olsa 			syscalls[i]();
118a65b9c62SJiri Olsa 		}
119a65b9c62SJiri Olsa 
120334f823eSKan Liang 	md = &evlist->mmap[0];
1217c4d4182SJiri Olsa 	if (perf_mmap__read_init(&md->core) < 0)
122334f823eSKan Liang 		goto out_init;
123334f823eSKan Liang 
124151ed5d7SJiri Olsa 	while ((event = perf_mmap__read_event(&md->core)) != NULL) {
125a65b9c62SJiri Olsa 		struct perf_sample sample;
126a65b9c62SJiri Olsa 
127a65b9c62SJiri Olsa 		if (event->header.type != PERF_RECORD_SAMPLE) {
128a65b9c62SJiri Olsa 			pr_debug("unexpected %s event\n",
129a65b9c62SJiri Olsa 				 perf_event__name(event->header.type));
130983874d1SArnaldo Carvalho de Melo 			goto out_delete_evlist;
131a65b9c62SJiri Olsa 		}
132a65b9c62SJiri Olsa 
133*dc6d2bc2SIan Rogers 		perf_sample__init(&sample, /*all=*/false);
1342a6599cdSArnaldo Carvalho de Melo 		err = evlist__parse_sample(evlist, event, &sample);
135a65b9c62SJiri Olsa 		if (err) {
136a65b9c62SJiri Olsa 			pr_err("Can't parse sample, err = %d\n", err);
137*dc6d2bc2SIan Rogers 			perf_sample__exit(&sample);
138983874d1SArnaldo Carvalho de Melo 			goto out_delete_evlist;
139a65b9c62SJiri Olsa 		}
140a65b9c62SJiri Olsa 
141c5d3d50dSArnaldo Carvalho de Melo 		err = -1;
1423ccf8a7bSArnaldo Carvalho de Melo 		evsel = evlist__id2evsel(evlist, sample.id);
143*dc6d2bc2SIan Rogers 		perf_sample__exit(&sample);
144a65b9c62SJiri Olsa 		if (evsel == NULL) {
145a65b9c62SJiri Olsa 			pr_debug("event with id %" PRIu64
146a65b9c62SJiri Olsa 				 " doesn't map to an evsel\n", sample.id);
147983874d1SArnaldo Carvalho de Melo 			goto out_delete_evlist;
148a65b9c62SJiri Olsa 		}
14938fe0e01SJiri Olsa 		nr_events[evsel->core.idx]++;
1507728fa0cSJiri Olsa 		perf_mmap__consume(&md->core);
151a65b9c62SJiri Olsa 	}
15232fdc2caSJiri Olsa 	perf_mmap__read_done(&md->core);
153a65b9c62SJiri Olsa 
154334f823eSKan Liang out_init:
155c5d3d50dSArnaldo Carvalho de Melo 	err = 0;
156e5cadb93SArnaldo Carvalho de Melo 	evlist__for_each_entry(evlist, evsel) {
15738fe0e01SJiri Olsa 		if (nr_events[evsel->core.idx] != expected_nr_events[evsel->core.idx]) {
158a65b9c62SJiri Olsa 			pr_debug("expected %d %s events, got %d\n",
15938fe0e01SJiri Olsa 				 expected_nr_events[evsel->core.idx],
16038fe0e01SJiri Olsa 				 evsel__name(evsel), nr_events[evsel->core.idx]);
161c5d3d50dSArnaldo Carvalho de Melo 			err = -1;
162983874d1SArnaldo Carvalho de Melo 			goto out_delete_evlist;
163a65b9c62SJiri Olsa 		}
164a65b9c62SJiri Olsa 	}
165a65b9c62SJiri Olsa 
166f26e1c7cSArnaldo Carvalho de Melo out_delete_evlist:
167c12995a5SJiri Olsa 	evlist__delete(evlist);
168a65b9c62SJiri Olsa out_free_cpus:
16938f01d8dSJiri Olsa 	perf_cpu_map__put(cpus);
170a65b9c62SJiri Olsa out_free_threads:
1717836e52eSJiri Olsa 	perf_thread_map__put(threads);
172a65b9c62SJiri Olsa 	return err;
173a65b9c62SJiri Olsa }
174d68f0365SIan Rogers 
test_stat_user_read(int event)1759bd70218SIan Rogers static int test_stat_user_read(int event)
1769bd70218SIan Rogers {
1779bd70218SIan Rogers 	struct perf_counts_values counts = { .val = 0 };
1789bd70218SIan Rogers 	struct perf_thread_map *threads;
1799bd70218SIan Rogers 	struct perf_evsel *evsel;
1809bd70218SIan Rogers 	struct perf_event_mmap_page *pc;
1819bd70218SIan Rogers 	struct perf_event_attr attr = {
1829bd70218SIan Rogers 		.type	= PERF_TYPE_HARDWARE,
1839bd70218SIan Rogers 		.config	= event,
1849bd70218SIan Rogers #ifdef __aarch64__
1859bd70218SIan Rogers 		.config1 = 0x2,		/* Request user access */
1869bd70218SIan Rogers #endif
1879bd70218SIan Rogers 	};
1889bd70218SIan Rogers 	int err, i, ret = TEST_FAIL;
1899bd70218SIan Rogers 	bool opened = false, mapped = false;
1909bd70218SIan Rogers 
1919bd70218SIan Rogers 	threads = perf_thread_map__new_dummy();
1929bd70218SIan Rogers 	TEST_ASSERT_VAL("failed to create threads", threads);
1939bd70218SIan Rogers 
1949bd70218SIan Rogers 	perf_thread_map__set_pid(threads, 0, 0);
1959bd70218SIan Rogers 
1969bd70218SIan Rogers 	evsel = perf_evsel__new(&attr);
1979bd70218SIan Rogers 	TEST_ASSERT_VAL("failed to create evsel", evsel);
1989bd70218SIan Rogers 
1999bd70218SIan Rogers 	err = perf_evsel__open(evsel, NULL, threads);
2009bd70218SIan Rogers 	if (err) {
2019bd70218SIan Rogers 		pr_err("failed to open evsel: %s\n", strerror(-err));
2029bd70218SIan Rogers 		ret = TEST_SKIP;
2039bd70218SIan Rogers 		goto out;
2049bd70218SIan Rogers 	}
2059bd70218SIan Rogers 	opened = true;
2069bd70218SIan Rogers 
2079bd70218SIan Rogers 	err = perf_evsel__mmap(evsel, 0);
2089bd70218SIan Rogers 	if (err) {
2099bd70218SIan Rogers 		pr_err("failed to mmap evsel: %s\n", strerror(-err));
2109bd70218SIan Rogers 		goto out;
2119bd70218SIan Rogers 	}
2129bd70218SIan Rogers 	mapped = true;
2139bd70218SIan Rogers 
2149bd70218SIan Rogers 	pc = perf_evsel__mmap_base(evsel, 0, 0);
2159bd70218SIan Rogers 	if (!pc) {
2169bd70218SIan Rogers 		pr_err("failed to get mmapped address\n");
2179bd70218SIan Rogers 		goto out;
2189bd70218SIan Rogers 	}
2199bd70218SIan Rogers 
2209bd70218SIan Rogers 	if (!pc->cap_user_rdpmc || !pc->index) {
2219bd70218SIan Rogers 		pr_err("userspace counter access not %s\n",
2229bd70218SIan Rogers 			!pc->cap_user_rdpmc ? "supported" : "enabled");
2239bd70218SIan Rogers 		ret = TEST_SKIP;
2249bd70218SIan Rogers 		goto out;
2259bd70218SIan Rogers 	}
2269bd70218SIan Rogers 	if (pc->pmc_width < 32) {
2279bd70218SIan Rogers 		pr_err("userspace counter width not set (%d)\n", pc->pmc_width);
2289bd70218SIan Rogers 		goto out;
2299bd70218SIan Rogers 	}
2309bd70218SIan Rogers 
2319bd70218SIan Rogers 	perf_evsel__read(evsel, 0, 0, &counts);
2329bd70218SIan Rogers 	if (counts.val == 0) {
2339bd70218SIan Rogers 		pr_err("failed to read value for evsel\n");
2349bd70218SIan Rogers 		goto out;
2359bd70218SIan Rogers 	}
2369bd70218SIan Rogers 
2379bd70218SIan Rogers 	for (i = 0; i < 5; i++) {
2389bd70218SIan Rogers 		volatile int count = 0x10000 << i;
2399bd70218SIan Rogers 		__u64 start, end, last = 0;
2409bd70218SIan Rogers 
2419bd70218SIan Rogers 		pr_debug("\tloop = %u, ", count);
2429bd70218SIan Rogers 
2439bd70218SIan Rogers 		perf_evsel__read(evsel, 0, 0, &counts);
2449bd70218SIan Rogers 		start = counts.val;
2459bd70218SIan Rogers 
2469bd70218SIan Rogers 		while (count--) ;
2479bd70218SIan Rogers 
2489bd70218SIan Rogers 		perf_evsel__read(evsel, 0, 0, &counts);
2499bd70218SIan Rogers 		end = counts.val;
2509bd70218SIan Rogers 
2519bd70218SIan Rogers 		if ((end - start) < last) {
2529bd70218SIan Rogers 			pr_err("invalid counter data: end=%llu start=%llu last= %llu\n",
2539bd70218SIan Rogers 				end, start, last);
2549bd70218SIan Rogers 			goto out;
2559bd70218SIan Rogers 		}
2569bd70218SIan Rogers 		last = end - start;
2579bd70218SIan Rogers 		pr_debug("count = %llu\n", end - start);
2589bd70218SIan Rogers 	}
2599bd70218SIan Rogers 	ret = TEST_OK;
2609bd70218SIan Rogers 
2619bd70218SIan Rogers out:
2629bd70218SIan Rogers 	if (mapped)
2639bd70218SIan Rogers 		perf_evsel__munmap(evsel);
2649bd70218SIan Rogers 	if (opened)
2659bd70218SIan Rogers 		perf_evsel__close(evsel);
2669bd70218SIan Rogers 	perf_evsel__delete(evsel);
2679bd70218SIan Rogers 
2689bd70218SIan Rogers 	perf_thread_map__put(threads);
2699bd70218SIan Rogers 	return ret;
2709bd70218SIan Rogers }
2719bd70218SIan Rogers 
test__mmap_user_read_instr(struct test_suite * test __maybe_unused,int subtest __maybe_unused)2729bd70218SIan Rogers static int test__mmap_user_read_instr(struct test_suite *test __maybe_unused,
2739bd70218SIan Rogers 				      int subtest __maybe_unused)
2749bd70218SIan Rogers {
2759bd70218SIan Rogers 	return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS);
2769bd70218SIan Rogers }
2779bd70218SIan Rogers 
test__mmap_user_read_cycles(struct test_suite * test __maybe_unused,int subtest __maybe_unused)2789bd70218SIan Rogers static int test__mmap_user_read_cycles(struct test_suite *test __maybe_unused,
2799bd70218SIan Rogers 				       int subtest __maybe_unused)
2809bd70218SIan Rogers {
2819bd70218SIan Rogers 	return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES);
2829bd70218SIan Rogers }
2839bd70218SIan Rogers 
2847312c36cSIan Rogers static struct test_case tests__basic_mmap[] = {
2857312c36cSIan Rogers 	TEST_CASE_REASON("Read samples using the mmap interface",
2867312c36cSIan Rogers 			 basic_mmap,
2877312c36cSIan Rogers 			 "permissions"),
2889bd70218SIan Rogers 	TEST_CASE_REASON("User space counter reading of instructions",
2899bd70218SIan Rogers 			 mmap_user_read_instr,
29026ba0424SAlexandre Ghiti #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
29126ba0424SAlexandre Ghiti 			 (defined(__riscv) && __riscv_xlen == 64)
2929bd70218SIan Rogers 			 "permissions"
2939bd70218SIan Rogers #else
2949bd70218SIan Rogers 			 "unsupported"
2959bd70218SIan Rogers #endif
2969bd70218SIan Rogers 		),
2979bd70218SIan Rogers 	TEST_CASE_REASON("User space counter reading of cycles",
2989bd70218SIan Rogers 			 mmap_user_read_cycles,
29926ba0424SAlexandre Ghiti #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
30026ba0424SAlexandre Ghiti 			 (defined(__riscv) && __riscv_xlen == 64)
3019bd70218SIan Rogers 			 "permissions"
3029bd70218SIan Rogers #else
3039bd70218SIan Rogers 			 "unsupported"
3049bd70218SIan Rogers #endif
3059bd70218SIan Rogers 		),
3067312c36cSIan Rogers 	{	.name = NULL, }
3077312c36cSIan Rogers };
3087312c36cSIan Rogers 
3097312c36cSIan Rogers struct test_suite suite__basic_mmap = {
3109bd70218SIan Rogers 	.desc = "mmap interface tests",
3117312c36cSIan Rogers 	.test_cases = tests__basic_mmap,
3127312c36cSIan Rogers };
313