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 */
test__basic_mmap(struct test_suite * test __maybe_unused,int subtest __maybe_unused)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 = evlist__id2evsel(evlist, sample.id);
146 perf_sample__exit(&sample);
147 if (evsel == NULL) {
148 pr_debug("event with id %" PRIu64
149 " doesn't map to an evsel\n", sample.id);
150 goto out_delete_evlist;
151 }
152 nr_events[evsel->core.idx]++;
153 perf_mmap__consume(&md->core);
154 }
155 perf_mmap__read_done(&md->core);
156
157 out_init:
158 err = 0;
159 evlist__for_each_entry(evlist, evsel) {
160 if (nr_events[evsel->core.idx] != expected_nr_events[evsel->core.idx]) {
161 pr_debug("expected %d %s events, got %d\n",
162 expected_nr_events[evsel->core.idx],
163 evsel__name(evsel), nr_events[evsel->core.idx]);
164 err = -1;
165 goto out_delete_evlist;
166 }
167 }
168
169 out_delete_evlist:
170 evlist__delete(evlist);
171 out_free_cpus:
172 perf_cpu_map__put(cpus);
173 out_free_threads:
174 perf_thread_map__put(threads);
175 return err;
176 }
177
178 enum user_read_state {
179 USER_READ_ENABLED,
180 USER_READ_DISABLED,
181 USER_READ_UNKNOWN,
182 };
183
set_user_read(struct perf_pmu * pmu,enum user_read_state enabled)184 static enum user_read_state set_user_read(struct perf_pmu *pmu, enum user_read_state enabled)
185 {
186 char buf[2] = {0, '\n'};
187 ssize_t len;
188 int events_fd, rdpmc_fd;
189 enum user_read_state old_user_read = USER_READ_UNKNOWN;
190
191 if (enabled == USER_READ_UNKNOWN)
192 return USER_READ_UNKNOWN;
193
194 events_fd = perf_pmu__event_source_devices_fd();
195 if (events_fd < 0)
196 return USER_READ_UNKNOWN;
197
198 rdpmc_fd = perf_pmu__pathname_fd(events_fd, pmu->name, "rdpmc", O_RDWR);
199 if (rdpmc_fd < 0) {
200 close(events_fd);
201 return USER_READ_UNKNOWN;
202 }
203
204 len = read(rdpmc_fd, buf, sizeof(buf));
205 if (len != sizeof(buf))
206 pr_debug("%s read failed\n", __func__);
207
208 // Note, on Intel hybrid disabling on 1 PMU will implicitly disable on
209 // all the core PMUs.
210 old_user_read = (buf[0] == '1') ? USER_READ_ENABLED : USER_READ_DISABLED;
211
212 if (enabled != old_user_read) {
213 buf[0] = (enabled == USER_READ_ENABLED) ? '1' : '0';
214 len = write(rdpmc_fd, buf, sizeof(buf));
215 if (len != sizeof(buf))
216 pr_debug("%s write failed\n", __func__);
217 }
218 close(rdpmc_fd);
219 close(events_fd);
220 return old_user_read;
221 }
222
test_stat_user_read(u64 event,enum user_read_state enabled)223 static int test_stat_user_read(u64 event, enum user_read_state enabled)
224 {
225 struct perf_pmu *pmu = NULL;
226 struct perf_thread_map *threads = perf_thread_map__new_dummy();
227 int ret = TEST_OK;
228
229 pr_err("User space counter reading %" PRIu64 "\n", event);
230 if (!threads) {
231 pr_err("User space counter reading [Failed to create threads]\n");
232 return TEST_FAIL;
233 }
234 perf_thread_map__set_pid(threads, 0, 0);
235
236 while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
237 enum user_read_state saved_user_read_state = set_user_read(pmu, enabled);
238 struct perf_event_attr attr = {
239 .type = PERF_TYPE_HARDWARE,
240 .config = perf_pmus__supports_extended_type()
241 ? event | ((u64)pmu->type << PERF_PMU_TYPE_SHIFT)
242 : event,
243 #ifdef __aarch64__
244 .config1 = 0x2, /* Request user access */
245 #endif
246 };
247 struct perf_evsel *evsel = NULL;
248 int err;
249 struct perf_event_mmap_page *pc;
250 bool mapped = false, opened = false, rdpmc_supported;
251 struct perf_counts_values counts = { .val = 0 };
252
253
254 pr_debug("User space counter reading for PMU %s\n", pmu->name);
255 /*
256 * Restrict scheduling to only use the rdpmc on the CPUs the
257 * event can be on. If the test doesn't run on the CPU of the
258 * event then the event will be disabled and the pc->index test
259 * will fail.
260 */
261 if (pmu->cpus != NULL)
262 cpu_map__set_affinity(pmu->cpus);
263
264 /* Make the evsel. */
265 evsel = perf_evsel__new(&attr);
266 if (!evsel) {
267 pr_err("User space counter reading for PMU %s [Failed to allocate evsel]\n",
268 pmu->name);
269 ret = TEST_FAIL;
270 goto cleanup;
271 }
272
273 err = perf_evsel__open(evsel, NULL, threads);
274 if (err) {
275 pr_err("User space counter reading for PMU %s [Failed to open evsel]\n",
276 pmu->name);
277 ret = TEST_SKIP;
278 goto cleanup;
279 }
280 opened = true;
281 err = perf_evsel__mmap(evsel, 0);
282 if (err) {
283 pr_err("User space counter reading for PMU %s [Failed to mmap evsel]\n",
284 pmu->name);
285 ret = TEST_FAIL;
286 goto cleanup;
287 }
288 mapped = true;
289
290 pc = perf_evsel__mmap_base(evsel, 0, 0);
291 if (!pc) {
292 pr_err("User space counter reading for PMU %s [Failed to get mmaped address]\n",
293 pmu->name);
294 ret = TEST_FAIL;
295 goto cleanup;
296 }
297
298 if (saved_user_read_state == USER_READ_UNKNOWN)
299 rdpmc_supported = pc->cap_user_rdpmc && pc->index;
300 else
301 rdpmc_supported = (enabled == USER_READ_ENABLED);
302
303 if (rdpmc_supported && (!pc->cap_user_rdpmc || !pc->index)) {
304 pr_err("User space counter reading for PMU %s [Failed unexpected supported counter access %d %d]\n",
305 pmu->name, pc->cap_user_rdpmc, pc->index);
306 ret = TEST_FAIL;
307 goto cleanup;
308 }
309
310 if (!rdpmc_supported && pc->cap_user_rdpmc) {
311 pr_err("User space counter reading for PMU %s [Failed unexpected unsupported counter access %d]\n",
312 pmu->name, pc->cap_user_rdpmc);
313 ret = TEST_FAIL;
314 goto cleanup;
315 }
316
317 if (rdpmc_supported && pc->pmc_width < 32) {
318 pr_err("User space counter reading for PMU %s [Failed width not set %d]\n",
319 pmu->name, pc->pmc_width);
320 ret = TEST_FAIL;
321 goto cleanup;
322 }
323
324 perf_evsel__read(evsel, 0, 0, &counts);
325 if (counts.val == 0) {
326 pr_err("User space counter reading for PMU %s [Failed read]\n", pmu->name);
327 ret = TEST_FAIL;
328 goto cleanup;
329 }
330
331 for (int i = 0; i < 5; i++) {
332 volatile int count = 0x10000 << i;
333 __u64 start, end, last = 0;
334
335 pr_debug("\tloop = %u, ", count);
336
337 perf_evsel__read(evsel, 0, 0, &counts);
338 start = counts.val;
339
340 while (count--) ;
341
342 perf_evsel__read(evsel, 0, 0, &counts);
343 end = counts.val;
344
345 if ((end - start) < last) {
346 pr_err("User space counter reading for PMU %s [Failed invalid counter data: end=%llu start=%llu last= %llu]\n",
347 pmu->name, end, start, last);
348 ret = TEST_FAIL;
349 goto cleanup;
350 }
351 last = end - start;
352 pr_debug("count = %llu\n", last);
353 }
354 pr_debug("User space counter reading for PMU %s [Success]\n", pmu->name);
355 cleanup:
356 if (mapped)
357 perf_evsel__munmap(evsel);
358 if (opened)
359 perf_evsel__close(evsel);
360 perf_evsel__delete(evsel);
361
362 /* If the affinity was changed, then put it back to all CPUs. */
363 if (pmu->cpus != NULL) {
364 struct perf_cpu_map *cpus = cpu_map__online();
365
366 cpu_map__set_affinity(cpus);
367 perf_cpu_map__put(cpus);
368 }
369 set_user_read(pmu, saved_user_read_state);
370 }
371 perf_thread_map__put(threads);
372 return ret;
373 }
374
test__mmap_user_read_instr(struct test_suite * test __maybe_unused,int subtest __maybe_unused)375 static int test__mmap_user_read_instr(struct test_suite *test __maybe_unused,
376 int subtest __maybe_unused)
377 {
378 return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS, USER_READ_ENABLED);
379 }
380
test__mmap_user_read_cycles(struct test_suite * test __maybe_unused,int subtest __maybe_unused)381 static int test__mmap_user_read_cycles(struct test_suite *test __maybe_unused,
382 int subtest __maybe_unused)
383 {
384 return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES, USER_READ_ENABLED);
385 }
386
test__mmap_user_read_instr_disabled(struct test_suite * test __maybe_unused,int subtest __maybe_unused)387 static int test__mmap_user_read_instr_disabled(struct test_suite *test __maybe_unused,
388 int subtest __maybe_unused)
389 {
390 return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS, USER_READ_DISABLED);
391 }
392
test__mmap_user_read_cycles_disabled(struct test_suite * test __maybe_unused,int subtest __maybe_unused)393 static int test__mmap_user_read_cycles_disabled(struct test_suite *test __maybe_unused,
394 int subtest __maybe_unused)
395 {
396 return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES, USER_READ_DISABLED);
397 }
398
399 static struct test_case tests__basic_mmap[] = {
400 TEST_CASE_REASON("Read samples using the mmap interface",
401 basic_mmap,
402 "permissions"),
403 TEST_CASE_REASON_EXCLUSIVE("User space counter reading of instructions",
404 mmap_user_read_instr,
405 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
406 (defined(__riscv) && __riscv_xlen == 64)
407 "permissions"
408 #else
409 "unsupported"
410 #endif
411 ),
412 TEST_CASE_REASON_EXCLUSIVE("User space counter reading of cycles",
413 mmap_user_read_cycles,
414 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
415 (defined(__riscv) && __riscv_xlen == 64)
416 "permissions"
417 #else
418 "unsupported"
419 #endif
420 ),
421 TEST_CASE_REASON_EXCLUSIVE("User space counter disabling instructions",
422 mmap_user_read_instr_disabled,
423 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
424 (defined(__riscv) && __riscv_xlen == 64)
425 "permissions"
426 #else
427 "unsupported"
428 #endif
429 ),
430 TEST_CASE_REASON_EXCLUSIVE("User space counter disabling cycles",
431 mmap_user_read_cycles_disabled,
432 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
433 (defined(__riscv) && __riscv_xlen == 64)
434 "permissions"
435 #else
436 "unsupported"
437 #endif
438 ),
439 { .name = NULL, }
440 };
441
442 struct test_suite suite__basic_mmap = {
443 .desc = "mmap interface tests",
444 .test_cases = tests__basic_mmap,
445 };
446