diff options
Diffstat (limited to '')
-rw-r--r-- | tools/perf/tests/mmap-basic.c | 177 |
1 files changed, 159 insertions, 18 deletions
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 7b0dbfc0e17d..012c8ae439fd 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -1,17 +1,17 @@ // SPDX-License-Identifier: GPL-2.0 #include <errno.h> #include <inttypes.h> -/* For the CLR_() macros */ -#include <pthread.h> #include <stdlib.h> #include <perf/cpumap.h> #include "debug.h" +#include "event.h" #include "evlist.h" #include "evsel.h" #include "thread_map.h" #include "tests.h" #include "util/mmap.h" +#include "util/sample.h" #include <linux/err.h> #include <linux/kernel.h> #include <linux/string.h> @@ -29,9 +29,9 @@ * Then it checks if the number of syscalls reported as perf events by * the kernel corresponds to the number of syscalls made. */ -int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unused) +static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { - int err = -1; + int err = TEST_FAIL; union perf_event *event; struct perf_thread_map *threads; struct perf_cpu_map *cpus; @@ -52,24 +52,25 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse return -1; } - cpus = perf_cpu_map__new(NULL); + cpus = perf_cpu_map__new_online_cpus(); if (cpus == NULL) { pr_debug("perf_cpu_map__new\n"); goto out_free_threads; } CPU_ZERO(&cpu_set); - CPU_SET(cpus->map[0], &cpu_set); + CPU_SET(perf_cpu_map__cpu(cpus, 0).cpu, &cpu_set); sched_setaffinity(0, sizeof(cpu_set), &cpu_set); if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { pr_debug("sched_setaffinity() failed on CPU %d: %s ", - cpus->map[0], str_error_r(errno, sbuf, sizeof(sbuf))); + perf_cpu_map__cpu(cpus, 0).cpu, + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_free_cpus; } evlist = evlist__new(); if (evlist == NULL) { - pr_debug("perf_evlist__new\n"); + pr_debug("evlist__new\n"); goto out_free_cpus; } @@ -82,6 +83,10 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse evsels[i] = evsel__newtp("syscalls", name); if (IS_ERR(evsels[i])) { pr_debug("evsel__new(%s)\n", name); + if (PTR_ERR(evsels[i]) == -EACCES) { + /* Permissions failure, flag the failure as a skip. */ + err = TEST_SKIP; + } goto out_delete_evlist; } @@ -109,8 +114,7 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse for (i = 0; i < nsyscalls; ++i) for (j = 0; j < expected_nr_events[i]; ++j) { - int foo = syscalls[i](); - ++foo; + syscalls[i](); } md = &evlist->mmap[0]; @@ -126,20 +130,20 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse goto out_delete_evlist; } - err = perf_evlist__parse_sample(evlist, event, &sample); + err = evlist__parse_sample(evlist, event, &sample); if (err) { pr_err("Can't parse sample, err = %d\n", err); goto out_delete_evlist; } err = -1; - evsel = perf_evlist__id2evsel(evlist, sample.id); + evsel = evlist__id2evsel(evlist, sample.id); if (evsel == NULL) { pr_debug("event with id %" PRIu64 " doesn't map to an evsel\n", sample.id); goto out_delete_evlist; } - nr_events[evsel->idx]++; + nr_events[evsel->core.idx]++; perf_mmap__consume(&md->core); } perf_mmap__read_done(&md->core); @@ -147,10 +151,10 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse out_init: err = 0; evlist__for_each_entry(evlist, evsel) { - if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { + if (nr_events[evsel->core.idx] != expected_nr_events[evsel->core.idx]) { pr_debug("expected %d %s events, got %d\n", - expected_nr_events[evsel->idx], - evsel__name(evsel), nr_events[evsel->idx]); + expected_nr_events[evsel->core.idx], + evsel__name(evsel), nr_events[evsel->core.idx]); err = -1; goto out_delete_evlist; } @@ -158,11 +162,148 @@ out_init: out_delete_evlist: evlist__delete(evlist); - cpus = NULL; - threads = NULL; out_free_cpus: perf_cpu_map__put(cpus); out_free_threads: perf_thread_map__put(threads); return err; } + +static int test_stat_user_read(int event) +{ + struct perf_counts_values counts = { .val = 0 }; + struct perf_thread_map *threads; + struct perf_evsel *evsel; + struct perf_event_mmap_page *pc; + struct perf_event_attr attr = { + .type = PERF_TYPE_HARDWARE, + .config = event, +#ifdef __aarch64__ + .config1 = 0x2, /* Request user access */ +#endif + }; + int err, i, ret = TEST_FAIL; + bool opened = false, mapped = false; + + threads = perf_thread_map__new_dummy(); + TEST_ASSERT_VAL("failed to create threads", threads); + + perf_thread_map__set_pid(threads, 0, 0); + + evsel = perf_evsel__new(&attr); + TEST_ASSERT_VAL("failed to create evsel", evsel); + + err = perf_evsel__open(evsel, NULL, threads); + if (err) { + pr_err("failed to open evsel: %s\n", strerror(-err)); + ret = TEST_SKIP; + goto out; + } + opened = true; + + err = perf_evsel__mmap(evsel, 0); + if (err) { + pr_err("failed to mmap evsel: %s\n", strerror(-err)); + goto out; + } + mapped = true; + + pc = perf_evsel__mmap_base(evsel, 0, 0); + if (!pc) { + pr_err("failed to get mmapped address\n"); + goto out; + } + + if (!pc->cap_user_rdpmc || !pc->index) { + pr_err("userspace counter access not %s\n", + !pc->cap_user_rdpmc ? "supported" : "enabled"); + ret = TEST_SKIP; + goto out; + } + if (pc->pmc_width < 32) { + pr_err("userspace counter width not set (%d)\n", pc->pmc_width); + goto out; + } + + perf_evsel__read(evsel, 0, 0, &counts); + if (counts.val == 0) { + pr_err("failed to read value for evsel\n"); + goto out; + } + + for (i = 0; i < 5; i++) { + volatile int count = 0x10000 << i; + __u64 start, end, last = 0; + + pr_debug("\tloop = %u, ", count); + + perf_evsel__read(evsel, 0, 0, &counts); + start = counts.val; + + while (count--) ; + + perf_evsel__read(evsel, 0, 0, &counts); + end = counts.val; + + if ((end - start) < last) { + pr_err("invalid counter data: end=%llu start=%llu last= %llu\n", + end, start, last); + goto out; + } + last = end - start; + pr_debug("count = %llu\n", end - start); + } + ret = TEST_OK; + +out: + if (mapped) + perf_evsel__munmap(evsel); + if (opened) + perf_evsel__close(evsel); + perf_evsel__delete(evsel); + + perf_thread_map__put(threads); + return ret; +} + +static int test__mmap_user_read_instr(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS); +} + +static int test__mmap_user_read_cycles(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES); +} + +static struct test_case tests__basic_mmap[] = { + TEST_CASE_REASON("Read samples using the mmap interface", + basic_mmap, + "permissions"), + TEST_CASE_REASON("User space counter reading of instructions", + mmap_user_read_instr, +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ + (defined(__riscv) && __riscv_xlen == 64) + "permissions" +#else + "unsupported" +#endif + ), + TEST_CASE_REASON("User space counter reading of cycles", + mmap_user_read_cycles, +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ + (defined(__riscv) && __riscv_xlen == 64) + "permissions" +#else + "unsupported" +#endif + ), + { .name = NULL, } +}; + +struct test_suite suite__basic_mmap = { + .desc = "mmap interface tests", + .test_cases = tests__basic_mmap, +}; |