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