summaryrefslogtreecommitdiff
path: root/tools/perf/tests/mmap-basic.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/tests/mmap-basic.c')
-rw-r--r--tools/perf/tests/mmap-basic.c189
1 files changed, 114 insertions, 75 deletions
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 5cec7644952c..602a78d48b10 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -2,6 +2,7 @@
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
+#include <unistd.h>
#include <fcntl.h>
#include <linux/err.h>
@@ -12,6 +13,8 @@
#include <perf/evlist.h>
#include <perf/mmap.h>
+#include <tools/config.h>
+
#include "cpumap.h"
#include "debug.h"
#include "event.h"
@@ -182,50 +185,83 @@ out_free_threads:
}
enum user_read_state {
- USER_READ_ENABLED,
- USER_READ_DISABLED,
- USER_READ_UNKNOWN,
+ USER_READ_ERR_PERM = -2,
+ USER_READ_ERR_NO_FILE = -1,
+
+ USER_READ_DISABLED = '0',
+ USER_READ_ENABLED = '1',
+#if defined(__i386__) || defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64)
+ /* Unrestricted access on x86, legacy access on RISC-V. */
+ USER_READ_LEGACY = '2',
+#endif
+ USER_READ_MAX
};
-static enum user_read_state set_user_read(struct perf_pmu *pmu, enum user_read_state enabled)
+static enum user_read_state user_read_file_op(int fd, enum user_read_state enabled)
{
char buf[2] = {0, '\n'};
- ssize_t len;
- int events_fd, rdpmc_fd;
- enum user_read_state old_user_read = USER_READ_UNKNOWN;
-
- if (enabled == USER_READ_UNKNOWN)
- return USER_READ_UNKNOWN;
-
- events_fd = perf_pmu__event_source_devices_fd();
- if (events_fd < 0)
- return USER_READ_UNKNOWN;
-
- rdpmc_fd = perf_pmu__pathname_fd(events_fd, pmu->name, "rdpmc", O_RDWR);
- if (rdpmc_fd < 0) {
- close(events_fd);
- return USER_READ_UNKNOWN;
- }
+ ssize_t len = read(fd, buf, 1);
+ enum user_read_state old_user_read = USER_READ_ERR_NO_FILE;
- len = read(rdpmc_fd, buf, sizeof(buf));
- if (len != sizeof(buf))
+ if (len <= 0) {
pr_debug("%s read failed\n", __func__);
+ goto out;
+ }
- // Note, on Intel hybrid disabling on 1 PMU will implicitly disable on
- // all the core PMUs.
- old_user_read = (buf[0] == '1') ? USER_READ_ENABLED : USER_READ_DISABLED;
+ old_user_read = buf[0];
if (enabled != old_user_read) {
- buf[0] = (enabled == USER_READ_ENABLED) ? '1' : '0';
- len = write(rdpmc_fd, buf, sizeof(buf));
+ buf[0] = enabled;
+ lseek(fd, 0, SEEK_SET);
+ len = write(fd, buf, sizeof(buf));
if (len != sizeof(buf))
pr_debug("%s write failed\n", __func__);
}
- close(rdpmc_fd);
- close(events_fd);
+
+out:
+ close(fd);
return old_user_read;
}
+static enum user_read_state set_user_read(struct perf_pmu *pmu,
+ enum user_read_state enabled)
+{
+ int events_fd, fd;
+ enum user_read_state ret = USER_READ_ERR_NO_FILE;
+
+ if (enabled == USER_READ_ERR_NO_FILE || enabled == USER_READ_ERR_PERM)
+ return enabled;
+
+ events_fd = perf_pmu__event_source_devices_fd();
+ if (events_fd >= 0) {
+ fd = perf_pmu__pathname_fd(events_fd, pmu->name, "rdpmc", O_RDWR);
+ if (fd >= 0) {
+ /*
+ * Note, on Intel hybrid disabling on 1 PMU will implicitly
+ * disable on all the core PMUs.
+ */
+ ret = user_read_file_op(fd, enabled);
+ close(events_fd);
+ return ret;
+ } else if (errno == EACCES || errno == EROFS) {
+ /* Permissions failure, flag the failure for a skip. */
+ close(events_fd);
+ return USER_READ_ERR_PERM;
+ }
+ close(events_fd);
+ }
+
+ /* Fallback: perf_user_access interface (arm64, riscv, or similar) */
+ fd = open("/proc/sys/kernel/perf_user_access", O_RDWR);
+ if (fd >= 0)
+ ret = user_read_file_op(fd, enabled);
+ else if (errno == EACCES || errno == EROFS)
+ ret = USER_READ_ERR_PERM;
+
+ return ret;
+}
+
+
static int test_stat_user_read(u64 event, enum user_read_state enabled)
{
struct perf_pmu *pmu = NULL;
@@ -246,9 +282,6 @@ static int test_stat_user_read(u64 event, enum user_read_state enabled)
.config = perf_pmus__supports_extended_type()
? event | ((u64)pmu->type << PERF_PMU_TYPE_SHIFT)
: event,
-#ifdef __aarch64__
- .config1 = 0x2, /* Request user access */
-#endif
};
struct perf_evsel *evsel = NULL;
int err;
@@ -256,8 +289,28 @@ static int test_stat_user_read(u64 event, enum user_read_state enabled)
bool mapped = false, opened = false, rdpmc_supported;
struct perf_counts_values counts = { .val = 0 };
+ if (__is_defined(__aarch64__) && enabled == USER_READ_ENABLED)
+ attr.config1 = 0x2; /* Request user access */
pr_debug("User space counter reading for PMU %s\n", pmu->name);
+
+ if (saved_user_read_state == USER_READ_ERR_PERM) {
+ pr_debug("User space counter reading for PMU %s [Failed to get user read state]\n",
+ pmu->name);
+ ret = TEST_SKIP;
+ goto cleanup;
+ }
+
+ /* Check value is in the expected range */
+ if (saved_user_read_state != USER_READ_ERR_NO_FILE &&
+ (saved_user_read_state < USER_READ_DISABLED ||
+ saved_user_read_state >= USER_READ_MAX)) {
+ pr_err("User space counter reading for PMU %s [Unexpected current state %d]\n",
+ pmu->name, saved_user_read_state);
+ ret = TEST_FAIL;
+ goto cleanup;
+ }
+
/*
* Restrict scheduling to only use the rdpmc on the CPUs the
* event can be on. If the test doesn't run on the CPU of the
@@ -301,21 +354,18 @@ static int test_stat_user_read(u64 event, enum user_read_state enabled)
goto cleanup;
}
- if (saved_user_read_state == USER_READ_UNKNOWN)
- rdpmc_supported = pc->cap_user_rdpmc && pc->index;
- else
- rdpmc_supported = (enabled == USER_READ_ENABLED);
+ rdpmc_supported = (enabled == USER_READ_ENABLED);
- if (rdpmc_supported && (!pc->cap_user_rdpmc || !pc->index)) {
- pr_err("User space counter reading for PMU %s [Failed unexpected supported counter access %d %d]\n",
- pmu->name, pc->cap_user_rdpmc, pc->index);
+ if (rdpmc_supported && !pc->index) {
+ pr_err("User space counter reading for PMU %s [index must be set when enabled %d]\n",
+ pmu->name, pc->index);
ret = TEST_FAIL;
goto cleanup;
}
- if (!rdpmc_supported && pc->cap_user_rdpmc) {
- pr_err("User space counter reading for PMU %s [Failed unexpected unsupported counter access %d]\n",
- pmu->name, pc->cap_user_rdpmc);
+ if (rdpmc_supported != pc->cap_user_rdpmc) {
+ pr_err("User space counter reading for PMU %s [cap should match requested state %d %d]\n",
+ pmu->name, pc->cap_user_rdpmc, rdpmc_supported);
ret = TEST_FAIL;
goto cleanup;
}
@@ -363,7 +413,8 @@ cleanup:
perf_evsel__munmap(evsel);
if (opened)
perf_evsel__close(evsel);
- perf_evsel__delete(evsel);
+ if (evsel)
+ perf_evsel__delete(evsel);
/* If the affinity was changed, then put it back to all CPUs. */
if (pmu->cpus != NULL) {
@@ -378,13 +429,13 @@ cleanup:
return ret;
}
-static int test__mmap_user_read_instr(struct test_suite *test __maybe_unused,
+static int __maybe_unused test__mmap_user_read_instr(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS, USER_READ_ENABLED);
}
-static int test__mmap_user_read_cycles(struct test_suite *test __maybe_unused,
+static int __maybe_unused 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, USER_READ_ENABLED);
@@ -406,46 +457,34 @@ static struct test_case tests__basic_mmap[] = {
TEST_CASE_REASON("Read samples using the mmap interface",
basic_mmap,
"permissions"),
- TEST_CASE_REASON_EXCLUSIVE("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
- ),
+ /*
+ * libperf only supports userspace read for these platforms, see
+ * tools/lib/perf/mmap.c
+ */
+ TEST_CASE_REASON_EXCLUSIVE("User space counter reading of instructions",
+ mmap_user_read_instr,
+ "permissions"),
TEST_CASE_REASON_EXCLUSIVE("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"
+ mmap_user_read_cycles,
+ "permissions"),
#endif
- ),
+
+ /* Counter read via userpage fallback is supported on all platforms */
TEST_CASE_REASON_EXCLUSIVE("User space counter disabling instructions",
- mmap_user_read_instr_disabled,
-#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
- (defined(__riscv) && __riscv_xlen == 64)
- "permissions"
-#else
- "unsupported"
-#endif
- ),
+ mmap_user_read_instr_disabled,
+ "permissions"),
TEST_CASE_REASON_EXCLUSIVE("User space counter disabling cycles",
- mmap_user_read_cycles_disabled,
-#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
- (defined(__riscv) && __riscv_xlen == 64)
- "permissions"
-#else
- "unsupported"
-#endif
- ),
+ mmap_user_read_cycles_disabled,
+ "permissions"),
+
{ .name = NULL, }
};
struct test_suite suite__basic_mmap = {
.desc = "mmap interface tests",
.test_cases = tests__basic_mmap,
+ .needs_mlock = true,
};