summaryrefslogtreecommitdiff
path: root/tools/perf/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/tests')
-rw-r--r--tools/perf/tests/Build1
-rw-r--r--tools/perf/tests/backward-ring-buffer.c2
-rw-r--r--tools/perf/tests/builtin-test.c276
-rw-r--r--tools/perf/tests/code-reading.c2
-rw-r--r--tools/perf/tests/dso-data.c7
-rw-r--r--tools/perf/tests/event_refresh.c162
-rw-r--r--tools/perf/tests/keep-tracking.c2
-rw-r--r--tools/perf/tests/mmap-basic.c189
-rw-r--r--tools/perf/tests/openat-syscall-tp-fields.c1
-rw-r--r--tools/perf/tests/pe-file-parsing.c22
-rw-r--r--tools/perf/tests/perf-record.c1
-rw-r--r--tools/perf/tests/perf-time-to-tsc.c1
-rw-r--r--tools/perf/tests/pmu-events.c5
-rw-r--r--tools/perf/tests/shell/attr/README10
-rw-r--r--tools/perf/tests/shell/attr/base-stat-group45
-rw-r--r--tools/perf/tests/shell/attr/test-record-graph-dwarf2
-rw-r--r--tools/perf/tests/shell/attr/test-record-group-sampling5
-rw-r--r--tools/perf/tests/shell/attr/test-record-group-sampling15
-rw-r--r--tools/perf/tests/shell/attr/test-record-group-sampling25
-rw-r--r--tools/perf/tests/shell/attr/test-record-group13
-rw-r--r--tools/perf/tests/shell/attr/test-record-group23
-rw-r--r--tools/perf/tests/shell/attr/test-record-group33
-rw-r--r--tools/perf/tests/shell/attr/test-stat-C01
-rw-r--r--tools/perf/tests/shell/attr/test-stat-basic1
-rw-r--r--tools/perf/tests/shell/attr/test-stat-default91
-rw-r--r--tools/perf/tests/shell/attr/test-stat-detailed-199
-rw-r--r--tools/perf/tests/shell/attr/test-stat-detailed-2111
-rw-r--r--tools/perf/tests/shell/attr/test-stat-detailed-3115
-rw-r--r--tools/perf/tests/shell/attr/test-stat-group13
-rw-r--r--tools/perf/tests/shell/attr/test-stat-no-inherit1
-rwxr-xr-xtools/perf/tests/shell/drm_pmu.sh2
-rwxr-xr-xtools/perf/tests/shell/ftrace.sh2
-rwxr-xr-xtools/perf/tests/shell/kallsyms.sh2
-rw-r--r--tools/perf/tests/shell/lib/attr.py461
-rwxr-xr-xtools/perf/tests/shell/list.sh2
-rwxr-xr-xtools/perf/tests/shell/perf_sched_stats.sh2
-rwxr-xr-xtools/perf/tests/shell/probe_vfs_getname.sh2
-rwxr-xr-xtools/perf/tests/shell/python-use.sh2
-rwxr-xr-xtools/perf/tests/shell/schedstat_snapshots.sh2
-rwxr-xr-xtools/perf/tests/shell/stat+csv_output.sh2
-rwxr-xr-xtools/perf/tests/shell/stat+csv_summary.sh2
-rwxr-xr-xtools/perf/tests/shell/stat+event_uniquifying.sh2
-rwxr-xr-xtools/perf/tests/shell/stat+json_output.sh2
-rwxr-xr-xtools/perf/tests/shell/stat+shadow_stat.sh2
-rwxr-xr-xtools/perf/tests/shell/stat+std_output.sh2
-rwxr-xr-xtools/perf/tests/shell/stat.sh2
-rwxr-xr-xtools/perf/tests/shell/stat_all_metricgroups.sh2
-rwxr-xr-xtools/perf/tests/shell/stat_all_metrics.sh2
-rwxr-xr-xtools/perf/tests/shell/stat_all_pfm.sh2
-rwxr-xr-xtools/perf/tests/shell/stat_bpf_counters_cgrp.sh2
-rwxr-xr-xtools/perf/tests/shell/stat_metrics_cgrp.sh2
-rwxr-xr-xtools/perf/tests/shell/stat_metrics_values.sh2
-rwxr-xr-xtools/perf/tests/shell/test_ilist_python.sh2
-rwxr-xr-xtools/perf/tests/shell/test_stat_cpi_python.sh2
-rwxr-xr-xtools/perf/tests/shell/test_test_junit_output.sh5
-rwxr-xr-xtools/perf/tests/shell/test_uprobe_from_different_cu.sh2
-rw-r--r--tools/perf/tests/sw-clock.c2
-rw-r--r--tools/perf/tests/task-exit.c1
-rw-r--r--tools/perf/tests/tests-scripts.c85
-rw-r--r--tools/perf/tests/tests.h18
60 files changed, 1444 insertions, 350 deletions
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 395f2866094a..58858f3d2bf9 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -23,6 +23,7 @@ perf-test-y += hists_output.o
perf-test-y += hists_cumulate.o
perf-test-y += bp_signal.o
perf-test-y += bp_signal_overflow.o
+perf-test-y += event_refresh.o
perf-test-y += bp_account.o
perf-test-y += wp.o
perf-test-y += task-exit.o
diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c
index 2735cc26d7ee..9314696858ff 100644
--- a/tools/perf/tests/backward-ring-buffer.c
+++ b/tools/perf/tests/backward-ring-buffer.c
@@ -167,4 +167,4 @@ out_put_evlist:
return ret;
}
-DEFINE_SUITE("Read backward ring buffer", backward_ring_buffer);
+DEFINE_SUITE_NEEDS_MLOCK("Read backward ring buffer", backward_ring_buffer);
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 98134b1c74cf..0b8897fd42ca 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -11,6 +11,7 @@
#include <execinfo.h>
#endif
#include <setjmp.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -32,6 +33,8 @@
#include <subcmd/parse-options.h>
#include <subcmd/run-command.h>
+#include <sys/mman.h>
+
#include "builtin.h"
#include "color.h"
#include "config.h"
@@ -42,6 +45,9 @@
#include "symbol.h"
#include "tests-scripts.h"
#include "tests.h"
+#include "util/cap.h"
+#include "util/event.h"
+#include "util/mutex.h"
#include "util/rlimit.h"
#include "util/strbuf.h"
#include "util/term.h"
@@ -56,10 +62,23 @@ static struct strbuf junit_xml_buf = STRBUF_INIT;
static bool dont_fork;
/* Fork the tests in parallel and wait for their completion. */
static bool sequential;
+/* List what each test needs, set by the "requisites" subcommand. */
+static bool list_requisites;
/* Number of times each test is run. */
static unsigned int runs_per_test = 1;
/* Number of lines to include in failure snippet. */
static unsigned int failure_snippet_lines = 10;
+/*
+ * The tests mapping ring buffers take turns using their share of
+ * kernel.perf_event_mlock_kb via this mutex, shared with the forked test
+ * processes and robust so that a test killed while holding it doesn't leave
+ * the budget locked, see mutex_init_pshared_robust().
+ */
+struct mlock_budget {
+ struct mutex lock;
+};
+
+static struct mlock_budget *mlock_budget;
const char *dso_to_test;
const char *test_objdump_path = "objdump";
static const char *workload_control;
@@ -101,6 +120,7 @@ static struct test_suite *generic_tests[] = {
&suite__hists_link,
&suite__bp_signal,
&suite__bp_signal_overflow,
+ &suite__event_refresh,
&suite__bp_accounting,
&suite__wp,
&suite__task_exit,
@@ -283,6 +303,30 @@ static const char *test_description(const struct test_suite *t, int test_case)
return t->desc;
}
+static void requisites__fprintf(FILE *fp, const struct test_suite *t, int test_case)
+{
+ bool needs_mlock = t->needs_mlock, exclusive;
+
+ if (test_case < 0)
+ test_case = test_suite__num_test_cases(t) == 1 ? 0 : -1;
+
+ if (test_case >= 0) {
+ exclusive = t->test_cases[test_case].exclusive;
+ /* The catch-all implies every other requisite. */
+ needs_mlock = needs_mlock || exclusive;
+ } else {
+ exclusive = false;
+ }
+
+ if (!exclusive && !needs_mlock)
+ return;
+
+ fprintf(fp, " (");
+ if (exclusive)
+ fprintf(fp, "exclusive, ");
+ fprintf(fp, "mlock)");
+}
+
static test_fnptr test_function(const struct test_suite *t, int test_case)
{
if (test_case <= 0)
@@ -352,12 +396,30 @@ static void child_test_sig_handler(int sig)
siglongjmp(run_test_jmp_buf, sig);
}
+static int run_test_case(struct child_test *child)
+{
+ return test_function(child->test, child->test_case_num)(child->test, child->test_case_num);
+}
+
+/* The thread safety analysis can't express a lock held conditionally. */
+static int run_test_case_mlocked(struct child_test *child)
+{
+ int err;
+
+ mutex_lock(&mlock_budget->lock);
+ err = run_test_case(child);
+ mutex_unlock(&mlock_budget->lock);
+
+ return err;
+}
+
static int run_test_child(struct child_process *process)
{
const int signals[] = {
SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGINT, SIGPIPE, SIGQUIT, SIGSEGV, SIGTERM,
};
struct child_test *child = container_of(process, struct child_test, process);
+ bool needs_mlock = mlock_budget && child->test->needs_mlock;
int err;
close_parent_fds();
@@ -374,7 +436,12 @@ static int run_test_child(struct child_process *process)
pr_debug("---- start ----\n");
pr_debug("test child forked, pid %d\n", getpid());
- err = test_function(child->test, child->test_case_num)(child->test, child->test_case_num);
+
+ if (needs_mlock)
+ err = run_test_case_mlocked(child);
+ else
+ err = run_test_case(child);
+
pr_debug("---- end(%d) ----\n", err);
check_leaks();
@@ -628,6 +695,47 @@ static void print_line_highlighted(FILE *fp, const char *line, size_t len)
}
+static bool is_blank_line(const char *line, size_t len)
+{
+ for (size_t i = 0; i < len; i++) {
+ if (!isspace((unsigned char)line[i]))
+ return false;
+ }
+ return true;
+}
+
+static bool is_stack_line(const char *line, size_t len)
+{
+ size_t i = 0;
+
+ while (i < len && isspace((unsigned char)line[i]))
+ i++;
+ return i + 1 < len && line[i] == '#' && isdigit((unsigned char)line[i + 1]);
+}
+
+static bool is_ignorable_snippet_line(const char *line, size_t len)
+{
+ return is_blank_line(line, len) || is_stack_line(line, len);
+}
+
+static bool has_non_blank_between(const char **lines, const size_t *line_lens,
+ size_t start, size_t end)
+{
+ for (size_t j = start + 1; j < end; j++) {
+ if (!is_blank_line(lines[j], line_lens[j]))
+ return true;
+ }
+ return false;
+}
+
+static void pick_snippet_line(bool *pick, size_t idx, unsigned int *picked_count)
+{
+ if (!pick[idx] && *picked_count < failure_snippet_lines) {
+ pick[idx] = true;
+ (*picked_count)++;
+ }
+}
+
static void print_test_failure_snippet(FILE *fp, const char *buf)
{
size_t num_lines = 0;
@@ -698,43 +806,63 @@ static void print_test_failure_snippet(FILE *fp, const char *buf)
}
/* Pass 0: Always pick the very first line */
- if (num_lines > 0 && picked_count < failure_snippet_lines) {
- pick[0] = true;
- picked_count++;
- }
+ if (num_lines > 0)
+ pick_snippet_line(pick, 0, &picked_count);
/* Pass 1: Pick lines with failure keywords from start (Highest Priority) */
for (i = 0; i < num_lines && picked_count < failure_snippet_lines; i++) {
size_t dummy;
- if (find_next_keyword(lines[i], line_lens[i], &dummy)) {
- if (!pick[i]) {
- pick[i] = true;
- picked_count++;
- }
- /* Prioritize getting the immediate next line for context */
- if (i + 1 < num_lines && !pick[i + 1] &&
- picked_count < failure_snippet_lines) {
- pick[i + 1] = true;
- picked_count++;
+ if (is_ignorable_snippet_line(lines[i], line_lens[i]))
+ continue;
+ if (!find_next_keyword(lines[i], line_lens[i], &dummy))
+ continue;
+
+ pick_snippet_line(pick, i, &picked_count);
+ /*
+ * For unexpected signals, prioritize the preceding non-blank
+ * line showing where the test had run to before the signal.
+ */
+ if (!strncmp(lines[i], "---- unexpected signal", 22)) {
+ size_t j = i;
+
+ while (j > 0) {
+ j--;
+ if (!is_ignorable_snippet_line(lines[j], line_lens[j])) {
+ pick_snippet_line(pick, j, &picked_count);
+ break;
+ }
}
}
+ /* Prioritize getting the immediate next line for context */
+ if (i + 1 < num_lines &&
+ !is_ignorable_snippet_line(lines[i + 1], line_lens[i + 1]))
+ pick_snippet_line(pick, i + 1, &picked_count);
}
- /* Pass 2: Fill remaining quota from the end backwards */
+ /*
+ * Pass 2: Fill remaining quota from the end backwards, skipping blank
+ * and stack trace lines so trailing test progress is shown instead of
+ * outermost stack frames like main/_start.
+ */
i = num_lines;
while (i > 0 && picked_count < failure_snippet_lines) {
i--;
- if (!pick[i]) {
- pick[i] = true;
- picked_count++;
- }
+ if (!is_ignorable_snippet_line(lines[i], line_lens[i]))
+ pick_snippet_line(pick, i, &picked_count);
+ }
+
+ /* Pass 3: Fallback to top stack frames if quota remains */
+ for (i = 0; i < num_lines && picked_count < failure_snippet_lines; i++) {
+ if (!is_blank_line(lines[i], line_lens[i]))
+ pick_snippet_line(pick, i, &picked_count);
}
for (i = 0; i < num_lines; i++) {
if (!pick[i])
continue;
- if (last_printed != -1 && (int)i > last_printed + 1) {
+ if (last_printed != -1 &&
+ has_non_blank_between(lines, line_lens, last_printed, i)) {
if (perf_use_color_default)
fprintf(fp, "%s...%s\n", PERF_COLOR_BLUE, PERF_COLOR_RESET);
else
@@ -1450,14 +1578,20 @@ static int perf_test__list(FILE *fp, struct test_suite **suites, int argc, const
if (!perf_test__matches(test_description(*t, -1), curr_suite, argc, argv))
continue;
- fprintf(fp, "%3d: %s\n", curr_suite + 1, test_description(*t, -1));
+ fprintf(fp, "%3d: %s", curr_suite + 1, test_description(*t, -1));
+ if (list_requisites)
+ requisites__fprintf(fp, *t, /*test_case=*/-1);
+ fprintf(fp, "\n");
if (test_suite__num_test_cases(*t) <= 1)
continue;
test_suite__for_each_test_case(*t, curr_test_case) {
- fprintf(fp, "%3d.%1d: %s\n", curr_suite + 1, curr_test_case + 1,
+ fprintf(fp, "%3d.%1d: %s", curr_suite + 1, curr_test_case + 1,
test_description(*t, curr_test_case));
+ if (list_requisites)
+ requisites__fprintf(fp, *t, curr_test_case);
+ fprintf(fp, "\n");
}
}
return 0;
@@ -1744,10 +1878,97 @@ static struct test_suite **build_suites(void)
#undef for_each_suite
}
+static bool perf_test__shares_mlock_budget(struct test_suite **suites, int argc,
+ const char *argv[], struct intlist *skiplist)
+{
+ int sharing = 0;
+
+ /* The selection rules mirrored here are __cmd_test()'s: when they change, change both. */
+ for (int curr_suite = 0; suites[curr_suite]; curr_suite++) {
+ struct test_suite *t = suites[curr_suite];
+ int curr_test_case;
+ bool suite_matched;
+
+ if (!t->needs_mlock || intlist__find(skiplist, curr_suite + 1))
+ continue;
+
+ suite_matched = perf_test__matches(test_description(t, /*test_case=*/-1),
+ curr_suite, argc, argv);
+ test_suite__for_each_test_case(t, curr_test_case) {
+ if (test_exclusive(t, curr_test_case))
+ continue;
+
+ if (suite_matched ||
+ perf_test__matches(test_description(t, curr_test_case),
+ curr_suite, argc, argv))
+ sharing += runs_per_test;
+ }
+ if (sharing > 1)
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Once the per user budget set in kernel.perf_event_mlock_kb is spent, what
+ * maps on top of it is charged against RLIMIT_MEMLOCK and the mapping is
+ * refused with EPERM when that runs out too, but only for the processes the
+ * kernel is paranoid about and that have no CAP_IPC_LOCK to lift the check,
+ * see perf_mmap_calc_limits() in the kernel: used by
+ * perf_test__setup_mlock_budget() below, that has nothing to take turns on
+ * when neither applies.
+ */
+static bool perf_test__mlock_budget_exhaustible(void)
+{
+ if (perf_cap__capable(CAP_IPC_LOCK))
+ return false;
+
+ return perf_event_paranoid() > -1;
+}
+
+static void perf_test__setup_mlock_budget(struct test_suite **suites, int argc,
+ const char *argv[], struct intlist *skiplist)
+{
+ /* Nothing can be denied the budget, nothing to take turns for. */
+ if (!perf_test__mlock_budget_exhaustible()) {
+ pr_debug("Not taking turns using the perf mlock budget: nothing can exhaust it\n");
+ return;
+ }
+
+ /* Nothing runs at the same time, nothing to share the budget with. */
+ if (sequential || !perf_test__shares_mlock_budget(suites, argc, argv, skiplist))
+ return;
+
+ mlock_budget = mmap(NULL, sizeof(*mlock_budget), PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, /*fd=*/-1, /*offset=*/0);
+ if (mlock_budget == MAP_FAILED) {
+ mlock_budget = NULL;
+ pr_err("Failed to map the shared area used to take turns using the perf mlock budget\n");
+ return;
+ }
+
+ if (!mutex_init_pshared_robust(&mlock_budget->lock)) {
+ munmap(mlock_budget, sizeof(*mlock_budget));
+ mlock_budget = NULL;
+ pr_debug("Not taking turns using the perf mlock budget\n");
+ }
+}
+
+static void perf_test__teardown_mlock_budget(void)
+{
+ if (!mlock_budget)
+ return;
+
+ mutex_destroy(&mlock_budget->lock);
+ munmap(mlock_budget, sizeof(*mlock_budget));
+ mlock_budget = NULL;
+}
+
int cmd_test(int argc, const char **argv)
{
const char *test_usage[] = {
- "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
+ "perf test [<options>] [{list|requisites} [<test-name-fragment>]|"
+ "[<test-name-fragments>|<test-numbers>]]",
NULL,
};
const char *skip = NULL;
@@ -1776,7 +1997,7 @@ int cmd_test(int argc, const char **argv)
"Generate junit XML output, default test.xml", "test.xml"),
OPT_END()
};
- const char * const test_subcommands[] = { "list", NULL };
+ const char * const test_subcommands[] = { "list", "requisites", NULL };
struct intlist *skiplist = NULL;
struct test_suite **suites;
int ret;
@@ -1808,10 +2029,11 @@ int cmd_test(int argc, const char **argv)
setvbuf(stdout, NULL, _IONBF, 0);
argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0);
- if (argc >= 1 && !strcmp(argv[0], "list")) {
+ if (argc >= 1 && (!strcmp(argv[0], "list") || !strcmp(argv[0], "requisites"))) {
suites = build_suites();
if (!suites)
return errno ? -errno : -ENOMEM;
+ list_requisites = !strcmp(argv[0], "requisites");
ret = perf_test__list(stdout, suites, argc - 1, argv + 1);
free(suites);
return ret;
@@ -1850,7 +2072,9 @@ int cmd_test(int argc, const char **argv)
intlist__delete(skiplist);
return err ? -err : -ENOMEM;
}
+ perf_test__setup_mlock_budget(suites, argc, argv, skiplist);
ret = __cmd_test(suites, argc, argv, skiplist);
+ perf_test__teardown_mlock_budget();
free(suites);
intlist__delete(skiplist);
return ret;
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index c50b526f44fb..130cd6021f93 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -885,4 +885,4 @@ static int test__code_reading(struct test_suite *test __maybe_unused, int subtes
};
}
-DEFINE_SUITE("Object code reading", code_reading);
+DEFINE_SUITE_NEEDS_MLOCK("Object code reading", code_reading);
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index 46bc3f597260..18b7052a2dc5 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -138,6 +138,10 @@ static int test__dso_data(struct test_suite *test __maybe_unused, int subtest __
dsos__init(&machine.dsos);
dso = dso__new(file);
+ TEST_ASSERT_VAL("Failed to get dso", dso);
+ /* override the binary type for dso data access */
+ dso__set_binary_type(dso, DSO_BINARY_TYPE__SYSTEM_PATH_DSO);
+ dso__set_bintype_searched(dso);
TEST_ASSERT_VAL("Failed to add dso", !dsos__add(&machine.dsos, dso));
TEST_ASSERT_VAL("Failed to access to dso",
dso__data_fd(dso, &machine) >= 0);
@@ -226,6 +230,9 @@ static int dsos__create(int cnt, int size, struct dsos *dsos)
TEST_ASSERT_VAL("failed to get dso file", file);
dso = dso__new(file);
TEST_ASSERT_VAL("failed to get dso", dso);
+ /* override the binary type for dso data access */
+ dso__set_binary_type(dso, DSO_BINARY_TYPE__SYSTEM_PATH_DSO);
+ dso__set_bintype_searched(dso);
TEST_ASSERT_VAL("failed to add dso", !dsos__add(dsos, dso));
dso__put(dso);
}
diff --git a/tools/perf/tests/event_refresh.c b/tools/perf/tests/event_refresh.c
new file mode 100644
index 000000000000..726e5de4c795
--- /dev/null
+++ b/tools/perf/tests/event_refresh.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Re-arm a sampling event from its overflow signal handler with
+ * PERF_EVENT_IOC_REFRESH and check that every overflow is delivered.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <linux/perf_event.h>
+
+#include "cloexec.h"
+#include "debug.h"
+#include "tests.h"
+#include "tp_pmu.h"
+#include <internal/lib.h> // page_size
+#include "../perf-sys.h"
+
+#define NR_EVENTS 1000
+/* A real-time signal is queued, so no overflow can be coalesced away. */
+#define REFRESH_SIGNAL (SIGRTMIN + 1)
+
+static volatile sig_atomic_t overflows, hups, refresh_errno;
+
+static void sig_handler(int signum __maybe_unused, siginfo_t *info,
+ void *uc __maybe_unused)
+{
+ int saved_errno = errno;
+
+ overflows++;
+ if (info->si_code == POLL_HUP)
+ hups++;
+ if (ioctl(info->si_fd, PERF_EVENT_IOC_REFRESH, 1) < 0)
+ refresh_errno = errno;
+ errno = saved_errno;
+}
+
+/* Count overflow signals for NR_EVENTS calls of trigger(), period 1. */
+static int count_overflows(struct perf_event_attr *attr, void (*trigger)(int i))
+{
+ struct sigaction sa, old_sa;
+ uint64_t count = 0;
+ int fd, i, err = TEST_FAIL;
+
+ attr->size = sizeof(*attr);
+ attr->sample_period = 1;
+ attr->disabled = 1;
+
+ fd = sys_perf_event_open(attr, 0, -1, -1, perf_event_open_cloexec_flag());
+ if (fd < 0) {
+ int open_errno = errno;
+
+ pr_debug("failed opening event: %s\n", strerror(open_errno));
+ return open_errno == EACCES || open_errno == EPERM ? TEST_SKIP : TEST_FAIL;
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = sig_handler;
+ sa.sa_flags = SA_SIGINFO;
+ if (sigaction(REFRESH_SIGNAL, &sa, &old_sa) < 0) {
+ pr_debug("failed setting up signal handler\n");
+ close(fd);
+ return TEST_FAIL;
+ }
+
+ if (fcntl(fd, F_SETFL, O_RDWR | O_NONBLOCK | O_ASYNC) < 0 ||
+ fcntl(fd, F_SETSIG, REFRESH_SIGNAL) < 0 ||
+ fcntl(fd, F_SETOWN, getpid()) < 0) {
+ pr_debug("failed setting up signal delivery: %s\n", strerror(errno));
+ goto out;
+ }
+
+ overflows = 0;
+ hups = 0;
+ refresh_errno = 0;
+ if (ioctl(fd, PERF_EVENT_IOC_REFRESH, 1) < 0) {
+ pr_debug("PERF_EVENT_IOC_REFRESH failed: %s\n", strerror(errno));
+ goto out;
+ }
+ for (i = 0; i < NR_EVENTS; i++)
+ trigger(i);
+ ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
+
+ if (read(fd, &count, sizeof(count)) != sizeof(count))
+ pr_debug("failed to read the event count\n");
+ pr_debug("%d events, count %" PRIu64 ", %d overflows (%d POLL_HUP), re-arm errno %d\n",
+ NR_EVENTS, count, overflows, hups, refresh_errno);
+ /* Unrelated page faults can only add overflows, never hide one. */
+ if (overflows >= NR_EVENTS)
+ err = TEST_OK;
+out:
+ /* Close first: a late signal must still find our handler. */
+ close(fd);
+ sigaction(REFRESH_SIGNAL, &old_sa, NULL);
+ return err;
+}
+
+static char *pages;
+
+static void touch_page(int i)
+{
+ pages[(long)i * page_size] = 1;
+}
+
+static int test__event_refresh_sw(struct test_suite *test __maybe_unused,
+ int subtest __maybe_unused)
+{
+ struct perf_event_attr attr = {
+ .type = PERF_TYPE_SOFTWARE,
+ .config = PERF_COUNT_SW_PAGE_FAULTS,
+ };
+ int err;
+
+ pages = mmap(NULL, (long)NR_EVENTS * page_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (pages == MAP_FAILED)
+ return TEST_FAIL;
+ /* One fault per touched page: a huge page would cover many of them. */
+ madvise(pages, (long)NR_EVENTS * page_size, MADV_NOHUGEPAGE);
+
+ err = count_overflows(&attr, touch_page);
+ munmap(pages, (long)NR_EVENTS * page_size);
+ return err;
+}
+
+static void call_getppid(int i __maybe_unused)
+{
+ syscall(SYS_getppid);
+}
+
+static int test__event_refresh_tp(struct test_suite *test __maybe_unused,
+ int subtest __maybe_unused)
+{
+ struct perf_event_attr attr = {
+ .type = PERF_TYPE_TRACEPOINT,
+ };
+ int id = tp_pmu__id("syscalls", "sys_enter_getppid");
+
+ if (id < 0) {
+ pr_debug("no syscalls:sys_enter_getppid tracepoint\n");
+ return TEST_SKIP;
+ }
+ attr.config = id;
+
+ return count_overflows(&attr, call_getppid);
+}
+
+static struct test_case tests__event_refresh[] = {
+ TEST_CASE_REASON("Software event", event_refresh_sw, "permissions"),
+ TEST_CASE_REASON("Tracepoint event", event_refresh_tp, "permissions"),
+ { .name = NULL, }
+};
+
+struct test_suite suite__event_refresh = {
+ .desc = "Event re-armed with PERF_EVENT_IOC_REFRESH",
+ .test_cases = tests__event_refresh,
+};
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index b760041bed30..6d8d8cd57200 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -161,4 +161,4 @@ out_err:
return err;
}
-DEFINE_SUITE("Use a dummy software event to keep tracking", keep_tracking);
+DEFINE_SUITE_NEEDS_MLOCK("Use a dummy software event to keep tracking", keep_tracking);
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,
};
diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c
index 5365889d326f..1ea336fbc7e7 100644
--- a/tools/perf/tests/openat-syscall-tp-fields.c
+++ b/tools/perf/tests/openat-syscall-tp-fields.c
@@ -160,4 +160,5 @@ static struct test_case tests__syscall_openat_tp_fields[] = {
struct test_suite suite__syscall_openat_tp_fields = {
.desc = "syscalls:sys_enter_openat event fields",
.test_cases = tests__syscall_openat_tp_fields,
+ .needs_mlock = true,
};
diff --git a/tools/perf/tests/pe-file-parsing.c b/tools/perf/tests/pe-file-parsing.c
index 30c7da79e109..190520ffc3ad 100644
--- a/tools/perf/tests/pe-file-parsing.c
+++ b/tools/perf/tests/pe-file-parsing.c
@@ -59,7 +59,7 @@ static int run_dir(const char *d)
TEST_ASSERT_VAL("Failed to get dso", dso);
ret = dso__load_bfd_symbols(dso, debugfile);
- TEST_ASSERT_VAL("Failed to load symbols", ret == 0);
+ TEST_ASSERT_VAL("Failed to load symbols", ret > 0);
dso__sort_by_name(dso);
sym = dso__find_symbol_by_name(dso, "main", &idx);
@@ -74,17 +74,20 @@ static int test__pe_file_parsing(struct test_suite *test __maybe_unused,
{
struct stat st;
char path_dir[PATH_MAX];
-
- /* First try development tree tests. */
- if (!lstat("./tests", &st))
- return run_dir("./tests");
-
- /* Then installed path. */
+ const char * const tests_dirs[] = {
+ "./tools/perf/tests",
+ "./tests",
+ "./source/tests",
+ path_dir,
+ };
snprintf(path_dir, PATH_MAX, "%s/tests", get_argv_exec_path());
- if (!lstat(path_dir, &st))
- return run_dir(path_dir);
+ for (size_t i = 0; i < ARRAY_SIZE(tests_dirs); ++i) {
+ if (!lstat(tests_dirs[i], &st))
+ return run_dir(tests_dirs[i]);
+ }
+ pr_debug("cannot find the tests directory\n");
return TEST_SKIP;
}
@@ -93,6 +96,7 @@ static int test__pe_file_parsing(struct test_suite *test __maybe_unused,
static int test__pe_file_parsing(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
+ pr_debug("libbfd is not available\n");
return TEST_SKIP;
}
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 0cac6ae1a1fc..370dbde08eac 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -372,4 +372,5 @@ static struct test_case tests__PERF_RECORD[] = {
struct test_suite suite__PERF_RECORD = {
.desc = "PERF_RECORD_* events & perf_sample fields",
.test_cases = tests__PERF_RECORD,
+ .needs_mlock = true,
};
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
index f8f71fdd32b1..0cefa2df2db7 100644
--- a/tools/perf/tests/perf-time-to-tsc.c
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -218,4 +218,5 @@ static struct test_case time_to_tsc_tests[] = {
struct test_suite suite__perf_time_to_tsc = {
.desc = "Convert perf time to TSC",
.test_cases = time_to_tsc_tests,
+ .needs_mlock = true,
};
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index f507ce39439a..e6e4f4cf1fa2 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -906,9 +906,12 @@ static int test__parsing_callback(const struct pmu_metric *pm,
struct metric_expr *mexp;
list_for_each_entry (mexp, &me->head, nd) {
+ double result;
+
if (strcmp(mexp->metric_name, pm->metric_name))
continue;
- pr_debug("Result %f\n", test_generic_metric(mexp, 0));
+ result = test_generic_metric(mexp, 0);
+ pr_debug("Result %f\n", result);
err = 0;
(*failures)--;
goto out_err;
diff --git a/tools/perf/tests/shell/attr/README b/tools/perf/tests/shell/attr/README
index 67c4ca76b85d..c7b49cdf8729 100644
--- a/tools/perf/tests/shell/attr/README
+++ b/tools/perf/tests/shell/attr/README
@@ -49,10 +49,10 @@ Following tests are defined (with perf commands):
perf record --call-graph dwarf kill (test-record-graph-dwarf)
perf record --call-graph fp kill (test-record-graph-fp)
perf record --call-graph fp kill (test-record-graph-fp-aarch64)
- perf record -e '{cycles,instructions}' kill (test-record-group1)
- perf record -e '{cycles/period=1/,instructions/period=2/}:S' kill (test-record-group2)
- perf record -e '{cycles,cache-misses}:S' kill (test-record-group-sampling1)
- perf record -c 10000 -e '{cycles,cache-misses}:S' kill (test-record-group-sampling2)
+ perf record -e '{cycles,default_core/legacy-hardware-config=1/}' kill (test-record-group1)
+ perf record -e '{cycles/period=1234000/,default_core/legacy-hardware-config=1,period=6789000/}:S' kill (test-record-group2)
+ perf record -e '{cycles,default_core/legacy-hardware-config=3/}:S' kill (test-record-group-sampling1)
+ perf record -c 10000 -e '{cycles,default_core/legacy-hardware-config=3/}:S' kill (test-record-group-sampling2)
perf record -D kill (test-record-no-delay)
perf record -i kill (test-record-no-inherit)
perf record -n kill (test-record-no-samples)
@@ -67,5 +67,5 @@ Following tests are defined (with perf commands):
perf stat -d kill (test-stat-detailed-1)
perf stat -dd kill (test-stat-detailed-2)
perf stat -ddd kill (test-stat-detailed-3)
- perf stat -e '{cycles,instructions}' kill (test-stat-group1)
+ perf stat -e '{cycles,default_core/legacy-hardware-config=1/}' kill (test-stat-group1)
perf stat -i -e cycles kill (test-stat-no-inherit)
diff --git a/tools/perf/tests/shell/attr/base-stat-group b/tools/perf/tests/shell/attr/base-stat-group
new file mode 100644
index 000000000000..9bcb8ab3687f
--- /dev/null
+++ b/tools/perf/tests/shell/attr/base-stat-group
@@ -0,0 +1,45 @@
+[event]
+fd=1
+group_fd=-1
+# 0 or PERF_FLAG_FD_CLOEXEC flag
+flags=0|8
+cpu=*
+type=0
+size=176
+config=0
+sample_period=0
+sample_type=65536
+# The default and -d/-dd/-ddd metrics open part of their events in groups:
+# the members get read_format=15 and are enabled right away, the standalone
+# ones keep read_format=3 and wait for the exec, and the leaders get 15 when
+# their group has members, 3 when alone, as create_perf_stat_counter() goes.
+read_format=3|15
+disabled=0|1
+inherit=1
+pinned=0
+exclusive=0
+exclude_user=0
+exclude_kernel=0|1
+exclude_hv=0|1
+exclude_idle=0
+mmap=0
+comm=0
+freq=0
+inherit_stat=0
+enable_on_exec=0|1
+task=0
+watermark=0
+precise_ip=0
+mmap_data=0
+sample_id_all=0
+exclude_host=0|1
+exclude_guest=0|1
+exclude_callchain_kernel=0
+exclude_callchain_user=0
+wakeup_events=0
+bp_type=0
+config1=0
+config2=0
+branch_sample_type=0
+sample_regs_user=0
+sample_stack_user=0
diff --git a/tools/perf/tests/shell/attr/test-record-graph-dwarf b/tools/perf/tests/shell/attr/test-record-graph-dwarf
index ae92061d611d..fbe0faa8cdb6 100644
--- a/tools/perf/tests/shell/attr/test-record-graph-dwarf
+++ b/tools/perf/tests/shell/attr/test-record-graph-dwarf
@@ -4,7 +4,7 @@ args = --no-bpf-event --call-graph dwarf -- kill >/dev/null 2>&1
ret = 1
[event:base-record]
-sample_type=45359
+sample_type=12583
exclude_callchain_user=1
sample_stack_user=8192
# TODO different for each arch, no support for that now
diff --git a/tools/perf/tests/shell/attr/test-record-group-sampling b/tools/perf/tests/shell/attr/test-record-group-sampling
index 86a940d7895d..ed47dd1e5984 100644
--- a/tools/perf/tests/shell/attr/test-record-group-sampling
+++ b/tools/perf/tests/shell/attr/test-record-group-sampling
@@ -1,8 +1,9 @@
[config]
command = record
-args = --no-bpf-event -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
+args = --no-bpf-event -e '{cycles,default_core/legacy-hardware-config=3/}:S' kill >/dev/null 2>&1
ret = 1
kernel_until = 6.12
+requires = core-pmu
[event-1:base-record]
fd=1
@@ -15,7 +16,7 @@ inherit=0
fd=2
group_fd=1
-# cache-misses
+# cache-misses, explicitly requested with the legacy hardware encoding
type=0
config=3
diff --git a/tools/perf/tests/shell/attr/test-record-group-sampling1 b/tools/perf/tests/shell/attr/test-record-group-sampling1
index 4748ab7bf684..9cf013dc03dd 100644
--- a/tools/perf/tests/shell/attr/test-record-group-sampling1
+++ b/tools/perf/tests/shell/attr/test-record-group-sampling1
@@ -1,8 +1,9 @@
[config]
command = record
-args = --no-bpf-event -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
+args = --no-bpf-event -e '{cycles,default_core/legacy-hardware-config=3/}:S' kill >/dev/null 2>&1
ret = 1
kernel_since = 6.12
+requires = core-pmu
[event-1:base-record]
fd=1
@@ -30,7 +31,7 @@ inherit=1
fd=2
group_fd=1
-# cache-misses
+# cache-misses, explicitly requested with the legacy hardware encoding
type=0
config=3
diff --git a/tools/perf/tests/shell/attr/test-record-group-sampling2 b/tools/perf/tests/shell/attr/test-record-group-sampling2
index e0432244a0eb..bd1eb4161e4a 100644
--- a/tools/perf/tests/shell/attr/test-record-group-sampling2
+++ b/tools/perf/tests/shell/attr/test-record-group-sampling2
@@ -1,8 +1,9 @@
[config]
command = record
-args = --no-bpf-event -c 10000 -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
+args = --no-bpf-event -c 10000 -e '{cycles,default_core/legacy-hardware-config=3/}:S' kill >/dev/null 2>&1
ret = 1
kernel_since = 6.12
+requires = core-pmu
[event-1:base-record]
fd=1
@@ -36,7 +37,7 @@ write_backward=0
fd=2
group_fd=1
-# cache-misses
+# cache-misses, explicitly requested with the legacy hardware encoding
type=0
config=3
diff --git a/tools/perf/tests/shell/attr/test-record-group1 b/tools/perf/tests/shell/attr/test-record-group1
index eeb1db392bc9..5fdd5288555f 100644
--- a/tools/perf/tests/shell/attr/test-record-group1
+++ b/tools/perf/tests/shell/attr/test-record-group1
@@ -1,7 +1,8 @@
[config]
command = record
-args = --no-bpf-event -e '{cycles,instructions}' kill >/dev/null 2>&1
+args = --no-bpf-event -e '{cycles,default_core/legacy-hardware-config=1/}' kill >/dev/null 2>&1
ret = 1
+requires = core-pmu
[event-1:base-record]
fd=1
diff --git a/tools/perf/tests/shell/attr/test-record-group2 b/tools/perf/tests/shell/attr/test-record-group2
index 891d41a7bddf..e7274108f5fd 100644
--- a/tools/perf/tests/shell/attr/test-record-group2
+++ b/tools/perf/tests/shell/attr/test-record-group2
@@ -1,8 +1,9 @@
[config]
command = record
-args = --no-bpf-event -e '{cycles/period=1234000/,instructions/period=6789000/}:S' kill >/dev/null 2>&1
+args = --no-bpf-event -e '{cycles/period=1234000/,default_core/legacy-hardware-config=1,period=6789000/}:S' kill >/dev/null 2>&1
ret = 1
kernel_until = 6.12
+requires = core-pmu
[event-1:base-record]
fd=1
diff --git a/tools/perf/tests/shell/attr/test-record-group3 b/tools/perf/tests/shell/attr/test-record-group3
index 249be884959e..e74fd3a48ac9 100644
--- a/tools/perf/tests/shell/attr/test-record-group3
+++ b/tools/perf/tests/shell/attr/test-record-group3
@@ -1,8 +1,9 @@
[config]
command = record
-args = --no-bpf-event -e '{cycles/period=1234000/,instructions/period=6789000/}:S' kill >/dev/null 2>&1
+args = --no-bpf-event -e '{cycles/period=1234000/,default_core/legacy-hardware-config=1,period=6789000/}:S' kill >/dev/null 2>&1
ret = 1
kernel_since = 6.12
+requires = core-pmu
[event-1:base-record]
fd=1
diff --git a/tools/perf/tests/shell/attr/test-stat-C0 b/tools/perf/tests/shell/attr/test-stat-C0
index a2c76d10b2bb..9d242e93e3a9 100644
--- a/tools/perf/tests/shell/attr/test-stat-C0
+++ b/tools/perf/tests/shell/attr/test-stat-C0
@@ -2,6 +2,7 @@
command = stat
args = -e cycles -C 0 kill >/dev/null 2>&1
ret = 1
+requires = core-pmu
[event:base-stat]
# events are disabled by default when attached to cpu
diff --git a/tools/perf/tests/shell/attr/test-stat-basic b/tools/perf/tests/shell/attr/test-stat-basic
index 69867d049fda..277897bd2626 100644
--- a/tools/perf/tests/shell/attr/test-stat-basic
+++ b/tools/perf/tests/shell/attr/test-stat-basic
@@ -2,6 +2,7 @@
command = stat
args = -e cycles kill >/dev/null 2>&1
ret = 1
+requires = core-pmu
[event:base-stat]
optional=1
diff --git a/tools/perf/tests/shell/attr/test-stat-default b/tools/perf/tests/shell/attr/test-stat-default
index 8dd27c1fb661..6a0c0c43f233 100644
--- a/tools/perf/tests/shell/attr/test-stat-default
+++ b/tools/perf/tests/shell/attr/test-stat-default
@@ -2,74 +2,75 @@
command = stat
args = kill >/dev/null 2>&1
ret = 1
+requires = core-pmu
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
-[event1:base-stat]
+[event1:base-stat-group]
fd=1
type=1
config=1
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
-[event2:base-stat]
+[event2:base-stat-group]
fd=2
type=1
config=3
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
-[event3:base-stat]
+[event3:base-stat-group]
fd=3
type=1
config=4
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
-[event4:base-stat]
+[event4:base-stat-group]
fd=4
type=1
config=2
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
-[event5:base-stat]
+[event5:base-stat-group]
fd=5
type=0
config=0
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
-[event6:base-stat]
+[event6:base-stat-group]
fd=6
type=0
config=7
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
-[event7:base-stat]
+[event7:base-stat-group]
fd=7
type=0
config=8
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
-[event8:base-stat]
+[event8:base-stat-group]
fd=8
type=0
config=1
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
-[event9:base-stat]
+[event9:base-stat-group]
fd=9
type=0
config=4
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
-[event10:base-stat]
+[event10:base-stat-group]
fd=10
type=0
config=5
optional=1
# PERF_TYPE_RAW / slots (0x400)
-[event11:base-stat]
+[event11:base-stat-group]
fd=11
group_fd=-1
type=4
@@ -78,7 +79,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-retiring (0x8000)
-[event12:base-stat]
+[event12:base-stat-group]
fd=12
group_fd=11
type=4
@@ -89,7 +90,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-bad-spec (0x8100)
-[event13:base-stat]
+[event13:base-stat-group]
fd=13
group_fd=11
type=4
@@ -100,7 +101,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fe-bound (0x8200)
-[event14:base-stat]
+[event14:base-stat-group]
fd=14
group_fd=11
type=4
@@ -111,7 +112,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-be-bound (0x8300)
-[event15:base-stat]
+[event15:base-stat-group]
fd=15
group_fd=11
type=4
@@ -122,7 +123,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-heavy-ops (0x8400)
-[event16:base-stat]
+[event16:base-stat-group]
fd=16
group_fd=11
type=4
@@ -133,7 +134,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-br-mispredict (0x8500)
-[event17:base-stat]
+[event17:base-stat-group]
fd=17
group_fd=11
type=4
@@ -144,7 +145,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fetch-lat (0x8600)
-[event18:base-stat]
+[event18:base-stat-group]
fd=18
group_fd=11
type=4
@@ -155,7 +156,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-mem-bound (0x8700)
-[event19:base-stat]
+[event19:base-stat-group]
fd=19
group_fd=11
type=4
@@ -166,71 +167,99 @@ read_format=15
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
-[event20:base-stat]
+[event20:base-stat-group]
fd=20
type=4
config=4109
optional=1
# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/
-[event21:base-stat]
+[event21:base-stat-group]
fd=21
type=4
config=17039629
optional=1
-# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD
-[event22:base-stat]
+# PERF_TYPE_RAW / cpu-cycles (core PMU sysfs event; Intel 0x3c, AMD 0x76)
+[event22:base-stat-group]
fd=22
type=4
-config=60
+config=60|118
optional=1
# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY
-[event23:base-stat]
+[event23:base-stat-group]
fd=23
type=4
config=2097421
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK
-[event24:base-stat]
+[event24:base-stat-group]
fd=24
type=4
config=316
optional=1
# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE
-[event25:base-stat]
+[event25:base-stat-group]
fd=25
type=4
config=412
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE
-[event26:base-stat]
+[event26:base-stat-group]
fd=26
type=4
config=572
optional=1
# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS
-[event27:base-stat]
+[event27:base-stat-group]
fd=27
type=4
config=706
optional=1
# PERF_TYPE_RAW / UOPS_ISSUED.ANY
-[event28:base-stat]
+[event28:base-stat-group]
fd=28
type=4
config=270
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
-[event29:base-stat]
+[event29:base-stat-group]
fd=29
type=4
config=4269
+optional=1
+
+# PERF_TYPE_RAW / instructions (core PMU sysfs event)
+[event30:base-stat-group]
+fd=30
+type=4
+config=192
+optional=1
+
+# PERF_TYPE_RAW / branch-misses (core PMU sysfs event; Intel 0xc5, AMD 0xc3)
+[event31:base-stat-group]
+fd=31
+type=4
+config=197|195
+optional=1
+
+# PERF_TYPE_RAW / stalled-cycles-frontend (core PMU sysfs event; Intel 0x180010e, AMD 0xd0/0x287/0xa9)
+[event32:base-stat-group]
+fd=32
+type=4
+config=25166094|208|647|169
+optional=1
+
+# PERF_TYPE_RAW / stalled-cycles-backend (core PMU sysfs event; Intel 0x18001b1/0x1803fb1, AMD 0xd1/0x187)
+[event33:base-stat-group]
+fd=33
+type=4
+config=25166257|25182129|209|391
optional=1 \ No newline at end of file
diff --git a/tools/perf/tests/shell/attr/test-stat-detailed-1 b/tools/perf/tests/shell/attr/test-stat-detailed-1
index 12a2ebf4e64a..3d47dc6f815f 100644
--- a/tools/perf/tests/shell/attr/test-stat-detailed-1
+++ b/tools/perf/tests/shell/attr/test-stat-detailed-1
@@ -2,76 +2,77 @@
command = stat
args = -d kill >/dev/null 2>&1
ret = 1
+requires = core-pmu
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
-[event1:base-stat]
+[event1:base-stat-group]
fd=1
type=1
config=1
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
-[event2:base-stat]
+[event2:base-stat-group]
fd=2
type=1
config=3
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
-[event3:base-stat]
+[event3:base-stat-group]
fd=3
type=1
config=4
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
-[event4:base-stat]
+[event4:base-stat-group]
fd=4
type=1
config=2
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
-[event5:base-stat]
+[event5:base-stat-group]
fd=5
type=0
config=0
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
-[event6:base-stat]
+[event6:base-stat-group]
fd=6
type=0
config=7
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
-[event7:base-stat]
+[event7:base-stat-group]
fd=7
type=0
config=8
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
-[event8:base-stat]
+[event8:base-stat-group]
fd=8
type=0
config=1
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
-[event9:base-stat]
+[event9:base-stat-group]
fd=9
type=0
config=4
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
-[event10:base-stat]
+[event10:base-stat-group]
fd=10
type=0
config=5
optional=1
# PERF_TYPE_RAW / slots (0x400)
-[event11:base-stat]
+[event11:base-stat-group]
fd=11
group_fd=-1
type=4
@@ -80,7 +81,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-retiring (0x8000)
-[event12:base-stat]
+[event12:base-stat-group]
fd=12
group_fd=11
type=4
@@ -91,7 +92,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-bad-spec (0x8100)
-[event13:base-stat]
+[event13:base-stat-group]
fd=13
group_fd=11
type=4
@@ -102,7 +103,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fe-bound (0x8200)
-[event14:base-stat]
+[event14:base-stat-group]
fd=14
group_fd=11
type=4
@@ -113,7 +114,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-be-bound (0x8300)
-[event15:base-stat]
+[event15:base-stat-group]
fd=15
group_fd=11
type=4
@@ -124,7 +125,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-heavy-ops (0x8400)
-[event16:base-stat]
+[event16:base-stat-group]
fd=16
group_fd=11
type=4
@@ -135,7 +136,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-br-mispredict (0x8500)
-[event17:base-stat]
+[event17:base-stat-group]
fd=17
group_fd=11
type=4
@@ -146,7 +147,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fetch-lat (0x8600)
-[event18:base-stat]
+[event18:base-stat-group]
fd=18
group_fd=11
type=4
@@ -157,7 +158,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-mem-bound (0x8700)
-[event19:base-stat]
+[event19:base-stat-group]
fd=19
group_fd=11
type=4
@@ -168,63 +169,63 @@ read_format=15
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
-[event20:base-stat]
+[event20:base-stat-group]
fd=20
type=4
config=4109
optional=1
# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/
-[event21:base-stat]
+[event21:base-stat-group]
fd=21
type=4
config=17039629
optional=1
-# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD
-[event22:base-stat]
+# PERF_TYPE_RAW / cpu-cycles (core PMU sysfs event; Intel 0x3c, AMD 0x76)
+[event22:base-stat-group]
fd=22
type=4
-config=60
+config=60|118
optional=1
# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY
-[event23:base-stat]
+[event23:base-stat-group]
fd=23
type=4
config=2097421
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK
-[event24:base-stat]
+[event24:base-stat-group]
fd=24
type=4
config=316
optional=1
# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE
-[event25:base-stat]
+[event25:base-stat-group]
fd=25
type=4
config=412
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE
-[event26:base-stat]
+[event26:base-stat-group]
fd=26
type=4
config=572
optional=1
# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS
-[event27:base-stat]
+[event27:base-stat-group]
fd=27
type=4
config=706
optional=1
# PERF_TYPE_RAW / UOPS_ISSUED.ANY
-[event28:base-stat]
+[event28:base-stat-group]
fd=28
type=4
config=270
@@ -234,7 +235,7 @@ optional=1
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
-[event29:base-stat]
+[event29:base-stat-group]
fd=29
type=3
config=0
@@ -244,7 +245,7 @@ optional=1
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
-[event30:base-stat]
+[event30:base-stat-group]
fd=30
type=3
config=65536
@@ -254,7 +255,7 @@ optional=1
# PERF_COUNT_HW_CACHE_LL << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
-[event31:base-stat]
+[event31:base-stat-group]
fd=31
type=3
config=2
@@ -264,15 +265,43 @@ optional=1
# PERF_COUNT_HW_CACHE_LL << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
-[event32:base-stat]
+[event32:base-stat-group]
fd=32
type=3
config=65538
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
-[event33:base-stat]
+[event33:base-stat-group]
fd=33
type=4
config=4269
+optional=1
+
+# PERF_TYPE_RAW / instructions (core PMU sysfs event)
+[event34:base-stat-group]
+fd=34
+type=4
+config=192
+optional=1
+
+# PERF_TYPE_RAW / branch-misses (core PMU sysfs event; Intel 0xc5, AMD 0xc3)
+[event35:base-stat-group]
+fd=35
+type=4
+config=197|195
+optional=1
+
+# PERF_TYPE_RAW / stalled-cycles-frontend (core PMU sysfs event; Intel 0x180010e, AMD 0xd0/0x287/0xa9)
+[event36:base-stat-group]
+fd=36
+type=4
+config=25166094|208|647|169
+optional=1
+
+# PERF_TYPE_RAW / stalled-cycles-backend (core PMU sysfs event; Intel 0x18001b1/0x1803fb1, AMD 0xd1/0x187)
+[event37:base-stat-group]
+fd=37
+type=4
+config=25166257|25182129|209|391
optional=1 \ No newline at end of file
diff --git a/tools/perf/tests/shell/attr/test-stat-detailed-2 b/tools/perf/tests/shell/attr/test-stat-detailed-2
index 66ea25b7d38f..ebe1f9e2736d 100644
--- a/tools/perf/tests/shell/attr/test-stat-detailed-2
+++ b/tools/perf/tests/shell/attr/test-stat-detailed-2
@@ -2,76 +2,77 @@
command = stat
args = -dd kill >/dev/null 2>&1
ret = 1
+requires = core-pmu
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
-[event1:base-stat]
+[event1:base-stat-group]
fd=1
type=1
config=1
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
-[event2:base-stat]
+[event2:base-stat-group]
fd=2
type=1
config=3
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
-[event3:base-stat]
+[event3:base-stat-group]
fd=3
type=1
config=4
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
-[event4:base-stat]
+[event4:base-stat-group]
fd=4
type=1
config=2
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
-[event5:base-stat]
+[event5:base-stat-group]
fd=5
type=0
config=0
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
-[event6:base-stat]
+[event6:base-stat-group]
fd=6
type=0
config=7
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
-[event7:base-stat]
+[event7:base-stat-group]
fd=7
type=0
config=8
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
-[event8:base-stat]
+[event8:base-stat-group]
fd=8
type=0
config=1
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
-[event9:base-stat]
+[event9:base-stat-group]
fd=9
type=0
config=4
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
-[event10:base-stat]
+[event10:base-stat-group]
fd=10
type=0
config=5
optional=1
# PERF_TYPE_RAW / slots (0x400)
-[event11:base-stat]
+[event11:base-stat-group]
fd=11
group_fd=-1
type=4
@@ -80,7 +81,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-retiring (0x8000)
-[event12:base-stat]
+[event12:base-stat-group]
fd=12
group_fd=11
type=4
@@ -91,7 +92,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-bad-spec (0x8100)
-[event13:base-stat]
+[event13:base-stat-group]
fd=13
group_fd=11
type=4
@@ -102,7 +103,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fe-bound (0x8200)
-[event14:base-stat]
+[event14:base-stat-group]
fd=14
group_fd=11
type=4
@@ -113,7 +114,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-be-bound (0x8300)
-[event15:base-stat]
+[event15:base-stat-group]
fd=15
group_fd=11
type=4
@@ -124,7 +125,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-heavy-ops (0x8400)
-[event16:base-stat]
+[event16:base-stat-group]
fd=16
group_fd=11
type=4
@@ -135,7 +136,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-br-mispredict (0x8500)
-[event17:base-stat]
+[event17:base-stat-group]
fd=17
group_fd=11
type=4
@@ -146,7 +147,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fetch-lat (0x8600)
-[event18:base-stat]
+[event18:base-stat-group]
fd=18
group_fd=11
type=4
@@ -157,7 +158,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-mem-bound (0x8700)
-[event19:base-stat]
+[event19:base-stat-group]
fd=19
group_fd=11
type=4
@@ -168,63 +169,63 @@ read_format=15
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
-[event20:base-stat]
+[event20:base-stat-group]
fd=20
type=4
config=4109
optional=1
# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/
-[event21:base-stat]
+[event21:base-stat-group]
fd=21
type=4
config=17039629
optional=1
-# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD
-[event22:base-stat]
+# PERF_TYPE_RAW / cpu-cycles (core PMU sysfs event; Intel 0x3c, AMD 0x76)
+[event22:base-stat-group]
fd=22
type=4
-config=60
+config=60|118
optional=1
# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY
-[event23:base-stat]
+[event23:base-stat-group]
fd=23
type=4
config=2097421
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK
-[event24:base-stat]
+[event24:base-stat-group]
fd=24
type=4
config=316
optional=1
# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE
-[event25:base-stat]
+[event25:base-stat-group]
fd=25
type=4
config=412
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE
-[event26:base-stat]
+[event26:base-stat-group]
fd=26
type=4
config=572
optional=1
# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS
-[event27:base-stat]
+[event27:base-stat-group]
fd=27
type=4
config=706
optional=1
# PERF_TYPE_RAW / UOPS_ISSUED.ANY
-[event28:base-stat]
+[event28:base-stat-group]
fd=28
type=4
config=270
@@ -234,7 +235,7 @@ optional=1
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
-[event29:base-stat]
+[event29:base-stat-group]
fd=29
type=3
config=0
@@ -244,7 +245,7 @@ optional=1
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
-[event30:base-stat]
+[event30:base-stat-group]
fd=30
type=3
config=65536
@@ -254,7 +255,7 @@ optional=1
# PERF_COUNT_HW_CACHE_LL << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
-[event31:base-stat]
+[event31:base-stat-group]
fd=31
type=3
config=2
@@ -264,7 +265,7 @@ optional=1
# PERF_COUNT_HW_CACHE_LL << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
-[event32:base-stat]
+[event32:base-stat-group]
fd=32
type=3
config=65538
@@ -274,7 +275,7 @@ optional=1
# PERF_COUNT_HW_CACHE_L1I << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
-[event33:base-stat]
+[event33:base-stat-group]
fd=33
type=3
config=1
@@ -284,7 +285,7 @@ optional=1
# PERF_COUNT_HW_CACHE_L1I << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
-[event34:base-stat]
+[event34:base-stat-group]
fd=34
type=3
config=65537
@@ -294,7 +295,7 @@ optional=1
# PERF_COUNT_HW_CACHE_DTLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
-[event35:base-stat]
+[event35:base-stat-group]
fd=35
type=3
config=3
@@ -304,7 +305,7 @@ optional=1
# PERF_COUNT_HW_CACHE_DTLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
-[event36:base-stat]
+[event36:base-stat-group]
fd=36
type=3
config=65539
@@ -314,7 +315,7 @@ optional=1
# PERF_COUNT_HW_CACHE_ITLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
-[event37:base-stat]
+[event37:base-stat-group]
fd=37
type=3
config=4
@@ -324,15 +325,43 @@ optional=1
# PERF_COUNT_HW_CACHE_ITLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
-[event38:base-stat]
+[event38:base-stat-group]
fd=38
type=3
config=65540
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
-[event39:base-stat]
+[event39:base-stat-group]
fd=39
type=4
config=4269
+optional=1
+
+# PERF_TYPE_RAW / instructions (core PMU sysfs event)
+[event40:base-stat-group]
+fd=40
+type=4
+config=192
+optional=1
+
+# PERF_TYPE_RAW / branch-misses (core PMU sysfs event; Intel 0xc5, AMD 0xc3)
+[event41:base-stat-group]
+fd=41
+type=4
+config=197|195
+optional=1
+
+# PERF_TYPE_RAW / stalled-cycles-frontend (core PMU sysfs event; Intel 0x180010e, AMD 0xd0/0x287/0xa9)
+[event42:base-stat-group]
+fd=42
+type=4
+config=25166094|208|647|169
+optional=1
+
+# PERF_TYPE_RAW / stalled-cycles-backend (core PMU sysfs event; Intel 0x18001b1/0x1803fb1, AMD 0xd1/0x187)
+[event43:base-stat-group]
+fd=43
+type=4
+config=25166257|25182129|209|391
optional=1 \ No newline at end of file
diff --git a/tools/perf/tests/shell/attr/test-stat-detailed-3 b/tools/perf/tests/shell/attr/test-stat-detailed-3
index 4a27bbfb9f87..e7eef828245c 100644
--- a/tools/perf/tests/shell/attr/test-stat-detailed-3
+++ b/tools/perf/tests/shell/attr/test-stat-detailed-3
@@ -2,76 +2,77 @@
command = stat
args = -ddd kill >/dev/null 2>&1
ret = 1
+requires = core-pmu
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
-[event1:base-stat]
+[event1:base-stat-group]
fd=1
type=1
config=1
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
-[event2:base-stat]
+[event2:base-stat-group]
fd=2
type=1
config=3
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
-[event3:base-stat]
+[event3:base-stat-group]
fd=3
type=1
config=4
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
-[event4:base-stat]
+[event4:base-stat-group]
fd=4
type=1
config=2
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
-[event5:base-stat]
+[event5:base-stat-group]
fd=5
type=0
config=0
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
-[event6:base-stat]
+[event6:base-stat-group]
fd=6
type=0
config=7
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
-[event7:base-stat]
+[event7:base-stat-group]
fd=7
type=0
config=8
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
-[event8:base-stat]
+[event8:base-stat-group]
fd=8
type=0
config=1
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
-[event9:base-stat]
+[event9:base-stat-group]
fd=9
type=0
config=4
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
-[event10:base-stat]
+[event10:base-stat-group]
fd=10
type=0
config=5
optional=1
# PERF_TYPE_RAW / slots (0x400)
-[event11:base-stat]
+[event11:base-stat-group]
fd=11
group_fd=-1
type=4
@@ -80,7 +81,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-retiring (0x8000)
-[event12:base-stat]
+[event12:base-stat-group]
fd=12
group_fd=11
type=4
@@ -91,7 +92,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-bad-spec (0x8100)
-[event13:base-stat]
+[event13:base-stat-group]
fd=13
group_fd=11
type=4
@@ -102,7 +103,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fe-bound (0x8200)
-[event14:base-stat]
+[event14:base-stat-group]
fd=14
group_fd=11
type=4
@@ -113,7 +114,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-be-bound (0x8300)
-[event15:base-stat]
+[event15:base-stat-group]
fd=15
group_fd=11
type=4
@@ -124,7 +125,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-heavy-ops (0x8400)
-[event16:base-stat]
+[event16:base-stat-group]
fd=16
group_fd=11
type=4
@@ -135,7 +136,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-br-mispredict (0x8500)
-[event17:base-stat]
+[event17:base-stat-group]
fd=17
group_fd=11
type=4
@@ -146,7 +147,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fetch-lat (0x8600)
-[event18:base-stat]
+[event18:base-stat-group]
fd=18
group_fd=11
type=4
@@ -157,7 +158,7 @@ read_format=15
optional=1
# PERF_TYPE_RAW / topdown-mem-bound (0x8700)
-[event19:base-stat]
+[event19:base-stat-group]
fd=19
group_fd=11
type=4
@@ -168,63 +169,63 @@ read_format=15
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
-[event20:base-stat]
+[event20:base-stat-group]
fd=20
type=4
config=4109
optional=1
# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/
-[event21:base-stat]
+[event21:base-stat-group]
fd=21
type=4
config=17039629
optional=1
-# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD
-[event22:base-stat]
+# PERF_TYPE_RAW / cpu-cycles (core PMU sysfs event; Intel 0x3c, AMD 0x76)
+[event22:base-stat-group]
fd=22
type=4
-config=60
+config=60|118
optional=1
# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY
-[event23:base-stat]
+[event23:base-stat-group]
fd=23
type=4
config=2097421
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK
-[event24:base-stat]
+[event24:base-stat-group]
fd=24
type=4
config=316
optional=1
# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE
-[event25:base-stat]
+[event25:base-stat-group]
fd=25
type=4
config=412
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE
-[event26:base-stat]
+[event26:base-stat-group]
fd=26
type=4
config=572
optional=1
# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS
-[event27:base-stat]
+[event27:base-stat-group]
fd=27
type=4
config=706
optional=1
# PERF_TYPE_RAW / UOPS_ISSUED.ANY
-[event28:base-stat]
+[event28:base-stat-group]
fd=28
type=4
config=270
@@ -234,7 +235,7 @@ optional=1
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
-[event29:base-stat]
+[event29:base-stat-group]
fd=29
type=3
config=0
@@ -244,7 +245,7 @@ optional=1
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
-[event30:base-stat]
+[event30:base-stat-group]
fd=30
type=3
config=65536
@@ -254,7 +255,7 @@ optional=1
# PERF_COUNT_HW_CACHE_LL << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
-[event31:base-stat]
+[event31:base-stat-group]
fd=31
type=3
config=2
@@ -264,7 +265,7 @@ optional=1
# PERF_COUNT_HW_CACHE_LL << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
-[event32:base-stat]
+[event32:base-stat-group]
fd=32
type=3
config=65538
@@ -274,7 +275,7 @@ optional=1
# PERF_COUNT_HW_CACHE_L1I << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
-[event33:base-stat]
+[event33:base-stat-group]
fd=33
type=3
config=1
@@ -284,7 +285,7 @@ optional=1
# PERF_COUNT_HW_CACHE_L1I << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
-[event34:base-stat]
+[event34:base-stat-group]
fd=34
type=3
config=65537
@@ -294,7 +295,7 @@ optional=1
# PERF_COUNT_HW_CACHE_DTLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
-[event35:base-stat]
+[event35:base-stat-group]
fd=35
type=3
config=3
@@ -304,7 +305,7 @@ optional=1
# PERF_COUNT_HW_CACHE_DTLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
-[event36:base-stat]
+[event36:base-stat-group]
fd=36
type=3
config=65539
@@ -314,7 +315,7 @@ optional=1
# PERF_COUNT_HW_CACHE_ITLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
-[event37:base-stat]
+[event37:base-stat-group]
fd=37
type=3
config=4
@@ -324,7 +325,7 @@ optional=1
# PERF_COUNT_HW_CACHE_ITLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
-[event38:base-stat]
+[event38:base-stat-group]
fd=38
type=3
config=65540
@@ -334,7 +335,7 @@ optional=1
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
-[event39:base-stat]
+[event39:base-stat-group]
fd=39
type=3
config=512
@@ -344,15 +345,43 @@ optional=1
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
-[event40:base-stat]
+[event40:base-stat-group]
fd=40
type=3
config=66048
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
-[event41:base-stat]
+[event41:base-stat-group]
fd=41
type=4
config=4269
+optional=1
+
+# PERF_TYPE_RAW / instructions (core PMU sysfs event)
+[event42:base-stat-group]
+fd=42
+type=4
+config=192
+optional=1
+
+# PERF_TYPE_RAW / branch-misses (core PMU sysfs event; Intel 0xc5, AMD 0xc3)
+[event43:base-stat-group]
+fd=43
+type=4
+config=197|195
+optional=1
+
+# PERF_TYPE_RAW / stalled-cycles-frontend (core PMU sysfs event; Intel 0x180010e, AMD 0xd0/0x287/0xa9)
+[event44:base-stat-group]
+fd=44
+type=4
+config=25166094|208|647|169
+optional=1
+
+# PERF_TYPE_RAW / stalled-cycles-backend (core PMU sysfs event; Intel 0x18001b1/0x1803fb1, AMD 0xd1/0x187)
+[event45:base-stat-group]
+fd=45
+type=4
+config=25166257|25182129|209|391
optional=1 \ No newline at end of file
diff --git a/tools/perf/tests/shell/attr/test-stat-group1 b/tools/perf/tests/shell/attr/test-stat-group1
index 1746751123dc..7a31b27933f1 100644
--- a/tools/perf/tests/shell/attr/test-stat-group1
+++ b/tools/perf/tests/shell/attr/test-stat-group1
@@ -1,7 +1,8 @@
[config]
command = stat
-args = -e '{cycles,instructions}' kill >/dev/null 2>&1
+args = -e '{cycles,default_core/legacy-hardware-config=1/}' kill >/dev/null 2>&1
ret = 1
+requires = core-pmu
[event-1:base-stat]
fd=1
diff --git a/tools/perf/tests/shell/attr/test-stat-no-inherit b/tools/perf/tests/shell/attr/test-stat-no-inherit
index 924fbb9300d1..38f746855b1b 100644
--- a/tools/perf/tests/shell/attr/test-stat-no-inherit
+++ b/tools/perf/tests/shell/attr/test-stat-no-inherit
@@ -2,6 +2,7 @@
command = stat
args = -i -e cycles kill >/dev/null 2>&1
ret = 1
+requires = core-pmu
[event:base-stat]
inherit=0
diff --git a/tools/perf/tests/shell/drm_pmu.sh b/tools/perf/tests/shell/drm_pmu.sh
index e629fe0e8463..c827e613fc66 100755
--- a/tools/perf/tests/shell/drm_pmu.sh
+++ b/tools/perf/tests/shell/drm_pmu.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# DRM PMU
+# DRM PMU (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
diff --git a/tools/perf/tests/shell/ftrace.sh b/tools/perf/tests/shell/ftrace.sh
index 9f6e590f6437..84d6126bf94d 100755
--- a/tools/perf/tests/shell/ftrace.sh
+++ b/tools/perf/tests/shell/ftrace.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf ftrace tests
+# perf ftrace tests (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
diff --git a/tools/perf/tests/shell/kallsyms.sh b/tools/perf/tests/shell/kallsyms.sh
index d0eb99753f47..e3674cc52b30 100755
--- a/tools/perf/tests/shell/kallsyms.sh
+++ b/tools/perf/tests/shell/kallsyms.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf kallsyms tests
+# perf kallsyms tests (no_mlock)
# SPDX-License-Identifier: GPL-2.0
err=0
diff --git a/tools/perf/tests/shell/lib/attr.py b/tools/perf/tests/shell/lib/attr.py
index 68f06df9565a..df1993883199 100644
--- a/tools/perf/tests/shell/lib/attr.py
+++ b/tools/perf/tests/shell/lib/attr.py
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
import configparser
+import errno
import os
import sys
import glob
@@ -28,6 +29,192 @@ def data_equal(a, b):
return False
+CORE_PMU_AVAILABLE = None
+CORE_PMU_COUNT = None
+
+def core_pmu_available():
+ """
+ Is there a core PMU on this machine? Without one hardware events aren't
+ supported and get replaced by the software fallback, so there's no way to
+ check the expectations that pin their legacy encodings. The answer can't
+ change while the tests run, so probe the binding only once.
+ """
+ core_pmu_probe()
+ return CORE_PMU_AVAILABLE
+
+def core_pmu_probe():
+ """
+ Ask perf itself, through its python binding, to parse and open 'cycles'
+ once: a parse failure or an ENOENT means no PMU can count it, any other
+ error means we can't tell whether there is one, and the number of events
+ it expanded to is the number of core PMUs, see
+ parse_events_multi_pmu_add(), which is what core_pmu_count() asks for.
+ """
+ global CORE_PMU_AVAILABLE, CORE_PMU_COUNT
+
+ if CORE_PMU_AVAILABLE is not None:
+ return
+
+ try:
+ import perf
+ parse_events = perf.parse_events
+ except (ImportError, AttributeError):
+ # Nothing to ask about it, let the expectations speak.
+ CORE_PMU_AVAILABLE = True
+ return
+
+ try:
+ evlist = parse_events('cycles')
+ except OSError:
+ # No PMU that can count it, the same as the ENOENT below.
+ CORE_PMU_AVAILABLE = False
+ return
+
+ CORE_PMU_COUNT = len(evlist)
+ try:
+ evlist.open()
+ except OSError as err:
+ # Anything else is a permission problem or alike, not our business here.
+ CORE_PMU_AVAILABLE = err.errno != errno.ENOENT
+ return
+ evlist.close()
+
+ CORE_PMU_AVAILABLE = True
+
+PERF_TYPE_HARDWARE = 0
+PERF_TYPE_HW_CACHE = 3
+PERF_SAMPLE_ID = 1 << 6
+PERF_SAMPLE_IDENTIFIER = 1 << 16
+PERF_TYPE_SOFTWARE = 1
+PERF_COUNT_SW_DUMMY = 9
+
+def is_dummy_tracking_event(event):
+ """
+ Is this the dummy event perf opens to carry the tracking events (mmap,
+ comm, task) when the requested ones can't, like when there is more than one
+ core PMU and each core PMU's events run on only part of the CPUs?
+ """
+ return (event.get('type') == str(PERF_TYPE_SOFTWARE) and
+ event.get('config') == str(PERF_COUNT_SW_DUMMY))
+
+# With more than one core PMU the tracking terms go to the dummy tracking event,
+# leaving the requested events without them, so they can't be matched there.
+TRACKING_TERMS = ['mmap', 'comm', 'task', 'mmap_data']
+
+# The legacy event types, where perf may qualify 'config' with the core PMU
+# type in its top 32 bits when there is more than one core PMU.
+LEGACY_TYPES = (str(PERF_TYPE_HARDWARE), str(PERF_TYPE_HW_CACHE))
+
+def mask_bits(value, bits):
+ """
+ Take the bits in 'bits' out of each of the '|'-separated alternatives in
+ 'value', keeping the rest of the expression, wildcards included.
+ """
+ masked = []
+
+ for alternative in value.split('|'):
+ try:
+ alternative = str(int(alternative, 0) & ~bits)
+ except ValueError:
+ pass
+ masked.append(alternative)
+
+ return '|'.join(masked)
+
+def hide_core_pmu_type(value):
+ """
+ The kernel can be told which core PMU a legacy type event is meant for by
+ putting its type in the top 32 bits of 'config', which perf only does when
+ there is more than one core PMU, so take those bits out to keep the
+ expectations written for the single core PMU case matching on
+ heterogeneous machines.
+ """
+ return mask_bits(value, 0xffffffff00000000)
+
+# The two sample id bits mean the same thing here: how the samples of the
+# events in the evlist get associated with the event that produced them.
+SAMPLE_ID_BITS = PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER
+
+# No real sample_type bit is this high, so it can stand for "either of the
+# sample id bits" when comparing the two sides.
+SAMPLE_ID_EITHER = 1 << 40
+
+PERF_FORMAT_GROUP = 1 << 3
+
+def core_pmu_count():
+ """
+ How many core PMUs does perf see? An event with no PMU named in it
+ becomes one event per core PMU, see parse_events_multi_pmu_add(), and
+ that is the expansion that leaves the clones for the other core PMUs
+ without any group members and that makes perf qualify 'config' with the
+ type of the PMU it is for, so this is the number of events perf makes of
+ 'cycles', from the probe core_pmu_available() shares.
+ """
+ core_pmu_probe()
+ return CORE_PMU_COUNT
+
+def single_core_pmu():
+ """
+ Does perf see only one core PMU? Asked for by the comparisons that need
+ it, not at import time, as a run may never get to one.
+ """
+ return core_pmu_count() == 1
+
+def hide_group_format(expected, recorded):
+ """
+ read_format's PERF_FORMAT_GROUP bit asks for the group members to be read
+ along with the leader, which aside from this bit is verified with the
+ fd/group_fd based group checking, and with more than one core PMU a group
+ whose members are pinned to one of them, say 'default_core', leaves the
+ clones for the other core PMUs without any members, so that bit isn't
+ there: whether it is there is a consequence of how the evlist got
+ expanded to more than one core PMU, not of what the expectations are
+ about, so take it out on both sides. On a machine with a single core PMU
+ there is nothing to expand, so the expectations keep verifying it.
+ """
+ if single_core_pmu():
+ return expected, recorded
+
+ return (mask_bits(expected, PERF_FORMAT_GROUP),
+ mask_bits(recorded, PERF_FORMAT_GROUP))
+
+def hide_sample_id(expected, recorded):
+ """
+ perf asks for a way to tell the samples apart, PERF_SAMPLE_IDENTIFIER where
+ available, PERF_SAMPLE_ID otherwise, see evlist__config(): whenever the
+ evlist has more than one event, and when asked to outright, with
+ --sample-identifier, by an auxtrace session, or by record__config() for a
+ pipe run, none of which depends on the sample types, as those only choose
+ between the two bits:
+ with more than one core PMU the dummy tracking events make the sample types
+ differ, so IDENTIFIER is asked for even for events whose expectations ask
+ for ID, written on a machine with a single core PMU.
+
+ So treat the two as the same thing: when the expectation asks for either
+ of them, ask for "an id of some sort" on both sides, and when the
+ expectation doesn't ask for any, take the bits out of what got recorded.
+ """
+ try:
+ asked = int(expected, 0) & SAMPLE_ID_BITS
+ except ValueError:
+ # The expectation is a wildcard or a set of alternatives.
+ return expected, recorded
+
+ try:
+ recorded_id_bits = int(recorded, 0) & SAMPLE_ID_BITS
+ except ValueError:
+ # The recorded side is a wildcard or a set of alternatives.
+ return expected, mask_bits(recorded, SAMPLE_ID_BITS)
+
+ if not asked:
+ if single_core_pmu():
+ return expected, recorded
+ return expected, mask_bits(recorded, SAMPLE_ID_BITS)
+
+ return (str(int(expected, 0) & ~SAMPLE_ID_BITS | SAMPLE_ID_EITHER),
+ str(int(recorded, 0) & ~SAMPLE_ID_BITS |
+ (SAMPLE_ID_EITHER if recorded_id_bits else 0)))
+
class Fail(Exception):
def __init__(self, test, msg):
self.msg = msg
@@ -36,17 +223,20 @@ class Fail(Exception):
return '\'%s\' - %s' % (self.test.path, self.msg)
class Notest(Exception):
- def __init__(self, test, arch):
- self.arch = arch
+ def __init__(self, test, reason):
+ self.reason = reason
self.test = test
def getMsg(self):
- return '[%s] \'%s\'' % (self.arch, self.test.path)
+ return '[%s] \'%s\'' % (self.reason, self.test.path)
class Unsup(Exception):
- def __init__(self, test):
+ def __init__(self, test, ret, expected):
self.test = test
+ self.ret = ret
+ self.expected = expected
def getMsg(self):
- return '\'%s\'' % self.test.path
+ return '\'%s\' exit %d, expected %s, no attrs recorded to verify' % (
+ self.test.path, self.ret, self.expected)
class Event(dict):
terms = [
@@ -101,12 +291,76 @@ class Event(dict):
self.add(base)
self.add(data)
+ def hide_core_pmu_type_terms(self, other):
+ """
+ Is this a legacy type event? Then the core PMU type that perf may have
+ put in the top 32 bits of 'config' to tell the kernel which core PMU it
+ wants isn't part of what we asked for, see hide_core_pmu_type().
+ """
+ for event in (self, other):
+ for type in event.get('type', '').split('|'):
+ if type in LEGACY_TYPES:
+ return True
+
+ return False
+
+ def hide_core_pmu_type(self, term, value, other):
+ if term == 'config' and self.hide_core_pmu_type_terms(other):
+ return hide_core_pmu_type(value)
+
+ return value
+
+ def hide_event_count_dependent_terms(self, term, expected, recorded):
+ if term == 'sample_type':
+ return hide_sample_id(expected, recorded)
+ if term == 'read_format':
+ return hide_group_format(expected, recorded)
+
+ return expected, recorded
+
+ def recorded_side(self, other):
+ """
+ Which one is what perf recorded? Both directions get compared, see
+ Test.compare(), so this can't be taken from the arguments' order.
+ """
+ if getattr(other, 'recorded', False):
+ return other
+
+ return self if getattr(self, 'recorded', False) else None
+
+ def hide_tracking_via_dummy(self, term, other):
+ """
+ The tracking terms are set on the tracking event, which is the dummy
+ event when there is more than one core PMU, leaving the requested
+ events without them, nothing to match on then.
+ """
+ if term not in TRACKING_TERMS:
+ return False
+
+ for event in (self, other):
+ if term in getattr(event, 'tracking_moved_to_dummy', ()):
+ return True
+
+ return False
+
def equal(self, other):
for t in Event.terms:
log.debug(" [%s] %s %s", t, self[t], other[t])
if t not in self or t not in other:
return False
- if not data_equal(self[t], other[t]):
+ if self.hide_tracking_via_dummy(t, other):
+ continue
+
+ recorded = self.recorded_side(other)
+ if recorded is self:
+ expected, got_event = other, self
+ else:
+ expected, got_event = self, other
+ exp = self.hide_core_pmu_type(t, expected[t], other)
+ got = self.hide_core_pmu_type(t, got_event[t], other)
+ if recorded is not None:
+ exp, got = self.hide_event_count_dependent_terms(t, exp, got)
+ if not data_equal(exp, got):
return False
return True
@@ -119,14 +373,30 @@ class Event(dict):
for t in Event.terms:
if t not in self or t not in other:
continue
- if not data_equal(self[t], other[t]):
- log.warning("expected %s=%s, got %s", t, self[t], other[t])
+ if self.hide_tracking_via_dummy(t, other):
+ continue
+
+ recorded = self.recorded_side(other)
+ if recorded is self:
+ expected, got_event = other, self
+ else:
+ expected, got_event = self, other
+ exp = self.hide_core_pmu_type(t, expected[t], other)
+ got = self.hide_core_pmu_type(t, got_event[t], other)
+ if recorded is not None:
+ exp, got = self.hide_event_count_dependent_terms(t, exp, got)
+ if not data_equal(exp, got):
+ log.warning("expected %s=%s, got %s", t, expected[t],
+ got_event[t])
def parse_version(version):
if not version:
return None
return [int(v) for v in version.split(".")[0:2]]
+def format_version(version):
+ return ".".join(str(v) for v in version)
+
# Test file description needs to have following sections:
# [config]
# - just single instance in file
@@ -138,6 +408,9 @@ def parse_version(version):
# 'arch' - architecture specific test (optional)
# comma separated list, ! at the beginning
# negates it.
+# 'requires' - Comma separated list of things the test needs, it is
+# skipped when any of them isn't there, currently:
+# core-pmu - the machine can count hardware events.
# 'auxv' - Truthy statement that is evaled in the scope of the auxv map. When false,
# the test is skipped. For example 'auxv["AT_HWCAP"] == 10'. (optional)
# 'kernel_since' - Inclusive kernel version from which the test will start running. Only the
@@ -173,6 +446,7 @@ class Test(object):
self.arch = ''
self.auxv = parser.get('config', 'auxv', fallback=None)
+ self.requires = parser.get('config', 'requires', fallback='')
self.kernel_since = parse_version(parser.get('config', 'kernel_since', fallback=None))
self.kernel_until = parse_version(parser.get('config', 'kernel_until', fallback=None))
self.expect = {}
@@ -188,13 +462,17 @@ class Test(object):
def skip_test_kernel_since(self):
if not self.kernel_since:
- return False
- return not self.kernel_since <= parse_version(platform.release())
+ return None
+ if self.kernel_since <= parse_version(platform.release()):
+ return None
+ return "kernel older than %s" % format_version(self.kernel_since)
def skip_test_kernel_until(self):
if not self.kernel_until:
- return False
- return not parse_version(platform.release()) < self.kernel_until
+ return None
+ if parse_version(platform.release()) < self.kernel_until:
+ return None
+ return "kernel newer than %s" % format_version(self.kernel_until)
def skip_test_auxv(self):
def new_auxv(a, pattern):
@@ -210,18 +488,20 @@ class Test(object):
return (items[0], value)
if not self.auxv:
- return False
+ return None
auxv = subprocess.check_output("LD_SHOW_AUXV=1 sleep 0", shell=True) \
.decode(sys.stdout.encoding)
pattern = re.compile(r"[: ]+")
auxv = dict([new_auxv(a, pattern) for a in auxv.splitlines()])
- return not eval(self.auxv)
+ if eval(self.auxv):
+ return None
+
+ return "the auxv condition doesn't hold here"
def skip_test_arch(self, myarch):
# If architecture not set always run test
if self.arch == '':
- # log.warning("test for arch %s is ok" % myarch)
- return False
+ return None
# Allow multiple values in assignment separated by ','
arch_list = self.arch.split(',')
@@ -231,16 +511,26 @@ class Test(object):
arch_list[0] = arch_list[0][1:]
log.warning("excluded architecture list %s", arch_list)
for arch_item in arch_list:
- # log.warning("test for %s arch is %s" % (arch_item, myarch))
if arch_item == myarch:
- return True
- return False
+ return "arch = %s, machine = %s" % (self.arch, myarch)
+ return None
for arch_item in arch_list:
- # log.warning("test for architecture '%s' current '%s'" % (arch_item, myarch))
if arch_item == myarch:
- return False
- return True
+ return None
+
+ return "arch = %s, machine = %s" % (self.arch, myarch)
+
+ def skip_test_requires(self):
+ for requirement in filter(None, map(str.strip, self.requires.split(','))):
+ if requirement == 'core-pmu':
+ if not core_pmu_available():
+ log.warning("test limitation 'requires %s'", requirement)
+ return "needs a core PMU, none here"
+ else:
+ log.warning("unknown requirement '%s', ignored", requirement)
+
+ return None
def restore_sample_rate(self, value=10000):
try:
@@ -284,17 +574,36 @@ class Test(object):
def run_cmd(self, tempdir):
_junk1, _junk2, _junk3, _junk4, myarch = (os.uname())
- if self.skip_test_arch(myarch):
- raise Notest(self, myarch)
-
- if self.skip_test_auxv():
- raise Notest(self, "auxv skip")
-
- if self.skip_test_kernel_since():
- raise Notest(self, "old kernel skip")
-
- if self.skip_test_kernel_until():
- raise Notest(self, "new kernel skip")
+ arch = self.skip_test_arch(myarch)
+ if arch:
+ log.debug(" detail: the test file has arch = %s, the machine reports %s",
+ self.arch, myarch)
+ raise Notest(self, arch)
+
+ auxv = self.skip_test_auxv()
+ if auxv:
+ log.debug(" detail: the auxv condition %s doesn't hold, the bits come "
+ "from the LD_SHOW_AUXV=1 output", self.auxv)
+ raise Notest(self, auxv)
+
+ kernel = self.skip_test_kernel_since()
+ if kernel:
+ log.debug(" detail: the test file's kernel_since = %s, this kernel is %s",
+ format_version(self.kernel_since), platform.release())
+ raise Notest(self, kernel)
+
+ kernel = self.skip_test_kernel_until()
+ if kernel:
+ log.debug(" detail: the test file's kernel_until = %s, this kernel is %s",
+ format_version(self.kernel_until), platform.release())
+ raise Notest(self, kernel)
+
+ requirement = self.skip_test_requires()
+ if requirement:
+ log.debug(" detail: requires core-pmu, nothing countable here, check "
+ "kernel.perf_event_paranoid and the PMU nodes under "
+ "/sys/bus/event_source/")
+ raise Notest(self, requirement)
self.restore_sample_rate()
cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir,
@@ -304,12 +613,80 @@ class Test(object):
log.info(" '%s' ret '%s', expected '%s'", cmd, str(ret), str(self.ret))
if not data_equal(str(ret), str(self.ret)):
+ plain_cmd = "%s %s -o /dev/null %s" % (
+ self.perf, self.command,
+ self.args.split('>/dev/null')[0].rstrip())
if self.test_ret:
raise Fail(self, "Perf exit code failure")
else:
- raise Unsup(self)
+ log.debug(" detail: '%s' exited with %d, the expectations want the "
+ "workload's %s exit, so there are no attrs recorded to "
+ "verify; this is normally a capability problem, run '%s' "
+ "to see why", plain_cmd, ret, self.ret, plain_cmd)
+ raise Unsup(self, ret, str(self.ret))
+
+ def drop_dummy_tracking_events(self):
+ """
+ Leave out the dummy event perf itself opened, see
+ is_dummy_tracking_event(), unless the expectations ask for one.
+ """
+ if any(is_dummy_tracking_event(e) for e in self.expect.values()):
+ return
+
+ if not any(is_dummy_tracking_event(e) for e in self.result.values()):
+ return
+
+ moved = set()
+ for name, event in list(self.result.items()):
+ if is_dummy_tracking_event(event):
+ log.debug(" dropping dummy tracking event [%s]", name)
+ moved.update(t for t in TRACKING_TERMS if event.get(t) == '1')
+ del self.result[name]
+
+ # The tracking terms the dropped dummies carried, flag the remaining
+ # events so that the match leaves only those out.
+ for event in self.result.values():
+ event.tracking_moved_to_dummy = moved
+
+ def drop_other_core_pmu_events(self, devices='/sys/bus/event_source/devices'):
+ """
+ Leave out the events of the other core PMUs, which have their own
+ encodings, when the expectations name one of the core PMUs.
+ """
+ asked = set()
+ for event in self.expect.values():
+ types = event.get('type', '').split('|')
+ if '*' in types:
+ return
+ asked.update(types)
- def compare(self, expect, result):
+ try:
+ names = os.listdir(devices)
+ except OSError:
+ return
+
+ core = set()
+ for name in names:
+ path = os.path.join(devices, name)
+ has_cpus = os.path.exists(os.path.join(path, 'cpus'))
+ if name not in ('cpu', 'cpum_cf') and not has_cpus:
+ continue
+ try:
+ with open(os.path.join(path, 'type'), encoding='utf-8') as f:
+ core.add(f.read().strip())
+ except OSError:
+ pass
+
+ if not core & asked:
+ return
+
+ others = core - asked
+ for name, event in list(self.result.items()):
+ if event.get('type') in others:
+ log.debug(" dropping other core PMU event [%s]", name)
+ del self.result[name]
+
+ def compare(self, expect, result, strict_groups=True):
match = {}
log.debug(" compare")
@@ -343,8 +720,9 @@ class Test(object):
match[exp_name] = exp_list
- # For each defined group in the expected events
- # check we match the same group in the result.
+ # Check that each expected group is matched in the result; an event
+ # opened in a group may match an expectation that doesn't declare
+ # one, as those only verify the event attributes.
for exp_name, exp_event in expect.items():
group = exp_event.group
@@ -353,6 +731,8 @@ class Test(object):
for res_name in match[exp_name]:
res_group = result[res_name].group
+ if res_group == '' and not strict_groups:
+ continue
if res_group not in match[group]:
raise Fail(self, 'group failure')
@@ -384,6 +764,11 @@ class Test(object):
log.debug(" loading result events")
for f in glob.glob(tempdir + '/event*'):
self.load_events(f, self.result)
+ for event in self.result.values():
+ event.recorded = True
+
+ self.drop_dummy_tracking_events()
+ self.drop_other_core_pmu_events()
# resolve group_fd to event names
self.resolve_groups(self.expect)
@@ -391,7 +776,7 @@ class Test(object):
# do the expectation - results matching - both ways
self.compare(self.expect, self.result)
- self.compare(self.result, self.expect)
+ self.compare(self.result, self.expect, strict_groups=False)
finally:
# cleanup
diff --git a/tools/perf/tests/shell/list.sh b/tools/perf/tests/shell/list.sh
index 14a03e0290ed..d4a0b04154d6 100755
--- a/tools/perf/tests/shell/list.sh
+++ b/tools/perf/tests/shell/list.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf list tests
+# perf list tests (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
diff --git a/tools/perf/tests/shell/perf_sched_stats.sh b/tools/perf/tests/shell/perf_sched_stats.sh
index f13eb0a75b76..4ede9d701630 100755
--- a/tools/perf/tests/shell/perf_sched_stats.sh
+++ b/tools/perf/tests/shell/perf_sched_stats.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# perf sched stats tests
+# perf sched stats tests (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
diff --git a/tools/perf/tests/shell/probe_vfs_getname.sh b/tools/perf/tests/shell/probe_vfs_getname.sh
index c40e5f3f0825..43bdd693076b 100755
--- a/tools/perf/tests/shell/probe_vfs_getname.sh
+++ b/tools/perf/tests/shell/probe_vfs_getname.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# Add vfs_getname probe to get syscall args filenames
+# Add vfs_getname probe to get syscall args filenames (no_mlock)
# SPDX-License-Identifier: GPL-2.0
# Arnaldo Carvalho de Melo <acme@kernel.org>, 2017
diff --git a/tools/perf/tests/shell/python-use.sh b/tools/perf/tests/shell/python-use.sh
index 2d6017d5dd9d..ece4d306869a 100755
--- a/tools/perf/tests/shell/python-use.sh
+++ b/tools/perf/tests/shell/python-use.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# 'import perf' in python
+# 'import perf' in python (no_mlock)
# SPDX-License-Identifier: GPL-2.0
# Just test if we can load the python binding.
set -e
diff --git a/tools/perf/tests/shell/schedstat_snapshots.sh b/tools/perf/tests/shell/schedstat_snapshots.sh
index a4bdf2673d43..2050478e3f1a 100755
--- a/tools/perf/tests/shell/schedstat_snapshots.sh
+++ b/tools/perf/tests/shell/schedstat_snapshots.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Validate CPU and domain pairing in perf sched stats snapshots
+# Validate CPU and domain pairing in perf sched stats snapshots (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
diff --git a/tools/perf/tests/shell/stat+csv_output.sh b/tools/perf/tests/shell/stat+csv_output.sh
index a5b34c42e8d7..8beb6c674d05 100755
--- a/tools/perf/tests/shell/stat+csv_output.sh
+++ b/tools/perf/tests/shell/stat+csv_output.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf stat CSV output linter
+# perf stat CSV output linter (no_mlock)
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
# Tests various perf stat CSV output commands for the
# correct number of fields and the CSV separator set to ','.
diff --git a/tools/perf/tests/shell/stat+csv_summary.sh b/tools/perf/tests/shell/stat+csv_summary.sh
index 9a4353db3825..6d8beb88fb6f 100755
--- a/tools/perf/tests/shell/stat+csv_summary.sh
+++ b/tools/perf/tests/shell/stat+csv_summary.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf stat csv summary test
+# perf stat csv summary test (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
diff --git a/tools/perf/tests/shell/stat+event_uniquifying.sh b/tools/perf/tests/shell/stat+event_uniquifying.sh
index b5dec6b6da36..f5c6fa30d8db 100755
--- a/tools/perf/tests/shell/stat+event_uniquifying.sh
+++ b/tools/perf/tests/shell/stat+event_uniquifying.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf stat events uniquifying
+# perf stat events uniquifying (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
diff --git a/tools/perf/tests/shell/stat+json_output.sh b/tools/perf/tests/shell/stat+json_output.sh
index 4969ad70b67b..cbf7a4ffd7e8 100755
--- a/tools/perf/tests/shell/stat+json_output.sh
+++ b/tools/perf/tests/shell/stat+json_output.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf stat JSON output linter
+# perf stat JSON output linter (no_mlock)
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
# Checks various perf stat JSON output commands for the
# correct number of fields.
diff --git a/tools/perf/tests/shell/stat+shadow_stat.sh b/tools/perf/tests/shell/stat+shadow_stat.sh
index cabbbf17c662..7a58e1507ce2 100755
--- a/tools/perf/tests/shell/stat+shadow_stat.sh
+++ b/tools/perf/tests/shell/stat+shadow_stat.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf stat metrics (shadow stat) test
+# perf stat metrics (shadow stat) test (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
diff --git a/tools/perf/tests/shell/stat+std_output.sh b/tools/perf/tests/shell/stat+std_output.sh
index 64c2b81f02de..b915656a20f6 100755
--- a/tools/perf/tests/shell/stat+std_output.sh
+++ b/tools/perf/tests/shell/stat+std_output.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf stat STD output linter
+# perf stat STD output linter (no_mlock)
# SPDX-License-Identifier: GPL-2.0
# Tests various perf stat STD output commands for
# default event and metricgroup
diff --git a/tools/perf/tests/shell/stat.sh b/tools/perf/tests/shell/stat.sh
index 1f5d4cc05807..ac9e031831da 100755
--- a/tools/perf/tests/shell/stat.sh
+++ b/tools/perf/tests/shell/stat.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf stat tests
+# perf stat tests (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
diff --git a/tools/perf/tests/shell/stat_all_metricgroups.sh b/tools/perf/tests/shell/stat_all_metricgroups.sh
index 81bc7070b5ab..074a437da0ae 100755
--- a/tools/perf/tests/shell/stat_all_metricgroups.sh
+++ b/tools/perf/tests/shell/stat_all_metricgroups.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf all metricgroups test
+# perf all metricgroups test (no_mlock)
# SPDX-License-Identifier: GPL-2.0
ParanoidAndNotRoot()
diff --git a/tools/perf/tests/shell/stat_all_metrics.sh b/tools/perf/tests/shell/stat_all_metrics.sh
index df5fa27b21ae..9d0d4b8a217e 100755
--- a/tools/perf/tests/shell/stat_all_metrics.sh
+++ b/tools/perf/tests/shell/stat_all_metrics.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf all metrics test
+# perf all metrics test (no_mlock)
# SPDX-License-Identifier: GPL-2.0
ParanoidAndNotRoot()
diff --git a/tools/perf/tests/shell/stat_all_pfm.sh b/tools/perf/tests/shell/stat_all_pfm.sh
index c08c186af2c4..78d8006fb729 100755
--- a/tools/perf/tests/shell/stat_all_pfm.sh
+++ b/tools/perf/tests/shell/stat_all_pfm.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf all libpfm4 events test
+# perf all libpfm4 events test (no_mlock)
# SPDX-License-Identifier: GPL-2.0
if perf version --build-options | grep HAVE_LIBPFM | grep -q OFF
diff --git a/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh b/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh
index febe3af06441..d1b4632c17a3 100755
--- a/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh
+++ b/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf stat --bpf-counters --for-each-cgroup test
+# perf stat --bpf-counters --for-each-cgroup test (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
diff --git a/tools/perf/tests/shell/stat_metrics_cgrp.sh b/tools/perf/tests/shell/stat_metrics_cgrp.sh
index 0728f48f21fa..75b8e01d11cc 100755
--- a/tools/perf/tests/shell/stat_metrics_cgrp.sh
+++ b/tools/perf/tests/shell/stat_metrics_cgrp.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf stat metrics --for-each-cgroup test
+# perf stat metrics --for-each-cgroup test (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
diff --git a/tools/perf/tests/shell/stat_metrics_values.sh b/tools/perf/tests/shell/stat_metrics_values.sh
index 0982f6b9737a..3e073a0e5b9f 100755
--- a/tools/perf/tests/shell/stat_metrics_values.sh
+++ b/tools/perf/tests/shell/stat_metrics_values.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf metrics value validation
+# perf metrics value validation (no_mlock)
# SPDX-License-Identifier: GPL-2.0
shelldir=$(dirname "$0")
diff --git a/tools/perf/tests/shell/test_ilist_python.sh b/tools/perf/tests/shell/test_ilist_python.sh
index 83048474710d..a235539c0176 100755
--- a/tools/perf/tests/shell/test_ilist_python.sh
+++ b/tools/perf/tests/shell/test_ilist_python.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# perf script ilist and perf list --tui test
+# perf script ilist and perf list --tui test (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
diff --git a/tools/perf/tests/shell/test_stat_cpi_python.sh b/tools/perf/tests/shell/test_stat_cpi_python.sh
index 6cb376c92e2f..d1571a20f468 100755
--- a/tools/perf/tests/shell/test_stat_cpi_python.sh
+++ b/tools/perf/tests/shell/test_stat_cpi_python.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
-# stat-cpi python test
+# stat-cpi python test (no_mlock)
set -e
diff --git a/tools/perf/tests/shell/test_test_junit_output.sh b/tools/perf/tests/shell/test_test_junit_output.sh
index 38a29e646906..8fc92e083c34 100755
--- a/tools/perf/tests/shell/test_test_junit_output.sh
+++ b/tools/perf/tests/shell/test_test_junit_output.sh
@@ -1,6 +1,9 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
-# perf test junit XML output validation
+# perf test junit XML output validation (no_mlock)
+#
+# Waiving the mlock requisite this way holds only while the 'perf test'
+# runs below keep picking tests that don't map ring buffers.
set -e
diff --git a/tools/perf/tests/shell/test_uprobe_from_different_cu.sh b/tools/perf/tests/shell/test_uprobe_from_different_cu.sh
index 33bf36c4037e..0a02ff9b86d6 100755
--- a/tools/perf/tests/shell/test_uprobe_from_different_cu.sh
+++ b/tools/perf/tests/shell/test_uprobe_from_different_cu.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# test perf probe of function from different CU
+# test perf probe of function from different CU (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
index d18185881635..1b62dae55f07 100644
--- a/tools/perf/tests/sw-clock.c
+++ b/tools/perf/tests/sw-clock.c
@@ -149,4 +149,4 @@ static int test__sw_clock_freq(struct test_suite *test __maybe_unused, int subte
return ret;
}
-DEFINE_SUITE("Software clock events period values", sw_clock_freq);
+DEFINE_SUITE_NEEDS_MLOCK("Software clock events period values", sw_clock_freq);
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
index 95393edbfe36..9fac426ac2f9 100644
--- a/tools/perf/tests/task-exit.c
+++ b/tools/perf/tests/task-exit.c
@@ -158,4 +158,5 @@ struct test_case tests__task_exit[] = {
struct test_suite suite__task_exit = {
.desc = "Number of exit events of a simple workload",
.test_cases = tests__task_exit,
+ .needs_mlock = true,
};
diff --git a/tools/perf/tests/tests-scripts.c b/tools/perf/tests/tests-scripts.c
index 0370bc701373..a86b5289f09b 100644
--- a/tools/perf/tests/tests-scripts.c
+++ b/tools/perf/tests/tests-scripts.c
@@ -2,6 +2,7 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdio.h>
#include <linux/ctype.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -179,6 +180,79 @@ static int shell_test__run(struct test_suite *test, int subtest __maybe_unused)
return WEXITSTATUS(err) == 2 ? TEST_SKIP : TEST_FAIL;
}
+/*
+ * The requisites are a comma separated list in the parens ending the
+ * description line, e.g. "perf stat tests (no_mlock)": "exclusive" is the
+ * catch-all, implying every other requisite, "no_mlock" waives the default of
+ * needing room in the per user budget set in kernel.perf_event_mlock_kb.
+ */
+static void shell_test__requisites(char *desc, bool *exclusive, bool *needs_mlock)
+{
+ char *lparen, *rparen, *requisites, *token, *tokp;
+ bool known = false;
+
+ /* Only a list closing the description line is taken for requisites. */
+ rparen = strrchr(desc, ')');
+ if (rparen == NULL || rparen[1] != '\0')
+ return;
+
+ lparen = strrchr(desc, '(');
+ if (lparen == NULL || lparen > rparen)
+ return;
+
+ /* Tokenize a copy: a list with nothing recognized leaves desc alone. */
+ requisites = strndup(lparen + 1, rparen - lparen - 1);
+ if (requisites == NULL) {
+ pr_err("Failed to copy the requisites of '%s'\n", desc);
+ return;
+ }
+
+ for (token = strtok_r(requisites, ",", &tokp); token;
+ token = strtok_r(NULL, ",", &tokp)) {
+ char *end = token + strlen(token);
+ const char *requisite = token;
+ bool waived;
+
+ while (isspace(*token))
+ token++;
+ while (end > token && isspace(end[-1]))
+ end--;
+ *end = '\0';
+
+ /* A "no_" prefix waives the requisite named after it. */
+ waived = strncmp(token, "no_", sizeof("no_") - 1) == 0;
+ if (waived)
+ token += sizeof("no_") - 1;
+
+ if (!strcmp(token, "mlock")) {
+ *needs_mlock = !waived;
+ } else if (!strcmp(token, "exclusive") && !waived) {
+ *exclusive = true;
+ } else {
+ pr_debug("Ignoring %s requisite '%s' in '%s'\n",
+ strcmp(token, "exclusive") == 0 ? "a waived" : "an unknown",
+ requisite, desc);
+ continue;
+ }
+
+ known = true;
+ }
+
+ zfree(&requisites);
+
+ if (!known)
+ return;
+
+ /* Drop the list and the space before it from the description. */
+ *lparen = '\0';
+ if (lparen > desc && isspace(lparen[-1]))
+ lparen[-1] = '\0';
+
+ /* The catch-all implies every other requisite, whatever the order. */
+ if (*exclusive)
+ *needs_mlock = true;
+}
+
static void append_script(int dir_fd, const char *name, char *desc,
struct test_suite ***result,
size_t *result_sz)
@@ -187,7 +261,8 @@ static void append_script(int dir_fd, const char *name, char *desc,
struct test_suite *test_suite, **result_tmp;
struct test_case *tests;
ssize_t len;
- char *exclusive;
+ /* Shell tests run perf, that maps ring buffers, so they need the budget. */
+ bool exclusive = false, needs_mlock = true;
snprintf(link, sizeof(link), "/proc/%d/fd/%d", getpid(), dir_fd);
len = readlink(link, filename, sizeof(filename) - 1);
@@ -204,11 +279,8 @@ static void append_script(int dir_fd, const char *name, char *desc,
return;
}
tests[0].name = strdup_check(name);
- exclusive = strstr(desc, " (exclusive)");
- if (exclusive != NULL) {
- tests[0].exclusive = true;
- exclusive[0] = '\0';
- }
+ shell_test__requisites(desc, &exclusive, &needs_mlock);
+ tests[0].exclusive = exclusive;
tests[0].desc = strdup_check(desc);
tests[0].run_case = shell_test__run;
test_suite = zalloc(sizeof(*test_suite));
@@ -220,6 +292,7 @@ static void append_script(int dir_fd, const char *name, char *desc,
test_suite->desc = desc;
test_suite->test_cases = tests;
test_suite->priv = strdup_check(filename);
+ test_suite->needs_mlock = needs_mlock;
/* Realloc is good enough, though we could realloc by chunks, not that
* anyone will ever measure performance here */
result_tmp = realloc(*result, (*result_sz + 1) * sizeof(*result_tmp));
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index f379620069d3..20ae3609892b 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -46,6 +46,12 @@ struct test_suite {
struct test_case *test_cases;
void *priv;
int (*setup)(struct test_suite *suite);
+ /*
+ * Set for the suites mapping perf ring buffers, that need room in the
+ * per user budget set in kernel.perf_event_mlock_kb, see
+ * shell_test__requisites() for the shell suites.
+ */
+ bool needs_mlock;
};
#define DECLARE_SUITE(name) \
@@ -103,6 +109,17 @@ struct test_suite {
.test_cases = tests__##_name, \
}
+#define DEFINE_SUITE_NEEDS_MLOCK(description, _name) \
+ struct test_case tests__##_name[] = { \
+ TEST_CASE(description, _name), \
+ { .name = NULL, } \
+ }; \
+ struct test_suite suite__##_name = { \
+ .desc = description, \
+ .test_cases = tests__##_name, \
+ .needs_mlock = true, \
+ }
+
/* Tests */
DECLARE_SUITE(vmlinux_matches_kallsyms);
DECLARE_SUITE(openat_syscall_event);
@@ -124,6 +141,7 @@ DECLARE_SUITE(parse_events);
DECLARE_SUITE(hists_link);
DECLARE_SUITE(bp_signal);
DECLARE_SUITE(bp_signal_overflow);
+DECLARE_SUITE(event_refresh);
DECLARE_SUITE(bp_accounting);
DECLARE_SUITE(wp);
DECLARE_SUITE(task_exit);