diff options
Diffstat (limited to 'tools/perf/tests')
210 files changed, 7559 insertions, 2688 deletions
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 5671ee530019..c2a67ce45941 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -4,12 +4,11 @@ perf-test-y += builtin-test.o perf-test-y += tests-scripts.o perf-test-y += parse-events.o perf-test-y += dso-data.o -perf-test-y += attr.o perf-test-y += vmlinux-kallsyms.o -perf-test-$(CONFIG_LIBTRACEEVENT) += openat-syscall.o -perf-test-$(CONFIG_LIBTRACEEVENT) += openat-syscall-all-cpus.o +perf-test-y += openat-syscall.o +perf-test-y += openat-syscall-all-cpus.o perf-test-$(CONFIG_LIBTRACEEVENT) += openat-syscall-tp-fields.o -perf-test-$(CONFIG_LIBTRACEEVENT) += mmap-basic.o +perf-test-y += mmap-basic.o perf-test-y += perf-record.o perf-test-y += evsel-roundtrip-name.o perf-test-$(CONFIG_LIBTRACEEVENT) += evsel-tp-sched.o @@ -21,7 +20,6 @@ perf-test-y += hists_link.o perf-test-y += hists_filter.o perf-test-y += hists_output.o perf-test-y += hists_cumulate.o -perf-test-y += python-use.o perf-test-y += bp_signal.o perf-test-y += bp_signal_overflow.o perf-test-y += bp_account.o @@ -57,6 +55,7 @@ perf-test-y += genelf.o perf-test-y += api-io.o perf-test-y += demangle-java-test.o perf-test-y += demangle-ocaml-test.o +perf-test-y += demangle-rust-v0-test.o perf-test-y += pfm.o perf-test-y += parse-metric.o perf-test-y += pe-file-parsing.o @@ -67,27 +66,55 @@ perf-test-y += sigtrap.o perf-test-y += event_groups.o perf-test-y += symbols.o perf-test-y += util.o +perf-test-y += hwmon_pmu.o +perf-test-y += tool_pmu.o +perf-test-y += subcmd-help.o +perf-test-y += kallsyms-split.o ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc)) perf-test-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o endif -CFLAGS_attr.o += -DBINDIR="BUILD_STR($(bindir_SQ))" -DPYTHON="BUILD_STR($(PYTHON_WORD))" -CFLAGS_python-use.o += -DPYTHONPATH="BUILD_STR($(OUTPUT)python)" -DPYTHON="BUILD_STR($(PYTHON_WORD))" CFLAGS_dwarf-unwind.o += -fno-optimize-sibling-calls perf-test-y += workloads/ ifdef SHELLCHECK SHELL_TESTS := $(shell find tests/shell -executable -type f -name '*.sh') - TEST_LOGS := $(SHELL_TESTS:tests/shell/%=shell/%.shellcheck_log) + SHELL_TEST_LOGS := $(SHELL_TESTS:tests/shell/%=shell/%.shellcheck_log) else SHELL_TESTS := - TEST_LOGS := + SHELL_TEST_LOGS := endif $(OUTPUT)%.shellcheck_log: % $(call rule_mkdir) - $(Q)$(call echo-cmd,test)shellcheck -a -S warning "$<" > $@ || (cat $@ && rm $@ && false) + $(Q)$(call echo-cmd,test)$(SHELLCHECK) "$<" > $@ || (cat $@ && rm $@ && false) -perf-test-y += $(TEST_LOGS) +perf-test-y += $(SHELL_TEST_LOGS) + +ifdef MYPY + PY_TESTS := $(shell find tests/shell -type f -name '*.py') + MYPY_TEST_LOGS := $(PY_TESTS:tests/shell/%=shell/%.mypy_log) +else + MYPY_TEST_LOGS := +endif + +$(OUTPUT)%.mypy_log: % + $(call rule_mkdir) + $(Q)$(call echo-cmd,test)mypy "$<" > $@ || (cat $@ && rm $@ && false) + +perf-test-y += $(MYPY_TEST_LOGS) + +ifdef PYLINT + PY_TESTS := $(shell find tests/shell -type f -name '*.py') + PYLINT_TEST_LOGS := $(PY_TESTS:tests/shell/%=shell/%.pylint_log) +else + PYLINT_TEST_LOGS := +endif + +$(OUTPUT)%.pylint_log: % + $(call rule_mkdir) + $(Q)$(call echo-cmd,test)pylint "$<" > $@ || (cat $@ && rm $@ && false) + +perf-test-y += $(PYLINT_TEST_LOGS) diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c deleted file mode 100644 index 97e1bdd6ec0e..000000000000 --- a/tools/perf/tests/attr.c +++ /dev/null @@ -1,218 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * The struct perf_event_attr test support. - * - * This test is embedded inside into perf directly and is governed - * by the PERF_TEST_ATTR environment variable and hook inside - * sys_perf_event_open function. - * - * The general idea is to store 'struct perf_event_attr' details for - * each event created within single perf command. Each event details - * are stored into separate text file. Once perf command is finished - * these files can be checked for values we expect for command. - * - * Besides 'struct perf_event_attr' values we also store 'fd' and - * 'group_fd' values to allow checking for groups created. - * - * This all is triggered by setting PERF_TEST_ATTR environment variable. - * It must contain name of existing directory with access and write - * permissions. All the event text files are stored there. - */ - -#include <debug.h> -#include <errno.h> -#include <inttypes.h> -#include <stdlib.h> -#include <stdio.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <subcmd/exec-cmd.h> -#include "event.h" -#include "util.h" -#include "tests.h" -#include "pmus.h" - -#define ENV "PERF_TEST_ATTR" - -static char *dir; -static bool ready; - -void test_attr__init(void) -{ - dir = getenv(ENV); - test_attr__enabled = (dir != NULL); -} - -#define BUFSIZE 1024 - -#define __WRITE_ASS(str, fmt, data) \ -do { \ - char buf[BUFSIZE]; \ - size_t size; \ - \ - size = snprintf(buf, BUFSIZE, #str "=%"fmt "\n", data); \ - if (1 != fwrite(buf, size, 1, file)) { \ - perror("test attr - failed to write event file"); \ - fclose(file); \ - return -1; \ - } \ - \ -} while (0) - -#define WRITE_ASS(field, fmt) __WRITE_ASS(field, fmt, attr->field) - -static int store_event(struct perf_event_attr *attr, pid_t pid, struct perf_cpu cpu, - int fd, int group_fd, unsigned long flags) -{ - FILE *file; - char path[PATH_MAX]; - - if (!ready) - return 0; - - snprintf(path, PATH_MAX, "%s/event-%d-%llu-%d", dir, - attr->type, attr->config, fd); - - file = fopen(path, "w+"); - if (!file) { - perror("test attr - failed to open event file"); - return -1; - } - - if (fprintf(file, "[event-%d-%llu-%d]\n", - attr->type, attr->config, fd) < 0) { - perror("test attr - failed to write event file"); - fclose(file); - return -1; - } - - /* syscall arguments */ - __WRITE_ASS(fd, "d", fd); - __WRITE_ASS(group_fd, "d", group_fd); - __WRITE_ASS(cpu, "d", cpu.cpu); - __WRITE_ASS(pid, "d", pid); - __WRITE_ASS(flags, "lu", flags); - - /* struct perf_event_attr */ - WRITE_ASS(type, PRIu32); - WRITE_ASS(size, PRIu32); - WRITE_ASS(config, "llu"); - WRITE_ASS(sample_period, "llu"); - WRITE_ASS(sample_type, "llu"); - WRITE_ASS(read_format, "llu"); - WRITE_ASS(disabled, "d"); - WRITE_ASS(inherit, "d"); - WRITE_ASS(pinned, "d"); - WRITE_ASS(exclusive, "d"); - WRITE_ASS(exclude_user, "d"); - WRITE_ASS(exclude_kernel, "d"); - WRITE_ASS(exclude_hv, "d"); - WRITE_ASS(exclude_idle, "d"); - WRITE_ASS(mmap, "d"); - WRITE_ASS(comm, "d"); - WRITE_ASS(freq, "d"); - WRITE_ASS(inherit_stat, "d"); - WRITE_ASS(enable_on_exec, "d"); - WRITE_ASS(task, "d"); - WRITE_ASS(watermark, "d"); - WRITE_ASS(precise_ip, "d"); - WRITE_ASS(mmap_data, "d"); - WRITE_ASS(sample_id_all, "d"); - WRITE_ASS(exclude_host, "d"); - WRITE_ASS(exclude_guest, "d"); - WRITE_ASS(exclude_callchain_kernel, "d"); - WRITE_ASS(exclude_callchain_user, "d"); - WRITE_ASS(mmap2, "d"); - WRITE_ASS(comm_exec, "d"); - WRITE_ASS(context_switch, "d"); - WRITE_ASS(write_backward, "d"); - WRITE_ASS(namespaces, "d"); - WRITE_ASS(use_clockid, "d"); - WRITE_ASS(wakeup_events, PRIu32); - WRITE_ASS(bp_type, PRIu32); - WRITE_ASS(config1, "llu"); - WRITE_ASS(config2, "llu"); - WRITE_ASS(branch_sample_type, "llu"); - WRITE_ASS(sample_regs_user, "llu"); - WRITE_ASS(sample_stack_user, PRIu32); - - fclose(file); - return 0; -} - -void test_attr__open(struct perf_event_attr *attr, pid_t pid, struct perf_cpu cpu, - int fd, int group_fd, unsigned long flags) -{ - int errno_saved = errno; - - if ((fd != -1) && store_event(attr, pid, cpu, fd, group_fd, flags)) { - pr_err("test attr FAILED"); - exit(128); - } - - errno = errno_saved; -} - -void test_attr__ready(void) -{ - if (unlikely(test_attr__enabled) && !ready) - ready = true; -} - -static int run_dir(const char *d, const char *perf) -{ - char v[] = "-vvvvv"; - int vcnt = min(verbose, (int) sizeof(v) - 1); - char cmd[3*PATH_MAX]; - - if (verbose > 0) - vcnt++; - - scnprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %.*s", - d, d, perf, vcnt, v); - - return system(cmd) ? TEST_FAIL : TEST_OK; -} - -static int test__attr(struct test_suite *test __maybe_unused, int subtest __maybe_unused) -{ - struct stat st; - char path_perf[PATH_MAX]; - char path_dir[PATH_MAX]; - char *exec_path; - - if (perf_pmus__num_core_pmus() > 1) { - /* - * TODO: Attribute tests hard code the PMU type. If there are >1 - * core PMU then each PMU will have a different type which - * requires additional support. - */ - pr_debug("Skip test on hybrid systems"); - return TEST_SKIP; - } - - /* First try development tree tests. */ - if (!lstat("./tests", &st)) - return run_dir("./tests", "./perf"); - - exec_path = get_argv_exec_path(); - if (exec_path == NULL) - return -1; - - /* Then installed path. */ - snprintf(path_dir, PATH_MAX, "%s/tests", exec_path); - snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR); - free(exec_path); - - if (!lstat(path_dir, &st) && - !lstat(path_perf, &st)) - return run_dir(path_dir, path_perf); - - return TEST_SKIP; -} - -DEFINE_SUITE("Setup struct perf_event_attr", attr); diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index 79a980b1e786..c5e7999f2817 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c @@ -91,7 +91,6 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in struct parse_events_error parse_error; struct record_opts opts = { .target = { - .uid = UINT_MAX, .uses_mmap = true, }, .freq = 0, diff --git a/tools/perf/tests/bp_account.c b/tools/perf/tests/bp_account.c index 4cb7d486b5c1..047433c977bc 100644 --- a/tools/perf/tests/bp_account.c +++ b/tools/perf/tests/bp_account.c @@ -104,6 +104,7 @@ static int bp_accounting(int wp_cnt, int share) fd_wp = wp_event((void *)&the_var, &attr_new); TEST_ASSERT_VAL("failed to create max wp\n", fd_wp != -1); pr_debug("wp max created\n"); + close(fd_wp); } for (i = 0; i < wp_cnt; i++) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 470a9709427d..bd6ffa8e4578 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -4,10 +4,15 @@ * * Builtin regression testing command: ever growing number of sanity tests */ +#include <ctype.h> #include <fcntl.h> #include <errno.h> +#ifdef HAVE_BACKTRACE_SUPPORT +#include <execinfo.h> +#endif #include <poll.h> #include <unistd.h> +#include <setjmp.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> @@ -39,11 +44,10 @@ * making them easier to debug. */ static bool dont_fork; -/* Don't fork the tests in parallel and wait for their completion. */ -static bool sequential = true; -/* Do it in parallel, lacks infrastructure to avoid running tests that clash for resources, - * So leave it as the developers choice to enable while working on the needed infra */ -static bool parallel; +/* Fork the tests in parallel and wait for their completion. */ +static bool sequential; +/* Number of times each test is run. */ +static unsigned int runs_per_test = 1; const char *dso_to_test; const char *test_objdump_path = "objdump"; @@ -62,26 +66,24 @@ static struct test_suite *arch_tests[] = { static struct test_suite *generic_tests[] = { &suite__vmlinux_matches_kallsyms, -#ifdef HAVE_LIBTRACEEVENT &suite__openat_syscall_event, &suite__openat_syscall_event_on_all_cpus, &suite__basic_mmap, -#endif &suite__mem, &suite__parse_events, &suite__expr, &suite__PERF_RECORD, &suite__pmu, &suite__pmu_events, + &suite__hwmon_pmu, + &suite__tool_pmu, &suite__dso_data, &suite__perf_evsel__roundtrip_name_test, #ifdef HAVE_LIBTRACEEVENT &suite__perf_evsel__tp_sched_test, &suite__syscall_openat_tp_fields, #endif - &suite__attr, &suite__hists_link, - &suite__python_use, &suite__bp_signal, &suite__bp_signal_overflow, &suite__bp_accounting, @@ -124,9 +126,10 @@ static struct test_suite *generic_tests[] = { &suite__jit_write_elf, &suite__pfm, &suite__api_io, - &suite__maps__merge_in, + &suite__maps, &suite__demangle_java, &suite__demangle_ocaml, + &suite__demangle_rust, &suite__parse_metric, &suite__pe_file_parsing, &suite__expand_cgroup_events, @@ -136,15 +139,11 @@ static struct test_suite *generic_tests[] = { &suite__event_groups, &suite__symbols, &suite__util, + &suite__subcmd_help, + &suite__kallsyms_split, NULL, }; -static struct test_suite **tests[] = { - generic_tests, - arch_tests, - NULL, /* shell tests created at runtime. */ -}; - static struct test_workload *workloads[] = { &workload__noploop, &workload__thloop, @@ -153,52 +152,122 @@ static struct test_workload *workloads[] = { &workload__brstack, &workload__datasym, &workload__landlock, + &workload__traploop, }; -static int num_subtests(const struct test_suite *t) +#define workloads__for_each(workload) \ + for (unsigned i = 0; i < ARRAY_SIZE(workloads) && ({ workload = workloads[i]; 1; }); i++) + +#define test_suite__for_each_test_case(suite, idx) \ + for (idx = 0; (suite)->test_cases && (suite)->test_cases[idx].name != NULL; idx++) + +static void close_parent_fds(void) { - int num; + DIR *dir = opendir("/proc/self/fd"); + struct dirent *ent; - if (!t->test_cases) - return 0; + while ((ent = readdir(dir))) { + char *end; + long fd; - num = 0; - while (t->test_cases[num].name) - num++; + if (ent->d_type != DT_LNK) + continue; - return num; + if (!isdigit(ent->d_name[0])) + continue; + + fd = strtol(ent->d_name, &end, 10); + if (*end) + continue; + + if (fd <= 3 || fd == dirfd(dir)) + continue; + + close(fd); + } + closedir(dir); +} + +static void check_leaks(void) +{ + DIR *dir = opendir("/proc/self/fd"); + struct dirent *ent; + int leaks = 0; + + while ((ent = readdir(dir))) { + char path[PATH_MAX]; + char *end; + long fd; + ssize_t len; + + if (ent->d_type != DT_LNK) + continue; + + if (!isdigit(ent->d_name[0])) + continue; + + fd = strtol(ent->d_name, &end, 10); + if (*end) + continue; + + if (fd <= 3 || fd == dirfd(dir)) + continue; + + leaks++; + len = readlinkat(dirfd(dir), ent->d_name, path, sizeof(path)); + if (len > 0 && (size_t)len < sizeof(path)) + path[len] = '\0'; + else + strncpy(path, ent->d_name, sizeof(path)); + pr_err("Leak of file descriptor %s that opened: '%s'\n", ent->d_name, path); + } + closedir(dir); + if (leaks) + abort(); } -static bool has_subtests(const struct test_suite *t) +static int test_suite__num_test_cases(const struct test_suite *t) { - return num_subtests(t) > 1; + int num; + + test_suite__for_each_test_case(t, num); + + return num; } -static const char *skip_reason(const struct test_suite *t, int subtest) +static const char *skip_reason(const struct test_suite *t, int test_case) { if (!t->test_cases) return NULL; - return t->test_cases[subtest >= 0 ? subtest : 0].skip_reason; + return t->test_cases[test_case >= 0 ? test_case : 0].skip_reason; } -static const char *test_description(const struct test_suite *t, int subtest) +static const char *test_description(const struct test_suite *t, int test_case) { - if (t->test_cases && subtest >= 0) - return t->test_cases[subtest].desc; + if (t->test_cases && test_case >= 0) + return t->test_cases[test_case].desc; return t->desc; } -static test_fnptr test_function(const struct test_suite *t, int subtest) +static test_fnptr test_function(const struct test_suite *t, int test_case) { - if (subtest <= 0) + if (test_case <= 0) return t->test_cases[0].run_case; - return t->test_cases[subtest].run_case; + return t->test_cases[test_case].run_case; +} + +static bool test_exclusive(const struct test_suite *t, int test_case) +{ + if (test_case <= 0) + return t->test_cases[0].exclusive; + + return t->test_cases[test_case].exclusive; } -static bool perf_test__matches(const char *desc, int curr, int argc, const char *argv[]) +static bool perf_test__matches(const char *desc, int suite_num, int argc, const char *argv[]) { int i; @@ -210,7 +279,7 @@ static bool perf_test__matches(const char *desc, int curr, int argc, const char long nr = strtoul(argv[i], &end, 10); if (*end == '\0') { - if (nr == curr + 1) + if (nr == suite_num + 1) return true; continue; } @@ -225,38 +294,82 @@ static bool perf_test__matches(const char *desc, int curr, int argc, const char struct child_test { struct child_process process; struct test_suite *test; - int test_num; - int subtest; + int suite_num; + int test_case_num; }; +static jmp_buf run_test_jmp_buf; + +static void child_test_sig_handler(int sig) +{ +#ifdef HAVE_BACKTRACE_SUPPORT + void *stackdump[32]; + size_t stackdump_size; +#endif + + fprintf(stderr, "\n---- unexpected signal (%d) ----\n", sig); +#ifdef HAVE_BACKTRACE_SUPPORT + stackdump_size = backtrace(stackdump, ARRAY_SIZE(stackdump)); + __dump_stack(stderr, stackdump, stackdump_size); +#endif + siglongjmp(run_test_jmp_buf, sig); +} + 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); int err; + close_parent_fds(); + + err = sigsetjmp(run_test_jmp_buf, 1); + if (err) { + /* Received signal. */ + err = err > 0 ? -err : -1; + goto err_out; + } + + for (size_t i = 0; i < ARRAY_SIZE(signals); i++) + signal(signals[i], child_test_sig_handler); + pr_debug("--- start ---\n"); pr_debug("test child forked, pid %d\n", getpid()); - err = test_function(child->test, child->subtest)(child->test, child->subtest); + err = test_function(child->test, child->test_case_num)(child->test, child->test_case_num); pr_debug("---- end(%d) ----\n", err); + + check_leaks(); +err_out: fflush(NULL); + for (size_t i = 0; i < ARRAY_SIZE(signals); i++) + signal(signals[i], SIG_DFL); return -err; } -static int print_test_result(struct test_suite *t, int i, int subtest, int result, int width) +#define TEST_RUNNING -3 + +static int print_test_result(struct test_suite *t, int curr_suite, int curr_test_case, + int result, int width, int running) { - if (has_subtests(t)) { + if (test_suite__num_test_cases(t) > 1) { int subw = width > 2 ? width - 2 : width; - pr_info("%3d.%1d: %-*s:", i + 1, subtest + 1, subw, test_description(t, subtest)); + pr_info("%3d.%1d: %-*s:", curr_suite + 1, curr_test_case + 1, subw, + test_description(t, curr_test_case)); } else - pr_info("%3d: %-*s:", i + 1, width, test_description(t, subtest)); + pr_info("%3d: %-*s:", curr_suite + 1, width, test_description(t, curr_test_case)); switch (result) { + case TEST_RUNNING: + color_fprintf(stderr, PERF_COLOR_YELLOW, " Running (%d active)\n", running); + break; case TEST_OK: pr_info(" Ok\n"); break; case TEST_SKIP: { - const char *reason = skip_reason(t, subtest); + const char *reason = skip_reason(t, curr_test_case); if (reason) color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (%s)\n", reason); @@ -273,34 +386,44 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resul return 0; } -static int finish_test(struct child_test *child_test, int width) +static void finish_test(struct child_test **child_tests, int running_test, int child_test_num, + int width) { - struct test_suite *t = child_test->test; - int i = child_test->test_num; - int subi = child_test->subtest; - int err = child_test->process.err; - bool err_done = err <= 0; + struct child_test *child_test = child_tests[running_test]; + struct test_suite *t; + int curr_suite, curr_test_case, err; + bool err_done = false; struct strbuf err_output = STRBUF_INIT; + int last_running = -1; int ret; + if (child_test == NULL) { + /* Test wasn't started. */ + return; + } + t = child_test->test; + curr_suite = child_test->suite_num; + curr_test_case = child_test->test_case_num; + err = child_test->process.err; /* * For test suites with subtests, display the suite name ahead of the * sub test names. */ - if (has_subtests(t) && subi == 0) - pr_info("%3d: %-*s:\n", i + 1, width, test_description(t, -1)); + if (test_suite__num_test_cases(t) > 1 && curr_test_case == 0) + pr_info("%3d: %-*s:\n", curr_suite + 1, width, test_description(t, -1)); /* * Busy loop reading from the child's stdout/stderr that are set to be * non-blocking until EOF. */ - if (!err_done) + if (err > 0) fcntl(err, F_SETFL, O_NONBLOCK); if (verbose > 1) { - if (has_subtests(t)) - pr_info("%3d.%1d: %s:\n", i + 1, subi + 1, test_description(t, subi)); + if (test_suite__num_test_cases(t) > 1) + pr_info("%3d.%1d: %s:\n", curr_suite + 1, curr_test_case + 1, + test_description(t, curr_test_case)); else - pr_info("%3d: %s:\n", i + 1, test_description(t, -1)); + pr_info("%3d: %s:\n", curr_suite + 1, test_description(t, -1)); } while (!err_done) { struct pollfd pfds[1] = { @@ -308,64 +431,99 @@ static int finish_test(struct child_test *child_test, int width) .events = POLLIN | POLLERR | POLLHUP | POLLNVAL, }, }; - char buf[512]; - ssize_t len; + if (perf_use_color_default) { + int running = 0; - /* Poll to avoid excessive spinning, timeout set for 100ms. */ - poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100); - if (!err_done && pfds[0].revents) { - errno = 0; - len = read(err, buf, sizeof(buf) - 1); + for (int y = running_test; y < child_test_num; y++) { + if (child_tests[y] == NULL) + continue; + if (check_if_command_finished(&child_tests[y]->process) == 0) + running++; + } + if (running != last_running) { + if (last_running != -1) { + /* + * Erase "Running (.. active)" line + * printed before poll/sleep. + */ + fprintf(debug_file(), PERF_COLOR_DELETE_LINE); + } + print_test_result(t, curr_suite, curr_test_case, TEST_RUNNING, + width, running); + last_running = running; + } + } - if (len <= 0) { - err_done = errno != EAGAIN; - } else { - buf[len] = '\0'; - if (verbose > 1) - fprintf(stdout, "%s", buf); - else + err_done = true; + if (err <= 0) { + /* No child stderr to poll, sleep for 10ms for child to complete. */ + usleep(10 * 1000); + } else { + /* Poll to avoid excessive spinning, timeout set for 100ms. */ + poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100); + if (pfds[0].revents) { + char buf[512]; + ssize_t len; + + len = read(err, buf, sizeof(buf) - 1); + + if (len > 0) { + err_done = false; + buf[len] = '\0'; strbuf_addstr(&err_output, buf); + } } } + if (err_done) + err_done = check_if_command_finished(&child_test->process); + } + if (perf_use_color_default && last_running != -1) { + /* Erase "Running (.. active)" line printed before poll/sleep. */ + fprintf(debug_file(), PERF_COLOR_DELETE_LINE); } /* Clean up child process. */ ret = finish_command(&child_test->process); - if (verbose == 1 && ret == TEST_FAIL) { - /* Add header for test that was skipped above. */ - if (has_subtests(t)) - pr_info("%3d.%1d: %s:\n", i + 1, subi + 1, test_description(t, subi)); - else - pr_info("%3d: %s:\n", i + 1, test_description(t, -1)); + if (verbose > 1 || (verbose == 1 && ret == TEST_FAIL)) fprintf(stderr, "%s", err_output.buf); - } + strbuf_release(&err_output); - print_test_result(t, i, subi, ret, width); + print_test_result(t, curr_suite, curr_test_case, ret, width, /*running=*/0); if (err > 0) close(err); - return 0; + zfree(&child_tests[running_test]); } -static int start_test(struct test_suite *test, int i, int subi, struct child_test **child, - int width) +static int start_test(struct test_suite *test, int curr_suite, int curr_test_case, + struct child_test **child, int width, int pass) { int err; *child = NULL; if (dont_fork) { - pr_debug("--- start ---\n"); - err = test_function(test, subi)(test, subi); - pr_debug("---- end ----\n"); - print_test_result(test, i, subi, err, width); + if (pass == 1) { + pr_debug("--- start ---\n"); + err = test_function(test, curr_test_case)(test, curr_test_case); + pr_debug("---- end ----\n"); + print_test_result(test, curr_suite, curr_test_case, err, width, + /*running=*/0); + } + return 0; + } + if (pass == 1 && !sequential && test_exclusive(test, curr_test_case)) { + /* When parallel, skip exclusive tests on the first pass. */ + return 0; + } + if (pass != 1 && (sequential || !test_exclusive(test, curr_test_case))) { + /* Sequential and non-exclusive tests were run on the first pass. */ return 0; } - *child = zalloc(sizeof(**child)); if (!*child) return -ENOMEM; (*child)->test = test; - (*child)->test_num = i; - (*child)->subtest = subi; + (*child)->suite_num = curr_suite; + (*child)->test_case_num = curr_test_case; (*child)->process.pid = -1; (*child)->process.no_stdin = 1; if (verbose <= 0) { @@ -377,138 +535,181 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes (*child)->process.err = -1; } (*child)->process.no_exec_cmd = run_test_child; - err = start_command(&(*child)->process); - if (err || !sequential) - return err; - return finish_test(*child, width); + if (sequential || pass == 2) { + err = start_command(&(*child)->process); + if (err) + return err; + finish_test(child, /*running_test=*/0, /*child_test_num=*/1, width); + return 0; + } + return start_command(&(*child)->process); } -#define for_each_test(j, k, t) \ - for (j = 0, k = 0; j < ARRAY_SIZE(tests); j++, k = 0) \ - while ((t = tests[j][k++]) != NULL) +/* State outside of __cmd_test for the sake of the signal handler. */ + +static size_t num_tests; +static struct child_test **child_tests; +static jmp_buf cmd_test_jmp_buf; -static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) +static void cmd_test_sig_handler(int sig) { - struct test_suite *t; - unsigned int j, k; - int i = 0; - int width = 0; - size_t num_tests = 0; - struct child_test **child_tests; - int child_test_num = 0; + siglongjmp(cmd_test_jmp_buf, sig); +} - for_each_test(j, k, t) { - int len = strlen(test_description(t, -1)); +static int __cmd_test(struct test_suite **suites, int argc, const char *argv[], + struct intlist *skiplist) +{ + static int width = 0; + int err = 0; + + for (struct test_suite **t = suites; *t; t++) { + int i, len = strlen(test_description(*t, -1)); if (width < len) width = len; - if (has_subtests(t)) { - for (int subi = 0, subn = num_subtests(t); subi < subn; subi++) { - len = strlen(test_description(t, subi)); - if (width < len) - width = len; - num_tests++; - } - } else { - num_tests++; + test_suite__for_each_test_case(*t, i) { + len = strlen(test_description(*t, i)); + if (width < len) + width = len; + num_tests += runs_per_test; } } child_tests = calloc(num_tests, sizeof(*child_tests)); if (!child_tests) return -ENOMEM; - for_each_test(j, k, t) { - int curr = i++; - - if (!perf_test__matches(test_description(t, -1), curr, argc, argv)) { - bool skip = true; + err = sigsetjmp(cmd_test_jmp_buf, 1); + if (err) { + pr_err("\nSignal (%d) while running tests.\nTerminating tests with the same signal\n", + err); + for (size_t x = 0; x < num_tests; x++) { + struct child_test *child_test = child_tests[x]; - for (int subi = 0, subn = num_subtests(t); subi < subn; subi++) { - if (perf_test__matches(test_description(t, subi), - curr, argc, argv)) - skip = false; - } - - if (skip) + if (!child_test || child_test->process.pid <= 0) continue; - } - if (intlist__find(skiplist, i)) { - pr_info("%3d: %-*s:", curr + 1, width, test_description(t, -1)); - color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n"); - continue; + pr_debug3("Killing %d pid %d\n", + child_test->suite_num + 1, + child_test->process.pid); + kill(child_test->process.pid, err); } + goto err_out; + } + signal(SIGINT, cmd_test_sig_handler); + signal(SIGTERM, cmd_test_sig_handler); - if (!has_subtests(t)) { - int err = start_test(t, curr, -1, &child_tests[child_test_num++], width); - - if (err) { - /* TODO: if !sequential waitpid the already forked children. */ - free(child_tests); - return err; + /* + * In parallel mode pass 1 runs non-exclusive tests in parallel, pass 2 + * runs the exclusive tests sequentially. In other modes all tests are + * run in pass 1. + */ + for (int pass = 1; pass <= 2; pass++) { + int child_test_num = 0; + int curr_suite = 0; + + for (struct test_suite **t = suites; *t; t++, curr_suite++) { + int curr_test_case; + bool suite_matched = false; + + if (!perf_test__matches(test_description(*t, -1), curr_suite, argc, argv)) { + /* + * Test suite shouldn't be run based on + * description. See if any test case should. + */ + bool skip = true; + + test_suite__for_each_test_case(*t, curr_test_case) { + if (perf_test__matches(test_description(*t, curr_test_case), + curr_suite, argc, argv)) { + skip = false; + break; + } + } + if (skip) + continue; + } else { + suite_matched = true; } - } else { - for (int subi = 0, subn = num_subtests(t); subi < subn; subi++) { - int err; - if (!perf_test__matches(test_description(t, subi), - curr, argc, argv)) - continue; + if (intlist__find(skiplist, curr_suite + 1)) { + pr_info("%3d: %-*s:", curr_suite + 1, width, + test_description(*t, -1)); + color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n"); + continue; + } - err = start_test(t, curr, subi, &child_tests[child_test_num++], - width); - if (err) - return err; + for (unsigned int run = 0; run < runs_per_test; run++) { + test_suite__for_each_test_case(*t, curr_test_case) { + if (!suite_matched && + !perf_test__matches(test_description(*t, curr_test_case), + curr_suite, argc, argv)) + continue; + err = start_test(*t, curr_suite, curr_test_case, + &child_tests[child_test_num++], + width, pass); + if (err) + goto err_out; + } } } - } - for (i = 0; i < child_test_num; i++) { if (!sequential) { - int ret = finish_test(child_tests[i], width); - - if (ret) - return ret; + /* Parallel mode starts tests but doesn't finish them. Do that now. */ + for (size_t x = 0; x < num_tests; x++) + finish_test(child_tests, x, num_tests, width); } - free(child_tests[i]); + } +err_out: + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + if (err) { + pr_err("Internal test harness failure. Completing any started tests:\n:"); + for (size_t x = 0; x < num_tests; x++) + finish_test(child_tests, x, num_tests, width); } free(child_tests); - return 0; + return err; } -static int perf_test__list(int argc, const char **argv) +static int perf_test__list(FILE *fp, struct test_suite **suites, int argc, const char **argv) { - unsigned int j, k; - struct test_suite *t; - int i = 0; + int curr_suite = 0; - for_each_test(j, k, t) { - int curr = i++; + for (struct test_suite **t = suites; *t; t++, curr_suite++) { + int curr_test_case; - if (!perf_test__matches(test_description(t, -1), curr, argc, argv)) + if (!perf_test__matches(test_description(*t, -1), curr_suite, argc, argv)) continue; - pr_info("%3d: %s\n", i, test_description(t, -1)); + fprintf(fp, "%3d: %s\n", curr_suite + 1, test_description(*t, -1)); - if (has_subtests(t)) { - int subn = num_subtests(t); - int subi; + if (test_suite__num_test_cases(*t) <= 1) + continue; - for (subi = 0; subi < subn; subi++) - pr_info("%3d:%1d: %s\n", i, subi + 1, - test_description(t, subi)); + test_suite__for_each_test_case(*t, curr_test_case) { + fprintf(fp, "%3d.%1d: %s\n", curr_suite + 1, curr_test_case + 1, + test_description(*t, curr_test_case)); } } return 0; } +static int workloads__fprintf_list(FILE *fp) +{ + struct test_workload *twl; + int printed = 0; + + workloads__for_each(twl) + printed += fprintf(fp, "%s\n", twl->name); + + return printed; +} + static int run_workload(const char *work, int argc, const char **argv) { - unsigned int i = 0; struct test_workload *twl; - for (i = 0; i < ARRAY_SIZE(workloads); i++) { - twl = workloads[i]; + workloads__for_each(twl) { if (!strcmp(twl->name, work)) return twl->func(argc, argv); } @@ -526,6 +727,52 @@ static int perf_test__config(const char *var, const char *value, return 0; } +static struct test_suite **build_suites(void) +{ + /* + * TODO: suites is static to avoid needing to clean up the scripts tests + * for leak sanitizer. + */ + static struct test_suite **suites[] = { + generic_tests, + arch_tests, + NULL, + }; + struct test_suite **result; + struct test_suite *t; + size_t n = 0, num_suites = 0; + + if (suites[2] == NULL) + suites[2] = create_script_test_suites(); + +#define for_each_suite(suite) \ + for (size_t i = 0, j = 0; i < ARRAY_SIZE(suites); i++, j = 0) \ + while ((suite = suites[i][j++]) != NULL) + + for_each_suite(t) + num_suites++; + + result = calloc(num_suites + 1, sizeof(struct test_suite *)); + + for (int pass = 1; pass <= 2; pass++) { + for_each_suite(t) { + bool exclusive = false; + int curr_test_case; + + test_suite__for_each_test_case(t, curr_test_case) { + if (test_exclusive(t, curr_test_case)) { + exclusive = true; + break; + } + } + if ((!exclusive && pass == 1) || (exclusive && pass == 2)) + result[n++] = t; + } + } + return result; +#undef for_each_suite +} + int cmd_test(int argc, const char **argv) { const char *test_usage[] = { @@ -534,16 +781,19 @@ int cmd_test(int argc, const char **argv) }; const char *skip = NULL; const char *workload = NULL; + bool list_workloads = false; const struct option test_options[] = { OPT_STRING('s', "skip", &skip, "tests", "tests to skip"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('F', "dont-fork", &dont_fork, "Do not fork for testcase"), - OPT_BOOLEAN('p', "parallel", ¶llel, "Run the tests in parallel"), OPT_BOOLEAN('S', "sequential", &sequential, "Run the tests one after another rather than in parallel"), - OPT_STRING('w', "workload", &workload, "work", "workload to run for testing"), + OPT_UINTEGER('r', "runs-per-test", &runs_per_test, + "Run each test the given number of times, default 1"), + OPT_STRING('w', "workload", &workload, "work", "workload to run for testing, use '--list-workloads' to list the available ones."), + OPT_BOOLEAN(0, "list-workloads", &list_workloads, "List the available builtin workloads to use with -w/--workload"), OPT_STRING(0, "dso", &dso_to_test, "dso", "dso to test"), OPT_STRING(0, "objdump", &test_objdump_path, "path", "objdump binary to use for disassembly and annotations"), @@ -552,6 +802,7 @@ int cmd_test(int argc, const char **argv) const char * const test_subcommands[] = { "list", NULL }; struct intlist *skiplist = NULL; int ret = hists__init(); + struct test_suite **suites; if (ret < 0) return ret; @@ -561,22 +812,29 @@ int cmd_test(int argc, const char **argv) /* Unbuffered output */ setvbuf(stdout, NULL, _IONBF, 0); - tests[2] = create_script_test_suites(); argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0); - if (argc >= 1 && !strcmp(argv[0], "list")) - return perf_test__list(argc - 1, argv + 1); + if (argc >= 1 && !strcmp(argv[0], "list")) { + suites = build_suites(); + ret = perf_test__list(stdout, suites, argc - 1, argv + 1); + free(suites); + return ret; + } if (workload) return run_workload(workload, argc, argv); + if (list_workloads) { + workloads__fprintf_list(stdout); + return 0; + } + if (dont_fork) sequential = true; - else if (parallel) - sequential = false; symbol_conf.priv_size = sizeof(int); symbol_conf.try_vmlinux_path = true; + if (symbol__init(NULL) < 0) return -1; @@ -588,5 +846,8 @@ int cmd_test(int argc, const char **argv) */ rlimit__bump_memlock(); - return __cmd_test(argc, argv, skiplist); + suites = build_suites(); + ret = __cmd_test(suites, argc, argv, skiplist); + free(suites); + return ret; } diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 27c82cfb7e7d..5927d1ea20e2 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 #include <errno.h> +#include <linux/kconfig.h> #include <linux/kernel.h> +#include <linux/rbtree.h> #include <linux/types.h> #include <inttypes.h> #include <stdlib.h> @@ -8,6 +10,7 @@ #include <stdio.h> #include <string.h> #include <sys/param.h> +#include <sys/utsname.h> #include <perf/cpumap.h> #include <perf/evlist.h> #include <perf/mmap.h> @@ -37,11 +40,69 @@ #define BUFSZ 1024 #define READLEN 128 -struct state { - u64 done[1024]; - size_t done_cnt; +struct tested_section { + struct rb_node rb_node; + u64 addr; + char *path; }; +static bool tested_code_insert_or_exists(const char *path, u64 addr, + struct rb_root *tested_sections) +{ + struct rb_node **node = &tested_sections->rb_node; + struct rb_node *parent = NULL; + struct tested_section *data; + + while (*node) { + int cmp; + + parent = *node; + data = rb_entry(*node, struct tested_section, rb_node); + cmp = strcmp(path, data->path); + if (!cmp) { + if (addr < data->addr) + cmp = -1; + else if (addr > data->addr) + cmp = 1; + else + return true; /* already tested */ + } + + if (cmp < 0) + node = &(*node)->rb_left; + else + node = &(*node)->rb_right; + } + + data = zalloc(sizeof(*data)); + if (!data) + return true; + + data->addr = addr; + data->path = strdup(path); + if (!data->path) { + free(data); + return true; + } + rb_link_node(&data->rb_node, parent, node); + rb_insert_color(&data->rb_node, tested_sections); + return false; +} + +static void tested_sections__free(struct rb_root *root) +{ + while (!RB_EMPTY_ROOT(root)) { + struct rb_node *node = rb_first(root); + struct tested_section *ts = rb_entry(node, + struct tested_section, + rb_node); + + rb_erase(node, root); + free(ts->path); + free(ts); + } +} + static size_t read_objdump_chunk(const char **line, unsigned char **buf, size_t *buf_len) { @@ -176,16 +237,104 @@ static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr) return err; } +/* + * Only gets GNU objdump version. Returns 0 for llvm-objdump. + */ +static int objdump_version(void) +{ + size_t line_len; + char cmd[PATH_MAX * 2]; + char *line = NULL; + const char *fmt; + FILE *f; + int ret; + + int version_tmp, version_num = 0; + char *version = 0, *token; + + fmt = "%s --version"; + ret = snprintf(cmd, sizeof(cmd), fmt, test_objdump_path); + if (ret <= 0 || (size_t)ret >= sizeof(cmd)) + return -1; + /* Ignore objdump errors */ + strcat(cmd, " 2>/dev/null"); + f = popen(cmd, "r"); + if (!f) { + pr_debug("popen failed\n"); + return -1; + } + /* Get first line of objdump --version output */ + ret = getline(&line, &line_len, f); + pclose(f); + if (ret < 0) { + pr_debug("getline failed\n"); + return -1; + } + + token = strsep(&line, " "); + if (token != NULL && !strcmp(token, "GNU")) { + // version is last part of first line of objdump --version output. + while ((token = strsep(&line, " "))) + version = token; + + // Convert version into a format we can compare with + token = strsep(&version, "."); + version_num = atoi(token); + if (version_num) + version_num *= 10000; + + token = strsep(&version, "."); + version_tmp = atoi(token); + if (token) + version_num += version_tmp * 100; + + token = strsep(&version, "."); + version_tmp = atoi(token); + if (token) + version_num += version_tmp; + } + + return version_num; +} + static int read_via_objdump(const char *filename, u64 addr, void *buf, size_t len) { + u64 stop_address = addr + len; + struct utsname uname_buf; char cmd[PATH_MAX * 2]; const char *fmt; FILE *f; int ret; + ret = uname(&uname_buf); + if (ret) { + pr_debug("uname failed\n"); + return -1; + } + + if (!strncmp(uname_buf.machine, "riscv", 5)) { + int version = objdump_version(); + + /* Default to this workaround if version parsing fails */ + if (version < 0 || version > 24100) { + /* + * Starting at riscv objdump version 2.41, dumping in + * the middle of an instruction is not supported. riscv + * instructions are aligned along 2-byte intervals and + * can be either 2-bytes or 4-bytes. This makes it + * possible that the stop-address lands in the middle of + * a 4-byte instruction. Increase the stop_address by + * two to ensure an instruction is not cut in half, but + * leave the len as-is so only the expected number of + * bytes are collected. + */ + stop_address += 2; + } + } + fmt = "%s -z -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s"; - ret = snprintf(cmd, sizeof(cmd), fmt, test_objdump_path, addr, addr + len, + ret = snprintf(cmd, sizeof(cmd), fmt, test_objdump_path, addr, stop_address, filename); if (ret <= 0 || (size_t)ret >= sizeof(cmd)) return -1; @@ -226,13 +375,15 @@ static void dump_buf(unsigned char *buf, size_t len) } static int read_object_code(u64 addr, size_t len, u8 cpumode, - struct thread *thread, struct state *state) + struct thread *thread, + struct rb_root *tested_sections) { struct addr_location al; unsigned char buf1[BUFSZ] = {0}; unsigned char buf2[BUFSZ] = {0}; size_t ret_len; u64 objdump_addr; + u64 skip_addr; const char *objdump_name; char decomp_name[KMOD_DECOMP_LEN]; bool decomp = false; @@ -260,6 +411,18 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, goto out; } + /* + * Don't retest the same addresses. objdump struggles with kcore - try + * each map only once even if the address is different. + */ + skip_addr = dso__is_kcore(dso) ? map__start(al.map) : al.addr; + if (tested_code_insert_or_exists(dso__long_name(dso), skip_addr, + tested_sections)) { + pr_debug("Already tested %s @ %#"PRIx64" - skipping\n", + dso__long_name(dso), skip_addr); + goto out; + } + pr_debug("On file address is: %#"PRIx64"\n", al.addr); if (len > BUFSZ) @@ -297,24 +460,6 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, goto out; } - /* objdump struggles with kcore - try each map only once */ - if (dso__is_kcore(dso)) { - size_t d; - - for (d = 0; d < state->done_cnt; d++) { - if (state->done[d] == map__start(al.map)) { - pr_debug("kcore map tested already"); - pr_debug(" - skipping\n"); - goto out; - } - } - if (state->done_cnt >= ARRAY_SIZE(state->done)) { - pr_debug("Too many kcore maps - skipping\n"); - goto out; - } - state->done[state->done_cnt++] = map__start(al.map); - } - objdump_name = dso__long_name(dso); if (dso__needs_decompress(dso)) { if (dso__decompress_kmodule_path(dso, objdump_name, @@ -381,35 +526,43 @@ out: return err; } -static int process_sample_event(struct machine *machine, - struct evlist *evlist, - union perf_event *event, struct state *state) +static int process_sample_event(struct machine *machine, struct evlist *evlist, + union perf_event *event, + struct rb_root *tested_sections) { struct perf_sample sample; struct thread *thread; int ret; - if (evlist__parse_sample(evlist, event, &sample)) { + perf_sample__init(&sample, /*all=*/false); + ret = evlist__parse_sample(evlist, event, &sample); + if (ret) { pr_debug("evlist__parse_sample failed\n"); - return -1; + ret = -1; + goto out; } thread = machine__findnew_thread(machine, sample.pid, sample.tid); if (!thread) { pr_debug("machine__findnew_thread failed\n"); - return -1; + ret = -1; + goto out; } - ret = read_object_code(sample.ip, READLEN, sample.cpumode, thread, state); + ret = read_object_code(sample.ip, READLEN, sample.cpumode, thread, + tested_sections); thread__put(thread); +out: + perf_sample__exit(&sample); return ret; } static int process_event(struct machine *machine, struct evlist *evlist, - union perf_event *event, struct state *state) + union perf_event *event, struct rb_root *tested_sections) { if (event->header.type == PERF_RECORD_SAMPLE) - return process_sample_event(machine, evlist, event, state); + return process_sample_event(machine, evlist, event, + tested_sections); if (event->header.type == PERF_RECORD_THROTTLE || event->header.type == PERF_RECORD_UNTHROTTLE) @@ -429,7 +582,7 @@ static int process_event(struct machine *machine, struct evlist *evlist, } static int process_events(struct machine *machine, struct evlist *evlist, - struct state *state) + struct rb_root *tested_sections) { union perf_event *event; struct mmap *md; @@ -441,7 +594,7 @@ static int process_events(struct machine *machine, struct evlist *evlist, continue; while ((event = perf_mmap__read_event(&md->core)) != NULL) { - ret = process_event(machine, evlist, event, state); + ret = process_event(machine, evlist, event, tested_sections); perf_mmap__consume(&md->core); if (ret < 0) return ret; @@ -541,9 +694,7 @@ static int do_test_code_reading(bool try_kcore) .uses_mmap = true, }, }; - struct state state = { - .done_cnt = 0, - }; + struct rb_root tested_sections = RB_ROOT; struct perf_thread_map *threads = NULL; struct perf_cpu_map *cpus = NULL; struct evlist *evlist = NULL; @@ -553,13 +704,14 @@ static int do_test_code_reading(bool try_kcore) struct map *map; bool have_vmlinux, have_kcore; struct dso *dso; - const char *events[] = { "cycles", "cycles:u", "cpu-clock", "cpu-clock:u", NULL }; + const char *events[] = { "cpu-cycles", "cpu-cycles:u", "cpu-clock", "cpu-clock:u", NULL }; int evidx = 0; + struct perf_env host_env; pid = getpid(); - machine = machine__new_host(); - machine->env = &perf_env; + perf_env__init(&host_env); + machine = machine__new_host(&host_env); ret = machine__create_kernel_maps(machine); if (ret < 0) { @@ -653,13 +805,6 @@ static int do_test_code_reading(bool try_kcore) pr_debug("perf_evlist__open() failed!\n%s\n", errbuf); } - /* - * Both cpus and threads are now owned by evlist - * and will be freed by following perf_evlist__set_maps - * call. Getting reference to keep them alive. - */ - perf_cpu_map__get(cpus); - perf_thread_map__get(threads); perf_evlist__set_maps(&evlist->core, NULL, NULL); evlist__delete(evlist); evlist = NULL; @@ -683,7 +828,7 @@ static int do_test_code_reading(bool try_kcore) evlist__disable(evlist); - ret = process_events(machine, evlist, &state); + ret = process_events(machine, evlist, &tested_sections); if (ret < 0) goto out_put; @@ -702,6 +847,8 @@ out_err: perf_cpu_map__put(cpus); perf_thread_map__put(threads); machine__delete(machine); + perf_env__exit(&host_env); + tested_sections__free(&tested_sections); return err; } diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c index 2f0168b2a5a9..2354246afc5a 100644 --- a/tools/perf/tests/cpumap.c +++ b/tools/perf/tests/cpumap.c @@ -156,21 +156,54 @@ static int test__cpu_map_print(struct test_suite *test __maybe_unused, int subte return 0; } -static int test__cpu_map_merge(struct test_suite *test __maybe_unused, int subtest __maybe_unused) +static int __test__cpu_map_merge(const char *lhs, const char *rhs, int nr, const char *expected) { - struct perf_cpu_map *a = perf_cpu_map__new("4,2,1"); - struct perf_cpu_map *b = perf_cpu_map__new("4,5,7"); - struct perf_cpu_map *c = perf_cpu_map__merge(a, b); + struct perf_cpu_map *a = perf_cpu_map__new(lhs); + struct perf_cpu_map *b = perf_cpu_map__new(rhs); char buf[100]; - TEST_ASSERT_VAL("failed to merge map: bad nr", perf_cpu_map__nr(c) == 5); - cpu_map__snprint(c, buf, sizeof(buf)); - TEST_ASSERT_VAL("failed to merge map: bad result", !strcmp(buf, "1-2,4-5,7")); + perf_cpu_map__merge(&a, b); + TEST_ASSERT_VAL("failed to merge map: bad nr", perf_cpu_map__nr(a) == nr); + cpu_map__snprint(a, buf, sizeof(buf)); + TEST_ASSERT_VAL("failed to merge map: bad result", !strcmp(buf, expected)); perf_cpu_map__put(b); - perf_cpu_map__put(c); + + /* + * If 'b' is a superset of 'a', 'a' points to the same map with the + * map 'b'. In this case, the owner 'b' has released the resource above + * but 'a' still keeps the ownership, the reference counter should be 1. + */ + TEST_ASSERT_VAL("unexpected refcnt: bad result", + refcount_read(perf_cpu_map__refcnt(a)) == 1); + + perf_cpu_map__put(a); return 0; } +static int test__cpu_map_merge(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + int ret; + + ret = __test__cpu_map_merge("4,2,1", "4,5,7", 5, "1-2,4-5,7"); + if (ret) + return ret; + ret = __test__cpu_map_merge("1-8", "6-9", 9, "1-9"); + if (ret) + return ret; + ret = __test__cpu_map_merge("1-8,12-20", "6-9,15", 18, "1-9,12-20"); + if (ret) + return ret; + ret = __test__cpu_map_merge("4,2,1", "1", 3, "1-2,4"); + if (ret) + return ret; + ret = __test__cpu_map_merge("1", "4,2,1", 3, "1-2,4"); + if (ret) + return ret; + ret = __test__cpu_map_merge("1", "1", 1, "1"); + return ret; +} + static int __test__cpu_map_intersect(const char *lhs, const char *rhs, int nr, const char *expected) { struct perf_cpu_map *a = perf_cpu_map__new(lhs); @@ -219,30 +252,29 @@ static int test__cpu_map_equal(struct test_suite *test __maybe_unused, int subte struct perf_cpu_map *empty = perf_cpu_map__intersect(one, two); struct perf_cpu_map *pair = perf_cpu_map__new("1-2"); struct perf_cpu_map *tmp; - struct perf_cpu_map *maps[] = {empty, any, one, two, pair}; + struct perf_cpu_map **maps[] = {&empty, &any, &one, &two, &pair}; for (size_t i = 0; i < ARRAY_SIZE(maps); i++) { /* Maps equal themself. */ - TEST_ASSERT_VAL("equal", perf_cpu_map__equal(maps[i], maps[i])); + TEST_ASSERT_VAL("equal", perf_cpu_map__equal(*maps[i], *maps[i])); for (size_t j = 0; j < ARRAY_SIZE(maps); j++) { /* Maps dont't equal each other. */ if (i == j) continue; - TEST_ASSERT_VAL("not equal", !perf_cpu_map__equal(maps[i], maps[j])); + TEST_ASSERT_VAL("not equal", !perf_cpu_map__equal(*maps[i], *maps[j])); } } /* Maps equal made maps. */ - tmp = perf_cpu_map__merge(perf_cpu_map__get(one), two); - TEST_ASSERT_VAL("pair", perf_cpu_map__equal(pair, tmp)); - perf_cpu_map__put(tmp); + perf_cpu_map__merge(&two, one); + TEST_ASSERT_VAL("pair", perf_cpu_map__equal(pair, two)); tmp = perf_cpu_map__intersect(pair, one); TEST_ASSERT_VAL("one", perf_cpu_map__equal(one, tmp)); perf_cpu_map__put(tmp); for (size_t i = 0; i < ARRAY_SIZE(maps); i++) - perf_cpu_map__put(maps[i]); + perf_cpu_map__put(*maps[i]); return TEST_OK; } diff --git a/tools/perf/tests/demangle-java-test.c b/tools/perf/tests/demangle-java-test.c index 44d1be303b67..0fb3e5a4a0ed 100644 --- a/tools/perf/tests/demangle-java-test.c +++ b/tools/perf/tests/demangle-java-test.c @@ -2,10 +2,10 @@ #include <string.h> #include <stdlib.h> #include <stdio.h> -#include "tests.h" -#include "session.h" +#include <linux/kernel.h> #include "debug.h" -#include "demangle-java.h" +#include "symbol.h" +#include "tests.h" static int test__demangle_java(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { @@ -17,19 +17,24 @@ static int test__demangle_java(struct test_suite *test __maybe_unused, int subte const char *mangled, *demangled; } test_cases[] = { { "Ljava/lang/StringLatin1;equals([B[B)Z", - "boolean java.lang.StringLatin1.equals(byte[], byte[])" }, + "java.lang.StringLatin1.equals(byte[], byte[])" }, { "Ljava/util/zip/ZipUtils;CENSIZ([BI)J", - "long java.util.zip.ZipUtils.CENSIZ(byte[], int)" }, + "java.util.zip.ZipUtils.CENSIZ(byte[], int)" }, { "Ljava/util/regex/Pattern$BmpCharProperty;match(Ljava/util/regex/Matcher;ILjava/lang/CharSequence;)Z", - "boolean java.util.regex.Pattern$BmpCharProperty.match(java.util.regex.Matcher, int, java.lang.CharSequence)" }, + "java.util.regex.Pattern$BmpCharProperty.match(java.util.regex.Matcher, int, java.lang.CharSequence)" }, { "Ljava/lang/AbstractStringBuilder;appendChars(Ljava/lang/String;II)V", - "void java.lang.AbstractStringBuilder.appendChars(java.lang.String, int, int)" }, + "java.lang.AbstractStringBuilder.appendChars(java.lang.String, int, int)" }, { "Ljava/lang/Object;<init>()V", - "void java.lang.Object<init>()" }, + "java.lang.Object<init>()" }, }; - for (i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]); i++) { - buf = java_demangle_sym(test_cases[i].mangled, 0); + for (i = 0; i < ARRAY_SIZE(test_cases); i++) { + buf = dso__demangle_sym(/*dso=*/NULL, /*kmodule=*/0, test_cases[i].mangled); + if (!buf) { + pr_debug("FAILED to demangle: \"%s\"\n \"%s\"\n", test_cases[i].mangled, + test_cases[i].demangled); + continue; + } if (strcmp(buf, test_cases[i].demangled)) { pr_debug("FAILED: %s: %s != %s\n", test_cases[i].mangled, buf, test_cases[i].demangled); diff --git a/tools/perf/tests/demangle-ocaml-test.c b/tools/perf/tests/demangle-ocaml-test.c index 90a4285e2ad5..612c788b7e0d 100644 --- a/tools/perf/tests/demangle-ocaml-test.c +++ b/tools/perf/tests/demangle-ocaml-test.c @@ -2,10 +2,9 @@ #include <string.h> #include <stdlib.h> #include <stdio.h> -#include "tests.h" -#include "session.h" #include "debug.h" -#include "demangle-ocaml.h" +#include "symbol.h" +#include "tests.h" static int test__demangle_ocaml(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { @@ -27,7 +26,7 @@ static int test__demangle_ocaml(struct test_suite *test __maybe_unused, int subt }; for (i = 0; i < ARRAY_SIZE(test_cases); i++) { - buf = ocaml_demangle_sym(test_cases[i].mangled); + buf = dso__demangle_sym(/*dso=*/NULL, /*kmodule=*/0, test_cases[i].mangled); if ((buf == NULL && test_cases[i].demangled != NULL) || (buf != NULL && test_cases[i].demangled == NULL) || (buf != NULL && strcmp(buf, test_cases[i].demangled))) { diff --git a/tools/perf/tests/demangle-rust-v0-test.c b/tools/perf/tests/demangle-rust-v0-test.c new file mode 100644 index 000000000000..904f966c65d7 --- /dev/null +++ b/tools/perf/tests/demangle-rust-v0-test.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT +#include "tests.h" +#include "debug.h" +#include "symbol.h" +#include <linux/kernel.h> +#include <stdlib.h> +#include <string.h> + +static int test__demangle_rust(struct test_suite *test __maybe_unused, int subtest __maybe_unused) +{ + int ret = TEST_OK; + char *buf = NULL; + size_t i; + + struct { + const char *mangled, *demangled; + } test_cases[] = { + { "_RNvMsr_NtCs3ssYzQotkvD_3std4pathNtB5_7PathBuf3newCs15kBYyAo9fc_7mycrate", + "<std::path::PathBuf>::new" }, + { "_RNvCs15kBYyAo9fc_7mycrate7example", + "mycrate::example" }, + { "_RNvMs_Cs4Cv8Wi1oAIB_7mycrateNtB4_7Example3foo", + "<mycrate::Example>::foo" }, + { "_RNvXCs15kBYyAo9fc_7mycrateNtB2_7ExampleNtB2_5Trait3foo", + "<mycrate::Example as mycrate::Trait>::foo" }, + { "_RNvMCs7qp2U7fqm6G_7mycrateNtB2_7Example3foo", + "<mycrate::Example>::foo" }, + { "_RNvMs_Cs7qp2U7fqm6G_7mycrateNtB4_7Example3bar", + "<mycrate::Example>::bar" }, + { "_RNvYNtCs15kBYyAo9fc_7mycrate7ExampleNtB4_5Trait7exampleB4_", + "<mycrate::Example as mycrate::Trait>::example" }, + { "_RNCNvCsgStHSCytQ6I_7mycrate4main0B3_", + "mycrate::main::{closure#0}" }, + { "_RNCNvCsgStHSCytQ6I_7mycrate4mains_0B3_", + "mycrate::main::{closure#1}" }, + { "_RINvCsgStHSCytQ6I_7mycrate7examplelKj1_EB2_", + "mycrate::example::<i32, 1>" }, + { "_RINvCs7qp2U7fqm6G_7mycrate7exampleFG0_RL1_hRL0_tEuEB2_", + "mycrate::example::<for<'a, 'b> fn(&'a u8, &'b u16)>", + }, + { "_RINvCs7qp2U7fqm6G_7mycrate7exampleKy12345678_EB2_", + "mycrate::example::<305419896>" }, + { "_RNvNvMCsd9PVOYlP1UU_7mycrateINtB4_7ExamplepKpE3foo14EXAMPLE_STATIC", + "<mycrate::Example<_, _>>::foo::EXAMPLE_STATIC", + }, + { "_RINvCs7qp2U7fqm6G_7mycrate7exampleAtj8_EB2_", + "mycrate::example::<[u16; 8]>" }, + { "_RINvCs7qp2U7fqm6G_7mycrate7exampleNtB2_7ExampleBw_EB2_", + "mycrate::example::<mycrate::Example, mycrate::Example>" }, + { "_RINvMsY_NtCseXNvpPnDBDp_3std4pathNtB6_4Path3neweECs7qp2U7fqm6G_7mycrate", + "<std::path::Path>::new::<str>" }, + { "_RNvNvNvCs7qp2U7fqm6G_7mycrate7EXAMPLE7___getit5___KEY", + "mycrate::EXAMPLE::__getit::__KEY" }, + }; + + for (i = 0; i < ARRAY_SIZE(test_cases); i++) { + buf = dso__demangle_sym(/*dso=*/NULL, /*kmodule=*/0, test_cases[i].mangled); + if (!buf) { + pr_debug("FAILED to demangle: \"%s\"\n \"%s\"\n", test_cases[i].mangled, + test_cases[i].demangled); + continue; + } + if (strcmp(buf, test_cases[i].demangled)) { + pr_debug("FAILED: %s: %s != %s\n", test_cases[i].mangled, + buf, test_cases[i].demangled); + ret = TEST_FAIL; + } + free(buf); + } + + return ret; +} + +DEFINE_SUITE("Demangle Rust", demangle_rust); diff --git a/tools/perf/tests/dlfilter-test.c b/tools/perf/tests/dlfilter-test.c index 54f59d1246bc..80a1c941138d 100644 --- a/tools/perf/tests/dlfilter-test.c +++ b/tools/perf/tests/dlfilter-test.c @@ -319,11 +319,12 @@ static int run_perf_script(struct test_data *td) static int test__dlfilter_test(struct test_data *td) { + struct perf_env host_env; u64 sample_type = TEST_SAMPLE_TYPE; pid_t pid = 12345; pid_t tid = 12346; u64 id = 99; - int err; + int err = TEST_OK; if (get_dlfilters_path(td->name, td->dlfilters, PATH_MAX)) return test_result("dlfilters not found", TEST_SKIP); @@ -352,38 +353,42 @@ static int test__dlfilter_test(struct test_data *td) return test_result("Failed to find program symbols", TEST_FAIL); pr_debug("Creating new host machine structure\n"); - td->machine = machine__new_host(); - td->machine->env = &perf_env; + perf_env__init(&host_env); + td->machine = machine__new_host(&host_env); td->fd = creat(td->perf_data_file_name, 0644); if (td->fd < 0) return test_result("Failed to create test perf.data file", TEST_FAIL); err = perf_header__write_pipe(td->fd); - if (err < 0) - return test_result("perf_header__write_pipe() failed", TEST_FAIL); - + if (err < 0) { + err = test_result("perf_header__write_pipe() failed", TEST_FAIL); + goto out; + } err = write_attr(td, sample_type, &id); - if (err) - return test_result("perf_event__synthesize_attr() failed", TEST_FAIL); - - if (write_comm(td->fd, pid, tid, "test-prog")) - return TEST_FAIL; - - if (write_mmap(td->fd, pid, tid, MAP_START, 0x10000, 0, td->prog_file_name)) - return TEST_FAIL; - - if (write_sample(td, sample_type, id, pid, tid) != TEST_OK) - return TEST_FAIL; - + if (err) { + err = test_result("perf_event__synthesize_attr() failed", TEST_FAIL); + goto out; + } + if (write_comm(td->fd, pid, tid, "test-prog")) { + err = TEST_FAIL; + goto out; + } + if (write_mmap(td->fd, pid, tid, MAP_START, 0x10000, 0, td->prog_file_name)) { + err = TEST_FAIL; + goto out; + } + if (write_sample(td, sample_type, id, pid, tid) != TEST_OK) { + err = TEST_FAIL; + goto out; + } if (verbose > 1) system_cmd("%s script -i %s -D", td->perf, td->perf_data_file_name); - err = run_perf_script(td); - if (err) - return TEST_FAIL; - - return TEST_OK; + err = run_perf_script(td) ? TEST_FAIL : TEST_OK; +out: + perf_env__exit(&host_env); + return err; } static void unlink_path(const char *path) diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 5286ae8bd2d7..a1fff4203b75 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c @@ -106,14 +106,25 @@ struct test_data_offset offsets[] = { /* move it from util/dso.c for compatibility */ static int dso__data_fd(struct dso *dso, struct machine *machine) { - int fd = dso__data_get_fd(dso, machine); + int fd = -1; - if (fd >= 0) + if (dso__data_get_fd(dso, machine, &fd)) dso__data_put_fd(dso); return fd; } +static void dsos__delete(struct dsos *dsos) +{ + for (unsigned int i = 0; i < dsos->cnt; i++) { + struct dso *dso = dsos->dsos[i]; + + dso__data_close(dso); + unlink(dso__name(dso)); + } + dsos__exit(dsos); +} + static int test__dso_data(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { struct machine machine; @@ -172,7 +183,7 @@ static int test__dso_data(struct test_suite *test __maybe_unused, int subtest __ } dso__put(dso); - dsos__exit(&machine.dsos); + dsos__delete(&machine.dsos); unlink(file); return 0; } @@ -222,17 +233,6 @@ static int dsos__create(int cnt, int size, struct dsos *dsos) return 0; } -static void dsos__delete(struct dsos *dsos) -{ - for (unsigned int i = 0; i < dsos->cnt; i++) { - struct dso *dso = dsos->dsos[i]; - - dso__data_close(dso); - unlink(dso__name(dso)); - } - dsos__exit(dsos); -} - static int set_fd_limit(int n) { struct rlimit rlim; diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c index f85d391ced98..9ed78d00fb87 100644 --- a/tools/perf/tests/dwarf-unwind.c +++ b/tools/perf/tests/dwarf-unwind.c @@ -7,6 +7,7 @@ #include <unistd.h> #include "tests.h" #include "debug.h" +#include "env.h" #include "machine.h" #include "event.h" #include "../util/unwind.h" @@ -15,7 +16,6 @@ #include "symbol.h" #include "thread.h" #include "callchain.h" -#include "util/synthetic-events.h" /* For bsearch. We try to unwind functions in shared object. */ #include <stdlib.h> @@ -37,24 +37,6 @@ #define NO_TAIL_CALL_BARRIER __asm__ __volatile__("" : : : "memory"); #endif -static int mmap_handler(const struct perf_tool *tool __maybe_unused, - union perf_event *event, - struct perf_sample *sample, - struct machine *machine) -{ - return machine__process_mmap2_event(machine, event, sample); -} - -static int init_live_machine(struct machine *machine) -{ - union perf_event event; - pid_t pid = getpid(); - - memset(&event, 0, sizeof(event)); - return perf_event__synthesize_mmap_events(NULL, &event, pid, pid, - mmap_handler, machine, true); -} - /* * We need to keep these functions global, despite the * fact that they are used only locally in this object, @@ -115,8 +97,7 @@ NO_TAIL_CALL_ATTRIBUTE noinline int test_dwarf_unwind__thread(struct thread *thr unsigned long cnt = 0; int err = -1; - memset(&sample, 0, sizeof(sample)); - + perf_sample__init(&sample, /*all=*/true); if (test__arch_unwind_sample(&sample, thread)) { pr_debug("failed to get unwind sample\n"); goto out; @@ -134,7 +115,8 @@ NO_TAIL_CALL_ATTRIBUTE noinline int test_dwarf_unwind__thread(struct thread *thr out: zfree(&sample.user_stack.data); - zfree(&sample.user_regs.regs); + zfree(&sample.user_regs->regs); + perf_sample__exit(&sample); return err; } @@ -199,33 +181,31 @@ NO_TAIL_CALL_ATTRIBUTE noinline int test_dwarf_unwind__krava_1(struct thread *th noinline int test__dwarf_unwind(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { + struct perf_env host_env; struct machine *machine; struct thread *thread; int err = -1; + pid_t pid = getpid(); - machine = machine__new_host(); + callchain_param.record_mode = CALLCHAIN_DWARF; + dwarf_callchain_users = true; + + perf_env__init(&host_env); + machine = machine__new_live(&host_env, /*kernel_maps=*/true, pid); if (!machine) { pr_err("Could not get machine\n"); - return -1; + goto out; } if (machine__create_kernel_maps(machine)) { pr_err("Failed to create kernel maps\n"); - return -1; - } - - callchain_param.record_mode = CALLCHAIN_DWARF; - dwarf_callchain_users = true; - - if (init_live_machine(machine)) { - pr_err("Could not init machine\n"); goto out; } if (verbose > 1) machine__fprintf(machine, stderr); - thread = machine__find_thread(machine, getpid(), getpid()); + thread = machine__find_thread(machine, pid, pid); if (!thread) { pr_err("Could not get thread\n"); goto out; @@ -236,6 +216,7 @@ noinline int test__dwarf_unwind(struct test_suite *test __maybe_unused, out: machine__delete(machine); + perf_env__exit(&host_env); return err; } diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c index e155f0e0e04d..ae3b98bb42cf 100644 --- a/tools/perf/tests/event-times.c +++ b/tools/perf/tests/event-times.c @@ -17,9 +17,7 @@ static int attach__enable_on_exec(struct evlist *evlist) { struct evsel *evsel = evlist__last(evlist); - struct target target = { - .uid = UINT_MAX, - }; + struct target target = {}; const char *argv[] = { "true", NULL, }; char sbuf[STRERR_BUFSIZE]; int err; @@ -64,7 +62,7 @@ static int attach__current_disabled(struct evlist *evlist) pr_debug("attaching to current thread as disabled\n"); - threads = thread_map__new(-1, getpid(), UINT_MAX); + threads = thread_map__new_by_tid(getpid()); if (threads == NULL) { pr_debug("thread_map__new\n"); return -1; @@ -90,7 +88,7 @@ static int attach__current_enabled(struct evlist *evlist) pr_debug("attaching to current thread as enabled\n"); - threads = thread_map__new(-1, getpid(), UINT_MAX); + threads = thread_map__new_by_tid(getpid()); if (threads == NULL) { pr_debug("failed to call thread_map__new\n"); return -1; @@ -126,6 +124,7 @@ static int attach__cpu_disabled(struct evlist *evlist) evsel->core.attr.disabled = 1; err = evsel__open_per_cpu(evsel, cpus, -1); + perf_cpu_map__put(cpus); if (err) { if (err == -EACCES) return TEST_SKIP; @@ -134,7 +133,6 @@ static int attach__cpu_disabled(struct evlist *evlist) return err; } - perf_cpu_map__put(cpus); return evsel__enable(evsel); } @@ -153,10 +151,10 @@ static int attach__cpu_enabled(struct evlist *evlist) } err = evsel__open_per_cpu(evsel, cpus, -1); + perf_cpu_map__put(cpus); if (err == -EACCES) return TEST_SKIP; - perf_cpu_map__put(cpus); return err ? TEST_FAIL : TEST_OK; } @@ -188,6 +186,7 @@ static int test_times(int (attach)(struct evlist *), err = attach(evlist); if (err == TEST_SKIP) { pr_debug(" SKIP : not enough rights\n"); + evlist__delete(evlist); return err; } diff --git a/tools/perf/tests/event_groups.c b/tools/perf/tests/event_groups.c index ccd9d8b2903f..c119ff114948 100644 --- a/tools/perf/tests/event_groups.c +++ b/tools/perf/tests/event_groups.c @@ -10,9 +10,10 @@ #include "header.h" #include "../perf-sys.h" -/* hw: cycles, sw: context-switch, uncore: [arch dependent] */ +/* hw: cycles,instructions sw: context-switch, uncore: [arch dependent] */ static int types[] = {0, 1, -1}; static unsigned long configs[] = {0, 3, 0}; +static unsigned long configs_hw[] = {1}; #define NR_UNCORE_PMUS 5 @@ -93,7 +94,18 @@ static int run_test(int i, int j, int k) return erroneous ? 0 : -1; } - sibling_fd2 = event_open(types[k], configs[k], group_fd); + /* + * if all three events (leader and two sibling events) + * are hardware events, use instructions as one of the + * sibling event. There is event constraint in powerpc that + * events using same counter cannot be programmed in a group. + * Since PERF_COUNT_HW_INSTRUCTIONS is a generic hardware + * event and present in all platforms, lets use that. + */ + if (!i && !j && !k) + sibling_fd2 = event_open(types[k], configs_hw[k], group_fd); + else + sibling_fd2 = event_open(types[k], configs[k], group_fd); if (sibling_fd2 == -1) { close(sibling_fd1); close(group_fd); @@ -124,9 +136,18 @@ static int test__event_groups(struct test_suite *text __maybe_unused, int subtes if (r) ret = TEST_FAIL; - pr_debug("0x%x 0x%lx, 0x%x 0x%lx, 0x%x 0x%lx: %s\n", - types[i], configs[i], types[j], configs[j], - types[k], configs[k], r ? "Fail" : "Pass"); + /* + * For all three events as HW events, second sibling + * event is picked from configs_hw. So print accordingly + */ + if (!i && !j && !k) + pr_debug("0x%x 0x%lx, 0x%x 0x%lx, 0x%x 0x%lx: %s\n", + types[i], configs[i], types[j], configs[j], + types[k], configs_hw[k], r ? "Fail" : "Pass"); + else + pr_debug("0x%x 0x%lx, 0x%x 0x%lx, 0x%x 0x%lx: %s\n", + types[i], configs[i], types[j], configs[j], + types[k], configs[k], r ? "Fail" : "Pass"); } } } diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index d6b4ce3ef4ee..cb9e6de2e033 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c @@ -109,7 +109,8 @@ static int test__event_update(struct test_suite *test __maybe_unused, int subtes TEST_ASSERT_VAL("failed to synthesize attr update name", !perf_event__synthesize_event_update_name(&tmp.tool, evsel, process_event_name)); - evsel->core.own_cpus = perf_cpu_map__new("1,2,3"); + perf_cpu_map__put(evsel->core.pmu_cpus); + evsel->core.pmu_cpus = perf_cpu_map__new("1,2,3"); TEST_ASSERT_VAL("failed to synthesize attr update cpus", !perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus)); diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c index cf4da3d748c2..226196fb9677 100644 --- a/tools/perf/tests/evsel-tp-sched.c +++ b/tools/perf/tests/evsel-tp-sched.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/err.h> -#include <traceevent/event-parse.h> +#include <event-parse.h> #include "evsel.h" #include "tests.h" #include "debug.h" @@ -36,33 +36,33 @@ static int test__perf_evsel__tp_sched_test(struct test_suite *test __maybe_unuse int subtest __maybe_unused) { struct evsel *evsel = evsel__newtp("sched", "sched_switch"); - int ret = 0; + int ret = TEST_OK; if (IS_ERR(evsel)) { pr_debug("evsel__newtp failed with %ld\n", PTR_ERR(evsel)); - return -1; + return PTR_ERR(evsel) == -EACCES ? TEST_SKIP : TEST_FAIL; } if (evsel__test_field(evsel, "prev_comm", 16, false)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "prev_pid", 4, true)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "prev_prio", 4, true)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "prev_state", sizeof(long), true)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "next_comm", 16, false)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "next_pid", 4, true)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "next_prio", 4, true)) - ret = -1; + ret = TEST_FAIL; evsel__delete(evsel); @@ -70,23 +70,33 @@ static int test__perf_evsel__tp_sched_test(struct test_suite *test __maybe_unuse if (IS_ERR(evsel)) { pr_debug("evsel__newtp failed with %ld\n", PTR_ERR(evsel)); - return -1; + return TEST_FAIL; } if (evsel__test_field(evsel, "comm", 16, false)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "pid", 4, true)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "prio", 4, true)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "target_cpu", 4, true)) - ret = -1; + ret = TEST_FAIL; evsel__delete(evsel); return ret; } -DEFINE_SUITE("Parse sched tracepoints fields", perf_evsel__tp_sched_test); +static struct test_case tests__perf_evsel__tp_sched_test[] = { + TEST_CASE_REASON("Parse sched tracepoints fields", + perf_evsel__tp_sched_test, + "permissions"), + { .name = NULL, } +}; + +struct test_suite suite__perf_evsel__tp_sched_test = { + .desc = "Parse sched tracepoints fields", + .test_cases = tests__perf_evsel__tp_sched_test, +}; diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c index 31966ff856f8..c7b32a220ca1 100644 --- a/tools/perf/tests/expand-cgroup.c +++ b/tools/perf/tests/expand-cgroup.c @@ -13,8 +13,7 @@ #include <stdlib.h> #include <string.h> -static int test_expand_events(struct evlist *evlist, - struct rblist *metric_events) +static int test_expand_events(struct evlist *evlist) { int i, ret = TEST_FAIL; int nr_events; @@ -47,7 +46,7 @@ static int test_expand_events(struct evlist *evlist, was_group_event = evsel__is_group_event(evlist__first(evlist)); nr_members = evlist__first(evlist)->core.nr_members; - ret = evlist__expand_cgroup(evlist, cgrp_str, metric_events, false); + ret = evlist__expand_cgroup(evlist, cgrp_str, false); if (ret < 0) { pr_debug("failed to expand events for cgroups\n"); goto out; @@ -100,13 +99,11 @@ out: for (i = 0; i < nr_events; i++) static int expand_default_events(void) { int ret; - struct rblist metric_events; struct evlist *evlist = evlist__new_default(); TEST_ASSERT_VAL("failed to get evlist", evlist); - rblist__init(&metric_events); - ret = test_expand_events(evlist, &metric_events); + ret = test_expand_events(evlist); evlist__delete(evlist); return ret; } @@ -115,7 +112,6 @@ static int expand_group_events(void) { int ret; struct evlist *evlist; - struct rblist metric_events; struct parse_events_error err; const char event_str[] = "{cycles,instructions}"; @@ -132,8 +128,7 @@ static int expand_group_events(void) goto out; } - rblist__init(&metric_events); - ret = test_expand_events(evlist, &metric_events); + ret = test_expand_events(evlist); out: parse_events_error__exit(&err); evlist__delete(evlist); @@ -144,7 +139,6 @@ static int expand_libpfm_events(void) { int ret; struct evlist *evlist; - struct rblist metric_events; const char event_str[] = "CYCLES"; struct option opt = { .value = &evlist, @@ -166,8 +160,7 @@ static int expand_libpfm_events(void) goto out; } - rblist__init(&metric_events); - ret = test_expand_events(evlist, &metric_events); + ret = test_expand_events(evlist); out: evlist__delete(evlist); return ret; @@ -177,25 +170,22 @@ static int expand_metric_events(void) { int ret; struct evlist *evlist; - struct rblist metric_events; const char metric_str[] = "CPI"; const struct pmu_metrics_table *pme_test; evlist = evlist__new(); TEST_ASSERT_VAL("failed to get evlist", evlist); - rblist__init(&metric_events); pme_test = find_core_metrics_table("testarch", "testcpu"); - ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str, &metric_events); + ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str); if (ret < 0) { pr_debug("failed to parse '%s' metric\n", metric_str); goto out; } - ret = test_expand_events(evlist, &metric_events); + ret = test_expand_events(evlist); out: - metricgroup__rblist_exit(&metric_events); evlist__delete(evlist); return ret; } diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c index e3aa9d4fcf3a..726cf8d4da28 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -6,6 +6,7 @@ #include "util/header.h" #include "util/smt.h" #include "tests.h" +#include <perf/cpumap.h> #include <math.h> #include <stdlib.h> #include <string.h> @@ -74,14 +75,12 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u double val, num_cpus_online, num_cpus, num_cores, num_dies, num_packages; int ret; struct expr_parse_ctx *ctx; - bool is_intel = false; char strcmp_cpuid_buf[256]; - struct perf_pmu *pmu = perf_pmus__find_core_pmu(); - char *cpuid = perf_pmu__getcpuid(pmu); + struct perf_cpu cpu = {-1}; + char *cpuid = get_cpuid_allow_env_override(cpu); char *escaped_cpuid1, *escaped_cpuid2; TEST_ASSERT_VAL("get_cpuid", cpuid); - is_intel = strstr(cpuid, "Intel") != NULL; TEST_ASSERT_EQUAL("ids_union", test_ids_union(), 0); @@ -244,12 +243,19 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u if (num_dies) // Some platforms do not have CPU die support, for example s390 TEST_ASSERT_VAL("#num_dies >= #num_packages", num_dies >= num_packages); - TEST_ASSERT_VAL("#system_tsc_freq", expr__parse(&val, ctx, "#system_tsc_freq") == 0); - if (is_intel) - TEST_ASSERT_VAL("#system_tsc_freq > 0", val > 0); - else - TEST_ASSERT_VAL("#system_tsc_freq == 0", fpclassify(val) == FP_ZERO); + if (expr__parse(&val, ctx, "#system_tsc_freq") == 0) { + bool is_intel = strstr(cpuid, "Intel") != NULL; + + if (is_intel) + TEST_ASSERT_VAL("#system_tsc_freq > 0", val > 0); + else + TEST_ASSERT_VAL("#system_tsc_freq == 0", fpclassify(val) == FP_ZERO); + } else { +#if defined(__i386__) || defined(__x86_64__) + TEST_ASSERT_VAL("#system_tsc_freq unsupported", 0); +#endif + } /* * Source count returns the number of events aggregating in a leader * event including the leader. Check parsing yields an id. diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index 1e0f5a310fd5..3eb9ef8d7ec6 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c @@ -295,7 +295,7 @@ static int test1(struct evsel *evsel, struct machine *machine) symbol_conf.cumulate_callchain = false; evsel__reset_sample_bit(evsel, CALLCHAIN); - setup_sorting(NULL); + setup_sorting(/*evlist=*/NULL, machine->env); callchain_register_param(&callchain_param); err = add_hist_entries(hists, machine); @@ -442,7 +442,7 @@ static int test2(struct evsel *evsel, struct machine *machine) symbol_conf.cumulate_callchain = false; evsel__set_sample_bit(evsel, CALLCHAIN); - setup_sorting(NULL); + setup_sorting(/*evlist=*/NULL, machine->env); callchain_register_param(&callchain_param); err = add_hist_entries(hists, machine); @@ -500,7 +500,7 @@ static int test3(struct evsel *evsel, struct machine *machine) symbol_conf.cumulate_callchain = true; evsel__reset_sample_bit(evsel, CALLCHAIN); - setup_sorting(NULL); + setup_sorting(/*evlist=*/NULL, machine->env); callchain_register_param(&callchain_param); err = add_hist_entries(hists, machine); @@ -684,7 +684,7 @@ static int test4(struct evsel *evsel, struct machine *machine) symbol_conf.cumulate_callchain = true; evsel__set_sample_bit(evsel, CALLCHAIN); - setup_sorting(NULL); + setup_sorting(/*evlist=*/NULL, machine->env); callchain_param = callchain_param_default; callchain_register_param(&callchain_param); diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index 4b2e4f2fbe48..1cebd20cc91c 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c @@ -131,10 +131,6 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes goto out; err = TEST_FAIL; - /* default sort order (comm,dso,sym) will be used */ - if (setup_sorting(NULL) < 0) - goto out; - machines__init(&machines); /* setup threads/dso/map/symbols also */ @@ -145,6 +141,10 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes if (verbose > 1) machine__fprintf(machine, stderr); + /* default sort order (comm,dso,sym) will be used */ + if (setup_sorting(evlist, machine->env) < 0) + goto out; + /* process sample events */ err = add_hist_entries(evlist, machine); if (err < 0) diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 5b6f1e883466..996f5f0b3bd1 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -303,10 +303,6 @@ static int test__hists_link(struct test_suite *test __maybe_unused, int subtest goto out; err = TEST_FAIL; - /* default sort order (comm,dso,sym) will be used */ - if (setup_sorting(NULL) < 0) - goto out; - machines__init(&machines); /* setup threads/dso/map/symbols also */ @@ -317,6 +313,10 @@ static int test__hists_link(struct test_suite *test __maybe_unused, int subtest if (verbose > 1) machine__fprintf(machine, stderr); + /* default sort order (comm,dso,sym) will be used */ + if (setup_sorting(evlist, machine->env) < 0) + goto out; + /* process sample events */ err = add_hist_entries(evlist, machine); if (err < 0) diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index 33b5cc8352a7..ee5ec8bda60e 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c @@ -146,7 +146,7 @@ static int test1(struct evsel *evsel, struct machine *machine) field_order = NULL; sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */ - setup_sorting(NULL); + setup_sorting(/*evlist=*/NULL, machine->env); /* * expected output: @@ -248,7 +248,7 @@ static int test2(struct evsel *evsel, struct machine *machine) field_order = "overhead,cpu"; sort_order = "pid"; - setup_sorting(NULL); + setup_sorting(/*evlist=*/NULL, machine->env); /* * expected output: @@ -304,7 +304,7 @@ static int test3(struct evsel *evsel, struct machine *machine) field_order = "comm,overhead,dso"; sort_order = NULL; - setup_sorting(NULL); + setup_sorting(/*evlist=*/NULL, machine->env); /* * expected output: @@ -378,7 +378,7 @@ static int test4(struct evsel *evsel, struct machine *machine) field_order = "dso,sym,comm,overhead,dso"; sort_order = "sym"; - setup_sorting(NULL); + setup_sorting(/*evlist=*/NULL, machine->env); /* * expected output: @@ -480,7 +480,7 @@ static int test5(struct evsel *evsel, struct machine *machine) field_order = "cpu,pid,comm,dso,sym"; sort_order = "dso,pid"; - setup_sorting(NULL); + setup_sorting(/*evlist=*/NULL, machine->env); /* * expected output: diff --git a/tools/perf/tests/hwmon_pmu.c b/tools/perf/tests/hwmon_pmu.c new file mode 100644 index 000000000000..4aa4aac94f09 --- /dev/null +++ b/tools/perf/tests/hwmon_pmu.c @@ -0,0 +1,357 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +#include "debug.h" +#include "evlist.h" +#include "hwmon_pmu.h" +#include "parse-events.h" +#include "tests.h" +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <linux/compiler.h> +#include <linux/kernel.h> +#include <linux/string.h> + +static const struct test_event { + const char *name; + const char *alias; + union hwmon_pmu_event_key key; +} test_events[] = { + { + "temp_test_hwmon_event1", + "temp1", + .key = { + .num = 1, + .type = 10 + }, + }, + { + "temp_test_hwmon_event2", + "temp2", + .key = { + .num = 2, + .type = 10 + }, + }, +}; + +/* Cleanup test PMU directory. */ +static int test_pmu_put(const char *dir, struct perf_pmu *hwm) +{ + char buf[PATH_MAX + 20]; + int ret; + + if (scnprintf(buf, sizeof(buf), "rm -fr %s", dir) < 0) { + pr_err("Failure to set up buffer for \"%s\"\n", dir); + return -EINVAL; + } + ret = system(buf); + if (ret) + pr_err("Failure to \"%s\"\n", buf); + + list_del(&hwm->list); + perf_pmu__delete(hwm); + return ret; +} + +/* + * Prepare test PMU directory data, normally exported by kernel at + * /sys/class/hwmon/hwmon<number>/. Give as input a buffer to hold the file + * path, the result is PMU loaded using that directory. + */ +static struct perf_pmu *test_pmu_get(char *dir, size_t sz) +{ + const char *test_hwmon_name_nl = "A test hwmon PMU\n"; + const char *test_hwmon_name = "A test hwmon PMU"; + /* Simulated hwmon items. */ + const struct test_item { + const char *name; + const char *value; + } test_items[] = { + { "temp1_label", "test hwmon event1\n", }, + { "temp1_input", "40000\n", }, + { "temp2_label", "test hwmon event2\n", }, + { "temp2_input", "50000\n", }, + }; + int hwmon_dirfd = -1, test_dirfd = -1, file; + struct perf_pmu *hwm = NULL; + ssize_t len; + + /* Create equivalent of sysfs mount point. */ + scnprintf(dir, sz, "/tmp/perf-hwmon-pmu-test-XXXXXX"); + if (!mkdtemp(dir)) { + pr_err("mkdtemp failed\n"); + dir[0] = '\0'; + return NULL; + } + test_dirfd = open(dir, O_PATH|O_DIRECTORY); + if (test_dirfd < 0) { + pr_err("Failed to open test directory \"%s\"\n", dir); + goto err_out; + } + + /* Create the test hwmon directory and give it a name. */ + if (mkdirat(test_dirfd, "hwmon1234", 0755) < 0) { + pr_err("Failed to mkdir hwmon directory\n"); + goto err_out; + } + strncat(dir, "/hwmon1234", sz - strlen(dir)); + hwmon_dirfd = open(dir, O_PATH|O_DIRECTORY); + if (hwmon_dirfd < 0) { + pr_err("Failed to open test hwmon directory \"%s\"\n", dir); + goto err_out; + } + file = openat(hwmon_dirfd, "name", O_WRONLY | O_CREAT, 0600); + if (file < 0) { + pr_err("Failed to open for writing file \"name\"\n"); + goto err_out; + } + len = strlen(test_hwmon_name_nl); + if (write(file, test_hwmon_name_nl, len) < len) { + close(file); + pr_err("Failed to write to 'name' file\n"); + goto err_out; + } + close(file); + + /* Create test hwmon files. */ + for (size_t i = 0; i < ARRAY_SIZE(test_items); i++) { + const struct test_item *item = &test_items[i]; + + file = openat(hwmon_dirfd, item->name, O_WRONLY | O_CREAT, 0600); + if (file < 0) { + pr_err("Failed to open for writing file \"%s\"\n", item->name); + goto err_out; + } + + if (write(file, item->value, strlen(item->value)) < 0) { + pr_err("Failed to write to file \"%s\"\n", item->name); + close(file); + goto err_out; + } + close(file); + } + + /* Make the PMU reading the files created above. */ + hwm = perf_pmus__add_test_hwmon_pmu(dir, "hwmon1234", test_hwmon_name); + if (!hwm) + pr_err("Test hwmon creation failed\n"); + +err_out: + if (!hwm) { + test_pmu_put(dir, hwm); + } + if (test_dirfd >= 0) + close(test_dirfd); + if (hwmon_dirfd >= 0) + close(hwmon_dirfd); + return hwm; +} + +static int do_test(size_t i, bool with_pmu, bool with_alias) +{ + const char *test_event = with_alias ? test_events[i].alias : test_events[i].name; + struct evlist *evlist = evlist__new(); + struct evsel *evsel; + struct parse_events_error err; + int ret; + char str[128]; + bool found = false; + + if (!evlist) { + pr_err("evlist allocation failed\n"); + return TEST_FAIL; + } + + if (with_pmu) + snprintf(str, sizeof(str), "hwmon_a_test_hwmon_pmu/%s/", test_event); + else + strlcpy(str, test_event, sizeof(str)); + + pr_debug("Testing '%s'\n", str); + parse_events_error__init(&err); + ret = parse_events(evlist, str, &err); + if (ret) { + pr_debug("FAILED %s:%d failed to parse event '%s', err %d\n", + __FILE__, __LINE__, str, ret); + parse_events_error__print(&err, str); + ret = TEST_FAIL; + goto out; + } + + ret = TEST_OK; + if (with_pmu ? (evlist->core.nr_entries != 1) : (evlist->core.nr_entries < 1)) { + pr_debug("FAILED %s:%d Unexpected number of events for '%s' of %d\n", + __FILE__, __LINE__, str, evlist->core.nr_entries); + ret = TEST_FAIL; + goto out; + } + + evlist__for_each_entry(evlist, evsel) { + if (!evsel->pmu || !evsel->pmu->name || + strcmp(evsel->pmu->name, "hwmon_a_test_hwmon_pmu")) + continue; + + if (evsel->core.attr.config != (u64)test_events[i].key.type_and_num) { + pr_debug("FAILED %s:%d Unexpected config for '%s', %lld != %ld\n", + __FILE__, __LINE__, str, + evsel->core.attr.config, + test_events[i].key.type_and_num); + ret = TEST_FAIL; + goto out; + } + found = true; + } + + if (!found) { + pr_debug("FAILED %s:%d Didn't find hwmon event '%s' in parsed evsels\n", + __FILE__, __LINE__, str); + ret = TEST_FAIL; + } + +out: + parse_events_error__exit(&err); + evlist__delete(evlist); + return ret; +} + +static int test__hwmon_pmu(bool with_pmu) +{ + char dir[PATH_MAX]; + struct perf_pmu *pmu = test_pmu_get(dir, sizeof(dir)); + int ret = TEST_OK; + + if (!pmu) + return TEST_FAIL; + + for (size_t i = 0; i < ARRAY_SIZE(test_events); i++) { + ret = do_test(i, with_pmu, /*with_alias=*/false); + + if (ret != TEST_OK) + break; + + ret = do_test(i, with_pmu, /*with_alias=*/true); + + if (ret != TEST_OK) + break; + } + test_pmu_put(dir, pmu); + return ret; +} + +static int test__hwmon_pmu_without_pmu(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + return test__hwmon_pmu(/*with_pmu=*/false); +} + +static int test__hwmon_pmu_with_pmu(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + return test__hwmon_pmu(/*with_pmu=*/true); +} + +static int test__parse_hwmon_filename(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + const struct hwmon_parse_test { + const char *filename; + enum hwmon_type type; + int number; + enum hwmon_item item; + bool alarm; + bool parse_ok; + } tests[] = { + { + .filename = "cpu0_accuracy", + .type = HWMON_TYPE_CPU, + .number = 0, + .item = HWMON_ITEM_ACCURACY, + .alarm = false, + .parse_ok = true, + }, + { + .filename = "temp1_input", + .type = HWMON_TYPE_TEMP, + .number = 1, + .item = HWMON_ITEM_INPUT, + .alarm = false, + .parse_ok = true, + }, + { + .filename = "fan2_vid", + .type = HWMON_TYPE_FAN, + .number = 2, + .item = HWMON_ITEM_VID, + .alarm = false, + .parse_ok = true, + }, + { + .filename = "power3_crit_alarm", + .type = HWMON_TYPE_POWER, + .number = 3, + .item = HWMON_ITEM_CRIT, + .alarm = true, + .parse_ok = true, + }, + { + .filename = "intrusion4_average_interval_min_alarm", + .type = HWMON_TYPE_INTRUSION, + .number = 4, + .item = HWMON_ITEM_AVERAGE_INTERVAL_MIN, + .alarm = true, + .parse_ok = true, + }, + { + .filename = "badtype5_baditem", + .type = HWMON_TYPE_NONE, + .number = 5, + .item = HWMON_ITEM_NONE, + .alarm = false, + .parse_ok = false, + }, + { + .filename = "humidity6_baditem", + .type = HWMON_TYPE_NONE, + .number = 6, + .item = HWMON_ITEM_NONE, + .alarm = false, + .parse_ok = false, + }, + }; + + for (size_t i = 0; i < ARRAY_SIZE(tests); i++) { + enum hwmon_type type; + int number; + enum hwmon_item item; + bool alarm; + + TEST_ASSERT_EQUAL("parse_hwmon_filename", + parse_hwmon_filename( + tests[i].filename, + &type, + &number, + &item, + &alarm), + tests[i].parse_ok + ); + if (tests[i].parse_ok) { + TEST_ASSERT_EQUAL("parse_hwmon_filename type", type, tests[i].type); + TEST_ASSERT_EQUAL("parse_hwmon_filename number", number, tests[i].number); + TEST_ASSERT_EQUAL("parse_hwmon_filename item", item, tests[i].item); + TEST_ASSERT_EQUAL("parse_hwmon_filename alarm", alarm, tests[i].alarm); + } + } + return TEST_OK; +} + +static struct test_case tests__hwmon_pmu[] = { + TEST_CASE("Basic parsing test", parse_hwmon_filename), + TEST_CASE("Parsing without PMU name", hwmon_pmu_without_pmu), + TEST_CASE("Parsing with PMU name", hwmon_pmu_with_pmu), + { .name = NULL, } +}; + +struct test_suite suite__hwmon_pmu = { + .desc = "Hwmon PMU", + .test_cases = tests__hwmon_pmu, +}; diff --git a/tools/perf/tests/kallsyms-split.c b/tools/perf/tests/kallsyms-split.c new file mode 100644 index 000000000000..bbbc66957e5d --- /dev/null +++ b/tools/perf/tests/kallsyms-split.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/compiler.h> +#include <fcntl.h> +#include <signal.h> +#include <unistd.h> +#include <sys/stat.h> +#include "util/dso.h" +#include "util/map.h" +#include "util/symbol.h" +#include "util/debug.h" +#include "util/machine.h" +#include "tests.h" + +/* + * This test is to check whether a bad symbol in a module won't split kallsyms maps. + * The main_symbol[1-3] should belong to the main [kernel.kallsyms] map even if the + * bad_symbol from the module is found in the middle. + */ +static char root_template[] = "/tmp/perf-test.XXXXXX"; +static char *root_dir; + +static const char proc_version[] = "Linux version X.Y.Z (just for perf test)\n"; +static const char proc_modules[] = "module 4096 1 - Live 0xffffffffcd000000\n"; +static const char proc_kallsyms[] = + "ffffffffab200000 T _stext\n" + "ffffffffab200010 T good_symbol\n" + "ffffffffab200020 t bad_symbol\n" + "ffffffffab200030 t main_symbol1\n" + "ffffffffab200040 t main_symbol2\n" + "ffffffffab200050 t main_symbol3\n" + "ffffffffab200060 T _etext\n" + "ffffffffcd000000 T start_module\t[module]\n" + "ffffffffab200020 u bad_symbol\t[module]\n" + "ffffffffcd000040 T end_module\t[module]\n"; + +static struct { + const char *name; + const char *contents; + long len; +} proc_files[] = { + { "version", proc_version, sizeof(proc_version) - 1 }, + { "modules", proc_modules, sizeof(proc_modules) - 1 }, + { "kallsyms", proc_kallsyms, sizeof(proc_kallsyms) - 1 }, +}; + +static void remove_proc_dir(int sig __maybe_unused) +{ + char buf[128]; + + if (root_dir == NULL) + return; + + for (unsigned i = 0; i < ARRAY_SIZE(proc_files); i++) { + scnprintf(buf, sizeof(buf), "%s/proc/%s", root_dir, proc_files[i].name); + remove(buf); + } + + scnprintf(buf, sizeof(buf), "%s/proc", root_dir); + rmdir(buf); + + rmdir(root_dir); + root_dir = NULL; +} + +static int create_proc_dir(void) +{ + char buf[128]; + + root_dir = mkdtemp(root_template); + if (root_dir == NULL) + return -1; + + scnprintf(buf, sizeof(buf), "%s/proc", root_dir); + if (mkdir(buf, 0700) < 0) + goto err; + + for (unsigned i = 0; i < ARRAY_SIZE(proc_files); i++) { + int fd, len; + + scnprintf(buf, sizeof(buf), "%s/proc/%s", root_dir, proc_files[i].name); + fd = open(buf, O_RDWR | O_CREAT, 0600); + if (fd < 0) + goto err; + + len = write(fd, proc_files[i].contents, proc_files[i].len); + close(fd); + if (len != proc_files[i].len) + goto err; + } + return 0; + +err: + remove_proc_dir(0); + return -1; +} + +static int test__kallsyms_split(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + struct machine m; + struct map *map = NULL; + int ret = TEST_FAIL; + + pr_debug("try to create fake root directory\n"); + if (create_proc_dir() < 0) { + pr_debug("SKIP: cannot create a fake root directory\n"); + return TEST_SKIP; + } + + signal(SIGINT, remove_proc_dir); + signal(SIGPIPE, remove_proc_dir); + signal(SIGSEGV, remove_proc_dir); + signal(SIGTERM, remove_proc_dir); + + pr_debug("create kernel maps from the fake root directory\n"); + machine__init(&m, root_dir, HOST_KERNEL_ID); + if (machine__create_kernel_maps(&m) < 0) { + pr_debug("FAIL: failed to create kernel maps\n"); + goto out; + } + + /* force to use /proc/kallsyms */ + symbol_conf.ignore_vmlinux = true; + symbol_conf.ignore_vmlinux_buildid = true; + symbol_conf.allow_aliases = true; + + if (map__load(machine__kernel_map(&m)) < 0) { + pr_debug("FAIL: failed to load kallsyms\n"); + goto out; + } + + pr_debug("kernel map loaded - check symbol and map\n"); + if (maps__nr_maps(machine__kernel_maps(&m)) != 2) { + pr_debug("FAIL: it should have the kernel and a module, but has %u maps\n", + maps__nr_maps(machine__kernel_maps(&m))); + goto out; + } + + if (machine__find_kernel_symbol_by_name(&m, "main_symbol3", &map) == NULL) { + pr_debug("FAIL: failed to find a symbol\n"); + goto out; + } + + if (!RC_CHK_EQUAL(map, machine__kernel_map(&m))) { + pr_debug("FAIL: the symbol is not in the kernel map\n"); + goto out; + } + ret = TEST_OK; + +out: + remove_proc_dir(0); + machine__exit(&m); + return ret; +} + +DEFINE_SUITE("split kallsyms", kallsyms_split); diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index 5a3b2bed07f3..729cc9cc1cb7 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c @@ -78,7 +78,7 @@ static int test__keep_tracking(struct test_suite *test __maybe_unused, int subte int found, err = -1; const char *comm; - threads = thread_map__new(-1, getpid(), UINT_MAX); + threads = thread_map__new_by_tid(getpid()); CHECK_NOT_NULL__(threads); cpus = perf_cpu_map__new_online_cpus(); @@ -90,7 +90,7 @@ static int test__keep_tracking(struct test_suite *test __maybe_unused, int subte perf_evlist__set_maps(&evlist->core, cpus, threads); CHECK__(parse_event(evlist, "dummy:u")); - CHECK__(parse_event(evlist, "cycles:u")); + CHECK__(parse_event(evlist, "cpu-cycles:u")); evlist__config(evlist, &opts, NULL); diff --git a/tools/perf/tests/make b/tools/perf/tests/make index a5040772043f..6641701e4828 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -73,31 +73,28 @@ make_extra_tests := EXTRA_TESTS=1 make_jevents_all := JEVENTS_ARCH=all make_no_bpf_skel := BUILD_BPF_SKEL=0 make_gen_vmlinux_h := GEN_VMLINUX_H=1 -make_no_libperl := NO_LIBPERL=1 +make_libperl := LIBPERL=1 make_no_libpython := NO_LIBPYTHON=1 -make_no_scripts := NO_LIBPYTHON=1 NO_LIBPERL=1 +make_no_scripts := NO_LIBPYTHON=1 make_no_slang := NO_SLANG=1 make_no_gtk2 := NO_GTK2=1 make_no_ui := NO_SLANG=1 NO_GTK2=1 make_no_demangle := NO_DEMANGLE=1 make_no_libelf := NO_LIBELF=1 -make_no_libunwind := NO_LIBUNWIND=1 +make_no_libdw := NO_LIBDW=1 +make_libunwind := LIBUNWIND=1 make_no_libdw_dwarf_unwind := NO_LIBDW_DWARF_UNWIND=1 make_no_backtrace := NO_BACKTRACE=1 make_no_libcapstone := NO_CAPSTONE=1 make_no_libnuma := NO_LIBNUMA=1 -make_no_libaudit := NO_LIBAUDIT=1 make_no_libbionic := NO_LIBBIONIC=1 -make_no_auxtrace := NO_AUXTRACE=1 make_no_libbpf := NO_LIBBPF=1 make_libbpf_dynamic := LIBBPF_DYNAMIC=1 make_no_libbpf_DEBUG := NO_LIBBPF=1 DEBUG=1 -make_no_libcrypto := NO_LIBCRYPTO=1 make_no_libllvm := NO_LIBLLVM=1 make_with_babeltrace:= LIBBABELTRACE=1 make_with_coresight := CORESIGHT=1 make_no_sdt := NO_SDT=1 -make_no_syscall_tbl := NO_SYSCALL_TABLE=1 make_no_libpfm4 := NO_LIBPFM4=1 make_with_gtk2 := GTK2=1 make_refcnt_check := EXTRA_CFLAGS="-DREFCNT_CHECKING=1" @@ -120,12 +117,12 @@ make_install_prefix_slash := install prefix=/tmp/krava/ make_static := LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX32=1 NO_JVMTI=1 NO_LIBTRACEEVENT=1 NO_LIBELF=1 # all the NO_* variable combined -make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_GTK2=1 -make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 -make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 -make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 -make_minimal += NO_LIBCRYPTO=1 NO_SDT=1 NO_JVMTI=1 NO_LIBZSTD=1 -make_minimal += NO_LIBCAP=1 NO_SYSCALL_TABLE=1 NO_CAPSTONE=1 +make_minimal := NO_LIBPYTHON=1 NO_GTK2=1 +make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_BACKTRACE=1 +make_minimal += NO_LIBNUMA=1 NO_LIBBIONIC=1 NO_LIBDW=1 +make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_LIBBPF=1 +make_minimal += NO_SDT=1 NO_JVMTI=1 NO_LIBZSTD=1 +make_minimal += NO_LIBCAP=1 NO_CAPSTONE=1 # $(run) contains all available tests run := make_pure @@ -145,7 +142,7 @@ run += make_extra_tests run += make_jevents_all run += make_no_bpf_skel run += make_gen_vmlinux_h -run += make_no_libperl +run += make_libperl run += make_no_libpython run += make_no_scripts run += make_no_slang @@ -153,17 +150,15 @@ run += make_no_gtk2 run += make_no_ui run += make_no_demangle run += make_no_libelf -run += make_no_libunwind +run += make_no_libdw +run += make_libunwind run += make_no_libdw_dwarf_unwind run += make_no_backtrace run += make_no_libcapstone run += make_no_libnuma -run += make_no_libaudit run += make_no_libbionic -run += make_no_auxtrace run += make_no_libbpf run += make_no_libbpf_DEBUG -run += make_no_libcrypto run += make_no_libllvm run += make_no_sdt run += make_no_syscall_tbl diff --git a/tools/perf/tests/maps.c b/tools/perf/tests/maps.c index 4f1f9385ea9c..2c05d62f40dc 100644 --- a/tools/perf/tests/maps.c +++ b/tools/perf/tests/maps.c @@ -162,4 +162,84 @@ static int test__maps__merge_in(struct test_suite *t __maybe_unused, int subtest return TEST_OK; } -DEFINE_SUITE("maps__merge_in", maps__merge_in); +static int test__maps__fixup_overlap_and_insert(struct test_suite *t __maybe_unused, + int subtest __maybe_unused) +{ + struct map_def initial_maps[] = { + { "target_map", 1000, 2000 }, + { "next_map", 3000, 4000 }, + }; + struct map_def insert_split = { "split_map", 1400, 1600 }; + struct map_def expected_after_split[] = { + { "target_map", 1000, 1400 }, + { "split_map", 1400, 1600 }, + { "target_map", 1600, 2000 }, + { "next_map", 3000, 4000 }, + }; + + struct map_def insert_eclipse = { "eclipse_map", 2500, 4500 }; + struct map_def expected_final[] = { + { "target_map", 1000, 1400 }, + { "split_map", 1400, 1600 }, + { "target_map", 1600, 2000 }, + { "eclipse_map", 2500, 4500 }, + /* "next_map" (3000-4000) is removed */ + }; + + struct map *map_split, *map_eclipse; + int ret; + unsigned int i; + struct maps *maps = maps__new(NULL); + + TEST_ASSERT_VAL("failed to create maps", maps); + + for (i = 0; i < ARRAY_SIZE(initial_maps); i++) { + struct map *map = dso__new_map(initial_maps[i].name); + + TEST_ASSERT_VAL("failed to create map", map); + map__set_start(map, initial_maps[i].start); + map__set_end(map, initial_maps[i].end); + TEST_ASSERT_VAL("failed to insert map", maps__insert(maps, map) == 0); + map__put(map); + } + + // Check splitting. + map_split = dso__new_map(insert_split.name); + TEST_ASSERT_VAL("failed to create split map", map_split); + map__set_start(map_split, insert_split.start); + map__set_end(map_split, insert_split.end); + + ret = maps__fixup_overlap_and_insert(maps, map_split); + TEST_ASSERT_VAL("failed to fixup and insert split map", !ret); + + map__zput(map_split); + ret = check_maps(expected_after_split, ARRAY_SIZE(expected_after_split), maps); + TEST_ASSERT_VAL("split check failed", !ret); + + // Check cover 1 map with another. + map_eclipse = dso__new_map(insert_eclipse.name); + TEST_ASSERT_VAL("failed to create eclipse map", map_eclipse); + map__set_start(map_eclipse, insert_eclipse.start); + map__set_end(map_eclipse, insert_eclipse.end); + + ret = maps__fixup_overlap_and_insert(maps, map_eclipse); + TEST_ASSERT_VAL("failed to fixup and insert eclipse map", !ret); + + map__zput(map_eclipse); + ret = check_maps(expected_final, ARRAY_SIZE(expected_final), maps); + TEST_ASSERT_VAL("eclipse check failed", !ret); + + maps__zput(maps); + return TEST_OK; +} + +static struct test_case tests__maps[] = { + TEST_CASE("Test merge_in interface", maps__merge_in), + TEST_CASE("Test fix up overlap interface", maps__fixup_overlap_and_insert), + { .name = NULL, } +}; + +struct test_suite suite__maps = { + .desc = "Maps - per process mmaps abstraction", + .test_cases = tests__maps, +}; diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 012c8ae439fd..3313c236104e 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -1,15 +1,18 @@ // SPDX-License-Identifier: GPL-2.0 #include <errno.h> +#include <fcntl.h> #include <inttypes.h> #include <stdlib.h> #include <perf/cpumap.h> +#include "cpumap.h" #include "debug.h" #include "event.h" #include "evlist.h" #include "evsel.h" #include "thread_map.h" #include "tests.h" +#include "util/affinity.h" #include "util/mmap.h" #include "util/sample.h" #include <linux/err.h> @@ -46,7 +49,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest char sbuf[STRERR_BUFSIZE]; struct mmap *md; - threads = thread_map__new(-1, getpid(), UINT_MAX); + threads = thread_map__new_by_tid(getpid()); if (threads == NULL) { pr_debug("thread_map__new\n"); return -1; @@ -130,14 +133,17 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest goto out_delete_evlist; } + perf_sample__init(&sample, /*all=*/false); err = evlist__parse_sample(evlist, event, &sample); if (err) { pr_err("Can't parse sample, err = %d\n", err); + perf_sample__exit(&sample); goto out_delete_evlist; } err = -1; evsel = evlist__id2evsel(evlist, sample.id); + perf_sample__exit(&sample); if (evsel == NULL) { pr_debug("event with id %" PRIu64 " doesn't map to an evsel\n", sample.id); @@ -169,99 +175,199 @@ out_free_threads: return err; } -static int test_stat_user_read(int event) -{ - struct perf_counts_values counts = { .val = 0 }; - struct perf_thread_map *threads; - struct perf_evsel *evsel; - struct perf_event_mmap_page *pc; - struct perf_event_attr attr = { - .type = PERF_TYPE_HARDWARE, - .config = event, -#ifdef __aarch64__ - .config1 = 0x2, /* Request user access */ -#endif - }; - int err, i, ret = TEST_FAIL; - bool opened = false, mapped = false; +enum user_read_state { + USER_READ_ENABLED, + USER_READ_DISABLED, + USER_READ_UNKNOWN, +}; - threads = perf_thread_map__new_dummy(); - TEST_ASSERT_VAL("failed to create threads", threads); +static enum user_read_state set_user_read(struct perf_pmu *pmu, 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; + } - perf_thread_map__set_pid(threads, 0, 0); + len = read(rdpmc_fd, buf, sizeof(buf)); + if (len != sizeof(buf)) + pr_debug("%s read failed\n", __func__); - evsel = perf_evsel__new(&attr); - TEST_ASSERT_VAL("failed to create evsel", evsel); + // 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; - err = perf_evsel__open(evsel, NULL, threads); - if (err) { - pr_err("failed to open evsel: %s\n", strerror(-err)); - ret = TEST_SKIP; - goto out; + if (enabled != old_user_read) { + buf[0] = (enabled == USER_READ_ENABLED) ? '1' : '0'; + len = write(rdpmc_fd, buf, sizeof(buf)); + if (len != sizeof(buf)) + pr_debug("%s write failed\n", __func__); } - opened = true; + close(rdpmc_fd); + close(events_fd); + return old_user_read; +} - err = perf_evsel__mmap(evsel, 0); - if (err) { - pr_err("failed to mmap evsel: %s\n", strerror(-err)); - goto out; +static int test_stat_user_read(u64 event, enum user_read_state enabled) +{ + struct perf_pmu *pmu = NULL; + struct perf_thread_map *threads = perf_thread_map__new_dummy(); + int ret = TEST_OK; + + pr_err("User space counter reading %" PRIu64 "\n", event); + if (!threads) { + pr_err("User space counter reading [Failed to create threads]\n"); + return TEST_FAIL; } - mapped = true; + perf_thread_map__set_pid(threads, 0, 0); - pc = perf_evsel__mmap_base(evsel, 0, 0); - if (!pc) { - pr_err("failed to get mmapped address\n"); - goto out; - } + while ((pmu = perf_pmus__scan_core(pmu)) != NULL) { + enum user_read_state saved_user_read_state = set_user_read(pmu, enabled); + struct perf_event_attr attr = { + .type = PERF_TYPE_HARDWARE, + .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; + struct perf_event_mmap_page *pc; + bool mapped = false, opened = false, rdpmc_supported; + struct perf_counts_values counts = { .val = 0 }; + + + pr_debug("User space counter reading for PMU %s\n", pmu->name); + /* + * 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 + * event then the event will be disabled and the pc->index test + * will fail. + */ + if (pmu->cpus != NULL) + cpu_map__set_affinity(pmu->cpus); + + /* Make the evsel. */ + evsel = perf_evsel__new(&attr); + if (!evsel) { + pr_err("User space counter reading for PMU %s [Failed to allocate evsel]\n", + pmu->name); + ret = TEST_FAIL; + goto cleanup; + } - if (!pc->cap_user_rdpmc || !pc->index) { - pr_err("userspace counter access not %s\n", - !pc->cap_user_rdpmc ? "supported" : "enabled"); - ret = TEST_SKIP; - goto out; - } - if (pc->pmc_width < 32) { - pr_err("userspace counter width not set (%d)\n", pc->pmc_width); - goto out; - } + err = perf_evsel__open(evsel, NULL, threads); + if (err) { + pr_err("User space counter reading for PMU %s [Failed to open evsel]\n", + pmu->name); + ret = TEST_SKIP; + goto cleanup; + } + opened = true; + err = perf_evsel__mmap(evsel, 0); + if (err) { + pr_err("User space counter reading for PMU %s [Failed to mmap evsel]\n", + pmu->name); + ret = TEST_FAIL; + goto cleanup; + } + mapped = true; + + pc = perf_evsel__mmap_base(evsel, 0, 0); + if (!pc) { + pr_err("User space counter reading for PMU %s [Failed to get mmaped address]\n", + pmu->name); + ret = TEST_FAIL; + goto cleanup; + } - perf_evsel__read(evsel, 0, 0, &counts); - if (counts.val == 0) { - pr_err("failed to read value for evsel\n"); - goto out; - } + if (saved_user_read_state == USER_READ_UNKNOWN) + rdpmc_supported = pc->cap_user_rdpmc && pc->index; + else + rdpmc_supported = (enabled == USER_READ_ENABLED); - for (i = 0; i < 5; i++) { - volatile int count = 0x10000 << i; - __u64 start, end, last = 0; + 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); + ret = TEST_FAIL; + goto cleanup; + } - pr_debug("\tloop = %u, ", count); + 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); + ret = TEST_FAIL; + goto cleanup; + } + + if (rdpmc_supported && pc->pmc_width < 32) { + pr_err("User space counter reading for PMU %s [Failed width not set %d]\n", + pmu->name, pc->pmc_width); + ret = TEST_FAIL; + goto cleanup; + } perf_evsel__read(evsel, 0, 0, &counts); - start = counts.val; + if (rdpmc_supported && counts.val == 0) { + pr_err("User space counter reading for PMU %s [Failed read]\n", pmu->name); + ret = TEST_FAIL; + goto cleanup; + } - while (count--) ; + for (int i = 0; i < 5; i++) { + volatile int count = 0x10000 << i; + __u64 start, end, last = 0; - perf_evsel__read(evsel, 0, 0, &counts); - end = counts.val; + pr_debug("\tloop = %u, ", count); - if ((end - start) < last) { - pr_err("invalid counter data: end=%llu start=%llu last= %llu\n", - end, start, last); - goto out; - } - last = end - start; - pr_debug("count = %llu\n", end - start); - } - ret = TEST_OK; + perf_evsel__read(evsel, 0, 0, &counts); + start = counts.val; + + while (count--) ; -out: - if (mapped) - perf_evsel__munmap(evsel); - if (opened) - perf_evsel__close(evsel); - perf_evsel__delete(evsel); + perf_evsel__read(evsel, 0, 0, &counts); + end = counts.val; + if ((end - start) < last) { + pr_err("User space counter reading for PMU %s [Failed invalid counter data: end=%llu start=%llu last= %llu]\n", + pmu->name, end, start, last); + ret = TEST_FAIL; + goto cleanup; + } + last = end - start; + pr_debug("count = %llu\n", last); + } + pr_debug("User space counter reading for PMU %s [Success]\n", pmu->name); +cleanup: + if (mapped) + perf_evsel__munmap(evsel); + if (opened) + perf_evsel__close(evsel); + perf_evsel__delete(evsel); + + /* If the affinity was changed, then put it back to all CPUs. */ + if (pmu->cpus != NULL) { + struct perf_cpu_map *cpus = cpu_map__online(); + + cpu_map__set_affinity(cpus); + perf_cpu_map__put(cpus); + } + set_user_read(pmu, saved_user_read_state); + } perf_thread_map__put(threads); return ret; } @@ -269,20 +375,32 @@ out: static int test__mmap_user_read_instr(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { - return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS); + 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, int subtest __maybe_unused) { - return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES); + return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES, USER_READ_ENABLED); +} + +static int test__mmap_user_read_instr_disabled(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS, USER_READ_DISABLED); +} + +static int test__mmap_user_read_cycles_disabled(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES, USER_READ_DISABLED); } static struct test_case tests__basic_mmap[] = { TEST_CASE_REASON("Read samples using the mmap interface", basic_mmap, "permissions"), - TEST_CASE_REASON("User space counter reading of instructions", + 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) @@ -291,7 +409,7 @@ static struct test_case tests__basic_mmap[] = { "unsupported" #endif ), - TEST_CASE_REASON("User space counter reading of cycles", + 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) @@ -300,6 +418,24 @@ static struct test_case tests__basic_mmap[] = { "unsupported" #endif ), + 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 + ), + 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 + ), { .name = NULL, } }; diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c index ddd1da9a4ba9..0c5619c6e6e9 100644 --- a/tools/perf/tests/mmap-thread-lookup.c +++ b/tools/perf/tests/mmap-thread-lookup.c @@ -8,6 +8,7 @@ #include <stdlib.h> #include <stdio.h> #include "debug.h" +#include "env.h" #include "event.h" #include "tests.h" #include "machine.h" @@ -155,6 +156,7 @@ static int synth_process(struct machine *machine) static int mmap_events(synth_cb synth) { + struct perf_env host_env; struct machine *machine; int err, i; @@ -167,7 +169,8 @@ static int mmap_events(synth_cb synth) */ TEST_ASSERT_VAL("failed to create threads", !threads_create()); - machine = machine__new_host(); + perf_env__init(&host_env); + machine = machine__new_host(&host_env); dump_trace = verbose > 1 ? 1 : 0; @@ -209,6 +212,7 @@ static int mmap_events(synth_cb synth) } machine__delete(machine); + perf_env__exit(&host_env); return err; } @@ -229,11 +233,11 @@ static int mmap_events(synth_cb synth) static int test__mmap_thread_lookup(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { /* perf_event__synthesize_threads synthesize */ - TEST_ASSERT_VAL("failed with sythesizing all", + TEST_ASSERT_VAL("failed with synthesizing all", !mmap_events(synth_all)); /* perf_event__synthesize_thread_map synthesize */ - TEST_ASSERT_VAL("failed with sythesizing process", + TEST_ASSERT_VAL("failed with synthesizing process", !mmap_events(synth_process)); return 0; diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index fb114118c876..3644d6f52c07 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -28,7 +28,7 @@ static int test__openat_syscall_event_on_all_cpus(struct test_suite *test __mayb struct evsel *evsel; unsigned int nr_openat_calls = 111, i; cpu_set_t cpu_set; - struct perf_thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); + struct perf_thread_map *threads = thread_map__new_by_tid(getpid()); char sbuf[STRERR_BUFSIZE]; char errbuf[BUFSIZ]; diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c index 888df8eca981..2a139d2781a8 100644 --- a/tools/perf/tests/openat-syscall-tp-fields.c +++ b/tools/perf/tests/openat-syscall-tp-fields.c @@ -28,7 +28,6 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused { struct record_opts opts = { .target = { - .uid = UINT_MAX, .uses_mmap = true, }, .no_buffering = true, @@ -40,7 +39,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused int flags = O_RDONLY | O_DIRECTORY; struct evlist *evlist = evlist__new(); struct evsel *evsel; - int err = -1, i, nr_events = 0, nr_polls = 0; + int ret = TEST_FAIL, err, i, nr_events = 0, nr_polls = 0; char sbuf[STRERR_BUFSIZE]; if (evlist == NULL) { @@ -51,6 +50,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused evsel = evsel__newtp("syscalls", "sys_enter_openat"); if (IS_ERR(evsel)) { pr_debug("%s: evsel__newtp\n", __func__); + ret = PTR_ERR(evsel) == -EACCES ? TEST_SKIP : TEST_FAIL; goto out_delete_evlist; } @@ -110,14 +110,16 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused continue; } + perf_sample__init(&sample, /*all=*/false); err = evsel__parse_sample(evsel, event, &sample); if (err) { pr_debug("Can't parse sample, err = %d\n", err); + perf_sample__exit(&sample); goto out_delete_evlist; } tp_flags = evsel__intval(evsel, &sample, "flags"); - + perf_sample__exit(&sample); if (flags != tp_flags) { pr_debug("%s: Expected flags=%#x, got %#x\n", __func__, flags, tp_flags); @@ -138,11 +140,21 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused } } out_ok: - err = 0; + ret = TEST_OK; out_delete_evlist: evlist__delete(evlist); out: - return err; + return ret; } -DEFINE_SUITE("syscalls:sys_enter_openat event fields", syscall_openat_tp_fields); +static struct test_case tests__syscall_openat_tp_fields[] = { + TEST_CASE_REASON("syscalls:sys_enter_openat event fields", + syscall_openat_tp_fields, + "permissions"), + { .name = NULL, } +}; + +struct test_suite suite__syscall_openat_tp_fields = { + .desc = "syscalls:sys_enter_openat event fields", + .test_cases = tests__syscall_openat_tp_fields, +}; diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c index 131b62271bfa..b54cbe5f1808 100644 --- a/tools/perf/tests/openat-syscall.c +++ b/tools/perf/tests/openat-syscall.c @@ -20,7 +20,7 @@ static int test__openat_syscall_event(struct test_suite *test __maybe_unused, int err = TEST_FAIL, fd; struct evsel *evsel; unsigned int nr_openat_calls = 111, i; - struct perf_thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); + struct perf_thread_map *threads = thread_map__new_by_tid(getpid()); char sbuf[STRERR_BUFSIZE]; char errbuf[BUFSIZ]; diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 9e3086d02150..128d21dc389f 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 #include "parse-events.h" #include "evsel.h" +#include "evsel_fprintf.h" #include "evlist.h" #include <api/fs/fs.h> #include "tests.h" #include "debug.h" #include "pmu.h" #include "pmus.h" +#include "strbuf.h" #include <dirent.h> #include <errno.h> #include "fncache.h" @@ -20,41 +22,62 @@ #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) -static int num_core_entries(void) +static bool check_evlist(const char *test, int line, bool cond, struct evlist *evlist) { - /* - * If the kernel supports extended type, expect events to be - * opened once for each core PMU type. Otherwise fall back to the legacy - * behavior of opening only one event even though there are multiple - * PMUs - */ - if (perf_pmus__supports_extended_type()) - return perf_pmus__num_core_pmus(); + struct strbuf sb = STRBUF_INIT; - return 1; + if (cond) + return true; + + evlist__format_evsels(evlist, &sb, 2048); + pr_debug("FAILED %s:%d: %s\nFor evlist: %s\n", __FILE__, line, test, sb.buf); + strbuf_release(&sb); + return false; } +#define TEST_ASSERT_EVLIST(test, cond, evlist) \ + if (!check_evlist(test, __LINE__, cond, evlist)) \ + return TEST_FAIL -static bool test_config(const struct evsel *evsel, __u64 expected_config) +static bool check_evsel(const char *test, int line, bool cond, struct evsel *evsel) { - __u32 type = evsel->core.attr.type; - __u64 config = evsel->core.attr.config; + struct perf_attr_details details = { .verbose = true, }; - if (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE) { - /* - * HARDWARE and HW_CACHE events encode the PMU's extended type - * in the top 32-bits. Mask in order to ignore. - */ - config &= PERF_HW_EVENT_MASK; - } - return config == expected_config; + if (cond) + return true; + + pr_debug("FAILED %s:%d: %s\nFor evsel: ", __FILE__, line, test); + evsel__fprintf(evsel, &details, debug_file()); + return false; } +#define TEST_ASSERT_EVSEL(test, cond, evsel) \ + if (!check_evsel(test, __LINE__, cond, evsel)) \ + return TEST_FAIL -static bool test_perf_config(const struct perf_evsel *evsel, __u64 expected_config) +static int num_core_entries(struct evlist *evlist) { - return (evsel->attr.config & PERF_HW_EVENT_MASK) == expected_config; + /* + * Returns number of core PMUs if the evlist has >1 core PMU, otherwise + * returns 1. The number of core PMUs is needed as wild carding can + * open an event for each core PMU. If the events were opened with a + * specified PMU then wild carding won't happen. + */ + struct perf_pmu *core_pmu = NULL; + struct evsel *evsel; + + evlist__for_each_entry(evlist, evsel) { + if (!evsel->pmu->is_core) + continue; + if (core_pmu != evsel->pmu && core_pmu != NULL) + return perf_pmus__num_core_pmus(); + core_pmu = evsel->pmu; + } + return 1; } -#ifdef HAVE_LIBTRACEEVENT +static bool test_hw_config(const struct evsel *evsel, __u64 expected_config) +{ + return (evsel->core.attr.config & PERF_HW_EVENT_MASK) == expected_config; +} #if defined(__s390x__) /* Return true if kvm module is available and loaded. Test this @@ -86,12 +109,12 @@ static int test__checkevent_tracepoint(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 0 == evlist__nr_groups(evlist)); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong sample_type", - PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type); - TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->core.attr.sample_period); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVLIST("wrong number of groups", 0 == evlist__nr_groups(evlist), evlist); + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong sample_type", + PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type, evsel); + TEST_ASSERT_EVSEL("wrong sample_period", 1 == evsel->core.attr.sample_period, evsel); return TEST_OK; } @@ -99,35 +122,38 @@ static int test__checkevent_tracepoint_multi(struct evlist *evlist) { struct evsel *evsel; - TEST_ASSERT_VAL("wrong number of entries", evlist->core.nr_entries > 1); - TEST_ASSERT_VAL("wrong number of groups", 0 == evlist__nr_groups(evlist)); + TEST_ASSERT_EVLIST("wrong number of entries", evlist->core.nr_entries > 1, evlist); + TEST_ASSERT_EVLIST("wrong number of groups", 0 == evlist__nr_groups(evlist), evlist); evlist__for_each_entry(evlist, evsel) { - TEST_ASSERT_VAL("wrong type", - PERF_TYPE_TRACEPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong sample_type", - PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type); - TEST_ASSERT_VAL("wrong sample_period", - 1 == evsel->core.attr.sample_period); + TEST_ASSERT_EVSEL("wrong type", + PERF_TYPE_TRACEPOINT == evsel->core.attr.type, + evsel); + TEST_ASSERT_EVSEL("wrong sample_type", + PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type, + evsel); + TEST_ASSERT_EVSEL("wrong sample_period", + 1 == evsel->core.attr.sample_period, + evsel); } return TEST_OK; } -#endif /* HAVE_LIBTRACEEVENT */ static int test__checkevent_raw(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; bool raw_type_match = false; - TEST_ASSERT_VAL("wrong number of entries", 0 != evlist->core.nr_entries); + TEST_ASSERT_EVLIST("wrong number of entries", 0 != evlist->core.nr_entries, evlist); - perf_evlist__for_each_evsel(&evlist->core, evsel) { + evlist__for_each_entry(evlist, evsel) { struct perf_pmu *pmu __maybe_unused = NULL; bool type_matched = false; - TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, 0x1a)); - TEST_ASSERT_VAL("event not parsed as raw type", - evsel->attr.type == PERF_TYPE_RAW); + TEST_ASSERT_EVSEL("wrong config", test_hw_config(evsel, 0x1a), evsel); + TEST_ASSERT_EVSEL("event not parsed as raw type", + evsel->core.attr.type == PERF_TYPE_RAW, + evsel); #if defined(__aarch64__) /* * Arm doesn't have a real raw type PMU in sysfs, so raw events @@ -138,15 +164,15 @@ static int test__checkevent_raw(struct evlist *evlist) type_matched = raw_type_match = true; #else while ((pmu = perf_pmus__scan(pmu)) != NULL) { - if (pmu->type == evsel->attr.type) { - TEST_ASSERT_VAL("PMU type expected once", !type_matched); + if (pmu->type == evsel->core.attr.type) { + TEST_ASSERT_EVSEL("PMU type expected once", !type_matched, evsel); type_matched = true; if (pmu->type == PERF_TYPE_RAW) raw_type_match = true; } } #endif - TEST_ASSERT_VAL("No PMU found for type", type_matched); + TEST_ASSERT_EVSEL("No PMU found for type", type_matched, evsel); } TEST_ASSERT_VAL("Raw PMU not matched", raw_type_match); return TEST_OK; @@ -156,62 +182,44 @@ static int test__checkevent_numeric(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", 1 == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 1)); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong type", 1 == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 1 == evsel->core.attr.config, evsel); return TEST_OK; } -static int assert_hw(struct perf_evsel *evsel, enum perf_hw_id id, const char *name) -{ - struct perf_pmu *pmu; - - if (evsel->attr.type == PERF_TYPE_HARDWARE) { - TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, id)); - return 0; - } - pmu = perf_pmus__find_by_type(evsel->attr.type); - - TEST_ASSERT_VAL("unexpected PMU type", pmu); - TEST_ASSERT_VAL("PMU missing event", perf_pmu__have_event(pmu, name)); - return 0; -} - static int test__checkevent_symbolic_name(struct evlist *evlist) { - struct perf_evsel *evsel; - - TEST_ASSERT_VAL("wrong number of entries", 0 != evlist->core.nr_entries); + struct evsel *evsel; - perf_evlist__for_each_evsel(&evlist->core, evsel) { - int ret = assert_hw(evsel, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); + TEST_ASSERT_EVLIST("wrong number of entries", 0 != evlist->core.nr_entries, evlist); - if (ret) - return ret; + evlist__for_each_entry(evlist, evsel) { + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS), + evsel); } - return TEST_OK; } static int test__checkevent_symbolic_name_config(struct evlist *evlist) { - struct perf_evsel *evsel; - - TEST_ASSERT_VAL("wrong number of entries", 0 != evlist->core.nr_entries); + struct evsel *evsel; - perf_evlist__for_each_evsel(&evlist->core, evsel) { - int ret = assert_hw(evsel, PERF_COUNT_HW_CPU_CYCLES, "cycles"); + TEST_ASSERT_EVLIST("wrong number of entries", 0 != evlist->core.nr_entries, evlist); - if (ret) - return ret; + evlist__for_each_entry(evlist, evsel) { + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); /* * The period value gets configured within evlist__config, * while this test executes only parse events method. */ - TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period); - TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1); - TEST_ASSERT_VAL("wrong config2", 1 == evsel->attr.config2); + TEST_ASSERT_EVSEL("wrong period", 0 == evsel->core.attr.sample_period, evsel); + TEST_ASSERT_EVSEL("wrong config1", 0 == evsel->core.attr.config1, evsel); + TEST_ASSERT_EVSEL("wrong config2", 1 == evsel->core.attr.config2, evsel); } return TEST_OK; } @@ -220,21 +228,21 @@ static int test__checkevent_symbolic_alias(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_SW_PAGE_FAULTS)); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong type/config", evsel__match(evsel, SOFTWARE, SW_PAGE_FAULTS), + evsel); return TEST_OK; } static int test__checkevent_genhw(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; - TEST_ASSERT_VAL("wrong number of entries", 0 != evlist->core.nr_entries); + TEST_ASSERT_EVLIST("wrong number of entries", 0 != evlist->core.nr_entries, evlist); - perf_evlist__for_each_entry(&evlist->core, evsel) { - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, 1 << 16)); + evlist__for_each_entry(evlist, evsel) { + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_HW_CACHE == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", test_hw_config(evsel, 1 << 16), evsel); } return TEST_OK; } @@ -243,13 +251,13 @@ static int test__checkevent_breakpoint(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 0)); - TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) == - evsel->core.attr.bp_type); - TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 == - evsel->core.attr.bp_len); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); + TEST_ASSERT_EVSEL("wrong bp_type", + (HW_BREAKPOINT_R | HW_BREAKPOINT_W) == evsel->core.attr.bp_type, + evsel); + TEST_ASSERT_EVSEL("wrong bp_len", HW_BREAKPOINT_LEN_4 == evsel->core.attr.bp_len, evsel); return TEST_OK; } @@ -257,12 +265,12 @@ static int test__checkevent_breakpoint_x(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 0)); - TEST_ASSERT_VAL("wrong bp_type", - HW_BREAKPOINT_X == evsel->core.attr.bp_type); - TEST_ASSERT_VAL("wrong bp_len", default_breakpoint_len() == evsel->core.attr.bp_len); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); + TEST_ASSERT_EVSEL("wrong bp_type", HW_BREAKPOINT_X == evsel->core.attr.bp_type, evsel); + TEST_ASSERT_EVSEL("wrong bp_len", default_breakpoint_len() == evsel->core.attr.bp_len, + evsel); return TEST_OK; } @@ -270,14 +278,11 @@ static int test__checkevent_breakpoint_r(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", - PERF_TYPE_BREAKPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 0)); - TEST_ASSERT_VAL("wrong bp_type", - HW_BREAKPOINT_R == evsel->core.attr.bp_type); - TEST_ASSERT_VAL("wrong bp_len", - HW_BREAKPOINT_LEN_4 == evsel->core.attr.bp_len); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); + TEST_ASSERT_EVSEL("wrong bp_type", HW_BREAKPOINT_R == evsel->core.attr.bp_type, evsel); + TEST_ASSERT_EVSEL("wrong bp_len", HW_BREAKPOINT_LEN_4 == evsel->core.attr.bp_len, evsel); return TEST_OK; } @@ -285,14 +290,11 @@ static int test__checkevent_breakpoint_w(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", - PERF_TYPE_BREAKPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 0)); - TEST_ASSERT_VAL("wrong bp_type", - HW_BREAKPOINT_W == evsel->core.attr.bp_type); - TEST_ASSERT_VAL("wrong bp_len", - HW_BREAKPOINT_LEN_4 == evsel->core.attr.bp_len); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); + TEST_ASSERT_EVSEL("wrong bp_type", HW_BREAKPOINT_W == evsel->core.attr.bp_type, evsel); + TEST_ASSERT_EVSEL("wrong bp_len", HW_BREAKPOINT_LEN_4 == evsel->core.attr.bp_len, evsel); return TEST_OK; } @@ -300,26 +302,25 @@ static int test__checkevent_breakpoint_rw(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", - PERF_TYPE_BREAKPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 0)); - TEST_ASSERT_VAL("wrong bp_type", - (HW_BREAKPOINT_R|HW_BREAKPOINT_W) == evsel->core.attr.bp_type); - TEST_ASSERT_VAL("wrong bp_len", - HW_BREAKPOINT_LEN_4 == evsel->core.attr.bp_len); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); + TEST_ASSERT_EVSEL("wrong bp_type", + (HW_BREAKPOINT_R|HW_BREAKPOINT_W) == evsel->core.attr.bp_type, + evsel); + TEST_ASSERT_EVSEL("wrong bp_len", HW_BREAKPOINT_LEN_4 == evsel->core.attr.bp_len, evsel); return TEST_OK; } -#ifdef HAVE_LIBTRACEEVENT static int test__checkevent_tracepoint_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); return test__checkevent_tracepoint(evlist); } @@ -327,81 +328,93 @@ static int test__checkevent_tracepoint_modifier(struct evlist *evlist) static int test__checkevent_tracepoint_multi_modifier(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; - TEST_ASSERT_VAL("wrong number of entries", evlist->core.nr_entries > 1); + TEST_ASSERT_EVLIST("wrong number of entries", evlist->core.nr_entries > 1, evlist); - perf_evlist__for_each_entry(&evlist->core, evsel) { - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + evlist__for_each_entry(evlist, evsel) { + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); } return test__checkevent_tracepoint_multi(evlist); } -#endif /* HAVE_LIBTRACEEVENT */ static int test__checkevent_raw_modifier(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; - perf_evlist__for_each_entry(&evlist->core, evsel) { - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + + evlist__for_each_entry(evlist, evsel) { + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip, evsel); } return test__checkevent_raw(evlist); } static int test__checkevent_numeric_modifier(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; + + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); - perf_evlist__for_each_entry(&evlist->core, evsel) { - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + evlist__for_each_entry(evlist, evsel) { + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip, evsel); } return test__checkevent_numeric(evlist); } static int test__checkevent_symbolic_name_modifier(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == num_core_entries()); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); - perf_evlist__for_each_entry(&evlist->core, evsel) { - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + evlist__for_each_entry(evlist, evsel) { + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); } return test__checkevent_symbolic_name(evlist); } static int test__checkevent_exclude_host_modifier(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; - perf_evlist__for_each_entry(&evlist->core, evsel) { - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); + + evlist__for_each_entry(evlist, evsel) { + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", evsel->core.attr.exclude_host, evsel); } return test__checkevent_symbolic_name(evlist); } static int test__checkevent_exclude_guest_modifier(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; - perf_evlist__for_each_entry(&evlist->core, evsel) { - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); + + evlist__for_each_entry(evlist, evsel) { + TEST_ASSERT_EVSEL("wrong exclude guest", evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); } return test__checkevent_symbolic_name(evlist); } @@ -410,23 +423,28 @@ static int test__checkevent_symbolic_alias_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); return test__checkevent_symbolic_alias(evlist); } static int test__checkevent_genhw_modifier(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; - perf_evlist__for_each_entry(&evlist->core, evsel) { - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); + + evlist__for_each_entry(evlist, evsel) { + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip, evsel); } return test__checkevent_genhw(evlist); } @@ -435,13 +453,17 @@ static int test__checkevent_exclude_idle_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude idle", evsel->core.attr.exclude_idle); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); + + TEST_ASSERT_EVSEL("wrong exclude idle", evsel->core.attr.exclude_idle, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); return test__checkevent_symbolic_name(evlist); } @@ -450,13 +472,17 @@ static int test__checkevent_exclude_idle_modifier_1(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude idle", evsel->core.attr.exclude_idle); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); + + TEST_ASSERT_EVSEL("wrong exclude idle", evsel->core.attr.exclude_idle, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); return test__checkevent_symbolic_name(evlist); } @@ -466,11 +492,11 @@ static int test__checkevent_breakpoint_modifier(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "mem:0:u")); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "mem:0:u"), evsel); return test__checkevent_breakpoint(evlist); } @@ -479,11 +505,11 @@ static int test__checkevent_breakpoint_x_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "mem:0:x:k")); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "mem:0:x:k"), evsel); return test__checkevent_breakpoint_x(evlist); } @@ -492,11 +518,11 @@ static int test__checkevent_breakpoint_r_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "mem:0:r:hp")); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "mem:0:r:hp"), evsel); return test__checkevent_breakpoint_r(evlist); } @@ -505,11 +531,11 @@ static int test__checkevent_breakpoint_w_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "mem:0:w:up")); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "mem:0:w:up"), evsel); return test__checkevent_breakpoint_w(evlist); } @@ -518,11 +544,11 @@ static int test__checkevent_breakpoint_rw_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "mem:0:rw:kp")); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "mem:0:rw:kp"), evsel); return test__checkevent_breakpoint_rw(evlist); } @@ -531,11 +557,11 @@ static int test__checkevent_breakpoint_modifier_name(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint")); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "breakpoint"), evsel); return test__checkevent_breakpoint(evlist); } @@ -544,11 +570,11 @@ static int test__checkevent_breakpoint_x_modifier_name(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint")); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "breakpoint"), evsel); return test__checkevent_breakpoint_x(evlist); } @@ -557,11 +583,11 @@ static int test__checkevent_breakpoint_r_modifier_name(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint")); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "breakpoint"), evsel); return test__checkevent_breakpoint_r(evlist); } @@ -570,11 +596,11 @@ static int test__checkevent_breakpoint_w_modifier_name(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint")); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "breakpoint"), evsel); return test__checkevent_breakpoint_w(evlist); } @@ -583,11 +609,11 @@ static int test__checkevent_breakpoint_rw_modifier_name(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint")); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "breakpoint"), evsel); return test__checkevent_breakpoint_rw(evlist); } @@ -596,15 +622,15 @@ static int test__checkevent_breakpoint_2_events(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); + TEST_ASSERT_EVSEL("wrong number of entries", 2 == evlist->core.nr_entries, evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint1")); + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "breakpoint1"), evsel); evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "breakpoint2")); + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "breakpoint2"), evsel); return TEST_OK; } @@ -613,82 +639,86 @@ static int test__checkevent_pmu(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 10)); - TEST_ASSERT_VAL("wrong config1", 1 == evsel->core.attr.config1); - TEST_ASSERT_VAL("wrong config2", 3 == evsel->core.attr.config2); - TEST_ASSERT_VAL("wrong config3", 0 == evsel->core.attr.config3); + struct perf_pmu *core_pmu = perf_pmus__find_core_pmu(); + + TEST_ASSERT_EVSEL("wrong number of entries", 1 == evlist->core.nr_entries, evsel); + TEST_ASSERT_EVSEL("wrong type", core_pmu->type == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", test_hw_config(evsel, 10), evsel); + TEST_ASSERT_EVSEL("wrong config1", 1 == evsel->core.attr.config1, evsel); + TEST_ASSERT_EVSEL("wrong config2", 3 == evsel->core.attr.config2, evsel); + TEST_ASSERT_EVSEL("wrong config3", 0 == evsel->core.attr.config3, evsel); + TEST_ASSERT_EVSEL("wrong config4", 0 == evsel->core.attr.config4, evsel); /* * The period value gets configured within evlist__config, * while this test executes only parse events method. */ - TEST_ASSERT_VAL("wrong period", 0 == evsel->core.attr.sample_period); + TEST_ASSERT_EVSEL("wrong period", 0 == evsel->core.attr.sample_period, evsel); return TEST_OK; } -#ifdef HAVE_LIBTRACEEVENT static int test__checkevent_list(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 3 <= evlist->core.nr_entries); + TEST_ASSERT_EVSEL("wrong number of entries", 3 <= evlist->core.nr_entries, evsel); /* r1 */ - TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT != evsel->core.attr.type); + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_TRACEPOINT != evsel->core.attr.type, evsel); while (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { - TEST_ASSERT_VAL("wrong config", test_config(evsel, 1)); - TEST_ASSERT_VAL("wrong config1", 0 == evsel->core.attr.config1); - TEST_ASSERT_VAL("wrong config2", 0 == evsel->core.attr.config2); - TEST_ASSERT_VAL("wrong config3", 0 == evsel->core.attr.config3); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); + TEST_ASSERT_EVSEL("wrong config", 1 == evsel->core.attr.config, evsel); + TEST_ASSERT_EVSEL("wrong config1", 0 == evsel->core.attr.config1, evsel); + TEST_ASSERT_EVSEL("wrong config2", 0 == evsel->core.attr.config2, evsel); + TEST_ASSERT_EVSEL("wrong config3", 0 == evsel->core.attr.config3, evsel); + TEST_ASSERT_EVSEL("wrong config4", 0 == evsel->core.attr.config4, evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); evsel = evsel__next(evsel); } /* syscalls:sys_enter_openat:k */ - TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong sample_type", - PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type); - TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->core.attr.sample_period); - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong sample_type", PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type, + evsel); + TEST_ASSERT_EVSEL("wrong sample_period", 1 == evsel->core.attr.sample_period, evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); /* 1:1:hp */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", 1 == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 1)); - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); + TEST_ASSERT_EVSEL("wrong type", 1 == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 1 == evsel->core.attr.config, evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip, evsel); return TEST_OK; } -#endif static int test__checkevent_pmu_name(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); + struct perf_pmu *core_pmu = perf_pmus__find_core_pmu(); + char buf[256]; - /* cpu/config=1,name=krava/u */ - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 1)); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "krava")); + /* default_core/config=1,name=krava/u */ + TEST_ASSERT_EVLIST("wrong number of entries", 2 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong type", core_pmu->type == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 1 == evsel->core.attr.config, evsel); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, "krava"), evsel); - /* cpu/config=2/u" */ + /* default_core/config=2/u" */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 2)); - TEST_ASSERT_VAL("wrong name", evsel__name_is(evsel, "cpu/config=2/u")); + TEST_ASSERT_EVSEL("wrong number of entries", 2 == evlist->core.nr_entries, evsel); + TEST_ASSERT_EVSEL("wrong type", core_pmu->type == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 2 == evsel->core.attr.config, evsel); + snprintf(buf, sizeof(buf), "%s/config=2/u", core_pmu->name); + TEST_ASSERT_EVSEL("wrong name", evsel__name_is(evsel, buf), evsel); return TEST_OK; } @@ -696,50 +726,55 @@ static int test__checkevent_pmu_name(struct evlist *evlist) static int test__checkevent_pmu_partial_time_callgraph(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); + struct perf_pmu *core_pmu = perf_pmus__find_core_pmu(); - /* cpu/config=1,call-graph=fp,time,period=100000/ */ - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 1)); + /* default_core/config=1,call-graph=fp,time,period=100000/ */ + TEST_ASSERT_EVLIST("wrong number of entries", 2 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong type", core_pmu->type == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 1 == evsel->core.attr.config, evsel); /* * The period, time and callgraph value gets configured within evlist__config, * while this test executes only parse events method. */ - TEST_ASSERT_VAL("wrong period", 0 == evsel->core.attr.sample_period); - TEST_ASSERT_VAL("wrong callgraph", !evsel__has_callchain(evsel)); - TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->core.attr.sample_type)); + TEST_ASSERT_EVSEL("wrong period", 0 == evsel->core.attr.sample_period, evsel); + TEST_ASSERT_EVSEL("wrong callgraph", !evsel__has_callchain(evsel), evsel); + TEST_ASSERT_EVSEL("wrong time", !(PERF_SAMPLE_TIME & evsel->core.attr.sample_type), evsel); - /* cpu/config=2,call-graph=no,time=0,period=2000/ */ + /* default_core/config=2,call-graph=no,time=0,period=2000/ */ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 2)); + TEST_ASSERT_EVSEL("wrong type", core_pmu->type == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 2 == evsel->core.attr.config, evsel); /* * The period, time and callgraph value gets configured within evlist__config, * while this test executes only parse events method. */ - TEST_ASSERT_VAL("wrong period", 0 == evsel->core.attr.sample_period); - TEST_ASSERT_VAL("wrong callgraph", !evsel__has_callchain(evsel)); - TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->core.attr.sample_type)); + TEST_ASSERT_EVSEL("wrong period", 0 == evsel->core.attr.sample_period, evsel); + TEST_ASSERT_EVSEL("wrong callgraph", !evsel__has_callchain(evsel), evsel); + TEST_ASSERT_EVSEL("wrong time", !(PERF_SAMPLE_TIME & evsel->core.attr.sample_type), evsel); return TEST_OK; } static int test__checkevent_pmu_events(struct evlist *evlist) { - struct evsel *evsel = evlist__first(evlist); + struct evsel *evsel; + struct perf_pmu *core_pmu = perf_pmus__find_core_pmu(); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type || - strcmp(evsel->pmu_name, "cpu")); - TEST_ASSERT_VAL("wrong exclude_user", - !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", - evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned); - TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.exclusive); + TEST_ASSERT_EVLIST("wrong number of entries", 1 <= evlist->core.nr_entries, evlist); + evlist__for_each_entry(evlist, evsel) { + TEST_ASSERT_EVSEL("wrong type", + core_pmu->type == evsel->core.attr.type || + !strncmp(evsel__name(evsel), evsel->pmu->name, + strlen(evsel->pmu->name)), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong pinned", !evsel->core.attr.pinned, evsel); + TEST_ASSERT_EVSEL("wrong exclusive", !evsel->core.attr.exclusive, evsel); + } return TEST_OK; } @@ -752,30 +787,26 @@ static int test__checkevent_pmu_events_mix(struct evlist *evlist) * The wild card event will be opened at least once, but it may be * opened on each core PMU. */ - TEST_ASSERT_VAL("wrong number of entries", evlist->core.nr_entries >= 2); + TEST_ASSERT_EVLIST("wrong number of entries", evlist->core.nr_entries >= 2, evlist); for (int i = 0; i < evlist->core.nr_entries - 1; i++) { evsel = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); /* pmu-event:u */ - TEST_ASSERT_VAL("wrong exclude_user", - !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", - evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned); - TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.exclusive); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong pinned", !evsel->core.attr.pinned, evsel); + TEST_ASSERT_EVSEL("wrong exclusive", !evsel->core.attr.exclusive, evsel); } - /* cpu/pmu-event/u*/ + /* default_core/pmu-event/u*/ evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", evsel__find_pmu(evsel)->is_core); - TEST_ASSERT_VAL("wrong exclude_user", - !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", - evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned); - TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.pinned); + TEST_ASSERT_EVSEL("wrong type", evsel__find_pmu(evsel)->is_core, evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong pinned", !evsel->core.attr.pinned, evsel); + TEST_ASSERT_EVSEL("wrong exclusive", !evsel->core.attr.pinned, evsel); return TEST_OK; } @@ -820,6 +851,15 @@ static int test__checkterms_simple(struct parse_events_terms *terms) TEST_ASSERT_VAL("wrong val", term->val.num == 4); TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "config3")); + /* config4=5 */ + term = list_entry(term->list.next, struct parse_events_term, list); + TEST_ASSERT_VAL("wrong type term", + term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG4); + TEST_ASSERT_VAL("wrong type val", + term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); + TEST_ASSERT_VAL("wrong val", term->val.num == 5); + TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "config4")); + /* umask=1*/ term = list_entry(term->list.next, struct parse_events_term, list); TEST_ASSERT_VAL("wrong type term", @@ -862,49 +902,45 @@ static int test__checkterms_simple(struct parse_events_terms *terms) static int test__group1(struct evlist *evlist) { - struct evsel *evsel, *leader; - - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == (num_core_entries() * 2)); - TEST_ASSERT_VAL("wrong number of groups", - evlist__nr_groups(evlist) == num_core_entries()); + struct evsel *evsel = NULL, *leader; - for (int i = 0; i < num_core_entries(); i++) { - int ret; + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == (num_core_entries(evlist) * 2), + evlist); + TEST_ASSERT_EVLIST("wrong number of groups", + evlist__nr_groups(evlist) == num_core_entries(evlist), + evlist); + for (int i = 0; i < num_core_entries(evlist); i++) { /* instructions:k */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 0); - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), evsel); + TEST_ASSERT_EVSEL("wrong core.nr_members", evsel->core.nr_members == 2, evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 0, evsel); + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); /* cycles:upp */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - /* use of precise requires exclude_guest */ - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 2); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip == 2, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 1, evsel); + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); } return TEST_OK; } @@ -913,222 +949,239 @@ static int test__group2(struct evlist *evlist) { struct evsel *evsel, *leader = NULL; - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == (2 * num_core_entries() + 1)); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == (2 * num_core_entries(evlist) + 1), + evlist); /* * TODO: Currently the software event won't be grouped with the hardware * event except for 1 PMU. */ - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist)); + TEST_ASSERT_EVLIST("wrong number of groups", 1 == evlist__nr_groups(evlist), evlist); evlist__for_each_entry(evlist, evsel) { - int ret; - - if (evsel->core.attr.type == PERF_TYPE_SOFTWARE) { + if (evsel__match(evsel, SOFTWARE, SW_PAGE_FAULTS)) { /* faults + :ku modifier */ leader = evsel; - TEST_ASSERT_VAL("wrong config", - test_config(evsel, PERF_COUNT_SW_PAGE_FAULTS)); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 0); - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, + evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, + evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, + evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, + evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), evsel); + TEST_ASSERT_EVSEL("wrong core.nr_members", evsel->core.nr_members == 2, + evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 0, evsel); + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); continue; } - if (evsel->core.attr.type == PERF_TYPE_HARDWARE && - test_config(evsel, PERF_COUNT_HW_BRANCH_INSTRUCTIONS)) { + if (evsel__match(evsel, HARDWARE, HW_BRANCH_INSTRUCTIONS)) { /* branches + :u modifier */ - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - if (evsel__has_leader(evsel, leader)) - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, + evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, + evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, + evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, + evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + if (evsel__has_leader(evsel, leader)) { + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 1, + evsel); + } + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); continue; } /* cycles:k */ - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), evsel); + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); } return TEST_OK; } -#ifdef HAVE_LIBTRACEEVENT static int test__group3(struct evlist *evlist __maybe_unused) { struct evsel *evsel, *group1_leader = NULL, *group2_leader = NULL; - int ret; - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == (3 * perf_pmus__num_core_pmus() + 2)); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == (3 * perf_pmus__num_core_pmus() + 2), + evlist); /* * Currently the software event won't be grouped with the hardware event * except for 1 PMU. This means there are always just 2 groups * regardless of the number of core PMUs. */ - TEST_ASSERT_VAL("wrong number of groups", 2 == evlist__nr_groups(evlist)); + TEST_ASSERT_EVLIST("wrong number of groups", 2 == evlist__nr_groups(evlist), evlist); evlist__for_each_entry(evlist, evsel) { if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) { /* group1 syscalls:sys_enter_openat:H */ group1_leader = evsel; - TEST_ASSERT_VAL("wrong sample_type", - evsel->core.attr.sample_type == PERF_TP_SAMPLE_TYPE); - TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->core.attr.sample_period); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong group name", !strcmp(evsel->group_name, "group1")); - TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 0); - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("wrong sample_type", + evsel->core.attr.sample_type == PERF_TP_SAMPLE_TYPE, + evsel); + TEST_ASSERT_EVSEL("wrong sample_period", + 1 == evsel->core.attr.sample_period, + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, + evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, + evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", evsel->core.attr.exclude_guest, + evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, + evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), evsel); + TEST_ASSERT_EVSEL("wrong group name", !strcmp(evsel->group_name, "group1"), + evsel); + TEST_ASSERT_EVSEL("wrong core.nr_members", evsel->core.nr_members == 2, + evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 0, evsel); + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); continue; } - if (evsel->core.attr.type == PERF_TYPE_HARDWARE && - test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)) { + if (evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) { if (evsel->core.attr.exclude_user) { /* group1 cycles:kppp */ - TEST_ASSERT_VAL("wrong exclude_user", - evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", - !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - /* use of precise requires exclude_guest */ - TEST_ASSERT_VAL("wrong exclude guest", - evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", - !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", - evsel->core.attr.precise_ip == 3); + TEST_ASSERT_EVSEL("wrong exclude_user", + evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", + !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, + evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", + !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", + !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", + evsel->core.attr.precise_ip == 3, evsel); if (evsel__has_leader(evsel, group1_leader)) { - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong group_idx", - evsel__group_idx(evsel) == 1); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, + evsel); + TEST_ASSERT_EVSEL("wrong group_idx", + evsel__group_idx(evsel) == 1, + evsel); } - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); } else { /* group2 cycles + G modifier */ group2_leader = evsel; - TEST_ASSERT_VAL("wrong exclude_kernel", - !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", - !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", - !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", - evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); + TEST_ASSERT_EVSEL("wrong exclude_kernel", + !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", + !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", + !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", + evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, + evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), + evsel); if (evsel->core.nr_members == 2) { - TEST_ASSERT_VAL("wrong group_idx", - evsel__group_idx(evsel) == 0); + TEST_ASSERT_EVSEL("wrong group_idx", + evsel__group_idx(evsel) == 0, + evsel); } - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); } continue; } if (evsel->core.attr.type == 1) { /* group2 1:3 + G modifier */ - TEST_ASSERT_VAL("wrong config", test_config(evsel, 3)); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - if (evsel__has_leader(evsel, group2_leader)) - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("wrong config", 3 == evsel->core.attr.config, evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, + evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, + evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, + evsel); + TEST_ASSERT_EVSEL("wrong exclude host", evsel->core.attr.exclude_host, + evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + if (evsel__has_leader(evsel, group2_leader)) { + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 1, + evsel); + } + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); continue; } /* instructions:u */ - ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), evsel); + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); } return TEST_OK; } -#endif static int test__group4(struct evlist *evlist __maybe_unused) { - struct evsel *evsel, *leader; - - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == (num_core_entries() * 2)); - TEST_ASSERT_VAL("wrong number of groups", - num_core_entries() == evlist__nr_groups(evlist)); + struct evsel *evsel = NULL, *leader; - for (int i = 0; i < num_core_entries(); i++) { - int ret; + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == (num_core_entries(evlist) * 2), + evlist); + TEST_ASSERT_EVLIST("wrong number of groups", + num_core_entries(evlist) == evlist__nr_groups(evlist), + evlist); + for (int i = 0; i < num_core_entries(evlist); i++) { /* cycles:u + p */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - /* use of precise requires exclude_guest */ - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 1); - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 0); - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip == 1, evsel); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), evsel); + TEST_ASSERT_EVSEL("wrong core.nr_members", evsel->core.nr_members == 2, evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 0, evsel); + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); /* instructions:kp + p */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - /* use of precise requires exclude_guest */ - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 2); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip == 2, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 1, evsel); + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); } return TEST_OK; } @@ -1136,96 +1189,92 @@ static int test__group4(struct evlist *evlist __maybe_unused) static int test__group5(struct evlist *evlist __maybe_unused) { struct evsel *evsel = NULL, *leader; - int ret; - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == (5 * num_core_entries())); - TEST_ASSERT_VAL("wrong number of groups", - evlist__nr_groups(evlist) == (2 * num_core_entries())); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == (5 * num_core_entries(evlist)), + evlist); + TEST_ASSERT_EVLIST("wrong number of groups", + evlist__nr_groups(evlist) == (2 * num_core_entries(evlist)), + evlist); - for (int i = 0; i < num_core_entries(); i++) { + for (int i = 0; i < num_core_entries(evlist); i++) { /* cycles + G */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 0); - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), evsel); + TEST_ASSERT_EVSEL("wrong core.nr_members", evsel->core.nr_members == 2, evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 0, evsel); + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); /* instructions + G */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 1, evsel); + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); } - for (int i = 0; i < num_core_entries(); i++) { + for (int i = 0; i < num_core_entries(evlist); i++) { /* cycles:G */ evsel = leader = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 0); - TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), evsel); + TEST_ASSERT_EVSEL("wrong core.nr_members", evsel->core.nr_members == 2, evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 0, evsel); + TEST_ASSERT_EVSEL("wrong sample_read", !evsel->sample_read, evsel); /* instructions:G */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 1, evsel); } - for (int i = 0; i < num_core_entries(); i++) { + for (int i = 0; i < num_core_entries(evlist); i++) { /* cycles */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), evsel); } return TEST_OK; } @@ -1234,45 +1283,43 @@ static int test__group_gh1(struct evlist *evlist) { struct evsel *evsel = NULL, *leader; - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == (2 * num_core_entries())); - TEST_ASSERT_VAL("wrong number of groups", - evlist__nr_groups(evlist) == num_core_entries()); - - for (int i = 0; i < num_core_entries(); i++) { - int ret; + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == (2 * num_core_entries(evlist)), + evlist); + TEST_ASSERT_EVLIST("wrong number of groups", + evlist__nr_groups(evlist) == num_core_entries(evlist), + evlist); + for (int i = 0; i < num_core_entries(evlist); i++) { /* cycles + :H group modifier */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 0); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), evsel); + TEST_ASSERT_EVSEL("wrong core.nr_members", evsel->core.nr_members == 2, evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 0, evsel); /* cache-misses:G + :H group modifier */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CACHE_MISSES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 1, evsel); } return TEST_OK; } @@ -1281,45 +1328,43 @@ static int test__group_gh2(struct evlist *evlist) { struct evsel *evsel = NULL, *leader; - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == (2 * num_core_entries())); - TEST_ASSERT_VAL("wrong number of groups", - evlist__nr_groups(evlist) == num_core_entries()); - - for (int i = 0; i < num_core_entries(); i++) { - int ret; + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == (2 * num_core_entries(evlist)), + evlist); + TEST_ASSERT_EVLIST("wrong number of groups", + evlist__nr_groups(evlist) == num_core_entries(evlist), + evlist); + for (int i = 0; i < num_core_entries(evlist); i++) { /* cycles + :G group modifier */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 0); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), evsel); + TEST_ASSERT_EVSEL("wrong core.nr_members", evsel->core.nr_members == 2, evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 0, evsel); /* cache-misses:H + :G group modifier */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CACHE_MISSES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 1, evsel); } return TEST_OK; } @@ -1328,45 +1373,43 @@ static int test__group_gh3(struct evlist *evlist) { struct evsel *evsel = NULL, *leader; - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == (2 * num_core_entries())); - TEST_ASSERT_VAL("wrong number of groups", - evlist__nr_groups(evlist) == num_core_entries()); - - for (int i = 0; i < num_core_entries(); i++) { - int ret; + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == (2 * num_core_entries(evlist)), + evlist); + TEST_ASSERT_EVLIST("wrong number of groups", + evlist__nr_groups(evlist) == num_core_entries(evlist), + evlist); + for (int i = 0; i < num_core_entries(evlist); i++) { /* cycles:G + :u group modifier */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 0); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), evsel); + TEST_ASSERT_EVSEL("wrong core.nr_members", evsel->core.nr_members == 2, evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 0, evsel); /* cache-misses:H + :u group modifier */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CACHE_MISSES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 1, evsel); } return TEST_OK; } @@ -1375,45 +1418,43 @@ static int test__group_gh4(struct evlist *evlist) { struct evsel *evsel = NULL, *leader; - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == (2 * num_core_entries())); - TEST_ASSERT_VAL("wrong number of groups", - evlist__nr_groups(evlist) == num_core_entries()); - - for (int i = 0; i < num_core_entries(); i++) { - int ret; + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == (2 * num_core_entries(evlist)), + evlist); + TEST_ASSERT_EVLIST("wrong number of groups", + evlist__nr_groups(evlist) == num_core_entries(evlist), + evlist); + for (int i = 0; i < num_core_entries(evlist); i++) { /* cycles:G + :uG group modifier */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); - TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 0); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__is_group_leader(evsel), evsel); + TEST_ASSERT_EVSEL("wrong core.nr_members", evsel->core.nr_members == 2, evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 0, evsel); /* cache-misses:H + :uG group modifier */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); - TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CACHE_MISSES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); + TEST_ASSERT_EVSEL("wrong group_idx", evsel__group_idx(evsel) == 1, evsel); } return TEST_OK; } @@ -1422,58 +1463,54 @@ static int test__leader_sample1(struct evlist *evlist) { struct evsel *evsel = NULL, *leader; - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == (3 * num_core_entries())); - - for (int i = 0; i < num_core_entries(); i++) { - int ret; + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == (3 * num_core_entries(evlist)), + evlist); + for (int i = 0; i < num_core_entries(evlist); i++) { /* cycles - sampling group leader */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); - TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); + TEST_ASSERT_EVSEL("wrong sample_read", evsel->sample_read, evsel); /* cache-misses - not sampling */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); - TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CACHE_MISSES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); + TEST_ASSERT_EVSEL("wrong sample_read", evsel->sample_read, evsel); /* branch-misses - not sampling */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); - TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", !evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); + TEST_ASSERT_EVSEL("wrong sample_read", evsel->sample_read, evsel); } return TEST_OK; } @@ -1482,43 +1519,40 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) { struct evsel *evsel = NULL, *leader; - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == (2 * num_core_entries())); - - for (int i = 0; i < num_core_entries(); i++) { - int ret; + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == (2 * num_core_entries(evlist)), + evlist); + for (int i = 0; i < num_core_entries(evlist); i++) { /* instructions - sampling group leader */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); - TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); + TEST_ASSERT_EVSEL("wrong sample_read", evsel->sample_read, evsel); /* branch-misses - not sampling */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); - TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES), + evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong exclude guest", !evsel->core.attr.exclude_guest, evsel); + TEST_ASSERT_EVSEL("wrong exclude host", !evsel->core.attr.exclude_host, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); + TEST_ASSERT_EVSEL("wrong sample_read", evsel->sample_read, evsel); } return TEST_OK; } @@ -1527,16 +1561,17 @@ static int test__checkevent_pinned_modifier(struct evlist *evlist) { struct evsel *evsel = NULL; - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == num_core_entries()); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); - for (int i = 0; i < num_core_entries(); i++) { + for (int i = 0; i < num_core_entries(evlist); i++) { evsel = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong pinned", evsel->core.attr.pinned); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong pinned", evsel->core.attr.pinned, evsel); } return test__checkevent_symbolic_name(evlist); } @@ -1545,39 +1580,35 @@ static int test__pinned_group(struct evlist *evlist) { struct evsel *evsel = NULL, *leader; - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == (3 * num_core_entries())); - - for (int i = 0; i < num_core_entries(); i++) { - int ret; + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == (3 * num_core_entries(evlist)), + evlist); + for (int i = 0; i < num_core_entries(evlist); i++) { /* cycles - group leader */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); /* TODO: The group modifier is not copied to the split group leader. */ if (perf_pmus__num_core_pmus() == 1) - TEST_ASSERT_VAL("wrong pinned", evsel->core.attr.pinned); + TEST_ASSERT_EVSEL("wrong pinned", evsel->core.attr.pinned, evsel); /* cache-misses - can not be pinned, but will go on with the leader */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CACHE_MISSES), + evsel); + TEST_ASSERT_EVSEL("wrong pinned", !evsel->core.attr.pinned, evsel); /* branch-misses - ditto */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES), + evsel); + TEST_ASSERT_EVSEL("wrong pinned", !evsel->core.attr.pinned, evsel); } return TEST_OK; } @@ -1586,11 +1617,14 @@ static int test__checkevent_exclusive_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong exclusive", evsel->core.attr.exclusive); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", evsel->core.attr.precise_ip, evsel); + TEST_ASSERT_EVSEL("wrong exclusive", evsel->core.attr.exclusive, evsel); return test__checkevent_symbolic_name(evlist); } @@ -1599,39 +1633,35 @@ static int test__exclusive_group(struct evlist *evlist) { struct evsel *evsel = NULL, *leader; - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == 3 * num_core_entries()); - - for (int i = 0; i < num_core_entries(); i++) { - int ret; + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == 3 * num_core_entries(evlist), + evlist); + for (int i = 0; i < num_core_entries(evlist); i++) { /* cycles - group leader */ evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel)); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + TEST_ASSERT_EVSEL("wrong group name", !evsel->group_name, evsel); + TEST_ASSERT_EVSEL("wrong leader", evsel__has_leader(evsel, leader), evsel); /* TODO: The group modifier is not copied to the split group leader. */ if (perf_pmus__num_core_pmus() == 1) - TEST_ASSERT_VAL("wrong exclusive", evsel->core.attr.exclusive); + TEST_ASSERT_EVSEL("wrong exclusive", evsel->core.attr.exclusive, evsel); /* cache-misses - can not be pinned, but will go on with the leader */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.exclusive); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CACHE_MISSES), + evsel); + TEST_ASSERT_EVSEL("wrong exclusive", !evsel->core.attr.exclusive, evsel); /* branch-misses - ditto */ evsel = evsel__next(evsel); - ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.exclusive); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES), + evsel); + TEST_ASSERT_EVSEL("wrong exclusive", !evsel->core.attr.exclusive, evsel); } return TEST_OK; } @@ -1639,13 +1669,13 @@ static int test__checkevent_breakpoint_len(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 0)); - TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) == - evsel->core.attr.bp_type); - TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_1 == - evsel->core.attr.bp_len); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); + TEST_ASSERT_EVSEL("wrong bp_type", + (HW_BREAKPOINT_R | HW_BREAKPOINT_W) == evsel->core.attr.bp_type, + evsel); + TEST_ASSERT_EVSEL("wrong bp_len", HW_BREAKPOINT_LEN_1 == evsel->core.attr.bp_len, evsel); return TEST_OK; } @@ -1654,13 +1684,11 @@ static int test__checkevent_breakpoint_len_w(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 0)); - TEST_ASSERT_VAL("wrong bp_type", HW_BREAKPOINT_W == - evsel->core.attr.bp_type); - TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_2 == - evsel->core.attr.bp_len); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 0 == evsel->core.attr.config, evsel); + TEST_ASSERT_EVSEL("wrong bp_type", HW_BREAKPOINT_W == evsel->core.attr.bp_type, evsel); + TEST_ASSERT_EVSEL("wrong bp_len", HW_BREAKPOINT_LEN_2 == evsel->core.attr.bp_len, evsel); return TEST_OK; } @@ -1670,10 +1698,11 @@ test__checkevent_breakpoint_len_rw_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong exclude_user", !evsel->core.attr.exclude_user, evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); + TEST_ASSERT_EVSEL("wrong exclude_hv", evsel->core.attr.exclude_hv, evsel); + TEST_ASSERT_EVSEL("wrong precise_ip", !evsel->core.attr.precise_ip, evsel); return test__checkevent_breakpoint_rw(evlist); } @@ -1682,10 +1711,10 @@ static int test__checkevent_precise_max_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", - evlist->core.nr_entries == 1 + num_core_entries()); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_SW_TASK_CLOCK)); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == 1 + num_core_entries(evlist), + evlist); + TEST_ASSERT_EVSEL("wrong type/config", evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK), evsel); return TEST_OK; } @@ -1693,7 +1722,10 @@ static int test__checkevent_config_symbol(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "insn")); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); + TEST_ASSERT_EVSEL("wrong name setting", evsel__name_is(evsel, "insn"), evsel); return TEST_OK; } @@ -1701,7 +1733,8 @@ static int test__checkevent_config_raw(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "rawpmu")); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong name setting", evsel__name_is(evsel, "rawpmu"), evsel); return TEST_OK; } @@ -1709,7 +1742,8 @@ static int test__checkevent_config_num(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "numpmu")); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong name setting", evsel__name_is(evsel, "numpmu"), evsel); return TEST_OK; } @@ -1717,18 +1751,16 @@ static int test__checkevent_config_cache(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "cachepmu")); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); + TEST_ASSERT_EVSEL("wrong name setting", evsel__name_is(evsel, "cachepmu"), evsel); return test__checkevent_genhw(evlist); } -static bool test__pmu_cpu_valid(void) +static bool test__pmu_default_core_event_valid(void) { - return !!perf_pmus__find("cpu"); -} - -static bool test__pmu_cpu_event_valid(void) -{ - struct perf_pmu *pmu = perf_pmus__find("cpu"); + struct perf_pmu *pmu = perf_pmus__find_core_pmu(); if (!pmu) return false; @@ -1745,7 +1777,56 @@ static int test__intel_pt(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong name setting", evsel__name_is(evsel, "intel_pt//u")); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong name setting", evsel__name_is(evsel, "intel_pt//u"), evsel); + return TEST_OK; +} + +static bool test__acr_valid(void) +{ + struct perf_pmu *pmu = NULL; + + while ((pmu = perf_pmus__scan_core(pmu)) != NULL) { + if (perf_pmu__has_format(pmu, "acr_mask")) + return true; + } + + return false; +} + +static int test__ratio_to_prev(struct evlist *evlist) +{ + struct evsel *evsel; + + TEST_ASSERT_VAL("wrong number of entries", 2 * perf_pmus__num_core_pmus() == evlist->core.nr_entries); + + evlist__for_each_entry(evlist, evsel) { + if (!perf_pmu__has_format(evsel->pmu, "acr_mask")) + return TEST_OK; + + if (evsel == evlist__first(evlist)) { + TEST_ASSERT_VAL("wrong config2", 0 == evsel->core.attr.config2); + TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 2); + TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 0); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), + evsel); + } else { + TEST_ASSERT_VAL("wrong config2", 0 == evsel->core.attr.config2); + TEST_ASSERT_VAL("wrong leader", !evsel__is_group_leader(evsel)); + TEST_ASSERT_VAL("wrong core.nr_members", evsel->core.nr_members == 0); + TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); + TEST_ASSERT_EVSEL("unexpected event", + evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS), + evsel); + } + /* + * The period value gets configured within evlist__config, + * while this test executes only parse events method. + */ + TEST_ASSERT_VAL("wrong period", 0 == evsel->core.attr.sample_period); + } return TEST_OK; } @@ -1753,9 +1834,13 @@ static int test__checkevent_complex_name(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong complex name parsing", - evsel__name_is(evsel, - "COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks")); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); + TEST_ASSERT_EVSEL("wrong complex name parsing", + evsel__name_is(evsel, + "COMPLEX_CYCLES_NAME:orig=cpu-cycles,desc=chip-clock-ticks"), + evsel); return TEST_OK; } @@ -1763,61 +1848,60 @@ static int test__checkevent_raw_pmu(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", test_config(evsel, 0x1a)); + TEST_ASSERT_EVLIST("wrong number of entries", 1 == evlist->core.nr_entries, evlist); + TEST_ASSERT_EVSEL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type, evsel); + TEST_ASSERT_EVSEL("wrong config", 0x1a == evsel->core.attr.config, evsel); return TEST_OK; } static int test__sym_event_slash(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - int ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - - if (ret) - return ret; - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); + TEST_ASSERT_EVSEL("unexpected event", evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), evsel); + TEST_ASSERT_EVSEL("wrong exclude_kernel", evsel->core.attr.exclude_kernel, evsel); return TEST_OK; } static int test__sym_event_dc(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - int ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - if (ret) - return ret; - - TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); + TEST_ASSERT_EVSEL("unexpected event", evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), evsel); + TEST_ASSERT_EVSEL("wrong exclude_user", evsel->core.attr.exclude_user, evsel); return TEST_OK; } static int test__term_equal_term(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - int ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - - if (ret) - return ret; - TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "name") == 0); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); + TEST_ASSERT_EVSEL("unexpected event", evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), evsel); + TEST_ASSERT_EVSEL("wrong name setting", strcmp(evsel->name, "name") == 0, evsel); return TEST_OK; } static int test__term_equal_legacy(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - int ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles"); - - if (ret) - return ret; - TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "l1d") == 0); + TEST_ASSERT_EVLIST("wrong number of entries", + evlist->core.nr_entries == num_core_entries(evlist), + evlist); + TEST_ASSERT_EVSEL("unexpected event", evsel__match(evsel, HARDWARE, HW_CPU_CYCLES), evsel); + TEST_ASSERT_EVSEL("wrong name setting", strcmp(evsel->name, "l1d") == 0, evsel); return TEST_OK; } -#ifdef HAVE_LIBTRACEEVENT static int count_tracepoints(void) { struct dirent *events_ent; @@ -1871,7 +1955,6 @@ static int test__all_tracepoints(struct evlist *evlist) return test__checkevent_tracepoint_multi(evlist); } -#endif /* HAVE_LIBTRACEVENT */ struct evlist_test { const char *name; @@ -1880,7 +1963,6 @@ struct evlist_test { }; static const struct evlist_test test__events[] = { -#ifdef HAVE_LIBTRACEEVENT { .name = "syscalls:sys_enter_openat", .check = test__checkevent_tracepoint, @@ -1891,7 +1973,6 @@ static const struct evlist_test test__events[] = { .check = test__checkevent_tracepoint_multi, /* 1 */ }, -#endif { .name = "r1a", .check = test__checkevent_raw, @@ -1908,7 +1989,7 @@ static const struct evlist_test test__events[] = { /* 4 */ }, { - .name = "cycles/period=100000,config2/", + .name = "cpu-cycles/period=100000,config2/", .check = test__checkevent_symbolic_name_config, /* 5 */ }, @@ -1942,7 +2023,6 @@ static const struct evlist_test test__events[] = { .check = test__checkevent_breakpoint_w, /* 1 */ }, -#ifdef HAVE_LIBTRACEEVENT { .name = "syscalls:sys_enter_openat:k", .check = test__checkevent_tracepoint_modifier, @@ -1953,7 +2033,6 @@ static const struct evlist_test test__events[] = { .check = test__checkevent_tracepoint_multi_modifier, /* 3 */ }, -#endif { .name = "r1a:kp", .check = test__checkevent_raw_modifier, @@ -1999,13 +2078,11 @@ static const struct evlist_test test__events[] = { .check = test__checkevent_breakpoint_w_modifier, /* 2 */ }, -#ifdef HAVE_LIBTRACEEVENT { .name = "r1,syscalls:sys_enter_openat:k,1:1:hp", .check = test__checkevent_list, /* 3 */ }, -#endif { .name = "instructions:G", .check = test__checkevent_exclude_host_modifier, @@ -2027,61 +2104,57 @@ static const struct evlist_test test__events[] = { /* 7 */ }, { - .name = "{instructions:k,cycles:upp}", + .name = "{instructions:k,cpu-cycles:upp}", .check = test__group1, /* 8 */ }, { - .name = "{faults:k,branches}:u,cycles:k", + .name = "{faults:k,branches}:u,cpu-cycles:k", .check = test__group2, /* 9 */ }, -#ifdef HAVE_LIBTRACEEVENT { - .name = "group1{syscalls:sys_enter_openat:H,cycles:kppp},group2{cycles,1:3}:G,instructions:u", + .name = "group1{syscalls:sys_enter_openat:H,cpu-cycles:kppp},group2{cpu-cycles,1:3}:G,instructions:u", .check = test__group3, /* 0 */ }, -#endif { - .name = "{cycles:u,instructions:kp}:p", + .name = "{cpu-cycles:u,instructions:kp}:p", .check = test__group4, /* 1 */ }, { - .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles", + .name = "{cpu-cycles,instructions}:G,{cpu-cycles:G,instructions:G},cpu-cycles", .check = test__group5, /* 2 */ }, -#ifdef HAVE_LIBTRACEEVENT { .name = "*:*", .check = test__all_tracepoints, /* 3 */ }, -#endif { - .name = "{cycles,cache-misses:G}:H", + .name = "{cpu-cycles,cache-misses:G}:H", .check = test__group_gh1, /* 4 */ }, { - .name = "{cycles,cache-misses:H}:G", + .name = "{cpu-cycles,cache-misses:H}:G", .check = test__group_gh2, /* 5 */ }, { - .name = "{cycles:G,cache-misses:H}:u", + .name = "{cpu-cycles:G,cache-misses:H}:u", .check = test__group_gh3, /* 6 */ }, { - .name = "{cycles:G,cache-misses:H}:uG", + .name = "{cpu-cycles:G,cache-misses:H}:uG", .check = test__group_gh4, /* 7 */ }, { - .name = "{cycles,cache-misses,branch-misses}:S", + .name = "{cpu-cycles,cache-misses,branch-misses}:S", .check = test__leader_sample1, /* 8 */ }, @@ -2096,7 +2169,7 @@ static const struct evlist_test test__events[] = { /* 0 */ }, { - .name = "{cycles,cache-misses,branch-misses}:D", + .name = "{cpu-cycles,cache-misses,branch-misses}:D", .check = test__pinned_group, /* 1 */ }, @@ -2115,7 +2188,7 @@ static const struct evlist_test test__events[] = { .check = test__checkevent_breakpoint_len_rw_modifier, /* 4 */ }, -#if defined(__s390x__) && defined(HAVE_LIBTRACEEVENT) +#if defined(__s390x__) { .name = "kvm-s390:kvm_s390_create_vm", .check = test__checkevent_tracepoint, @@ -2134,7 +2207,7 @@ static const struct evlist_test test__events[] = { /* 6 */ }, { - .name = "task-clock:P,cycles", + .name = "task-clock:P,cpu-cycles", .check = test__checkevent_precise_max_modifier, /* 7 */ }, @@ -2165,17 +2238,17 @@ static const struct evlist_test test__events[] = { /* 2 */ }, { - .name = "cycles/name='COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks'/Duk", + .name = "cpu-cycles/name='COMPLEX_CYCLES_NAME:orig=cpu-cycles,desc=chip-clock-ticks'/Duk", .check = test__checkevent_complex_name, /* 3 */ }, { - .name = "cycles//u", + .name = "cpu-cycles//u", .check = test__sym_event_slash, /* 4 */ }, { - .name = "cycles:k", + .name = "cpu-cycles:k", .check = test__sym_event_dc, /* 5 */ }, @@ -2185,17 +2258,17 @@ static const struct evlist_test test__events[] = { /* 6 */ }, { - .name = "{cycles,cache-misses,branch-misses}:e", + .name = "{cpu-cycles,cache-misses,branch-misses}:e", .check = test__exclusive_group, /* 7 */ }, { - .name = "cycles/name=name/", + .name = "cpu-cycles/name=name/", .check = test__term_equal_term, /* 8 */ }, { - .name = "cycles/name=l1d/", + .name = "cpu-cycles/name=l1d/", .check = test__term_equal_legacy, /* 9 */ }, @@ -2269,37 +2342,39 @@ static const struct evlist_test test__events[] = { .check = test__checkevent_breakpoint_2_events, /* 3 */ }, -#ifdef HAVE_LIBTRACEEVENT { .name = "9p:9p_client_req", .check = test__checkevent_tracepoint, /* 4 */ }, -#endif + { + .name = "{cycles,instructions/period=200000,ratio-to-prev=2.0/}", + .valid = test__acr_valid, + .check = test__ratio_to_prev, + /* 5 */ + }, + }; static const struct evlist_test test__events_pmu[] = { { - .name = "cpu/config=10,config1=1,config2=3,period=1000/u", - .valid = test__pmu_cpu_valid, + .name = "default_core/config=10,config1=1,config2=3,period=1000/u", .check = test__checkevent_pmu, /* 0 */ }, { - .name = "cpu/config=1,name=krava/u,cpu/config=2/u", - .valid = test__pmu_cpu_valid, + .name = "default_core/config=1,name=krava/u,default_core/config=2/u", .check = test__checkevent_pmu_name, /* 1 */ }, { - .name = "cpu/config=1,call-graph=fp,time,period=100000/,cpu/config=2,call-graph=no,time=0,period=2000/", - .valid = test__pmu_cpu_valid, + .name = "default_core/config=1,call-graph=fp,time,period=100000/,default_core/config=2,call-graph=no,time=0,period=2000/", .check = test__checkevent_pmu_partial_time_callgraph, /* 2 */ }, { - .name = "cpu/name='COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks',period=0x1,event=0x2/ukp", - .valid = test__pmu_cpu_event_valid, + .name = "default_core/name='COMPLEX_CYCLES_NAME:orig=cpu-cycles,desc=chip-clock-ticks',period=0x1,event=0x2/ukp", + .valid = test__pmu_default_core_event_valid, .check = test__checkevent_complex_name, /* 3 */ }, @@ -2314,158 +2389,132 @@ static const struct evlist_test test__events_pmu[] = { /* 5 */ }, { - .name = "cpu/L1-dcache-load-miss/", - .valid = test__pmu_cpu_valid, + .name = "default_core/L1-dcache-load-miss/", .check = test__checkevent_genhw, /* 6 */ }, { - .name = "cpu/L1-dcache-load-miss/kp", - .valid = test__pmu_cpu_valid, + .name = "default_core/L1-dcache-load-miss/kp", .check = test__checkevent_genhw_modifier, /* 7 */ }, { - .name = "cpu/L1-dcache-misses,name=cachepmu/", - .valid = test__pmu_cpu_valid, + .name = "default_core/L1-dcache-misses,name=cachepmu/", .check = test__checkevent_config_cache, /* 8 */ }, { - .name = "cpu/instructions/", - .valid = test__pmu_cpu_valid, + .name = "default_core/instructions/", .check = test__checkevent_symbolic_name, /* 9 */ }, { - .name = "cpu/cycles,period=100000,config2/", - .valid = test__pmu_cpu_valid, + .name = "default_core/cycles,period=100000,config2/", .check = test__checkevent_symbolic_name_config, /* 0 */ }, { - .name = "cpu/instructions/h", - .valid = test__pmu_cpu_valid, + .name = "default_core/instructions/h", .check = test__checkevent_symbolic_name_modifier, /* 1 */ }, { - .name = "cpu/instructions/G", - .valid = test__pmu_cpu_valid, + .name = "default_core/instructions/G", .check = test__checkevent_exclude_host_modifier, /* 2 */ }, { - .name = "cpu/instructions/H", - .valid = test__pmu_cpu_valid, + .name = "default_core/instructions/H", .check = test__checkevent_exclude_guest_modifier, /* 3 */ }, { - .name = "{cpu/instructions/k,cpu/cycles/upp}", - .valid = test__pmu_cpu_valid, + .name = "{default_core/instructions/k,default_core/cycles/upp}", .check = test__group1, /* 4 */ }, { - .name = "{cpu/cycles/u,cpu/instructions/kp}:p", - .valid = test__pmu_cpu_valid, + .name = "{default_core/cycles/u,default_core/instructions/kp}:p", .check = test__group4, /* 5 */ }, { - .name = "{cpu/cycles/,cpu/cache-misses/G}:H", - .valid = test__pmu_cpu_valid, + .name = "{default_core/cycles/,default_core/cache-misses/G}:H", .check = test__group_gh1, /* 6 */ }, { - .name = "{cpu/cycles/,cpu/cache-misses/H}:G", - .valid = test__pmu_cpu_valid, + .name = "{default_core/cycles/,default_core/cache-misses/H}:G", .check = test__group_gh2, /* 7 */ }, { - .name = "{cpu/cycles/G,cpu/cache-misses/H}:u", - .valid = test__pmu_cpu_valid, + .name = "{default_core/cycles/G,default_core/cache-misses/H}:u", .check = test__group_gh3, /* 8 */ }, { - .name = "{cpu/cycles/G,cpu/cache-misses/H}:uG", - .valid = test__pmu_cpu_valid, + .name = "{default_core/cycles/G,default_core/cache-misses/H}:uG", .check = test__group_gh4, /* 9 */ }, { - .name = "{cpu/cycles/,cpu/cache-misses/,cpu/branch-misses/}:S", - .valid = test__pmu_cpu_valid, + .name = "{default_core/cycles/,default_core/cache-misses/,default_core/branch-misses/}:S", .check = test__leader_sample1, /* 0 */ }, { - .name = "{cpu/instructions/,cpu/branch-misses/}:Su", - .valid = test__pmu_cpu_valid, + .name = "{default_core/instructions/,default_core/branch-misses/}:Su", .check = test__leader_sample2, /* 1 */ }, { - .name = "cpu/instructions/uDp", - .valid = test__pmu_cpu_valid, + .name = "default_core/instructions/uDp", .check = test__checkevent_pinned_modifier, /* 2 */ }, { - .name = "{cpu/cycles/,cpu/cache-misses/,cpu/branch-misses/}:D", - .valid = test__pmu_cpu_valid, + .name = "{default_core/cycles/,default_core/cache-misses/,default_core/branch-misses/}:D", .check = test__pinned_group, /* 3 */ }, { - .name = "cpu/instructions/I", - .valid = test__pmu_cpu_valid, + .name = "default_core/instructions/I", .check = test__checkevent_exclude_idle_modifier, /* 4 */ }, { - .name = "cpu/instructions/kIG", - .valid = test__pmu_cpu_valid, + .name = "default_core/instructions/kIG", .check = test__checkevent_exclude_idle_modifier_1, /* 5 */ }, { - .name = "cpu/cycles/u", - .valid = test__pmu_cpu_valid, + .name = "default_core/cycles/u", .check = test__sym_event_slash, /* 6 */ }, { - .name = "cpu/cycles/k", - .valid = test__pmu_cpu_valid, + .name = "default_core/cycles/k", .check = test__sym_event_dc, /* 7 */ }, { - .name = "cpu/instructions/uep", - .valid = test__pmu_cpu_valid, + .name = "default_core/instructions/uep", .check = test__checkevent_exclusive_modifier, /* 8 */ }, { - .name = "{cpu/cycles/,cpu/cache-misses/,cpu/branch-misses/}:e", - .valid = test__pmu_cpu_valid, + .name = "{default_core/cycles/,default_core/cache-misses/,default_core/branch-misses/}:e", .check = test__exclusive_group, /* 9 */ }, { - .name = "cpu/cycles,name=name/", - .valid = test__pmu_cpu_valid, + .name = "default_core/cycles,name=name/", .check = test__term_equal_term, /* 0 */ }, { - .name = "cpu/cycles,name=l1d/", - .valid = test__pmu_cpu_valid, + .name = "default_core/cycles,name=l1d/", .check = test__term_equal_legacy, /* 1 */ }, @@ -2478,7 +2527,7 @@ struct terms_test { static const struct terms_test test__terms[] = { [0] = { - .str = "config=10,config1,config2=3,config3=4,umask=1,read,r0xead", + .str = "config=10,config1,config2=3,config3=4,config4=5,umask=1,read,r0xead", .check = test__checkterms_simple, }, }; @@ -2555,15 +2604,30 @@ static int combine_test_results(int existing, int latest) static int test_events(const struct evlist_test *events, int cnt) { int ret = TEST_OK; + struct perf_pmu *core_pmu = perf_pmus__find_core_pmu(); for (int i = 0; i < cnt; i++) { - const struct evlist_test *e = &events[i]; + struct evlist_test e = events[i]; int test_ret; + const char *pos = e.name; + char buf[1024], *buf_pos = buf, *end; + + while ((end = strstr(pos, "default_core"))) { + size_t len = end - pos; + + strncpy(buf_pos, pos, len); + pos = end + 12; + buf_pos += len; + strcpy(buf_pos, core_pmu->name); + buf_pos += strlen(core_pmu->name); + } + strcpy(buf_pos, pos); - pr_debug("running test %d '%s'\n", i, e->name); - test_ret = test_event(e); + e.name = buf; + pr_debug("running test %d '%s'\n", i, e.name); + test_ret = test_event(&e); if (test_ret != TEST_OK) { - pr_debug("Event test failure: test %d '%s'", i, e->name); + pr_debug("Event test failure: test %d '%s'", i, e.name); ret = combine_test_results(ret, test_ret); } } @@ -2583,7 +2647,7 @@ static int test_term(const struct terms_test *t) parse_events_terms__init(&terms); - ret = parse_events_terms(&terms, t->str, /*input=*/ NULL); + ret = parse_events_terms(&terms, t->str); if (ret) { pr_debug("failed to parse terms '%s', err %d\n", t->str , ret); @@ -2804,8 +2868,9 @@ static int test__checkevent_pmu_events_alias(struct evlist *evlist) struct evsel *evsel1 = evlist__first(evlist); struct evsel *evsel2 = evlist__last(evlist); - TEST_ASSERT_VAL("wrong type", evsel1->core.attr.type == evsel2->core.attr.type); - TEST_ASSERT_VAL("wrong config", evsel1->core.attr.config == evsel2->core.attr.config); + TEST_ASSERT_EVSEL("wrong type", evsel1->core.attr.type == evsel2->core.attr.type, evsel1); + TEST_ASSERT_EVSEL("wrong config", evsel1->core.attr.config == evsel2->core.attr.config, + evsel1); return TEST_OK; } diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c index 2c28fb50dc24..6bbc209a5c6a 100644 --- a/tools/perf/tests/parse-metric.c +++ b/tools/perf/tests/parse-metric.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/compiler.h> +#include <errno.h> #include <string.h> #include <perf/cpumap.h> #include <perf/evlist.h> @@ -40,20 +41,17 @@ static void load_runtime_stat(struct evlist *evlist, struct value *vals) count = find_value(evsel->name, vals); evsel->supported = true; evsel->stats->aggr->counts.val = count; - if (evsel__name_is(evsel, "duration_time")) - update_stats(&walltime_nsecs_stats, count); } } -static double compute_single(struct rblist *metric_events, struct evlist *evlist, - const char *name) +static double compute_single(struct evlist *evlist, const char *name) { struct metric_expr *mexp; struct metric_event *me; struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - me = metricgroup__lookup(metric_events, evsel, false); + me = metricgroup__lookup(&evlist->metric_events, evsel, false); if (me != NULL) { list_for_each_entry (mexp, &me->head, nd) { if (strcmp(mexp->metric_name, name)) @@ -69,9 +67,6 @@ static int __compute_metric(const char *name, struct value *vals, const char *name1, double *ratio1, const char *name2, double *ratio2) { - struct rblist metric_events = { - .nr_entries = 0, - }; const struct pmu_metrics_table *pme_test; struct perf_cpu_map *cpus; struct evlist *evlist; @@ -95,8 +90,7 @@ static int __compute_metric(const char *name, struct value *vals, /* Parse the metric into metric_events list. */ pme_test = find_core_metrics_table("testarch", "testcpu"); - err = metricgroup__parse_groups_test(evlist, pme_test, name, - &metric_events); + err = metricgroup__parse_groups_test(evlist, pme_test, name); if (err) goto out; @@ -109,13 +103,12 @@ static int __compute_metric(const char *name, struct value *vals, /* And execute the metric */ if (name1 && ratio1) - *ratio1 = compute_single(&metric_events, evlist, name1); + *ratio1 = compute_single(evlist, name1); if (name2 && ratio2) - *ratio2 = compute_single(&metric_events, evlist, name2); + *ratio2 = compute_single(evlist, name2); out: /* ... cleanup. */ - metricgroup__rblist_exit(&metric_events); evlist__free_stats(evlist); perf_cpu_map__put(cpus); evlist__delete(evlist); diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c index 202f0a9a6796..50e68b7d43aa 100644 --- a/tools/perf/tests/parse-no-sample-id-all.c +++ b/tools/perf/tests/parse-no-sample-id-all.c @@ -13,6 +13,7 @@ static int process_event(struct evlist **pevlist, union perf_event *event) { struct perf_sample sample; + int ret; if (event->header.type == PERF_RECORD_HEADER_ATTR) { if (perf_event__process_attr(NULL, event, pevlist)) { @@ -28,7 +29,10 @@ static int process_event(struct evlist **pevlist, union perf_event *event) if (!*pevlist) return -1; - if (evlist__parse_sample(*pevlist, event, &sample)) { + perf_sample__init(&sample, /*all=*/false); + ret = evlist__parse_sample(*pevlist, event, &sample); + perf_sample__exit(&sample); + if (ret) { pr_debug("evlist__parse_sample failed\n"); return -1; } diff --git a/tools/perf/tests/pe-file-parsing.c b/tools/perf/tests/pe-file-parsing.c index fff58b220c07..30c7da79e109 100644 --- a/tools/perf/tests/pe-file-parsing.c +++ b/tools/perf/tests/pe-file-parsing.c @@ -24,7 +24,7 @@ static int run_dir(const char *d) { char filename[PATH_MAX]; char debugfile[PATH_MAX]; - struct build_id bid; + struct build_id bid = { .size = 0, }; char debuglink[PATH_MAX]; char expect_build_id[] = { 0x5a, 0x0f, 0xd8, 0x82, 0xb5, 0x30, 0x84, 0x22, diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 1c4feec1adff..efbd9cd60c63 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -13,15 +13,19 @@ #include "tests.h" #include "util/mmap.h" #include "util/sample.h" +#include "util/cpumap.h" static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t *maskp) { - int i, cpu = -1, nrcpus = 1024; + int i, cpu = -1; + int nrcpus = cpu__max_cpu().cpu; + size_t size = CPU_ALLOC_SIZE(nrcpus); + realloc: - CPU_ZERO(maskp); + CPU_ZERO_S(size, maskp); - if (sched_getaffinity(pid, sizeof(*maskp), maskp) == -1) { - if (errno == EINVAL && nrcpus < (1024 << 8)) { + if (sched_getaffinity(pid, size, maskp) == -1) { + if (errno == EINVAL && nrcpus < (cpu__max_cpu().cpu << 8)) { nrcpus = nrcpus << 2; goto realloc; } @@ -30,11 +34,11 @@ realloc: } for (i = 0; i < nrcpus; i++) { - if (CPU_ISSET(i, maskp)) { + if (CPU_ISSET_S(i, size, maskp)) { if (cpu == -1) cpu = i; else - CPU_CLR(i, maskp); + CPU_CLR_S(i, size, maskp); } } @@ -45,14 +49,14 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest { struct record_opts opts = { .target = { - .uid = UINT_MAX, .uses_mmap = true, }, .no_buffering = true, .mmap_pages = 256, }; - cpu_set_t cpu_mask; - size_t cpu_mask_size = sizeof(cpu_mask); + int nrcpus = cpu__max_cpu().cpu; + cpu_set_t *cpu_mask; + size_t cpu_mask_size; struct evlist *evlist = evlist__new_dummy(); struct evsel *evsel; struct perf_sample sample; @@ -70,11 +74,22 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; char sbuf[STRERR_BUFSIZE]; + cpu_mask = CPU_ALLOC(nrcpus); + if (!cpu_mask) { + pr_debug("failed to create cpumask\n"); + goto out; + } + + cpu_mask_size = CPU_ALLOC_SIZE(nrcpus); + CPU_ZERO_S(cpu_mask_size, cpu_mask); + + perf_sample__init(&sample, /*all=*/false); if (evlist == NULL) /* Fallback for kernels lacking PERF_COUNT_SW_DUMMY */ evlist = evlist__new_default(); if (evlist == NULL) { pr_debug("Not enough memory to create evlist\n"); + CPU_FREE(cpu_mask); goto out; } @@ -111,10 +126,11 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest evsel__set_sample_bit(evsel, TIME); evlist__config(evlist, &opts, NULL); - err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); + err = sched__get_first_possible_cpu(evlist->workload.pid, cpu_mask); if (err < 0) { pr_debug("sched__get_first_possible_cpu: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); + evlist__cancel_workload(evlist); goto out_delete_evlist; } @@ -123,9 +139,10 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest /* * So that we can check perf_sample.cpu on all the samples. */ - if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { + if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, cpu_mask) < 0) { pr_debug("sched_setaffinity: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); + evlist__cancel_workload(evlist); goto out_delete_evlist; } @@ -137,6 +154,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest if (err < 0) { pr_debug("perf_evlist__open: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); + evlist__cancel_workload(evlist); goto out_delete_evlist; } @@ -149,6 +167,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest if (err < 0) { pr_debug("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); + evlist__cancel_workload(evlist); goto out_delete_evlist; } @@ -328,8 +347,10 @@ found_exit: ++errs; } out_delete_evlist: + CPU_FREE(cpu_mask); evlist__delete(evlist); out: + perf_sample__exit(&sample); if (err == -EACCES) return TEST_SKIP; if (err < 0 || errs != 0) diff --git a/tools/perf/tests/perf-targz-src-pkg b/tools/perf/tests/perf-targz-src-pkg index b3075c168cb2..52a90e6bd8af 100755 --- a/tools/perf/tests/perf-targz-src-pkg +++ b/tools/perf/tests/perf-targz-src-pkg @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # Test one of the main kernel Makefile targets to generate a perf sources tarball # suitable for build outside the full kernel sources. diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c index bbe2ddeb9b74..cca41bd37ae3 100644 --- a/tools/perf/tests/perf-time-to-tsc.c +++ b/tools/perf/tests/perf-time-to-tsc.c @@ -90,7 +90,7 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su struct mmap *md; - threads = thread_map__new(-1, getpid(), UINT_MAX); + threads = thread_map__new_by_tid(getpid()); CHECK_NOT_NULL__(threads); cpus = perf_cpu_map__new_online_cpus(); @@ -101,11 +101,11 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su perf_evlist__set_maps(&evlist->core, cpus, threads); - CHECK__(parse_event(evlist, "cycles:u")); + CHECK__(parse_event(evlist, "cpu-cycles:u")); evlist__config(evlist, &opts, NULL); - /* For hybrid "cycles:u", it creates two events */ + /* For hybrid "cpu-cycles:u", it creates two events */ evlist__for_each_entry(evlist, evsel) { evsel->core.attr.comm = 1; evsel->core.attr.disabled = 1; @@ -153,6 +153,7 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su while ((event = perf_mmap__read_event(&md->core)) != NULL) { struct perf_sample sample; + perf_sample__init(&sample, /*all=*/false); if (event->header.type != PERF_RECORD_COMM || (pid_t)event->comm.pid != getpid() || (pid_t)event->comm.tid != getpid()) @@ -170,6 +171,7 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su } next_event: perf_mmap__consume(&md->core); + perf_sample__exit(&sample); } perf_mmap__read_done(&md->core); } diff --git a/tools/perf/tests/pfm.c b/tools/perf/tests/pfm.c index 2e38dfa34b6c..fca4a86452df 100644 --- a/tools/perf/tests/pfm.c +++ b/tools/perf/tests/pfm.c @@ -4,6 +4,7 @@ * * Copyright 2020 Google LLC. */ +#include <errno.h> #include "tests.h" #include "util/debug.h" #include "util/evlist.h" diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index db004d26fcb0..a99716862168 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -22,10 +22,6 @@ struct perf_pmu_test_event { /* used for matching against events from generated pmu-events.c */ struct pmu_event event; - /* used for matching against event aliases */ - /* extra events for aliases */ - const char *alias_str; - /* * Note: For when PublicDescription does not exist in the JSON, we * will have no long_desc in pmu_event.long_desc, but long_desc may @@ -38,7 +34,9 @@ struct perf_pmu_test_event { }; struct perf_pmu_test_pmu { - struct perf_pmu pmu; + const char *pmu_name; + bool pmu_is_uncore; + const char *pmu_id; struct perf_pmu_test_event const *aliases[10]; }; @@ -50,8 +48,6 @@ static const struct perf_pmu_test_event bp_l1_btb_correct = { .desc = "L1 BTB Correction", .topic = "branch", }, - .alias_str = "event=0x8a", - .alias_long_desc = "L1 BTB Correction", }; static const struct perf_pmu_test_event bp_l2_btb_correct = { @@ -62,8 +58,6 @@ static const struct perf_pmu_test_event bp_l2_btb_correct = { .desc = "L2 BTB Correction", .topic = "branch", }, - .alias_str = "event=0x8b", - .alias_long_desc = "L2 BTB Correction", }; static const struct perf_pmu_test_event segment_reg_loads_any = { @@ -74,8 +68,6 @@ static const struct perf_pmu_test_event segment_reg_loads_any = { .desc = "Number of segment register loads", .topic = "other", }, - .alias_str = "event=0x6,period=0x30d40,umask=0x80", - .alias_long_desc = "Number of segment register loads", }; static const struct perf_pmu_test_event dispatch_blocked_any = { @@ -86,8 +78,6 @@ static const struct perf_pmu_test_event dispatch_blocked_any = { .desc = "Memory cluster signals to block micro-op dispatch for any reason", .topic = "other", }, - .alias_str = "event=0x9,period=0x30d40,umask=0x20", - .alias_long_desc = "Memory cluster signals to block micro-op dispatch for any reason", }; static const struct perf_pmu_test_event eist_trans = { @@ -98,8 +88,6 @@ static const struct perf_pmu_test_event eist_trans = { .desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", .topic = "other", }, - .alias_str = "event=0x3a,period=0x30d40", - .alias_long_desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", }; static const struct perf_pmu_test_event l3_cache_rd = { @@ -111,7 +99,6 @@ static const struct perf_pmu_test_event l3_cache_rd = { .long_desc = "Attributable Level 3 cache access, read", .topic = "cache", }, - .alias_str = "event=0x40", .alias_long_desc = "Attributable Level 3 cache access, read", }; @@ -131,11 +118,8 @@ static const struct perf_pmu_test_event uncore_hisi_ddrc_flux_wcmd = { .event = "event=2", .desc = "DDRC write commands", .topic = "uncore", - .long_desc = "DDRC write commands", .pmu = "hisi_sccl,ddrc", }, - .alias_str = "event=0x2", - .alias_long_desc = "DDRC write commands", .matching_pmu = "hisi_sccl1_ddrc2", }; @@ -145,11 +129,8 @@ static const struct perf_pmu_test_event unc_cbo_xsnp_response_miss_eviction = { .event = "event=0x22,umask=0x81", .desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", .topic = "uncore", - .long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", .pmu = "uncore_cbox", }, - .alias_str = "event=0x22,umask=0x81", - .alias_long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", .matching_pmu = "uncore_cbox_0", }; @@ -159,11 +140,8 @@ static const struct perf_pmu_test_event uncore_hyphen = { .event = "event=0xe0", .desc = "UNC_CBO_HYPHEN", .topic = "uncore", - .long_desc = "UNC_CBO_HYPHEN", .pmu = "uncore_cbox", }, - .alias_str = "event=0xe0", - .alias_long_desc = "UNC_CBO_HYPHEN", .matching_pmu = "uncore_cbox_0", }; @@ -173,11 +151,8 @@ static const struct perf_pmu_test_event uncore_two_hyph = { .event = "event=0xc0", .desc = "UNC_CBO_TWO_HYPH", .topic = "uncore", - .long_desc = "UNC_CBO_TWO_HYPH", .pmu = "uncore_cbox", }, - .alias_str = "event=0xc0", - .alias_long_desc = "UNC_CBO_TWO_HYPH", .matching_pmu = "uncore_cbox_0", }; @@ -187,11 +162,8 @@ static const struct perf_pmu_test_event uncore_hisi_l3c_rd_hit_cpipe = { .event = "event=7", .desc = "Total read hits", .topic = "uncore", - .long_desc = "Total read hits", .pmu = "hisi_sccl,l3c", }, - .alias_str = "event=0x7", - .alias_long_desc = "Total read hits", .matching_pmu = "hisi_sccl3_l3c7", }; @@ -201,11 +173,8 @@ static const struct perf_pmu_test_event uncore_imc_free_running_cache_miss = { .event = "event=0x12", .desc = "Total cache misses", .topic = "uncore", - .long_desc = "Total cache misses", .pmu = "uncore_imc_free_running", }, - .alias_str = "event=0x12", - .alias_long_desc = "Total cache misses", .matching_pmu = "uncore_imc_free_running_0", }; @@ -215,11 +184,8 @@ static const struct perf_pmu_test_event uncore_imc_cache_hits = { .event = "event=0x34", .desc = "Total cache hits", .topic = "uncore", - .long_desc = "Total cache hits", .pmu = "uncore_imc", }, - .alias_str = "event=0x34", - .alias_long_desc = "Total cache hits", .matching_pmu = "uncore_imc_0", }; @@ -243,8 +209,6 @@ static const struct perf_pmu_test_event sys_ddr_pmu_write_cycles = { .pmu = "uncore_sys_ddr_pmu", .compat = "v8", }, - .alias_str = "event=0x2b", - .alias_long_desc = "ddr write-cycles event", .matching_pmu = "uncore_sys_ddr_pmu0", }; @@ -257,8 +221,6 @@ static const struct perf_pmu_test_event sys_ccn_pmu_read_cycles = { .pmu = "uncore_sys_ccn_pmu", .compat = "0x01", }, - .alias_str = "config=0x2c", - .alias_long_desc = "ccn read-cycles event", .matching_pmu = "uncore_sys_ccn_pmu4", }; @@ -271,8 +233,6 @@ static const struct perf_pmu_test_event sys_cmn_pmu_hnf_cache_miss = { .pmu = "uncore_sys_cmn_pmu", .compat = "(434|436|43c|43a).*", }, - .alias_str = "eventid=0x1,type=0x5", - .alias_long_desc = "Counts total cache misses in first lookup result (high priority)", .matching_pmu = "uncore_sys_cmn_pmu0", }; @@ -394,9 +354,9 @@ static int compare_alias_to_test_event(struct pmu_event_info *alias, return -1; } - if (!is_same(alias->str, test_event->alias_str)) { + if (!is_same(alias->str, test_event->event.event)) { pr_debug("testing aliases PMU %s: mismatched str, %s vs %s\n", - pmu_name, alias->str, test_event->alias_str); + pmu_name, alias->str, test_event->event.event); return -1; } @@ -553,11 +513,10 @@ static int __test_core_pmu_event_aliases(const char *pmu_name, int *count) if (!pmu) return -1; - INIT_LIST_HEAD(&pmu->format); - INIT_LIST_HEAD(&pmu->aliases); - INIT_LIST_HEAD(&pmu->caps); - INIT_LIST_HEAD(&pmu->list); - pmu->name = strdup(pmu_name); + if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, pmu_name) != 0) { + perf_pmu__delete(pmu); + return -1; + } pmu->is_core = true; pmu->events_table = table; @@ -594,14 +553,30 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu) { int alias_count = 0, to_match_count = 0, matched_count = 0; struct perf_pmu_test_event const **table; - struct perf_pmu *pmu = &test_pmu->pmu; - const char *pmu_name = pmu->name; + struct perf_pmu *pmu; const struct pmu_events_table *events_table; int res = 0; events_table = find_core_events_table("testarch", "testcpu"); if (!events_table) return -1; + + pmu = zalloc(sizeof(*pmu)); + if (!pmu) + return -1; + + if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, test_pmu->pmu_name) != 0) { + perf_pmu__delete(pmu); + return -1; + } + pmu->is_uncore = test_pmu->pmu_is_uncore; + if (test_pmu->pmu_id) { + pmu->id = strdup(test_pmu->pmu_id); + if (!pmu->id) { + perf_pmu__delete(pmu); + return -1; + } + } pmu->events_table = events_table; pmu_add_cpu_aliases_table(pmu, events_table); pmu->cpu_aliases_added = true; @@ -617,7 +592,8 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu) if (alias_count != to_match_count) { pr_debug("testing aliases uncore PMU %s: mismatch expected aliases (%d) vs found (%d)\n", - pmu_name, to_match_count, alias_count); + pmu->name, to_match_count, alias_count); + perf_pmu__delete(pmu); return -1; } @@ -630,9 +606,10 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu) .count = &matched_count, }; - if (strcmp(pmu_name, test_event.matching_pmu)) { + if (strcmp(pmu->name, test_event.matching_pmu)) { pr_debug("testing aliases uncore PMU %s: mismatched matching_pmu, %s vs %s\n", - pmu_name, test_event.matching_pmu, pmu_name); + pmu->name, test_event.matching_pmu, pmu->name); + perf_pmu__delete(pmu); return -1; } @@ -641,34 +618,32 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu) if (err) { res = err; pr_debug("testing aliases uncore PMU %s: could not match alias %s\n", - pmu_name, event->name); + pmu->name, event->name); + perf_pmu__delete(pmu); return -1; } } if (alias_count != matched_count) { pr_debug("testing aliases uncore PMU %s: mismatch found aliases (%d) vs matched (%d)\n", - pmu_name, matched_count, alias_count); + pmu->name, matched_count, alias_count); res = -1; } + perf_pmu__delete(pmu); return res; } static struct perf_pmu_test_pmu test_pmus[] = { { - .pmu = { - .name = "hisi_sccl1_ddrc2", - .is_uncore = 1, - }, + .pmu_name = "hisi_sccl1_ddrc2", + .pmu_is_uncore = 1, .aliases = { &uncore_hisi_ddrc_flux_wcmd, }, }, { - .pmu = { - .name = "uncore_cbox_0", - .is_uncore = 1, - }, + .pmu_name = "uncore_cbox_0", + .pmu_is_uncore = 1, .aliases = { &unc_cbo_xsnp_response_miss_eviction, &uncore_hyphen, @@ -676,88 +651,70 @@ static struct perf_pmu_test_pmu test_pmus[] = { }, }, { - .pmu = { - .name = "hisi_sccl3_l3c7", - .is_uncore = 1, - }, + .pmu_name = "hisi_sccl3_l3c7", + .pmu_is_uncore = 1, .aliases = { &uncore_hisi_l3c_rd_hit_cpipe, }, }, { - .pmu = { - .name = "uncore_imc_free_running_0", - .is_uncore = 1, - }, + .pmu_name = "uncore_imc_free_running_0", + .pmu_is_uncore = 1, .aliases = { &uncore_imc_free_running_cache_miss, }, }, { - .pmu = { - .name = "uncore_imc_0", - .is_uncore = 1, - }, + .pmu_name = "uncore_imc_0", + .pmu_is_uncore = 1, .aliases = { &uncore_imc_cache_hits, }, }, { - .pmu = { - .name = "uncore_sys_ddr_pmu0", - .is_uncore = 1, - .id = "v8", - }, + .pmu_name = "uncore_sys_ddr_pmu0", + .pmu_is_uncore = 1, + .pmu_id = "v8", .aliases = { &sys_ddr_pmu_write_cycles, }, }, { - .pmu = { - .name = "uncore_sys_ccn_pmu4", - .is_uncore = 1, - .id = "0x01", - }, + .pmu_name = "uncore_sys_ccn_pmu4", + .pmu_is_uncore = 1, + .pmu_id = "0x01", .aliases = { &sys_ccn_pmu_read_cycles, }, }, { - .pmu = { - .name = (char *)"uncore_sys_cmn_pmu0", - .is_uncore = 1, - .id = (char *)"43401", - }, + .pmu_name = "uncore_sys_cmn_pmu0", + .pmu_is_uncore = 1, + .pmu_id = "43401", .aliases = { &sys_cmn_pmu_hnf_cache_miss, }, }, { - .pmu = { - .name = (char *)"uncore_sys_cmn_pmu0", - .is_uncore = 1, - .id = (char *)"43602", - }, + .pmu_name = "uncore_sys_cmn_pmu0", + .pmu_is_uncore = 1, + .pmu_id = "43602", .aliases = { &sys_cmn_pmu_hnf_cache_miss, }, }, { - .pmu = { - .name = (char *)"uncore_sys_cmn_pmu0", - .is_uncore = 1, - .id = (char *)"43c03", - }, + .pmu_name = "uncore_sys_cmn_pmu0", + .pmu_is_uncore = 1, + .pmu_id = "43c03", .aliases = { &sys_cmn_pmu_hnf_cache_miss, }, }, { - .pmu = { - .name = (char *)"uncore_sys_cmn_pmu0", - .is_uncore = 1, - .id = (char *)"43a01", - }, + .pmu_name = "uncore_sys_cmn_pmu0", + .pmu_is_uncore = 1, + .pmu_id = "43a01", .aliases = { &sys_cmn_pmu_hnf_cache_miss, }, @@ -796,10 +753,6 @@ static int test__aliases(struct test_suite *test __maybe_unused, for (i = 0; i < ARRAY_SIZE(test_pmus); i++) { int res; - INIT_LIST_HEAD(&test_pmus[i].pmu.format); - INIT_LIST_HEAD(&test_pmus[i].pmu.aliases); - INIT_LIST_HEAD(&test_pmus[i].pmu.caps); - res = __test_uncore_pmu_event_aliases(&test_pmus[i]); if (res) return res; @@ -873,9 +826,6 @@ static int test__parsing_callback(const struct pmu_metric *pm, struct evlist *evlist; struct perf_cpu_map *cpus; struct evsel *evsel; - struct rblist metric_events = { - .nr_entries = 0, - }; int err = 0; if (!pm->metric_expr) @@ -900,7 +850,7 @@ static int test__parsing_callback(const struct pmu_metric *pm, perf_evlist__set_maps(&evlist->core, cpus, NULL); - err = metricgroup__parse_groups_test(evlist, table, pm->metric_name, &metric_events); + err = metricgroup__parse_groups_test(evlist, table, pm->metric_name); if (err) { if (!strcmp(pm->metric_name, "M1") || !strcmp(pm->metric_name, "M2") || !strcmp(pm->metric_name, "M3")) { @@ -922,12 +872,10 @@ static int test__parsing_callback(const struct pmu_metric *pm, evlist__alloc_aggr_stats(evlist, 1); evlist__for_each_entry(evlist, evsel) { evsel->stats->aggr->counts.val = k; - if (evsel__name_is(evsel, "duration_time")) - update_stats(&walltime_nsecs_stats, k); k++; } evlist__for_each_entry(evlist, evsel) { - struct metric_event *me = metricgroup__lookup(&metric_events, evsel, false); + struct metric_event *me = metricgroup__lookup(&evlist->metric_events, evsel, false); if (me != NULL) { struct metric_expr *mexp; @@ -949,7 +897,6 @@ out_err: pr_debug("Broken metric %s\n", pm->metric_name); /* ... cleanup. */ - metricgroup__rblist_exit(&metric_events); evlist__free_stats(evlist); perf_cpu_map__put(cpus); evlist__delete(evlist); diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c index be18506f6a24..cbded2c6faa4 100644 --- a/tools/perf/tests/pmu.c +++ b/tools/perf/tests/pmu.c @@ -169,14 +169,14 @@ static int test__pmu_format(struct test_suite *test __maybe_unused, int subtest parse_events_terms__init(&terms); if (parse_events_terms(&terms, "krava01=15,krava02=170,krava03=1,krava11=27,krava12=1," - "krava13=2,krava21=119,krava22=11,krava23=2", - NULL)) { + "krava13=2,krava21=119,krava22=11,krava23=2")) { pr_err("Term parsing failed\n"); goto err_out; } memset(&attr, 0, sizeof(attr)); - ret = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/false, /*err=*/NULL); + ret = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/false, + /*apply_hardcoded=*/false, /*err=*/NULL); if (ret) { pr_err("perf_pmu__config_terms failed"); goto err_out; @@ -451,9 +451,9 @@ static int test__name_cmp(struct test_suite *test __maybe_unused, int subtest __ } /** - * Test perf_pmu__match() that's used to search for a PMU given a name passed + * Test perf_pmu__wildcard_match() that's used to search for a PMU given a name passed * on the command line. The name that's passed may also be a filename type glob - * match. If the name does not match, perf_pmu__match() attempts to match the + * match. If the name does not match, perf_pmu__wildcard_match() attempts to match the * alias of the PMU, if provided. */ static int test__pmu_match(struct test_suite *test __maybe_unused, int subtest __maybe_unused) @@ -462,41 +462,44 @@ static int test__pmu_match(struct test_suite *test __maybe_unused, int subtest _ .name = "pmuname", }; - TEST_ASSERT_EQUAL("Exact match", perf_pmu__match(&test_pmu, "pmuname"), true); - TEST_ASSERT_EQUAL("Longer token", perf_pmu__match(&test_pmu, "longertoken"), false); - TEST_ASSERT_EQUAL("Shorter token", perf_pmu__match(&test_pmu, "pmu"), false); +#define TEST_PMU_MATCH(msg, to_match, expect) \ + TEST_ASSERT_EQUAL(msg, perf_pmu__wildcard_match(&test_pmu, to_match), expect) + + TEST_PMU_MATCH("Exact match", "pmuname", true); + TEST_PMU_MATCH("Longer token", "longertoken", false); + TEST_PMU_MATCH("Shorter token", "pmu", false); test_pmu.name = "pmuname_10"; - TEST_ASSERT_EQUAL("Diff suffix_", perf_pmu__match(&test_pmu, "pmuname_2"), false); - TEST_ASSERT_EQUAL("Sub suffix_", perf_pmu__match(&test_pmu, "pmuname_1"), true); - TEST_ASSERT_EQUAL("Same suffix_", perf_pmu__match(&test_pmu, "pmuname_10"), true); - TEST_ASSERT_EQUAL("No suffix_", perf_pmu__match(&test_pmu, "pmuname"), true); - TEST_ASSERT_EQUAL("Underscore_", perf_pmu__match(&test_pmu, "pmuname_"), true); - TEST_ASSERT_EQUAL("Substring_", perf_pmu__match(&test_pmu, "pmuna"), false); + TEST_PMU_MATCH("Diff suffix_", "pmuname_2", false); + TEST_PMU_MATCH("Sub suffix_", "pmuname_1", true); + TEST_PMU_MATCH("Same suffix_", "pmuname_10", true); + TEST_PMU_MATCH("No suffix_", "pmuname", true); + TEST_PMU_MATCH("Underscore_", "pmuname_", true); + TEST_PMU_MATCH("Substring_", "pmuna", false); test_pmu.name = "pmuname_ab23"; - TEST_ASSERT_EQUAL("Diff suffix hex_", perf_pmu__match(&test_pmu, "pmuname_2"), false); - TEST_ASSERT_EQUAL("Sub suffix hex_", perf_pmu__match(&test_pmu, "pmuname_ab"), true); - TEST_ASSERT_EQUAL("Same suffix hex_", perf_pmu__match(&test_pmu, "pmuname_ab23"), true); - TEST_ASSERT_EQUAL("No suffix hex_", perf_pmu__match(&test_pmu, "pmuname"), true); - TEST_ASSERT_EQUAL("Underscore hex_", perf_pmu__match(&test_pmu, "pmuname_"), true); - TEST_ASSERT_EQUAL("Substring hex_", perf_pmu__match(&test_pmu, "pmuna"), false); + TEST_PMU_MATCH("Diff suffix hex_", "pmuname_2", false); + TEST_PMU_MATCH("Sub suffix hex_", "pmuname_ab", true); + TEST_PMU_MATCH("Same suffix hex_", "pmuname_ab23", true); + TEST_PMU_MATCH("No suffix hex_", "pmuname", true); + TEST_PMU_MATCH("Underscore hex_", "pmuname_", true); + TEST_PMU_MATCH("Substring hex_", "pmuna", false); test_pmu.name = "pmuname10"; - TEST_ASSERT_EQUAL("Diff suffix", perf_pmu__match(&test_pmu, "pmuname2"), false); - TEST_ASSERT_EQUAL("Sub suffix", perf_pmu__match(&test_pmu, "pmuname1"), true); - TEST_ASSERT_EQUAL("Same suffix", perf_pmu__match(&test_pmu, "pmuname10"), true); - TEST_ASSERT_EQUAL("No suffix", perf_pmu__match(&test_pmu, "pmuname"), true); - TEST_ASSERT_EQUAL("Underscore", perf_pmu__match(&test_pmu, "pmuname_"), false); - TEST_ASSERT_EQUAL("Substring", perf_pmu__match(&test_pmu, "pmuna"), false); + TEST_PMU_MATCH("Diff suffix", "pmuname2", false); + TEST_PMU_MATCH("Sub suffix", "pmuname1", true); + TEST_PMU_MATCH("Same suffix", "pmuname10", true); + TEST_PMU_MATCH("No suffix", "pmuname", true); + TEST_PMU_MATCH("Underscore", "pmuname_", false); + TEST_PMU_MATCH("Substring", "pmuna", false); test_pmu.name = "pmunameab23"; - TEST_ASSERT_EQUAL("Diff suffix hex", perf_pmu__match(&test_pmu, "pmuname2"), false); - TEST_ASSERT_EQUAL("Sub suffix hex", perf_pmu__match(&test_pmu, "pmunameab"), true); - TEST_ASSERT_EQUAL("Same suffix hex", perf_pmu__match(&test_pmu, "pmunameab23"), true); - TEST_ASSERT_EQUAL("No suffix hex", perf_pmu__match(&test_pmu, "pmuname"), true); - TEST_ASSERT_EQUAL("Underscore hex", perf_pmu__match(&test_pmu, "pmuname_"), false); - TEST_ASSERT_EQUAL("Substring hex", perf_pmu__match(&test_pmu, "pmuna"), false); + TEST_PMU_MATCH("Diff suffix hex", "pmuname2", false); + TEST_PMU_MATCH("Sub suffix hex", "pmunameab", true); + TEST_PMU_MATCH("Same suffix hex", "pmunameab23", true); + TEST_PMU_MATCH("No suffix hex", "pmuname", true); + TEST_PMU_MATCH("Underscore hex", "pmuname_", false); + TEST_PMU_MATCH("Substring hex", "pmuna", false); /* * 2 hex chars or less are not considered suffixes so it shouldn't be @@ -504,7 +507,7 @@ static int test__pmu_match(struct test_suite *test __maybe_unused, int subtest _ * false results here than above. */ test_pmu.name = "pmuname_a3"; - TEST_ASSERT_EQUAL("Diff suffix 2 hex_", perf_pmu__match(&test_pmu, "pmuname_2"), false); + TEST_PMU_MATCH("Diff suffix 2 hex_", "pmuname_2", false); /* * This one should be false, but because pmuname_a3 ends in 3 which is * decimal, it's not possible to determine if it's a short hex suffix or @@ -512,19 +515,19 @@ static int test__pmu_match(struct test_suite *test __maybe_unused, int subtest _ * length of decimal suffix. Run the test anyway and expect the wrong * result. And slightly fuzzy matching shouldn't do too much harm. */ - TEST_ASSERT_EQUAL("Sub suffix 2 hex_", perf_pmu__match(&test_pmu, "pmuname_a"), true); - TEST_ASSERT_EQUAL("Same suffix 2 hex_", perf_pmu__match(&test_pmu, "pmuname_a3"), true); - TEST_ASSERT_EQUAL("No suffix 2 hex_", perf_pmu__match(&test_pmu, "pmuname"), false); - TEST_ASSERT_EQUAL("Underscore 2 hex_", perf_pmu__match(&test_pmu, "pmuname_"), false); - TEST_ASSERT_EQUAL("Substring 2 hex_", perf_pmu__match(&test_pmu, "pmuna"), false); + TEST_PMU_MATCH("Sub suffix 2 hex_", "pmuname_a", true); + TEST_PMU_MATCH("Same suffix 2 hex_", "pmuname_a3", true); + TEST_PMU_MATCH("No suffix 2 hex_", "pmuname", false); + TEST_PMU_MATCH("Underscore 2 hex_", "pmuname_", false); + TEST_PMU_MATCH("Substring 2 hex_", "pmuna", false); test_pmu.name = "pmuname_5"; - TEST_ASSERT_EQUAL("Glob 1", perf_pmu__match(&test_pmu, "pmu*"), true); - TEST_ASSERT_EQUAL("Glob 2", perf_pmu__match(&test_pmu, "nomatch*"), false); - TEST_ASSERT_EQUAL("Seq 1", perf_pmu__match(&test_pmu, "pmuname_[12345]"), true); - TEST_ASSERT_EQUAL("Seq 2", perf_pmu__match(&test_pmu, "pmuname_[67890]"), false); - TEST_ASSERT_EQUAL("? 1", perf_pmu__match(&test_pmu, "pmuname_?"), true); - TEST_ASSERT_EQUAL("? 2", perf_pmu__match(&test_pmu, "pmuname_1?"), false); + TEST_PMU_MATCH("Glob 1", "pmu*", true); + TEST_PMU_MATCH("Glob 2", "nomatch*", false); + TEST_PMU_MATCH("Seq 1", "pmuname_[12345]", true); + TEST_PMU_MATCH("Seq 2", "pmuname_[67890]", false); + TEST_PMU_MATCH("? 1", "pmuname_?", true); + TEST_PMU_MATCH("? 2", "pmuname_1?", false); return TEST_OK; } diff --git a/tools/perf/tests/python-use.c b/tools/perf/tests/python-use.c deleted file mode 100644 index 0ebc22ac8d5b..000000000000 --- a/tools/perf/tests/python-use.c +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Just test if we can load the python binding. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <linux/compiler.h> -#include "tests.h" -#include "util/debug.h" - -static int test__python_use(struct test_suite *test __maybe_unused, int subtest __maybe_unused) -{ - char *cmd; - int ret; - - if (asprintf(&cmd, "echo \"import sys ; sys.path.insert(0, '%s'); import perf\" | %s %s", - PYTHONPATH, PYTHON, verbose > 0 ? "" : "2> /dev/null") < 0) - return -1; - - pr_debug("python usage test: \"%s\"\n", cmd); - ret = system(cmd) ? -1 : 0; - free(cmd); - return ret; -} - -DEFINE_SUITE("'import perf' in python", python_use); diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c index 25a3f6cece50..a7327c942ca2 100644 --- a/tools/perf/tests/sample-parsing.c +++ b/tools/perf/tests/sample-parsing.c @@ -40,8 +40,8 @@ #define BS_EXPECTED_LE 0x1aa00000000 #define FLAG(s) s->branch_stack->entries[i].flags -static bool samples_same(const struct perf_sample *s1, - const struct perf_sample *s2, +static bool samples_same(struct perf_sample *s1, + struct perf_sample *s2, u64 type, u64 read_format, bool needs_swap) { size_t i; @@ -126,13 +126,15 @@ static bool samples_same(const struct perf_sample *s1, } if (type & PERF_SAMPLE_REGS_USER) { - size_t sz = hweight_long(s1->user_regs.mask) * sizeof(u64); - - COMP(user_regs.mask); - COMP(user_regs.abi); - if (s1->user_regs.abi && - (!s1->user_regs.regs || !s2->user_regs.regs || - memcmp(s1->user_regs.regs, s2->user_regs.regs, sz))) { + struct regs_dump *s1_regs = perf_sample__user_regs(s1); + struct regs_dump *s2_regs = perf_sample__user_regs(s2); + size_t sz = hweight_long(s1_regs->mask) * sizeof(u64); + + COMP(user_regs->mask); + COMP(user_regs->abi); + if (s1_regs->abi && + (!s1_regs->regs || !s2_regs->regs || + memcmp(s1_regs->regs, s2_regs->regs, sz))) { pr_debug("Samples differ at 'user_regs'\n"); return false; } @@ -150,6 +152,12 @@ static bool samples_same(const struct perf_sample *s1, if (type & PERF_SAMPLE_WEIGHT) COMP(weight); + if (type & PERF_SAMPLE_WEIGHT_STRUCT) { + COMP(weight); + COMP(ins_lat); + COMP(weight3); + } + if (type & PERF_SAMPLE_DATA_SRC) COMP(data_src); @@ -157,13 +165,15 @@ static bool samples_same(const struct perf_sample *s1, COMP(transaction); if (type & PERF_SAMPLE_REGS_INTR) { - size_t sz = hweight_long(s1->intr_regs.mask) * sizeof(u64); - - COMP(intr_regs.mask); - COMP(intr_regs.abi); - if (s1->intr_regs.abi && - (!s1->intr_regs.regs || !s2->intr_regs.regs || - memcmp(s1->intr_regs.regs, s2->intr_regs.regs, sz))) { + struct regs_dump *s1_regs = perf_sample__intr_regs(s1); + struct regs_dump *s2_regs = perf_sample__intr_regs(s2); + size_t sz = hweight_long(s1_regs->mask) * sizeof(u64); + + COMP(intr_regs->mask); + COMP(intr_regs->abi); + if (s1_regs->abi && + (!s1_regs->regs || !s2_regs->regs || + memcmp(s1_regs->regs, s2_regs->regs, sz))) { pr_debug("Samples differ at 'intr_regs'\n"); return false; } @@ -223,6 +233,16 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) const u32 raw_data[] = {0x12345678, 0x0a0b0c0d, 0x11020304, 0x05060708, 0 }; const u64 data[] = {0x2211443366558877ULL, 0, 0xaabbccddeeff4321ULL}; const u64 aux_data[] = {0xa55a, 0, 0xeeddee, 0x0282028202820282}; + struct regs_dump user_regs = { + .abi = PERF_SAMPLE_REGS_ABI_64, + .mask = sample_regs, + .regs = regs, + }; + struct regs_dump intr_regs = { + .abi = PERF_SAMPLE_REGS_ABI_64, + .mask = sample_regs, + .regs = regs, + }; struct perf_sample sample = { .ip = 101, .pid = 102, @@ -241,11 +261,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) .callchain = &callchain.callchain, .no_hw_idx = false, .branch_stack = &branch_stack.branch_stack, - .user_regs = { - .abi = PERF_SAMPLE_REGS_ABI_64, - .mask = sample_regs, - .regs = regs, - }, + .user_regs = &user_regs, .user_stack = { .size = sizeof(data), .data = (void *)data, @@ -254,15 +270,13 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) .time_enabled = 0x030a59d664fca7deULL, .time_running = 0x011b6ae553eb98edULL, }, - .intr_regs = { - .abi = PERF_SAMPLE_REGS_ABI_64, - .mask = sample_regs, - .regs = regs, - }, + .intr_regs = &intr_regs, .phys_addr = 113, .cgroup = 114, .data_page_size = 115, .code_page_size = 116, + .ins_lat = 117, + .weight3 = 118, .aux_sample = { .size = sizeof(aux_data), .data = (void *)aux_data, @@ -273,6 +287,8 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) size_t i, sz, bufsz; int err, ret = -1; + perf_sample__init(&sample_out, /*all=*/false); + perf_sample__init(&sample_out_endian, /*all=*/false); if (sample_type & PERF_SAMPLE_REGS_USER) evsel.core.attr.sample_regs_user = sample_regs; @@ -361,6 +377,8 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format) ret = 0; out_free: free(event); + perf_sample__exit(&sample_out_endian); + perf_sample__exit(&sample_out); if (ret && read_format) pr_debug("read_format %#"PRIx64"\n", read_format); return ret; @@ -429,6 +447,12 @@ static int test__sample_parsing(struct test_suite *test __maybe_unused, int subt if (err) return err; } + sample_type = (PERF_SAMPLE_MAX - 1) & ~PERF_SAMPLE_WEIGHT_STRUCT; + for (i = 0; i < ARRAY_SIZE(rf); i++) { + err = do_test(sample_type, sample_regs, rf[i]); + if (err) + return err; + } return 0; } diff --git a/tools/perf/tests/sdt.c b/tools/perf/tests/sdt.c index 919712899251..93baee2eae42 100644 --- a/tools/perf/tests/sdt.c +++ b/tools/perf/tests/sdt.c @@ -28,7 +28,7 @@ static int target_function(void) static int build_id_cache__add_file(const char *filename) { char sbuild_id[SBUILD_ID_SIZE]; - struct build_id bid; + struct build_id bid = { .size = 0, }; int err; err = filename__read_build_id(filename, &bid); @@ -37,7 +37,7 @@ static int build_id_cache__add_file(const char *filename) return err; } - build_id__sprintf(&bid, sbuild_id); + build_id__snprintf(&bid, sbuild_id, sizeof(sbuild_id)); err = build_id_cache__add_s(sbuild_id, filename, NULL, false, false); if (err < 0) pr_debug("Failed to add build id cache of %s\n", filename); diff --git a/tools/perf/tests/shell/amd-ibs-swfilt.sh b/tools/perf/tests/shell/amd-ibs-swfilt.sh new file mode 100755 index 000000000000..e7f66df05c4b --- /dev/null +++ b/tools/perf/tests/shell/amd-ibs-swfilt.sh @@ -0,0 +1,92 @@ +#!/bin/bash +# AMD IBS software filtering + +ParanoidAndNotRoot() { + [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] +} + +echo "check availability of IBS swfilt" + +# check if IBS PMU is available +if [ ! -d /sys/bus/event_source/devices/ibs_op ]; then + echo "[SKIP] IBS PMU does not exist" + exit 2 +fi + +# check if IBS PMU has swfilt format +if [ ! -f /sys/bus/event_source/devices/ibs_op/format/swfilt ]; then + echo "[SKIP] IBS PMU does not have swfilt" + exit 2 +fi + +echo "run perf record with modifier and swfilt" +err=0 + +# setting any modifiers should fail +perf record -B -e ibs_op//u -o /dev/null true 2> /dev/null +if [ $? -eq 0 ]; then + echo "[FAIL] IBS PMU should not accept exclude_kernel" + exit 1 +fi + +# setting it with swfilt should be fine +perf record -B -e ibs_op/swfilt/u -o /dev/null true +if [ $? -ne 0 ]; then + echo "[FAIL] IBS op PMU cannot handle swfilt for exclude_kernel" + exit 1 +fi + +if ! ParanoidAndNotRoot 1 +then + # setting it with swfilt=1 should be fine + perf record -B -e ibs_op/swfilt=1/k -o /dev/null true + if [ $? -ne 0 ]; then + echo "[FAIL] IBS op PMU cannot handle swfilt for exclude_user" + exit 1 + fi +else + echo "[SKIP] not root and perf_event_paranoid too high for exclude_user" + err=2 +fi + +# check ibs_fetch PMU as well +perf record -B -e ibs_fetch/swfilt/u -o /dev/null true +if [ $? -ne 0 ]; then + echo "[FAIL] IBS fetch PMU cannot handle swfilt for exclude_kernel" + exit 1 +fi + +# check system wide recording +if ! ParanoidAndNotRoot 0 +then + perf record -aB --synth=no -e ibs_op/swfilt/k -o /dev/null true + if [ $? -ne 0 ]; then + echo "[FAIL] IBS op PMU cannot handle swfilt in system-wide mode" + exit 1 + fi +else + echo "[SKIP] not root and perf_event_paranoid too high for system-wide/exclude_user" + err=2 +fi + +echo "check number of samples with swfilt" + +kernel_sample=$(perf record -e ibs_op/swfilt/u -o- true | perf script -i- -F misc | grep -c ^K) +if [ ${kernel_sample} -ne 0 ]; then + echo "[FAIL] unexpected kernel samples: " ${kernel_sample} + exit 1 +fi + +if ! ParanoidAndNotRoot 1 +then + user_sample=$(perf record -e ibs_fetch/swfilt/k -o- true | perf script -i- -F misc | grep -c ^U) + if [ ${user_sample} -ne 0 ]; then + echo "[FAIL] unexpected user samples: " ${user_sample} + exit 1 + fi +else + echo "[SKIP] not root and perf_event_paranoid too high for exclude_user" + err=2 +fi + +exit $err diff --git a/tools/perf/tests/shell/annotate.sh b/tools/perf/tests/shell/annotate.sh index 2ccf4f1d46b6..689de58e9238 100755 --- a/tools/perf/tests/shell/annotate.sh +++ b/tools/perf/tests/shell/annotate.sh @@ -35,54 +35,79 @@ trap_cleanup() { trap trap_cleanup EXIT TERM INT test_basic() { - echo "Basic perf annotate test" - if ! perf record -o "${perfdata}" ${testprog} 2> /dev/null + mode=$1 + echo "${mode} perf annotate test" + if [ "x${mode}" == "xBasic" ] then - echo "Basic annotate [Failed: perf record]" + perf record -o "${perfdata}" ${testprog} 2> /dev/null + else + perf record -o - ${testprog} 2> /dev/null > "${perfdata}" + fi + if [ "x$?" != "x0" ] + then + echo "${mode} annotate [Failed: perf record]" err=1 return fi # Generate the annotated output file - perf annotate -i "${perfdata}" --stdio 2> /dev/null > "${perfout}" + if [ "x${mode}" == "xBasic" ] + then + perf annotate --no-demangle -i "${perfdata}" --stdio --percent-limit 10 2> /dev/null > "${perfout}" + else + perf annotate --no-demangle -i - --stdio 2> /dev/null --percent-limit 10 < "${perfdata}" > "${perfout}" + fi # check if it has the target symbol - if ! grep "${testsym}" "${perfout}" + if ! grep -q "${testsym}" "${perfout}" then - echo "Basic annotate [Failed: missing target symbol]" + echo "${mode} annotate [Failed: missing target symbol]" + cat "${perfout}" err=1 return fi # check if it has the disassembly lines - if ! grep "${disasm_regex}" "${perfout}" + if ! grep -q "${disasm_regex}" "${perfout}" then - echo "Basic annotate [Failed: missing disasm output from default disassembler]" + echo "${mode} annotate [Failed: missing disasm output from default disassembler]" err=1 return fi # check again with a target symbol name - if ! perf annotate -i "${perfdata}" "${testsym}" 2> /dev/null | \ - grep -m 3 "${disasm_regex}" + if [ "x${mode}" == "xBasic" ] then - echo "Basic annotate [Failed: missing disasm output when specifying the target symbol]" + perf annotate --no-demangle -i "${perfdata}" "${testsym}" 2> /dev/null > "${perfout}" + else + perf annotate --no-demangle -i - "${testsym}" 2> /dev/null < "${perfdata}" > "${perfout}" + fi + + if ! head -250 "${perfout}"| grep -q -m 3 "${disasm_regex}" + then + echo "${mode} annotate [Failed: missing disasm output when specifying the target symbol]" err=1 return fi # check one more with external objdump tool (forced by --objdump option) - if ! perf annotate -i "${perfdata}" --objdump=objdump 2> /dev/null | \ - grep -m 3 "${disasm_regex}" + if [ "x${mode}" == "xBasic" ] + then + perf annotate --no-demangle -i "${perfdata}" --percent-limit 10 --objdump=objdump 2> /dev/null > "${perfout}" + else + perf annotate --no-demangle -i - "${testsym}" --percent-limit 10 --objdump=objdump 2> /dev/null < "${perfdata}" > "${perfout}" + fi + if ! grep -q -m 3 "${disasm_regex}" "${perfout}" then - echo "Basic annotate [Failed: missing disasm output from non default disassembler (using --objdump)]" + echo "${mode} annotate [Failed: missing disasm output from non default disassembler (using --objdump)]" err=1 return fi - echo "Basic annotate test [Success]" + echo "${mode} annotate test [Success]" } -test_basic +test_basic Basic +test_basic Pipe cleanup exit $err diff --git a/tools/perf/tests/shell/attr.sh b/tools/perf/tests/shell/attr.sh new file mode 100755 index 000000000000..5a4e43b2471d --- /dev/null +++ b/tools/perf/tests/shell/attr.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# Perf attribute expectations test +# SPDX-License-Identifier: GPL-2.0 + +err=0 + +cleanup() { + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +shelldir=$(dirname "$0") +perf_path=$(which perf) +python "${shelldir}"/lib/attr.py -d "${shelldir}"/attr -v -p "$perf_path" +cleanup +exit $err diff --git a/tools/perf/tests/attr/README b/tools/perf/tests/shell/attr/README index 4066fec7180a..67c4ca76b85d 100644 --- a/tools/perf/tests/attr/README +++ b/tools/perf/tests/shell/attr/README @@ -51,6 +51,8 @@ Following tests are defined (with perf commands): 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 -D kill (test-record-no-delay) perf record -i kill (test-record-no-inherit) perf record -n kill (test-record-no-samples) diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/shell/attr/base-record index b44e4e6e4443..b44e4e6e4443 100644 --- a/tools/perf/tests/attr/base-record +++ b/tools/perf/tests/shell/attr/base-record diff --git a/tools/perf/tests/attr/base-record-spe b/tools/perf/tests/shell/attr/base-record-spe index 08fa96b59240..08fa96b59240 100644 --- a/tools/perf/tests/attr/base-record-spe +++ b/tools/perf/tests/shell/attr/base-record-spe diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/shell/attr/base-stat index fccd8ec4d1b0..fccd8ec4d1b0 100644 --- a/tools/perf/tests/attr/base-stat +++ b/tools/perf/tests/shell/attr/base-stat diff --git a/tools/perf/tests/attr/system-wide-dummy b/tools/perf/tests/shell/attr/system-wide-dummy index a1e1d6a263bf..a1e1d6a263bf 100644 --- a/tools/perf/tests/attr/system-wide-dummy +++ b/tools/perf/tests/shell/attr/system-wide-dummy diff --git a/tools/perf/tests/attr/test-record-C0 b/tools/perf/tests/shell/attr/test-record-C0 index 198e8429a1bf..1049ac8b52f2 100644 --- a/tools/perf/tests/attr/test-record-C0 +++ b/tools/perf/tests/shell/attr/test-record-C0 @@ -18,5 +18,7 @@ sample_type=65927 mmap=0 comm=0 task=0 +inherit=0 [event:system-wide-dummy] +inherit=0 diff --git a/tools/perf/tests/attr/test-record-basic b/tools/perf/tests/shell/attr/test-record-basic index b0ca42a5ecc9..b0ca42a5ecc9 100644 --- a/tools/perf/tests/attr/test-record-basic +++ b/tools/perf/tests/shell/attr/test-record-basic diff --git a/tools/perf/tests/attr/test-record-branch-any b/tools/perf/tests/shell/attr/test-record-branch-any index 1a99b3ce6b89..1a99b3ce6b89 100644 --- a/tools/perf/tests/attr/test-record-branch-any +++ b/tools/perf/tests/shell/attr/test-record-branch-any diff --git a/tools/perf/tests/attr/test-record-branch-filter-any b/tools/perf/tests/shell/attr/test-record-branch-filter-any index 709768b508c6..709768b508c6 100644 --- a/tools/perf/tests/attr/test-record-branch-filter-any +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-any diff --git a/tools/perf/tests/attr/test-record-branch-filter-any_call b/tools/perf/tests/shell/attr/test-record-branch-filter-any_call index f943221f7825..f943221f7825 100644 --- a/tools/perf/tests/attr/test-record-branch-filter-any_call +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-any_call diff --git a/tools/perf/tests/attr/test-record-branch-filter-any_ret b/tools/perf/tests/shell/attr/test-record-branch-filter-any_ret index fd4f5b4154a9..fd4f5b4154a9 100644 --- a/tools/perf/tests/attr/test-record-branch-filter-any_ret +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-any_ret diff --git a/tools/perf/tests/attr/test-record-branch-filter-hv b/tools/perf/tests/shell/attr/test-record-branch-filter-hv index 4e52d685ebe1..4e52d685ebe1 100644 --- a/tools/perf/tests/attr/test-record-branch-filter-hv +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-hv diff --git a/tools/perf/tests/attr/test-record-branch-filter-ind_call b/tools/perf/tests/shell/attr/test-record-branch-filter-ind_call index e08c6ab3796e..e08c6ab3796e 100644 --- a/tools/perf/tests/attr/test-record-branch-filter-ind_call +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-ind_call diff --git a/tools/perf/tests/attr/test-record-branch-filter-k b/tools/perf/tests/shell/attr/test-record-branch-filter-k index b4b98f84fc2f..b4b98f84fc2f 100644 --- a/tools/perf/tests/attr/test-record-branch-filter-k +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-k diff --git a/tools/perf/tests/attr/test-record-branch-filter-u b/tools/perf/tests/shell/attr/test-record-branch-filter-u index fb9610edbb0d..fb9610edbb0d 100644 --- a/tools/perf/tests/attr/test-record-branch-filter-u +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-u diff --git a/tools/perf/tests/attr/test-record-count b/tools/perf/tests/shell/attr/test-record-count index 5e9b9019d786..5e9b9019d786 100644 --- a/tools/perf/tests/attr/test-record-count +++ b/tools/perf/tests/shell/attr/test-record-count diff --git a/tools/perf/tests/attr/test-record-data b/tools/perf/tests/shell/attr/test-record-data index a99bb13149c2..a99bb13149c2 100644 --- a/tools/perf/tests/attr/test-record-data +++ b/tools/perf/tests/shell/attr/test-record-data diff --git a/tools/perf/tests/attr/test-record-dummy-C0 b/tools/perf/tests/shell/attr/test-record-dummy-C0 index 576ec48b3aaf..91499405fff4 100644 --- a/tools/perf/tests/attr/test-record-dummy-C0 +++ b/tools/perf/tests/shell/attr/test-record-dummy-C0 @@ -19,7 +19,7 @@ sample_period=4000 sample_type=391 read_format=4|20 disabled=0 -inherit=1 +inherit=0 pinned=0 exclusive=0 exclude_user=0 @@ -37,7 +37,7 @@ precise_ip=0 mmap_data=0 sample_id_all=1 exclude_host=0 -exclude_guest=1 +exclude_guest=0 exclude_callchain_kernel=0 exclude_callchain_user=0 mmap2=1 diff --git a/tools/perf/tests/attr/test-record-freq b/tools/perf/tests/shell/attr/test-record-freq index 89e29f6b2ae0..89e29f6b2ae0 100644 --- a/tools/perf/tests/attr/test-record-freq +++ b/tools/perf/tests/shell/attr/test-record-freq diff --git a/tools/perf/tests/attr/test-record-graph-default b/tools/perf/tests/shell/attr/test-record-graph-default index f0a18b4ea4f5..f0a18b4ea4f5 100644 --- a/tools/perf/tests/attr/test-record-graph-default +++ b/tools/perf/tests/shell/attr/test-record-graph-default diff --git a/tools/perf/tests/attr/test-record-graph-default-aarch64 b/tools/perf/tests/shell/attr/test-record-graph-default-aarch64 index e98d62efb6f7..e98d62efb6f7 100644 --- a/tools/perf/tests/attr/test-record-graph-default-aarch64 +++ b/tools/perf/tests/shell/attr/test-record-graph-default-aarch64 diff --git a/tools/perf/tests/attr/test-record-graph-dwarf b/tools/perf/tests/shell/attr/test-record-graph-dwarf index ae92061d611d..ae92061d611d 100644 --- a/tools/perf/tests/attr/test-record-graph-dwarf +++ b/tools/perf/tests/shell/attr/test-record-graph-dwarf diff --git a/tools/perf/tests/attr/test-record-graph-fp b/tools/perf/tests/shell/attr/test-record-graph-fp index a6e60e839205..a6e60e839205 100644 --- a/tools/perf/tests/attr/test-record-graph-fp +++ b/tools/perf/tests/shell/attr/test-record-graph-fp diff --git a/tools/perf/tests/attr/test-record-graph-fp-aarch64 b/tools/perf/tests/shell/attr/test-record-graph-fp-aarch64 index cbeea9971285..cbeea9971285 100644 --- a/tools/perf/tests/attr/test-record-graph-fp-aarch64 +++ b/tools/perf/tests/shell/attr/test-record-graph-fp-aarch64 diff --git a/tools/perf/tests/attr/test-record-group-sampling b/tools/perf/tests/shell/attr/test-record-group-sampling index 97e7e64a38f0..86a940d7895d 100644 --- a/tools/perf/tests/attr/test-record-group-sampling +++ b/tools/perf/tests/shell/attr/test-record-group-sampling @@ -2,6 +2,7 @@ command = record args = --no-bpf-event -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1 ret = 1 +kernel_until = 6.12 [event-1:base-record] fd=1 @@ -18,7 +19,7 @@ group_fd=1 type=0 config=3 -# default | PERF_SAMPLE_READ +# default | PERF_SAMPLE_READ | PERF_SAMPLE_PERIOD sample_type=343 # PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST diff --git a/tools/perf/tests/shell/attr/test-record-group-sampling1 b/tools/perf/tests/shell/attr/test-record-group-sampling1 new file mode 100644 index 000000000000..4748ab7bf684 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-group-sampling1 @@ -0,0 +1,50 @@ +[config] +command = record +args = --no-bpf-event -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1 +ret = 1 +kernel_since = 6.12 + +[event-1:base-record] +fd=1 +group_fd=-1 + +# cycles +type=0 +config=0 + +# default | PERF_SAMPLE_READ | PERF_SAMPLE_PERIOD +sample_type=343 + +# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING +read_format=28|31 +task=1 +mmap=1 +comm=1 +enable_on_exec=1 +disabled=1 + +# inherit is enabled for group sampling +inherit=1 + +[event-2:base-record] +fd=2 +group_fd=1 + +# cache-misses +type=0 +config=3 + +# default | PERF_SAMPLE_READ | PERF_SAMPLE_PERIOD +sample_type=343 + +# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING +read_format=28|31 +task=0 +mmap=0 +comm=0 +enable_on_exec=0 +disabled=0 +freq=0 + +# inherit is enabled for group sampling +inherit=1 diff --git a/tools/perf/tests/shell/attr/test-record-group-sampling2 b/tools/perf/tests/shell/attr/test-record-group-sampling2 new file mode 100644 index 000000000000..e0432244a0eb --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-group-sampling2 @@ -0,0 +1,61 @@ +[config] +command = record +args = --no-bpf-event -c 10000 -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1 +ret = 1 +kernel_since = 6.12 + +[event-1:base-record] +fd=1 +group_fd=-1 + +# cycles +type=0 +config=0 + +# default | PERF_SAMPLE_READ +sample_type=87 + +# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING +read_format=28|31 +task=1 +mmap=1 +comm=1 +enable_on_exec=1 +disabled=1 + +# inherit is enabled for group sampling +inherit=1 + +# sampling disabled +sample_freq=0 +sample_period=10000 +freq=0 +write_backward=0 + +[event-2:base-record] +fd=2 +group_fd=1 + +# cache-misses +type=0 +config=3 + +# default | PERF_SAMPLE_READ +sample_type=87 + +# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING +read_format=28|31 +task=0 +mmap=0 +comm=0 +enable_on_exec=0 +disabled=0 + +# inherit is enabled for group sampling +inherit=1 + +# sampling disabled +sample_freq=0 +sample_period=0 +freq=0 +write_backward=0 diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/shell/attr/test-record-group1 index eeb1db392bc9..eeb1db392bc9 100644 --- a/tools/perf/tests/attr/test-record-group1 +++ b/tools/perf/tests/shell/attr/test-record-group1 diff --git a/tools/perf/tests/attr/test-record-group2 b/tools/perf/tests/shell/attr/test-record-group2 index cebdaa8e64e4..891d41a7bddf 100644 --- a/tools/perf/tests/attr/test-record-group2 +++ b/tools/perf/tests/shell/attr/test-record-group2 @@ -2,6 +2,7 @@ command = record args = --no-bpf-event -e '{cycles/period=1234000/,instructions/period=6789000/}:S' kill >/dev/null 2>&1 ret = 1 +kernel_until = 6.12 [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 new file mode 100644 index 000000000000..249be884959e --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-group3 @@ -0,0 +1,31 @@ +[config] +command = record +args = --no-bpf-event -e '{cycles/period=1234000/,instructions/period=6789000/}:S' kill >/dev/null 2>&1 +ret = 1 +kernel_since = 6.12 + +[event-1:base-record] +fd=1 +group_fd=-1 +config=0|1 +sample_period=1234000 +sample_type=87 +read_format=28|31 +disabled=1 +inherit=1 +freq=0 + +[event-2:base-record] +fd=2 +group_fd=1 +config=0|1 +sample_period=6789000 +sample_type=87 +read_format=28|31 +disabled=0 +inherit=1 +mmap=0 +comm=0 +freq=0 +enable_on_exec=0 +task=0 diff --git a/tools/perf/tests/attr/test-record-no-buffering b/tools/perf/tests/shell/attr/test-record-no-buffering index 583dcbb078ba..583dcbb078ba 100644 --- a/tools/perf/tests/attr/test-record-no-buffering +++ b/tools/perf/tests/shell/attr/test-record-no-buffering diff --git a/tools/perf/tests/attr/test-record-no-inherit b/tools/perf/tests/shell/attr/test-record-no-inherit index 15d1dc162e1c..15d1dc162e1c 100644 --- a/tools/perf/tests/attr/test-record-no-inherit +++ b/tools/perf/tests/shell/attr/test-record-no-inherit diff --git a/tools/perf/tests/attr/test-record-no-samples b/tools/perf/tests/shell/attr/test-record-no-samples index 596fbd6d5a2c..596fbd6d5a2c 100644 --- a/tools/perf/tests/attr/test-record-no-samples +++ b/tools/perf/tests/shell/attr/test-record-no-samples diff --git a/tools/perf/tests/attr/test-record-period b/tools/perf/tests/shell/attr/test-record-period index 119101154c5e..119101154c5e 100644 --- a/tools/perf/tests/attr/test-record-period +++ b/tools/perf/tests/shell/attr/test-record-period diff --git a/tools/perf/tests/attr/test-record-pfm-period b/tools/perf/tests/shell/attr/test-record-pfm-period index 368f5b814094..368f5b814094 100644 --- a/tools/perf/tests/attr/test-record-pfm-period +++ b/tools/perf/tests/shell/attr/test-record-pfm-period diff --git a/tools/perf/tests/attr/test-record-raw b/tools/perf/tests/shell/attr/test-record-raw index 13a5f7860c78..13a5f7860c78 100644 --- a/tools/perf/tests/attr/test-record-raw +++ b/tools/perf/tests/shell/attr/test-record-raw diff --git a/tools/perf/tests/attr/test-record-spe-period b/tools/perf/tests/shell/attr/test-record-spe-period index 75f8c9cd8e3f..75f8c9cd8e3f 100644 --- a/tools/perf/tests/attr/test-record-spe-period +++ b/tools/perf/tests/shell/attr/test-record-spe-period diff --git a/tools/perf/tests/attr/test-record-spe-period-term b/tools/perf/tests/shell/attr/test-record-spe-period-term index 8f60a4fec657..8f60a4fec657 100644 --- a/tools/perf/tests/attr/test-record-spe-period-term +++ b/tools/perf/tests/shell/attr/test-record-spe-period-term diff --git a/tools/perf/tests/attr/test-record-spe-physical-address b/tools/perf/tests/shell/attr/test-record-spe-physical-address index 7ebcf5012ce3..7ebcf5012ce3 100644 --- a/tools/perf/tests/attr/test-record-spe-physical-address +++ b/tools/perf/tests/shell/attr/test-record-spe-physical-address diff --git a/tools/perf/tests/attr/test-record-user-regs-no-sve-aarch64 b/tools/perf/tests/shell/attr/test-record-user-regs-no-sve-aarch64 index bed765450ca9..bed765450ca9 100644 --- a/tools/perf/tests/attr/test-record-user-regs-no-sve-aarch64 +++ b/tools/perf/tests/shell/attr/test-record-user-regs-no-sve-aarch64 diff --git a/tools/perf/tests/attr/test-record-user-regs-old-sve-aarch64 b/tools/perf/tests/shell/attr/test-record-user-regs-old-sve-aarch64 index 15ebfc3418e3..15ebfc3418e3 100644 --- a/tools/perf/tests/attr/test-record-user-regs-old-sve-aarch64 +++ b/tools/perf/tests/shell/attr/test-record-user-regs-old-sve-aarch64 diff --git a/tools/perf/tests/attr/test-record-user-regs-sve-aarch64 b/tools/perf/tests/shell/attr/test-record-user-regs-sve-aarch64 index a65113cd7311..a65113cd7311 100644 --- a/tools/perf/tests/attr/test-record-user-regs-sve-aarch64 +++ b/tools/perf/tests/shell/attr/test-record-user-regs-sve-aarch64 diff --git a/tools/perf/tests/attr/test-stat-C0 b/tools/perf/tests/shell/attr/test-stat-C0 index a2c76d10b2bb..a2c76d10b2bb 100644 --- a/tools/perf/tests/attr/test-stat-C0 +++ b/tools/perf/tests/shell/attr/test-stat-C0 diff --git a/tools/perf/tests/attr/test-stat-basic b/tools/perf/tests/shell/attr/test-stat-basic index 69867d049fda..69867d049fda 100644 --- a/tools/perf/tests/attr/test-stat-basic +++ b/tools/perf/tests/shell/attr/test-stat-basic diff --git a/tools/perf/tests/attr/test-stat-default b/tools/perf/tests/shell/attr/test-stat-default index a1e2da0a9a6d..8dd27c1fb661 100644 --- a/tools/perf/tests/attr/test-stat-default +++ b/tools/perf/tests/shell/attr/test-stat-default @@ -88,98 +88,149 @@ enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / topdown-fe-bound (0x8200) +# PERF_TYPE_RAW / topdown-bad-spec (0x8100) [event13:base-stat] fd=13 group_fd=11 type=4 -config=33280 +config=33024 disabled=0 enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / topdown-be-bound (0x8300) +# PERF_TYPE_RAW / topdown-fe-bound (0x8200) [event14:base-stat] fd=14 group_fd=11 type=4 -config=33536 +config=33280 disabled=0 enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / topdown-bad-spec (0x8100) +# PERF_TYPE_RAW / topdown-be-bound (0x8300) [event15:base-stat] fd=15 group_fd=11 type=4 -config=33024 +config=33536 disabled=0 enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +# PERF_TYPE_RAW / topdown-heavy-ops (0x8400) [event16:base-stat] fd=16 +group_fd=11 type=4 -config=4109 +config=33792 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ +# PERF_TYPE_RAW / topdown-br-mispredict (0x8500) [event17:base-stat] fd=17 +group_fd=11 type=4 -config=17039629 +config=34048 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD +# PERF_TYPE_RAW / topdown-fetch-lat (0x8600) [event18:base-stat] fd=18 +group_fd=11 type=4 -config=60 +config=34304 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY +# PERF_TYPE_RAW / topdown-mem-bound (0x8700) [event19:base-stat] fd=19 +group_fd=11 type=4 -config=2097421 +config=34560 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING [event20:base-stat] fd=20 type=4 -config=316 +config=4109 optional=1 -# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE +# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ [event21:base-stat] fd=21 type=4 -config=412 +config=17039629 optional=1 -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD [event22:base-stat] fd=22 type=4 -config=572 +config=60 optional=1 -# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS +# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY [event23:base-stat] fd=23 type=4 -config=706 +config=2097421 optional=1 -# PERF_TYPE_RAW / UOPS_ISSUED.ANY +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK [event24:base-stat] fd=24 type=4 +config=316 +optional=1 + +# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE +[event25:base-stat] +fd=25 +type=4 +config=412 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE +[event26:base-stat] +fd=26 +type=4 +config=572 +optional=1 + +# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS +[event27:base-stat] +fd=27 +type=4 +config=706 +optional=1 + +# PERF_TYPE_RAW / UOPS_ISSUED.ANY +[event28:base-stat] +fd=28 +type=4 config=270 optional=1 + +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +[event29:base-stat] +fd=29 +type=4 +config=4269 +optional=1
\ No newline at end of file diff --git a/tools/perf/tests/attr/test-stat-detailed-1 b/tools/perf/tests/shell/attr/test-stat-detailed-1 index 1c52cb05c900..12a2ebf4e64a 100644 --- a/tools/perf/tests/attr/test-stat-detailed-1 +++ b/tools/perf/tests/shell/attr/test-stat-detailed-1 @@ -90,99 +90,143 @@ enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / topdown-fe-bound (0x8200) +# PERF_TYPE_RAW / topdown-bad-spec (0x8100) [event13:base-stat] fd=13 group_fd=11 type=4 -config=33280 +config=33024 disabled=0 enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / topdown-be-bound (0x8300) +# PERF_TYPE_RAW / topdown-fe-bound (0x8200) [event14:base-stat] fd=14 group_fd=11 type=4 -config=33536 +config=33280 disabled=0 enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / topdown-bad-spec (0x8100) +# PERF_TYPE_RAW / topdown-be-bound (0x8300) [event15:base-stat] fd=15 group_fd=11 type=4 -config=33024 +config=33536 disabled=0 enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +# PERF_TYPE_RAW / topdown-heavy-ops (0x8400) [event16:base-stat] fd=16 +group_fd=11 type=4 -config=4109 +config=33792 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ +# PERF_TYPE_RAW / topdown-br-mispredict (0x8500) [event17:base-stat] fd=17 +group_fd=11 type=4 -config=17039629 +config=34048 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD +# PERF_TYPE_RAW / topdown-fetch-lat (0x8600) [event18:base-stat] fd=18 +group_fd=11 type=4 -config=60 +config=34304 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY +# PERF_TYPE_RAW / topdown-mem-bound (0x8700) [event19:base-stat] fd=19 +group_fd=11 type=4 -config=2097421 +config=34560 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING [event20:base-stat] fd=20 type=4 -config=316 +config=4109 optional=1 -# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE +# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ [event21:base-stat] fd=21 type=4 -config=412 +config=17039629 optional=1 -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD [event22:base-stat] fd=22 type=4 -config=572 +config=60 optional=1 -# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS +# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY [event23:base-stat] fd=23 type=4 -config=706 +config=2097421 optional=1 -# PERF_TYPE_RAW / UOPS_ISSUED.ANY +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK [event24:base-stat] fd=24 type=4 +config=316 +optional=1 + +# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE +[event25:base-stat] +fd=25 +type=4 +config=412 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE +[event26:base-stat] +fd=26 +type=4 +config=572 +optional=1 + +# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS +[event27:base-stat] +fd=27 +type=4 +config=706 +optional=1 + +# PERF_TYPE_RAW / UOPS_ISSUED.ANY +[event28:base-stat] +fd=28 +type=4 config=270 optional=1 @@ -190,8 +234,8 @@ optional=1 # PERF_COUNT_HW_CACHE_L1D << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event25:base-stat] -fd=25 +[event29:base-stat] +fd=29 type=3 config=0 optional=1 @@ -200,8 +244,8 @@ optional=1 # PERF_COUNT_HW_CACHE_L1D << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event26:base-stat] -fd=26 +[event30:base-stat] +fd=30 type=3 config=65536 optional=1 @@ -210,8 +254,8 @@ optional=1 # PERF_COUNT_HW_CACHE_LL << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event27:base-stat] -fd=27 +[event31:base-stat] +fd=31 type=3 config=2 optional=1 @@ -220,8 +264,15 @@ optional=1 # PERF_COUNT_HW_CACHE_LL << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event28:base-stat] -fd=28 +[event32:base-stat] +fd=32 type=3 config=65538 optional=1 + +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +[event33:base-stat] +fd=33 +type=4 +config=4269 +optional=1
\ No newline at end of file diff --git a/tools/perf/tests/attr/test-stat-detailed-2 b/tools/perf/tests/shell/attr/test-stat-detailed-2 index 7e961d24a885..66ea25b7d38f 100644 --- a/tools/perf/tests/attr/test-stat-detailed-2 +++ b/tools/perf/tests/shell/attr/test-stat-detailed-2 @@ -90,99 +90,143 @@ enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / topdown-fe-bound (0x8200) +# PERF_TYPE_RAW / topdown-bad-spec (0x8100) [event13:base-stat] fd=13 group_fd=11 type=4 -config=33280 +config=33024 disabled=0 enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / topdown-be-bound (0x8300) +# PERF_TYPE_RAW / topdown-fe-bound (0x8200) [event14:base-stat] fd=14 group_fd=11 type=4 -config=33536 +config=33280 disabled=0 enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / topdown-bad-spec (0x8100) +# PERF_TYPE_RAW / topdown-be-bound (0x8300) [event15:base-stat] fd=15 group_fd=11 type=4 -config=33024 +config=33536 disabled=0 enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +# PERF_TYPE_RAW / topdown-heavy-ops (0x8400) [event16:base-stat] fd=16 +group_fd=11 type=4 -config=4109 +config=33792 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ +# PERF_TYPE_RAW / topdown-br-mispredict (0x8500) [event17:base-stat] fd=17 +group_fd=11 type=4 -config=17039629 +config=34048 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD +# PERF_TYPE_RAW / topdown-fetch-lat (0x8600) [event18:base-stat] fd=18 +group_fd=11 type=4 -config=60 +config=34304 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY +# PERF_TYPE_RAW / topdown-mem-bound (0x8700) [event19:base-stat] fd=19 +group_fd=11 type=4 -config=2097421 +config=34560 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING [event20:base-stat] fd=20 type=4 -config=316 +config=4109 optional=1 -# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE +# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ [event21:base-stat] fd=21 type=4 -config=412 +config=17039629 optional=1 -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD [event22:base-stat] fd=22 type=4 -config=572 +config=60 optional=1 -# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS +# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY [event23:base-stat] fd=23 type=4 -config=706 +config=2097421 optional=1 -# PERF_TYPE_RAW / UOPS_ISSUED.ANY +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK [event24:base-stat] fd=24 type=4 +config=316 +optional=1 + +# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE +[event25:base-stat] +fd=25 +type=4 +config=412 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE +[event26:base-stat] +fd=26 +type=4 +config=572 +optional=1 + +# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS +[event27:base-stat] +fd=27 +type=4 +config=706 +optional=1 + +# PERF_TYPE_RAW / UOPS_ISSUED.ANY +[event28:base-stat] +fd=28 +type=4 config=270 optional=1 @@ -190,8 +234,8 @@ optional=1 # PERF_COUNT_HW_CACHE_L1D << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event25:base-stat] -fd=25 +[event29:base-stat] +fd=29 type=3 config=0 optional=1 @@ -200,8 +244,8 @@ optional=1 # PERF_COUNT_HW_CACHE_L1D << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event26:base-stat] -fd=26 +[event30:base-stat] +fd=30 type=3 config=65536 optional=1 @@ -210,8 +254,8 @@ optional=1 # PERF_COUNT_HW_CACHE_LL << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event27:base-stat] -fd=27 +[event31:base-stat] +fd=31 type=3 config=2 optional=1 @@ -220,8 +264,8 @@ optional=1 # PERF_COUNT_HW_CACHE_LL << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event28:base-stat] -fd=28 +[event32:base-stat] +fd=32 type=3 config=65538 optional=1 @@ -230,8 +274,8 @@ optional=1 # PERF_COUNT_HW_CACHE_L1I << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event29:base-stat] -fd=29 +[event33:base-stat] +fd=33 type=3 config=1 optional=1 @@ -240,8 +284,8 @@ optional=1 # PERF_COUNT_HW_CACHE_L1I << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event30:base-stat] -fd=30 +[event34:base-stat] +fd=34 type=3 config=65537 optional=1 @@ -250,8 +294,8 @@ optional=1 # PERF_COUNT_HW_CACHE_DTLB << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event31:base-stat] -fd=31 +[event35:base-stat] +fd=35 type=3 config=3 optional=1 @@ -260,8 +304,8 @@ optional=1 # PERF_COUNT_HW_CACHE_DTLB << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event32:base-stat] -fd=32 +[event36:base-stat] +fd=36 type=3 config=65539 optional=1 @@ -270,8 +314,8 @@ optional=1 # PERF_COUNT_HW_CACHE_ITLB << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event33:base-stat] -fd=33 +[event37:base-stat] +fd=37 type=3 config=4 optional=1 @@ -280,8 +324,15 @@ optional=1 # PERF_COUNT_HW_CACHE_ITLB << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event34:base-stat] -fd=34 +[event38:base-stat] +fd=38 type=3 config=65540 optional=1 + +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +[event39:base-stat] +fd=39 +type=4 +config=4269 +optional=1
\ No newline at end of file diff --git a/tools/perf/tests/attr/test-stat-detailed-3 b/tools/perf/tests/shell/attr/test-stat-detailed-3 index e50535f45977..4a27bbfb9f87 100644 --- a/tools/perf/tests/attr/test-stat-detailed-3 +++ b/tools/perf/tests/shell/attr/test-stat-detailed-3 @@ -90,99 +90,143 @@ enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / topdown-fe-bound (0x8200) +# PERF_TYPE_RAW / topdown-bad-spec (0x8100) [event13:base-stat] fd=13 group_fd=11 type=4 -config=33280 +config=33024 disabled=0 enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / topdown-be-bound (0x8300) +# PERF_TYPE_RAW / topdown-fe-bound (0x8200) [event14:base-stat] fd=14 group_fd=11 type=4 -config=33536 +config=33280 disabled=0 enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / topdown-bad-spec (0x8100) +# PERF_TYPE_RAW / topdown-be-bound (0x8300) [event15:base-stat] fd=15 group_fd=11 type=4 -config=33024 +config=33536 disabled=0 enable_on_exec=0 read_format=15 optional=1 -# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +# PERF_TYPE_RAW / topdown-heavy-ops (0x8400) [event16:base-stat] fd=16 +group_fd=11 type=4 -config=4109 +config=33792 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ +# PERF_TYPE_RAW / topdown-br-mispredict (0x8500) [event17:base-stat] fd=17 +group_fd=11 type=4 -config=17039629 +config=34048 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD +# PERF_TYPE_RAW / topdown-fetch-lat (0x8600) [event18:base-stat] fd=18 +group_fd=11 type=4 -config=60 +config=34304 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY +# PERF_TYPE_RAW / topdown-mem-bound (0x8700) [event19:base-stat] fd=19 +group_fd=11 type=4 -config=2097421 +config=34560 +disabled=0 +enable_on_exec=0 +read_format=15 optional=1 -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING [event20:base-stat] fd=20 type=4 -config=316 +config=4109 optional=1 -# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE +# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ [event21:base-stat] fd=21 type=4 -config=412 +config=17039629 optional=1 -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD [event22:base-stat] fd=22 type=4 -config=572 +config=60 optional=1 -# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS +# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY [event23:base-stat] fd=23 type=4 -config=706 +config=2097421 optional=1 -# PERF_TYPE_RAW / UOPS_ISSUED.ANY +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK [event24:base-stat] fd=24 type=4 +config=316 +optional=1 + +# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE +[event25:base-stat] +fd=25 +type=4 +config=412 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE +[event26:base-stat] +fd=26 +type=4 +config=572 +optional=1 + +# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS +[event27:base-stat] +fd=27 +type=4 +config=706 +optional=1 + +# PERF_TYPE_RAW / UOPS_ISSUED.ANY +[event28:base-stat] +fd=28 +type=4 config=270 optional=1 @@ -190,8 +234,8 @@ optional=1 # PERF_COUNT_HW_CACHE_L1D << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event25:base-stat] -fd=25 +[event29:base-stat] +fd=29 type=3 config=0 optional=1 @@ -200,8 +244,8 @@ optional=1 # PERF_COUNT_HW_CACHE_L1D << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event26:base-stat] -fd=26 +[event30:base-stat] +fd=30 type=3 config=65536 optional=1 @@ -210,8 +254,8 @@ optional=1 # PERF_COUNT_HW_CACHE_LL << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event27:base-stat] -fd=27 +[event31:base-stat] +fd=31 type=3 config=2 optional=1 @@ -220,8 +264,8 @@ optional=1 # PERF_COUNT_HW_CACHE_LL << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event28:base-stat] -fd=28 +[event32:base-stat] +fd=32 type=3 config=65538 optional=1 @@ -230,8 +274,8 @@ optional=1 # PERF_COUNT_HW_CACHE_L1I << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event29:base-stat] -fd=29 +[event33:base-stat] +fd=33 type=3 config=1 optional=1 @@ -240,8 +284,8 @@ optional=1 # PERF_COUNT_HW_CACHE_L1I << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event30:base-stat] -fd=30 +[event34:base-stat] +fd=34 type=3 config=65537 optional=1 @@ -250,8 +294,8 @@ optional=1 # PERF_COUNT_HW_CACHE_DTLB << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event31:base-stat] -fd=31 +[event35:base-stat] +fd=35 type=3 config=3 optional=1 @@ -260,8 +304,8 @@ optional=1 # PERF_COUNT_HW_CACHE_DTLB << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event32:base-stat] -fd=32 +[event36:base-stat] +fd=36 type=3 config=65539 optional=1 @@ -270,8 +314,8 @@ optional=1 # PERF_COUNT_HW_CACHE_ITLB << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event33:base-stat] -fd=33 +[event37:base-stat] +fd=37 type=3 config=4 optional=1 @@ -280,8 +324,8 @@ optional=1 # PERF_COUNT_HW_CACHE_ITLB << 0 | # (PERF_COUNT_HW_CACHE_OP_READ << 8) | # (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event34:base-stat] -fd=34 +[event38:base-stat] +fd=38 type=3 config=65540 optional=1 @@ -290,8 +334,8 @@ optional=1 # PERF_COUNT_HW_CACHE_L1D << 0 | # (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | # (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event35:base-stat] -fd=35 +[event39:base-stat] +fd=39 type=3 config=512 optional=1 @@ -300,8 +344,15 @@ optional=1 # PERF_COUNT_HW_CACHE_L1D << 0 | # (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | # (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event36:base-stat] -fd=36 +[event40:base-stat] +fd=40 type=3 config=66048 optional=1 + +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +[event41:base-stat] +fd=41 +type=4 +config=4269 +optional=1
\ No newline at end of file diff --git a/tools/perf/tests/attr/test-stat-group1 b/tools/perf/tests/shell/attr/test-stat-group1 index 1746751123dc..1746751123dc 100644 --- a/tools/perf/tests/attr/test-stat-group1 +++ b/tools/perf/tests/shell/attr/test-stat-group1 diff --git a/tools/perf/tests/attr/test-stat-no-inherit b/tools/perf/tests/shell/attr/test-stat-no-inherit index 924fbb9300d1..924fbb9300d1 100644 --- a/tools/perf/tests/attr/test-stat-no-inherit +++ b/tools/perf/tests/shell/attr/test-stat-no-inherit diff --git a/tools/perf/tests/shell/base_probe/test_adding_blacklisted.sh b/tools/perf/tests/shell/base_probe/test_adding_blacklisted.sh index bead723e34af..f74aab5c5d7f 100755 --- a/tools/perf/tests/shell/base_probe/test_adding_blacklisted.sh +++ b/tools/perf/tests/shell/base_probe/test_adding_blacklisted.sh @@ -1,5 +1,5 @@ #!/bin/bash - +# perf_probe :: Reject blacklisted probes (exclusive) # SPDX-License-Identifier: GPL-2.0 # @@ -13,16 +13,17 @@ # they must be skipped. # -# include working environment -. ../common/init.sh - +DIR_PATH="$(dirname $0)" TEST_RESULT=0 +# include working environment +. "$DIR_PATH/../common/init.sh" + # skip if not supported BLACKFUNC_LIST=`head -n 5 /sys/kernel/debug/kprobes/blacklist 2> /dev/null | cut -f2` if [ -z "$BLACKFUNC_LIST" ]; then print_overall_skipped - exit 0 + exit 2 fi # try to find vmlinux with DWARF debug info @@ -53,7 +54,8 @@ for BLACKFUNC in $BLACKFUNC_LIST; do PERF_EXIT_CODE=$? # check for bad DWARF polluting the result - ../common/check_all_patterns_found.pl "$REGEX_MISSING_DECL_LINE" >/dev/null < $LOGS_DIR/adding_blacklisted.err + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "$REGEX_MISSING_DECL_LINE" >/dev/null < $LOGS_DIR/adding_blacklisted.err if [ $? -eq 0 ]; then SKIP_DWARF=1 @@ -73,7 +75,11 @@ for BLACKFUNC in $BLACKFUNC_LIST; do fi fi else - ../common/check_all_lines_matched.pl "$REGEX_SKIP_MESSAGE" "$REGEX_NOT_FOUND_MESSAGE" "$REGEX_ERROR_MESSAGE" "$REGEX_SCOPE_FAIL" "$REGEX_INVALID_ARGUMENT" "$REGEX_SYMBOL_FAIL" "$REGEX_OUT_SECTION" < $LOGS_DIR/adding_blacklisted.err + "$DIR_PATH/../common/check_all_lines_matched.pl" \ + "$REGEX_SKIP_MESSAGE" "$REGEX_NOT_FOUND_MESSAGE" \ + "$REGEX_ERROR_MESSAGE" "$REGEX_SCOPE_FAIL" \ + "$REGEX_INVALID_ARGUMENT" "$REGEX_SYMBOL_FAIL" \ + "$REGEX_OUT_SECTION" < $LOGS_DIR/adding_blacklisted.err CHECK_EXIT_CODE=$? SKIP_DWARF=0 @@ -94,7 +100,9 @@ fi $CMD_PERF list probe:\* > $LOGS_DIR/adding_blacklisted_list.log PERF_EXIT_CODE=$? -../common/check_all_lines_matched.pl "$RE_LINE_EMPTY" "List of pre-defined events" "Metric Groups:" < $LOGS_DIR/adding_blacklisted_list.log +"$DIR_PATH/../common/check_all_lines_matched.pl" \ + "$RE_LINE_EMPTY" "List of pre-defined events" "Metric Groups:" \ + < $LOGS_DIR/adding_blacklisted_list.log CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "listing blacklisted probe (should NOT be listed)" diff --git a/tools/perf/tests/shell/base_probe/test_adding_kernel.sh b/tools/perf/tests/shell/base_probe/test_adding_kernel.sh index d541ffd44a93..555a825d55f2 100755 --- a/tools/perf/tests/shell/base_probe/test_adding_kernel.sh +++ b/tools/perf/tests/shell/base_probe/test_adding_kernel.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Add 'perf probe's, list and remove them +# perf_probe :: Add probes, list and remove them (exclusive) # SPDX-License-Identifier: GPL-2.0 # @@ -13,13 +13,14 @@ # and removing. # -# include working environment -. ../common/init.sh - +DIR_PATH="$(dirname $0)" TEST_RESULT=0 +# include working environment +. "$DIR_PATH/../common/init.sh" + # shellcheck source=lib/probe_vfs_getname.sh -. "$(dirname "$0")/../lib/probe_vfs_getname.sh" +. "$DIR_PATH/../lib/probe_vfs_getname.sh" TEST_PROBE=${TEST_PROBE:-"inode_permission"} @@ -33,7 +34,7 @@ fi check_kprobes_available if [ $? -ne 0 ]; then print_overall_skipped - exit 0 + exit 2 fi @@ -44,7 +45,9 @@ for opt in "" "-a" "--add"; do $CMD_PERF probe $opt $TEST_PROBE 2> $LOGS_DIR/adding_kernel_add$opt.err PERF_EXIT_CODE=$? - ../common/check_all_patterns_found.pl "Added new events?:" "probe:$TEST_PROBE" "on $TEST_PROBE" < $LOGS_DIR/adding_kernel_add$opt.err + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "Added new events?:" "probe:$TEST_PROBE" "on $TEST_PROBE" \ + < $LOGS_DIR/adding_kernel_add$opt.err CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "adding probe $TEST_PROBE :: $opt" @@ -58,7 +61,10 @@ done $CMD_PERF list probe:\* > $LOGS_DIR/adding_kernel_list.log PERF_EXIT_CODE=$? -../common/check_all_lines_matched.pl "$RE_LINE_EMPTY" "List of pre-defined events" "probe:${TEST_PROBE}(?:_\d+)?\s+\[Tracepoint event\]" "Metric Groups:" < $LOGS_DIR/adding_kernel_list.log +"$DIR_PATH/../common/check_all_lines_matched.pl" \ + "$RE_LINE_EMPTY" "List of pre-defined events" \ + "probe:${TEST_PROBE}(?:_\d+)?\s+\[Tracepoint event\]" \ + "Metric Groups:" < $LOGS_DIR/adding_kernel_list.log CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "listing added probe :: perf list" @@ -71,7 +77,9 @@ print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "listing added probe :: perf list $CMD_PERF probe -l > $LOGS_DIR/adding_kernel_list-l.log PERF_EXIT_CODE=$? -../common/check_all_patterns_found.pl "\s*probe:${TEST_PROBE}(?:_\d+)?\s+\(on ${TEST_PROBE}(?:[:\+]$RE_NUMBER_HEX)?@.+\)" < $LOGS_DIR/adding_kernel_list-l.log +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "\s*probe:${TEST_PROBE}(?:_\d+)?\s+\(on ${TEST_PROBE}(?:[:\+]$RE_NUMBER_HEX)?@.+\)" \ + < $LOGS_DIR/adding_kernel_list-l.log CHECK_EXIT_CODE=$? if [ $NO_DEBUGINFO ] ; then @@ -93,9 +101,13 @@ REGEX_STAT_VALUES="\s*\d+\s+probe:$TEST_PROBE" # the value should be greater than 1 REGEX_STAT_VALUE_NONZERO="\s*[1-9][0-9]*\s+probe:$TEST_PROBE" REGEX_STAT_TIME="\s*$RE_NUMBER\s+seconds (?:time elapsed|user|sys)" -../common/check_all_lines_matched.pl "$REGEX_STAT_HEADER" "$REGEX_STAT_VALUES" "$REGEX_STAT_TIME" "$RE_LINE_COMMENT" "$RE_LINE_EMPTY" < $LOGS_DIR/adding_kernel_using_probe.log +"$DIR_PATH/../common/check_all_lines_matched.pl" \ + "$REGEX_STAT_HEADER" "$REGEX_STAT_VALUES" "$REGEX_STAT_TIME" \ + "$RE_LINE_COMMENT" "$RE_LINE_EMPTY" < $LOGS_DIR/adding_kernel_using_probe.log CHECK_EXIT_CODE=$? -../common/check_all_patterns_found.pl "$REGEX_STAT_HEADER" "$REGEX_STAT_VALUE_NONZERO" "$REGEX_STAT_TIME" < $LOGS_DIR/adding_kernel_using_probe.log +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "$REGEX_STAT_HEADER" "$REGEX_STAT_VALUE_NONZERO" "$REGEX_STAT_TIME" \ + < $LOGS_DIR/adding_kernel_using_probe.log (( CHECK_EXIT_CODE += $? )) print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "using added probe" @@ -108,7 +120,8 @@ print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "using added probe" $CMD_PERF probe -d $TEST_PROBE\* 2> $LOGS_DIR/adding_kernel_removing.err PERF_EXIT_CODE=$? -../common/check_all_lines_matched.pl "Removed event: probe:$TEST_PROBE" < $LOGS_DIR/adding_kernel_removing.err +"$DIR_PATH/../common/check_all_lines_matched.pl" \ + "Removed event: probe:$TEST_PROBE" < $LOGS_DIR/adding_kernel_removing.err CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "deleting added probe" @@ -121,7 +134,9 @@ print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "deleting added probe" $CMD_PERF list probe:\* > $LOGS_DIR/adding_kernel_list_removed.log PERF_EXIT_CODE=$? -../common/check_all_lines_matched.pl "$RE_LINE_EMPTY" "List of pre-defined events" "Metric Groups:" < $LOGS_DIR/adding_kernel_list_removed.log +"$DIR_PATH/../common/check_all_lines_matched.pl" \ + "$RE_LINE_EMPTY" "List of pre-defined events" "Metric Groups:" \ + < $LOGS_DIR/adding_kernel_list_removed.log CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "listing removed probe (should NOT be listed)" @@ -135,7 +150,9 @@ $CMD_PERF probe -n --add $TEST_PROBE 2> $LOGS_DIR/adding_kernel_dryrun.err PERF_EXIT_CODE=$? # check for the output (should be the same as usual) -../common/check_all_patterns_found.pl "Added new events?:" "probe:$TEST_PROBE" "on $TEST_PROBE" < $LOGS_DIR/adding_kernel_dryrun.err +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "Added new events?:" "probe:$TEST_PROBE" "on $TEST_PROBE" \ + < $LOGS_DIR/adding_kernel_dryrun.err CHECK_EXIT_CODE=$? # check that no probe was added in real @@ -152,7 +169,9 @@ print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "dry run :: adding probe" $CMD_PERF probe --add $TEST_PROBE 2> $LOGS_DIR/adding_kernel_forceadd_01.err PERF_EXIT_CODE=$? -../common/check_all_patterns_found.pl "Added new events?:" "probe:$TEST_PROBE" "on $TEST_PROBE" < $LOGS_DIR/adding_kernel_forceadd_01.err +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "Added new events?:" "probe:$TEST_PROBE" "on $TEST_PROBE" \ + < $LOGS_DIR/adding_kernel_forceadd_01.err CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "force-adding probes :: first probe adding" @@ -162,18 +181,22 @@ print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "force-adding probes :: first pro ! $CMD_PERF probe --add $TEST_PROBE 2> $LOGS_DIR/adding_kernel_forceadd_02.err PERF_EXIT_CODE=$? -../common/check_all_patterns_found.pl "Error: event \"$TEST_PROBE\" already exists." "Error: Failed to add events." < $LOGS_DIR/adding_kernel_forceadd_02.err +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "Error: event \"$TEST_PROBE\" already exists." \ + "Error: Failed to add events." < $LOGS_DIR/adding_kernel_forceadd_02.err CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "force-adding probes :: second probe adding (without force)" (( TEST_RESULT += $? )) # adding existing probe with '--force' should pass -NO_OF_PROBES=`$CMD_PERF probe -l | wc -l` +NO_OF_PROBES=`$CMD_PERF probe -l $TEST_PROBE| wc -l` $CMD_PERF probe --force --add $TEST_PROBE 2> $LOGS_DIR/adding_kernel_forceadd_03.err PERF_EXIT_CODE=$? -../common/check_all_patterns_found.pl "Added new events?:" "probe:${TEST_PROBE}_${NO_OF_PROBES}" "on $TEST_PROBE" < $LOGS_DIR/adding_kernel_forceadd_03.err +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "Added new events?:" "probe:${TEST_PROBE}_${NO_OF_PROBES}" \ + "on $TEST_PROBE" < $LOGS_DIR/adding_kernel_forceadd_03.err CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "force-adding probes :: second probe adding (with force)" @@ -187,7 +210,9 @@ $CMD_PERF stat -e probe:$TEST_PROBE -e probe:${TEST_PROBE}_${NO_OF_PROBES} -x';' PERF_EXIT_CODE=$? REGEX_LINE="$RE_NUMBER;+probe:${TEST_PROBE}_?(?:$NO_OF_PROBES)?;$RE_NUMBER;$RE_NUMBER" -../common/check_all_lines_matched.pl "$REGEX_LINE" "$RE_LINE_EMPTY" "$RE_LINE_COMMENT" < $LOGS_DIR/adding_kernel_using_two.log +"$DIR_PATH/../common/check_all_lines_matched.pl" \ + "$REGEX_LINE" "$RE_LINE_EMPTY" "$RE_LINE_COMMENT" \ + < $LOGS_DIR/adding_kernel_using_two.log CHECK_EXIT_CODE=$? VALUE_1=`grep "$TEST_PROBE;" $LOGS_DIR/adding_kernel_using_two.log | awk -F';' '{print $1}'` @@ -205,7 +230,9 @@ print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "using doubled probe" $CMD_PERF probe --del \* 2> $LOGS_DIR/adding_kernel_removing_wildcard.err PERF_EXIT_CODE=$? -../common/check_all_lines_matched.pl "Removed event: probe:$TEST_PROBE" "Removed event: probe:${TEST_PROBE}_1" < $LOGS_DIR/adding_kernel_removing_wildcard.err +"$DIR_PATH/../common/check_all_lines_matched.pl" \ + "Removed event: probe:$TEST_PROBE" \ + "Removed event: probe:${TEST_PROBE}_1" < $LOGS_DIR/adding_kernel_removing_wildcard.err CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "removing multiple probes" @@ -217,7 +244,9 @@ print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "removing multiple probes" $CMD_PERF probe -nf --max-probes=512 -a 'vfs_* $params' 2> $LOGS_DIR/adding_kernel_adding_wildcard.err PERF_EXIT_CODE=$? -../common/check_all_patterns_found.pl "probe:vfs_mknod" "probe:vfs_create" "probe:vfs_rmdir" "probe:vfs_link" "probe:vfs_write" < $LOGS_DIR/adding_kernel_adding_wildcard.err +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "probe:vfs_mknod" "probe:vfs_create" "probe:vfs_rmdir" \ + "probe:vfs_link" "probe:vfs_write" < $LOGS_DIR/adding_kernel_adding_wildcard.err CHECK_EXIT_CODE=$? if [ $NO_DEBUGINFO ] ; then @@ -240,13 +269,22 @@ test $PERF_EXIT_CODE -ne 139 -a $PERF_EXIT_CODE -ne 0 PERF_EXIT_CODE=$? # check that the error message is reasonable -../common/check_all_patterns_found.pl "Failed to find" "somenonexistingrandomstuffwhichisalsoprettylongorevenlongertoexceed64" < $LOGS_DIR/adding_kernel_nonexisting.err +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "Failed to find" \ + "somenonexistingrandomstuffwhichisalsoprettylongorevenlongertoexceed64" \ + < $LOGS_DIR/adding_kernel_nonexisting.err CHECK_EXIT_CODE=$? -../common/check_all_patterns_found.pl "in this function|at this address" "Error" "Failed to add events" < $LOGS_DIR/adding_kernel_nonexisting.err +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "in this function|at this address" "Error" "Failed to add events" \ + < $LOGS_DIR/adding_kernel_nonexisting.err (( CHECK_EXIT_CODE += $? )) -../common/check_all_lines_matched.pl "Failed to find" "Error" "Probe point .+ not found" "optimized out" "Use.+\-\-range option to show.+location range" < $LOGS_DIR/adding_kernel_nonexisting.err +"$DIR_PATH/../common/check_all_lines_matched.pl" \ + "Failed to find" "Error" "Probe point .+ not found" "optimized out" \ + "Use.+\-\-range option to show.+location range" \ + < $LOGS_DIR/adding_kernel_nonexisting.err (( CHECK_EXIT_CODE += $? )) -../common/check_no_patterns_found.pl "$RE_SEGFAULT" < $LOGS_DIR/adding_kernel_nonexisting.err +"$DIR_PATH/../common/check_no_patterns_found.pl" \ + "$RE_SEGFAULT" < $LOGS_DIR/adding_kernel_nonexisting.err (( CHECK_EXIT_CODE += $? )) if [ $NO_DEBUGINFO ]; then @@ -264,7 +302,10 @@ fi $CMD_PERF probe --add "$TEST_PROBE%return \$retval" 2> $LOGS_DIR/adding_kernel_func_retval_add.err PERF_EXIT_CODE=$? -../common/check_all_patterns_found.pl "Added new events?:" "probe:$TEST_PROBE" "on $TEST_PROBE%return with \\\$retval" < $LOGS_DIR/adding_kernel_func_retval_add.err +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "Added new events?:" "probe:$TEST_PROBE" \ + "on $TEST_PROBE%return with \\\$retval" \ + < $LOGS_DIR/adding_kernel_func_retval_add.err CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "function with retval :: add" @@ -274,7 +315,9 @@ print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "function with retval :: add" $CMD_PERF record -e probe:$TEST_PROBE\* -o $CURRENT_TEST_DIR/perf.data -- cat /proc/cpuinfo > /dev/null 2> $LOGS_DIR/adding_kernel_func_retval_record.err PERF_EXIT_CODE=$? -../common/check_all_patterns_found.pl "$RE_LINE_RECORD1" "$RE_LINE_RECORD2" < $LOGS_DIR/adding_kernel_func_retval_record.err +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "$RE_LINE_RECORD1" "$RE_LINE_RECORD2" \ + < $LOGS_DIR/adding_kernel_func_retval_record.err CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "function with retval :: record" @@ -285,9 +328,11 @@ $CMD_PERF script -i $CURRENT_TEST_DIR/perf.data > $LOGS_DIR/adding_kernel_func_r PERF_EXIT_CODE=$? REGEX_SCRIPT_LINE="\s*cat\s+$RE_NUMBER\s+\[$RE_NUMBER\]\s+$RE_NUMBER:\s+probe:$TEST_PROBE\w*:\s+\($RE_NUMBER_HEX\s+<\-\s+$RE_NUMBER_HEX\)\s+arg1=$RE_NUMBER_HEX" -../common/check_all_lines_matched.pl "$REGEX_SCRIPT_LINE" < $LOGS_DIR/adding_kernel_func_retval_script.log +"$DIR_PATH/../common/check_all_lines_matched.pl" \ + "$REGEX_SCRIPT_LINE" < $LOGS_DIR/adding_kernel_func_retval_script.log CHECK_EXIT_CODE=$? -../common/check_all_patterns_found.pl "$REGEX_SCRIPT_LINE" < $LOGS_DIR/adding_kernel_func_retval_script.log +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "$REGEX_SCRIPT_LINE" < $LOGS_DIR/adding_kernel_func_retval_script.log (( CHECK_EXIT_CODE += $? )) print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "function argument probing :: script" diff --git a/tools/perf/tests/shell/base_probe/test_basic.sh b/tools/perf/tests/shell/base_probe/test_basic.sh index 09669ec479f2..162838ddc974 100755 --- a/tools/perf/tests/shell/base_probe/test_basic.sh +++ b/tools/perf/tests/shell/base_probe/test_basic.sh @@ -1,5 +1,5 @@ #!/bin/bash - +# perf_probe :: Basic perf probe functionality (exclusive) # SPDX-License-Identifier: GPL-2.0 # @@ -12,14 +12,15 @@ # This test tests basic functionality of perf probe command. # -# include working environment -. ../common/init.sh - +DIR_PATH="$(dirname $0)" TEST_RESULT=0 +# include working environment +. "$DIR_PATH/../common/init.sh" + if ! check_kprobes_available; then print_overall_skipped - exit 0 + exit 2 fi @@ -30,15 +31,25 @@ if [ "$PARAM_GENERAL_HELP_TEXT_CHECK" = "y" ]; then $CMD_PERF probe --help > $LOGS_DIR/basic_helpmsg.log 2> $LOGS_DIR/basic_helpmsg.err PERF_EXIT_CODE=$? - ../common/check_all_patterns_found.pl "PERF-PROBE" "NAME" "SYNOPSIS" "DESCRIPTION" "OPTIONS" "PROBE\s+SYNTAX" "PROBE\s+ARGUMENT" "LINE\s+SYNTAX" < $LOGS_DIR/basic_helpmsg.log + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "PERF-PROBE" "NAME" "SYNOPSIS" "DESCRIPTION" "OPTIONS" \ + "PROBE\s+SYNTAX" "PROBE\s+ARGUMENT" "LINE\s+SYNTAX" \ + < $LOGS_DIR/basic_helpmsg.log CHECK_EXIT_CODE=$? - ../common/check_all_patterns_found.pl "LAZY\s+MATCHING" "FILTER\s+PATTERN" "EXAMPLES" "SEE\s+ALSO" < $LOGS_DIR/basic_helpmsg.log + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "LAZY\s+MATCHING" "FILTER\s+PATTERN" "EXAMPLES" "SEE\s+ALSO" \ + < $LOGS_DIR/basic_helpmsg.log (( CHECK_EXIT_CODE += $? )) - ../common/check_all_patterns_found.pl "vmlinux" "module=" "source=" "verbose" "quiet" "add=" "del=" "list.*EVENT" "line=" "vars=" "externs" < $LOGS_DIR/basic_helpmsg.log + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "vmlinux" "module=" "source=" "verbose" "quiet" "add=" "del=" \ + "list.*EVENT" "line=" "vars=" "externs" < $LOGS_DIR/basic_helpmsg.log (( CHECK_EXIT_CODE += $? )) - ../common/check_all_patterns_found.pl "no-inlines" "funcs.*FILTER" "filter=FILTER" "force" "dry-run" "max-probes" "exec=" "demangle-kernel" < $LOGS_DIR/basic_helpmsg.log + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "no-inlines" "funcs.*FILTER" "filter=FILTER" "force" "dry-run" \ + "max-probes" "exec=" "demangle-kernel" < $LOGS_DIR/basic_helpmsg.log (( CHECK_EXIT_CODE += $? )) - ../common/check_no_patterns_found.pl "No manual entry for" < $LOGS_DIR/basic_helpmsg.err + "$DIR_PATH/../common/check_no_patterns_found.pl" \ + "No manual entry for" < $LOGS_DIR/basic_helpmsg.err (( CHECK_EXIT_CODE += $? )) print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "help message" @@ -53,7 +64,9 @@ fi # without any args perf-probe should print usage $CMD_PERF probe 2> $LOGS_DIR/basic_usage.log > /dev/null -../common/check_all_patterns_found.pl "[Uu]sage" "perf probe" "verbose" "quiet" "add" "del" "force" "line" "vars" "externs" "range" < $LOGS_DIR/basic_usage.log +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "[Uu]sage" "perf probe" "verbose" "quiet" "add" "del" "force" \ + "line" "vars" "externs" "range" < $LOGS_DIR/basic_usage.log CHECK_EXIT_CODE=$? print_results 0 $CHECK_EXIT_CODE "usage message" diff --git a/tools/perf/tests/shell/base_probe/test_invalid_options.sh b/tools/perf/tests/shell/base_probe/test_invalid_options.sh index 1fedfd8b0d0d..44a3ae014bfa 100755 --- a/tools/perf/tests/shell/base_probe/test_invalid_options.sh +++ b/tools/perf/tests/shell/base_probe/test_invalid_options.sh @@ -1,5 +1,5 @@ #!/bin/bash - +# perf_probe :: Reject invalid options (exclusive) # SPDX-License-Identifier: GPL-2.0 # @@ -12,16 +12,20 @@ # This test checks whether the invalid and incompatible options are reported # -# include working environment -. ../common/init.sh - +DIR_PATH="$(dirname $0)" TEST_RESULT=0 +# include working environment +. "$DIR_PATH/../common/init.sh" + if ! check_kprobes_available; then print_overall_skipped - exit 0 + exit 2 fi +# Check for presence of DWARF +$CMD_PERF check feature -q dwarf +[ $? -ne 0 ] && HINT_FAIL="Some of the tests need DWARF to run" ### missing argument @@ -30,7 +34,9 @@ for opt in '-a' '-d' '-L' '-V'; do ! $CMD_PERF probe $opt 2> $LOGS_DIR/invalid_options_missing_argument$opt.err PERF_EXIT_CODE=$? - ../common/check_all_patterns_found.pl "Error: switch .* requires a value" < $LOGS_DIR/invalid_options_missing_argument$opt.err + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "Error: switch .* requires a value" \ + < $LOGS_DIR/invalid_options_missing_argument$opt.err CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "missing argument for $opt" @@ -63,7 +69,8 @@ for opt in '-a xxx -d xxx' '-a xxx -L foo' '-a xxx -V foo' '-a xxx -l' '-a xxx - ! $CMD_PERF probe $opt > /dev/null 2> $LOGS_DIR/aux.log PERF_EXIT_CODE=$? - ../common/check_all_patterns_found.pl "Error: switch .+ cannot be used with switch .+" < $LOGS_DIR/aux.log + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "Error: switch .+ cannot be used with switch .+" < $LOGS_DIR/aux.log CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "mutually exclusive options :: $opt" @@ -75,5 +82,5 @@ done # print overall results -print_overall_results "$TEST_RESULT" +print_overall_results "$TEST_RESULT" $HINT_FAIL exit $? diff --git a/tools/perf/tests/shell/base_probe/test_line_semantics.sh b/tools/perf/tests/shell/base_probe/test_line_semantics.sh index d8f4bde0f585..576442d87a44 100755 --- a/tools/perf/tests/shell/base_probe/test_line_semantics.sh +++ b/tools/perf/tests/shell/base_probe/test_line_semantics.sh @@ -1,5 +1,5 @@ #!/bin/bash - +# perf_probe :: Check patterns for line semantics (exclusive) # SPDX-License-Identifier: GPL-2.0 # @@ -13,16 +13,20 @@ # arguments are properly reported. # -# include working environment -. ../common/init.sh - +DIR_PATH="$(dirname $0)" TEST_RESULT=0 +# include working environment +. "$DIR_PATH/../common/init.sh" + if ! check_kprobes_available; then print_overall_skipped - exit 0 + exit 2 fi +# Check for presence of DWARF +$CMD_PERF check feature -q dwarf +[ $? -ne 0 ] && HINT_FAIL="Some of the tests need DWARF to run" ### acceptable --line descriptions @@ -51,5 +55,5 @@ done # print overall results -print_overall_results "$TEST_RESULT" +print_overall_results "$TEST_RESULT" $HINT_FAIL exit $? diff --git a/tools/perf/tests/shell/base_report/setup.sh b/tools/perf/tests/shell/base_report/setup.sh index 4caa496660c6..bb49b0fabb11 100755 --- a/tools/perf/tests/shell/base_report/setup.sh +++ b/tools/perf/tests/shell/base_report/setup.sh @@ -1,5 +1,5 @@ #!/bin/bash - +# perftool-testsuite :: perf_report # SPDX-License-Identifier: GPL-2.0 # @@ -12,8 +12,12 @@ # # +DIR_PATH="$(dirname $0)" + # include working environment -. ../common/init.sh +. "$DIR_PATH/../common/init.sh" + +TEST_RESULT=0 test -d "$HEADER_TAR_DIR" || mkdir -p "$HEADER_TAR_DIR" @@ -22,11 +26,27 @@ SW_EVENT="cpu-clock" $CMD_PERF record -asdg -e $SW_EVENT -o $CURRENT_TEST_DIR/perf.data -- $CMD_LONGER_SLEEP 2> $LOGS_DIR/setup.log PERF_EXIT_CODE=$? -../common/check_all_patterns_found.pl "$RE_LINE_RECORD1" "$RE_LINE_RECORD2" < $LOGS_DIR/setup.log +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "$RE_LINE_RECORD1" "$RE_LINE_RECORD2" < $LOGS_DIR/setup.log CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "prepare the perf.data file" -TEST_RESULT=$? +(( TEST_RESULT += $? )) + +# Some minimal parallel workload. +$CMD_PERF record --latency -o $CURRENT_TEST_DIR/perf.data.1 bash -c "for i in {1..100} ; do cat /proc/cpuinfo 1> /dev/null & done; sleep 1" 2> $LOGS_DIR/setup-latency.log +PERF_EXIT_CODE=$? + +echo ================== +cat $LOGS_DIR/setup-latency.log +echo ================== + +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "$RE_LINE_RECORD1" "$RE_LINE_RECORD2" < $LOGS_DIR/setup-latency.log +CHECK_EXIT_CODE=$? + +print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "prepare the perf.data.1 file" +(( TEST_RESULT += $? )) print_overall_results $TEST_RESULT exit $? diff --git a/tools/perf/tests/shell/base_report/test_basic.sh b/tools/perf/tests/shell/base_report/test_basic.sh index 47677cbd4df3..0dfe7e5fd1ca 100755 --- a/tools/perf/tests/shell/base_report/test_basic.sh +++ b/tools/perf/tests/shell/base_report/test_basic.sh @@ -1,5 +1,5 @@ #!/bin/bash - +# perf_report :: Basic perf report options (exclusive) # SPDX-License-Identifier: GPL-2.0 # @@ -12,11 +12,12 @@ # # -# include working environment -. ../common/init.sh - +DIR_PATH="$(dirname $0)" TEST_RESULT=0 +# include working environment +. "$DIR_PATH/../common/init.sh" + ### help message @@ -25,19 +26,37 @@ if [ "$PARAM_GENERAL_HELP_TEXT_CHECK" = "y" ]; then $CMD_PERF report --help > $LOGS_DIR/basic_helpmsg.log 2> $LOGS_DIR/basic_helpmsg.err PERF_EXIT_CODE=$? - ../common/check_all_patterns_found.pl "PERF-REPORT" "NAME" "SYNOPSIS" "DESCRIPTION" "OPTIONS" "OVERHEAD\s+CALCULATION" "SEE ALSO" < $LOGS_DIR/basic_helpmsg.log + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "PERF-REPORT" "NAME" "SYNOPSIS" "DESCRIPTION" "OPTIONS" \ + "OVERHEAD\s+CALCULATION" "SEE ALSO" < $LOGS_DIR/basic_helpmsg.log CHECK_EXIT_CODE=$? - ../common/check_all_patterns_found.pl "input" "verbose" "show-nr-samples" "show-cpu-utilization" "threads" "comms" "pid" "tid" "dsos" "symbols" "symbol-filter" < $LOGS_DIR/basic_helpmsg.log + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "input" "verbose" "show-nr-samples" "show-cpu-utilization" \ + "threads" "comms" "pid" "tid" "dsos" "symbols" "symbol-filter" \ + < $LOGS_DIR/basic_helpmsg.log (( CHECK_EXIT_CODE += $? )) - ../common/check_all_patterns_found.pl "hide-unresolved" "sort" "fields" "parent" "exclude-other" "column-widths" "field-separator" "dump-raw-trace" "children" < $LOGS_DIR/basic_helpmsg.log + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "hide-unresolved" "sort" "fields" "parent" "exclude-other" \ + "column-widths" "field-separator" "dump-raw-trace" "children" \ + < $LOGS_DIR/basic_helpmsg.log (( CHECK_EXIT_CODE += $? )) - ../common/check_all_patterns_found.pl "call-graph" "max-stack" "inverted" "ignore-callees" "pretty" "stdio" "tui" "gtk" "vmlinux" "kallsyms" "modules" < $LOGS_DIR/basic_helpmsg.log + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "call-graph" "max-stack" "inverted" "ignore-callees" "pretty" \ + "stdio" "tui" "gtk" "vmlinux" "kallsyms" "modules" \ + < $LOGS_DIR/basic_helpmsg.log (( CHECK_EXIT_CODE += $? )) - ../common/check_all_patterns_found.pl "force" "symfs" "cpu" "disassembler-style" "source" "asm-raw" "show-total-period" "show-info" "branch-stack" "group" < $LOGS_DIR/basic_helpmsg.log + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "force" "symfs" "cpu" "disassembler-style" "source" "asm-raw" \ + "show-total-period" "show-info" "branch-stack" "group" \ + < $LOGS_DIR/basic_helpmsg.log (( CHECK_EXIT_CODE += $? )) - ../common/check_all_patterns_found.pl "branch-history" "objdump" "demangle" "percent-limit" "percentage" "header" "itrace" "full-source-path" "show-ref-call-graph" < $LOGS_DIR/basic_helpmsg.log + "$DIR_PATH/../common/check_all_patterns_found.pl" \ + "branch-history" "objdump" "demangle" "percent-limit" "percentage" \ + "header" "itrace" "full-source-path" "show-ref-call-graph" \ + < $LOGS_DIR/basic_helpmsg.log (( CHECK_EXIT_CODE += $? )) - ../common/check_no_patterns_found.pl "No manual entry for" < $LOGS_DIR/basic_helpmsg.err + "$DIR_PATH/../common/check_no_patterns_found.pl" \ + "No manual entry for" < $LOGS_DIR/basic_helpmsg.err (( CHECK_EXIT_CODE += $? )) print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "help message" @@ -57,9 +76,12 @@ REGEX_LOST_SAMPLES_INFO="#\s*Total Lost Samples:\s+$RE_NUMBER" REGEX_SAMPLES_INFO="#\s*Samples:\s+(?:$RE_NUMBER)\w?\s+of\s+event\s+'$RE_EVENT_ANY'" REGEX_LINES_HEADER="#\s*Children\s+Self\s+Command\s+Shared Object\s+Symbol" REGEX_LINES="\s*$RE_NUMBER%\s+$RE_NUMBER%\s+\S+\s+\[kernel\.(?:vmlinux)|(?:kallsyms)\]\s+\[[k\.]\]\s+\w+" -../common/check_all_patterns_found.pl "$REGEX_LOST_SAMPLES_INFO" "$REGEX_SAMPLES_INFO" "$REGEX_LINES_HEADER" "$REGEX_LINES" < $LOGS_DIR/basic_basic.log +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "$REGEX_LOST_SAMPLES_INFO" "$REGEX_SAMPLES_INFO" \ + "$REGEX_LINES_HEADER" "$REGEX_LINES" < $LOGS_DIR/basic_basic.log CHECK_EXIT_CODE=$? -../common/check_errors_whitelisted.pl "stderr-whitelist.txt" < $LOGS_DIR/basic_basic.err +"$DIR_PATH/../common/check_errors_whitelisted.pl" \ + "$DIR_PATH/stderr-whitelist.txt" < $LOGS_DIR/basic_basic.err (( CHECK_EXIT_CODE += $? )) print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "basic execution" @@ -74,9 +96,11 @@ PERF_EXIT_CODE=$? REGEX_LINES_HEADER="#\s*Children\s+Self\s+Samples\s+Command\s+Shared Object\s+Symbol" REGEX_LINES="\s*$RE_NUMBER%\s+$RE_NUMBER%\s+$RE_NUMBER\s+\S+\s+\[kernel\.(?:vmlinux)|(?:kallsyms)\]\s+\[[k\.]\]\s+\w+" -../common/check_all_patterns_found.pl "$REGEX_LINES_HEADER" "$REGEX_LINES" < $LOGS_DIR/basic_nrsamples.log +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "$REGEX_LINES_HEADER" "$REGEX_LINES" < $LOGS_DIR/basic_nrsamples.log CHECK_EXIT_CODE=$? -../common/check_errors_whitelisted.pl "stderr-whitelist.txt" < $LOGS_DIR/basic_nrsamples.err +"$DIR_PATH/../common/check_errors_whitelisted.pl" \ + "$DIR_PATH/stderr-whitelist.txt" < $LOGS_DIR/basic_nrsamples.err (( CHECK_EXIT_CODE += $? )) print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "number of samples" @@ -98,7 +122,10 @@ REGEX_LINE_CPUS_ONLINE="#\s+nrcpus online\s*:\s*$MY_CPUS_ONLINE" REGEX_LINE_CPUS_AVAIL="#\s+nrcpus avail\s*:\s*$MY_CPUS_AVAILABLE" # disable precise check for "nrcpus avail" in BASIC runmode test $PERFTOOL_TESTSUITE_RUNMODE -lt $RUNMODE_STANDARD && REGEX_LINE_CPUS_AVAIL="#\s+nrcpus avail\s*:\s*$RE_NUMBER" -../common/check_all_patterns_found.pl "$REGEX_LINE_TIMESTAMP" "$REGEX_LINE_HOSTNAME" "$REGEX_LINE_KERNEL" "$REGEX_LINE_PERF" "$REGEX_LINE_ARCH" "$REGEX_LINE_CPUS_ONLINE" "$REGEX_LINE_CPUS_AVAIL" < $LOGS_DIR/basic_header.log +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "$REGEX_LINE_TIMESTAMP" "$REGEX_LINE_HOSTNAME" "$REGEX_LINE_KERNEL" \ + "$REGEX_LINE_PERF" "$REGEX_LINE_ARCH" "$REGEX_LINE_CPUS_ONLINE" \ + "$REGEX_LINE_CPUS_AVAIL" < $LOGS_DIR/basic_header.log CHECK_EXIT_CODE=$? print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "header" @@ -129,9 +156,11 @@ PERF_EXIT_CODE=$? REGEX_LINES_HEADER="#\s*Children\s+Self\s+sys\s+usr\s+Command\s+Shared Object\s+Symbol" REGEX_LINES="\s*$RE_NUMBER%\s+$RE_NUMBER%\s+$RE_NUMBER%\s+$RE_NUMBER%\s+\S+\s+\[kernel\.(?:vmlinux)|(?:kallsyms)\]\s+\[[k\.]\]\s+\w+" -../common/check_all_patterns_found.pl "$REGEX_LINES_HEADER" "$REGEX_LINES" < $LOGS_DIR/basic_cpuut.log +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "$REGEX_LINES_HEADER" "$REGEX_LINES" < $LOGS_DIR/basic_cpuut.log CHECK_EXIT_CODE=$? -../common/check_errors_whitelisted.pl "stderr-whitelist.txt" < $LOGS_DIR/basic_cpuut.err +"$DIR_PATH/../common/check_errors_whitelisted.pl" \ + "$DIR_PATH/stderr-whitelist.txt" < $LOGS_DIR/basic_cpuut.err (( CHECK_EXIT_CODE += $? )) print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "show CPU utilization" @@ -144,9 +173,11 @@ print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "show CPU utilization" $CMD_PERF report --stdio -i $CURRENT_TEST_DIR/perf.data --pid=1 > $LOGS_DIR/basic_pid.log 2> $LOGS_DIR/basic_pid.err PERF_EXIT_CODE=$? -grep -P -v '^#' $LOGS_DIR/basic_pid.log | grep -P '\s+[\d\.]+%' | ../common/check_all_lines_matched.pl "systemd|init" +grep -P -v '^#' $LOGS_DIR/basic_pid.log | grep -P '\s+[\d\.]+%' | \ + "$DIR_PATH/../common/check_all_lines_matched.pl" "systemd|init" CHECK_EXIT_CODE=$? -../common/check_errors_whitelisted.pl "stderr-whitelist.txt" < $LOGS_DIR/basic_pid.err +"$DIR_PATH/../common/check_errors_whitelisted.pl" \ + "$DIR_PATH/stderr-whitelist.txt" < $LOGS_DIR/basic_pid.err (( CHECK_EXIT_CODE += $? )) print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "pid" @@ -159,9 +190,11 @@ print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "pid" $CMD_PERF report --stdio -i $CURRENT_TEST_DIR/perf.data --symbols=dummynonexistingsymbol > $LOGS_DIR/basic_symbols.log 2> $LOGS_DIR/basic_symbols.err PERF_EXIT_CODE=$? -../common/check_all_lines_matched.pl "$RE_LINE_EMPTY" "$RE_LINE_COMMENT" < $LOGS_DIR/basic_symbols.log +"$DIR_PATH/../common/check_all_lines_matched.pl" \ + "$RE_LINE_EMPTY" "$RE_LINE_COMMENT" < $LOGS_DIR/basic_symbols.log CHECK_EXIT_CODE=$? -../common/check_errors_whitelisted.pl "stderr-whitelist.txt" < $LOGS_DIR/basic_symbols.err +"$DIR_PATH/../common/check_errors_whitelisted.pl" \ + "$DIR_PATH/stderr-whitelist.txt" < $LOGS_DIR/basic_symbols.err (( CHECK_EXIT_CODE += $? )) print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "non-existing symbol" @@ -174,15 +207,77 @@ print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "non-existing symbol" $CMD_PERF report --stdio -i $CURRENT_TEST_DIR/perf.data --symbol-filter=map > $LOGS_DIR/basic_symbolfilter.log 2> $LOGS_DIR/basic_symbolfilter.err PERF_EXIT_CODE=$? -grep -P -v '^#' $LOGS_DIR/basic_symbolfilter.log | grep -P '\s+[\d\.]+%' | ../common/check_all_lines_matched.pl "\[[k\.]\]\s+.*map" +grep -P -v '^#' $LOGS_DIR/basic_symbolfilter.log | grep -P '\s+[\d\.]+%' | \ + "$DIR_PATH/../common/check_all_lines_matched.pl" "\[[k\.]\]\s+.*map" CHECK_EXIT_CODE=$? -../common/check_errors_whitelisted.pl "stderr-whitelist.txt" < $LOGS_DIR/basic_symbolfilter.err +"$DIR_PATH/../common/check_errors_whitelisted.pl" \ + "$DIR_PATH/stderr-whitelist.txt" < $LOGS_DIR/basic_symbolfilter.err (( CHECK_EXIT_CODE += $? )) print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "symbol filter" (( TEST_RESULT += $? )) +### latency and parallelism + +# Record with --latency should record with context switches. +$CMD_PERF report -i $CURRENT_TEST_DIR/perf.data.1 --stdio --header-only > $LOGS_DIR/latency_header.log +PERF_EXIT_CODE=$? + +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + ", context_switch = 1, " < $LOGS_DIR/latency_header.log +CHECK_EXIT_CODE=$? + +print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "latency header" +(( TEST_RESULT += $? )) + + +# The default report for latency profile should show Overhead and Latency fields (in that order). +$CMD_PERF report --stdio -i $CURRENT_TEST_DIR/perf.data.1 > $LOGS_DIR/latency_default.log 2> $LOGS_DIR/latency_default.err +PERF_EXIT_CODE=$? + +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "# Overhead Latency Command" < $LOGS_DIR/latency_default.log +CHECK_EXIT_CODE=$? +"$DIR_PATH/../common/check_errors_whitelisted.pl" \ + "stderr-whitelist.txt" < $LOGS_DIR/latency_default.err +(( CHECK_EXIT_CODE += $? )) + +print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "default report for latency profile" +(( TEST_RESULT += $? )) + + +# The latency report for latency profile should show Latency and Overhead fields (in that order). +$CMD_PERF report --latency --stdio -i $CURRENT_TEST_DIR/perf.data.1 > $LOGS_DIR/latency_latency.log 2> $LOGS_DIR/latency_latency.err +PERF_EXIT_CODE=$? + +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "# Latency Overhead Command" < $LOGS_DIR/latency_latency.log +CHECK_EXIT_CODE=$? +"$DIR_PATH/../common/check_errors_whitelisted.pl" \ + "stderr-whitelist.txt" < $LOGS_DIR/latency_latency.err +(( CHECK_EXIT_CODE += $? )) + +print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "latency report for latency profile" +(( TEST_RESULT += $? )) + + +# Ensure parallelism histogram with parallelism filter does not fail/crash. +$CMD_PERF report --hierarchy --sort latency,parallelism,comm,symbol --parallelism=1,2 --stdio -i $CURRENT_TEST_DIR/perf.data.1 > $LOGS_DIR/parallelism_hierarchy.log 2> $LOGS_DIR/parallelism_hierarchy.err +PERF_EXIT_CODE=$? + +"$DIR_PATH/../common/check_all_patterns_found.pl" \ + "# Latency Parallelism / Command / Symbol" \ + < $LOGS_DIR/parallelism_hierarchy.log +CHECK_EXIT_CODE=$? +"$DIR_PATH/../common/check_errors_whitelisted.pl" \ + "stderr-whitelist.txt" < $LOGS_DIR/parallelism_hierarchy.err +(( CHECK_EXIT_CODE += $? )) + +print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "parallelism histogram" +(( TEST_RESULT += $? )) + + # TODO: $CMD_PERF report -n --showcpuutilization -TUxDg 2> 01.log # print overall results diff --git a/tools/perf/tests/shell/buildid.sh b/tools/perf/tests/shell/buildid.sh index 3383ca3399d4..102808cca9db 100755 --- a/tools/perf/tests/shell/buildid.sh +++ b/tools/perf/tests/shell/buildid.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # build id cache operations # SPDX-License-Identifier: GPL-2.0 @@ -36,16 +36,69 @@ if [ ${run_pe} -eq 1 ]; then unset WAYLAND_DISPLAY fi -ex_md5=$(mktemp /tmp/perf.ex.MD5.XXX) -ex_sha1=$(mktemp /tmp/perf.ex.SHA1.XXX) +build_id_dir= +ex_source=$(mktemp /tmp/perf_buildid_test.ex.XXX.c) +ex_md5=$(mktemp /tmp/perf_buildid_test.ex.MD5.XXX) +ex_sha1=$(mktemp /tmp/perf_buildid_test.ex.SHA1.XXX) ex_pe=$(dirname $0)/../pe-file.exe +data=$(mktemp /tmp/perf_buildid_test.data.XXX) +log_out=$(mktemp /tmp/perf_buildid_test.log.out.XXX) +log_err=$(mktemp /tmp/perf_buildid_test.log.err.XXX) -echo 'int main(void) { return 0; }' | cc -Wl,--build-id=sha1 -o ${ex_sha1} -x c - -echo 'int main(void) { return 0; }' | cc -Wl,--build-id=md5 -o ${ex_md5} -x c - +cleanup() { + rm -f ${ex_source} ${ex_md5} ${ex_sha1} ${data} ${log_out} ${log_err} + if [ ${run_pe} -eq 1 ]; then + rm -r ${wineprefix} + fi + if [ -d ${build_id_dir} ]; then + rm -rf ${build_id_dir} + fi + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +# Test program based on the noploop workload. +cat <<EOF > ${ex_source} +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +static volatile sig_atomic_t done; + +static void sighandler(int sig) +{ + (void)sig; + done = 1; +} + +int main(int argc, const char **argv) +{ + int sec = 1; + + if (argc > 1) + sec = atoi(argv[1]); + + signal(SIGINT, sighandler); + signal(SIGALRM, sighandler); + alarm(sec); + + while (!done) + continue; + + return 0; +} +EOF +cc -Wl,--build-id=sha1 ${ex_source} -o ${ex_sha1} -x c - +cc -Wl,--build-id=md5 ${ex_source} -o ${ex_md5} -x c - echo "test binaries: ${ex_sha1} ${ex_md5} ${ex_pe}" -check() +get_build_id() { case $1 in *.exe) @@ -64,6 +117,15 @@ check() id=`readelf -n ${1} 2>/dev/null | grep 'Build ID' | awk '{print $3}'` ;; esac + echo ${id} +} + +check() +{ + file=$1 + perf_data=$2 + + id=$(get_build_id $file) echo "build id: ${id}" id_file=${id#??} @@ -76,45 +138,53 @@ check() exit 1 fi - file=${build_id_dir}/.build-id/$id_dir/`readlink ${link}`/elf - echo "file: ${file}" + cached_file=${build_id_dir}/.build-id/$id_dir/`readlink ${link}`/elf + echo "file: ${cached_file}" # Check for file permission of original file # in case of pe-file.exe file echo $1 | grep ".exe" if [ $? -eq 0 ]; then - if [ -x $1 ] && [ ! -x $file ]; then - echo "failed: file ${file} executable does not exist" + if [ -x $1 ] && [ ! -x $cached_file ]; then + echo "failed: file ${cached_file} executable does not exist" exit 1 fi - if [ ! -x $file ] && [ ! -e $file ]; then - echo "failed: file ${file} does not exist" + if [ ! -x $cached_file ] && [ ! -e $cached_file ]; then + echo "failed: file ${cached_file} does not exist" exit 1 fi - elif [ ! -x $file ]; then - echo "failed: file ${file} does not exist" + elif [ ! -x $cached_file ]; then + echo "failed: file ${cached_file} does not exist" exit 1 fi - diff ${file} ${1} + diff ${cached_file} ${1} if [ $? -ne 0 ]; then - echo "failed: ${file} do not match" + echo "failed: ${cached_file} do not match" exit 1 fi - ${perf} buildid-cache -l | grep ${id} + ${perf} buildid-cache -l | grep -q ${id} if [ $? -ne 0 ]; then echo "failed: ${id} is not reported by \"perf buildid-cache -l\"" exit 1 fi + if [ -n "${perf_data}" ]; then + ${perf} buildid-list -i ${perf_data} | grep -q ${id} + if [ $? -ne 0 ]; then + echo "failed: ${id} is not reported by \"perf buildid-list -i ${perf_data}\"" + exit 1 + fi + fi + echo "OK for ${1}" } test_add() { - build_id_dir=$(mktemp -d /tmp/perf.debug.XXX) + build_id_dir=$(mktemp -d /tmp/perf_buildid_test.debug.XXX) perf="perf --buildid-dir ${build_id_dir}" ${perf} buildid-cache -v -a ${1} @@ -128,12 +198,88 @@ test_add() rm -rf ${build_id_dir} } +test_remove() +{ + build_id_dir=$(mktemp -d /tmp/perf_buildid_test.debug.XXX) + perf="perf --buildid-dir ${build_id_dir}" + + ${perf} buildid-cache -v -a ${1} + if [ $? -ne 0 ]; then + echo "failed: add ${1} to build id cache" + exit 1 + fi + + id=$(get_build_id ${1}) + if ! ${perf} buildid-cache -l | grep -q ${id}; then + echo "failed: ${id} not in cache" + exit 1 + fi + + ${perf} buildid-cache -v -r ${1} + if [ $? -ne 0 ]; then + echo "failed: remove ${id} from build id cache" + exit 1 + fi + + if ${perf} buildid-cache -l | grep -q ${id}; then + echo "failed: ${id} still in cache after remove" + exit 1 + fi + + echo "remove: OK" + rm -rf ${build_id_dir} +} + +test_purge() +{ + build_id_dir=$(mktemp -d /tmp/perf_buildid_test.debug.XXX) + perf="perf --buildid-dir ${build_id_dir}" + + id1=$(get_build_id ${ex_sha1}) + ${perf} buildid-cache -v -a ${ex_sha1} + if ! ${perf} buildid-cache -l | grep -q ${id1}; then + echo "failed: ${id1} not in cache" + exit 1 + fi + + id2=$(get_build_id ${ex_md5}) + ${perf} buildid-cache -v -a ${ex_md5} + if ! ${perf} buildid-cache -l | grep -q ${id2}; then + echo "failed: ${id2} not in cache" + exit 1 + fi + + # Purge by path + ${perf} buildid-cache -v -p ${ex_sha1} + if [ $? -ne 0 ]; then + echo "failed: purge build id cache of ${ex_sha1}" + exit 1 + fi + + ${perf} buildid-cache -v -p ${ex_md5} + if [ $? -ne 0 ]; then + echo "failed: purge build id cache of ${ex_md5}" + exit 1 + fi + + # Verify both are gone + if ${perf} buildid-cache -l | grep -q ${id1}; then + echo "failed: ${id1} still in cache after purge" + exit 1 + fi + + if ${perf} buildid-cache -l | grep -q ${id2}; then + echo "failed: ${id2} still in cache after purge" + exit 1 + fi + + echo "purge: OK" + rm -rf ${build_id_dir} +} + test_record() { - data=$(mktemp /tmp/perf.data.XXX) - build_id_dir=$(mktemp -d /tmp/perf.debug.XXX) - log_out=$(mktemp /tmp/perf.log.out.XXX) - log_err=$(mktemp /tmp/perf.log.err.XXX) + build_id_dir=$(mktemp -d /tmp/perf_buildid_test.debug.XXX) perf="perf --buildid-dir ${build_id_dir}" echo "running: perf record $*" @@ -145,7 +291,7 @@ test_record() fi args="$*" - check ${args##* } + check ${args##* } ${data} rm -f ${log_out} ${log_err} rm -rf ${build_id_dir} @@ -166,10 +312,15 @@ if [ ${run_pe} -eq 1 ]; then test_record wine ${ex_pe} fi -# cleanup -rm ${ex_sha1} ${ex_md5} -if [ ${run_pe} -eq 1 ]; then - rm -r ${wineprefix} +# remove binaries manually via perf buildid-cache -r +test_remove ${ex_sha1} +test_remove ${ex_md5} +if [ ${add_pe} -eq 1 ]; then + test_remove ${ex_pe} fi +# purge binaries manually via perf buildid-cache -p +test_purge + +cleanup exit 0 diff --git a/tools/perf/tests/shell/c2c.sh b/tools/perf/tests/shell/c2c.sh new file mode 100755 index 000000000000..2471d44595c3 --- /dev/null +++ b/tools/perf/tests/shell/c2c.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# perf c2c tests +# SPDX-License-Identifier: GPL-2.0 + +set -e + +err=0 +perfdata=$(mktemp /tmp/__perf_c2c_test.perf.data.XXXXX) + +cleanup() { + rm -f "${perfdata}" + rm -f "${perfdata}".old + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +check_c2c_support() { + # Check if perf c2c record works. + if ! perf c2c record -o "${perfdata}" -- true > /dev/null 2>&1 ; then + return 1 + fi + return 0 +} + +test_c2c_record_report() { + echo "c2c record and report test" + if ! check_c2c_support ; then + echo "c2c record and report test [Skipped: perf c2c record failed (possibly missing hardware support)]" + err=2 + return + fi + + # Run a workload that does some memory operations. + if ! perf c2c record -o "${perfdata}" -- perf test -w datasym 1 > /dev/null 2>&1 ; then + echo "c2c record and report test [Skipped: perf c2c record failed during workload]" + return + fi + + if ! perf c2c report -i "${perfdata}" --stdio > /dev/null 2>&1 ; then + echo "c2c record and report test [Failed: report failed]" + err=1 + return + fi + + if ! perf c2c report -i "${perfdata}" -N > /dev/null 2>&1 ; then + echo "c2c record and report test [Failed: report -N failed]" + err=1 + return + fi + + echo "c2c record and report test [Success]" +} + +test_c2c_record_report +cleanup +exit $err diff --git a/tools/perf/tests/shell/common/init.sh b/tools/perf/tests/shell/common/init.sh index 075f17623c8e..cbfc78bec974 100644 --- a/tools/perf/tests/shell/common/init.sh +++ b/tools/perf/tests/shell/common/init.sh @@ -11,8 +11,8 @@ # -. ../common/settings.sh -. ../common/patterns.sh +. "$(dirname $0)/../common/settings.sh" +. "$(dirname $0)/../common/patterns.sh" THIS_TEST_NAME=`basename $0 .sh` @@ -46,10 +46,13 @@ print_results() print_overall_results() { RETVAL="$1"; shift + TASK_COMMENT="$*" + test -n "$TASK_COMMENT" && TASK_COMMENT=":: $TASK_COMMENT" + if [ $RETVAL -eq 0 ]; then _echo "$MALLPASS## [ PASS ] ##$MEND $TEST_NAME :: $THIS_TEST_NAME SUMMARY" else - _echo "$MALLFAIL## [ FAIL ] ##$MEND $TEST_NAME :: $THIS_TEST_NAME SUMMARY :: $RETVAL failures found" + _echo "$MALLFAIL## [ FAIL ] ##$MEND $TEST_NAME :: $THIS_TEST_NAME SUMMARY :: $RETVAL failures found $TASK_COMMENT" fi return $RETVAL } @@ -85,7 +88,7 @@ consider_skipping() # the runmode of a testcase needs to be at least the current suite's runmode if [ $PERFTOOL_TESTSUITE_RUNMODE -lt $TESTCASE_RUNMODE ]; then print_overall_skipped - exit 0 + exit 2 fi } diff --git a/tools/perf/tests/shell/coresight/Makefile b/tools/perf/tests/shell/coresight/Makefile index b070e779703e..fa08fd9a5991 100644 --- a/tools/perf/tests/shell/coresight/Makefile +++ b/tools/perf/tests/shell/coresight/Makefile @@ -24,6 +24,6 @@ CLEANDIRS = $(SUBDIRS:%=clean-%) clean: $(CLEANDIRS) $(CLEANDIRS): - $(call QUIET_CLEAN, test-$(@:clean-%=%)) $(Q)$(MAKE) -C $(@:clean-%=%) clean >/dev/null + $(call QUIET_CLEAN, test-$(@:clean-%=%)) $(MAKE) -C $(@:clean-%=%) clean >/dev/null .PHONY: all clean $(SUBDIRS) $(CLEANDIRS) $(INSTALLDIRS) diff --git a/tools/perf/tests/shell/coresight/asm_pure_loop.sh b/tools/perf/tests/shell/coresight/asm_pure_loop.sh index 2d65defb7e0f..0301904b9637 100755 --- a/tools/perf/tests/shell/coresight/asm_pure_loop.sh +++ b/tools/perf/tests/shell/coresight/asm_pure_loop.sh @@ -1,5 +1,5 @@ -#!/bin/sh -e -# CoreSight / ASM Pure Loop +#!/bin/bash -e +# CoreSight / ASM Pure Loop (exclusive) # SPDX-License-Identifier: GPL-2.0 # Carsten Haitzler <carsten.haitzler@arm.com>, 2021 diff --git a/tools/perf/tests/shell/coresight/asm_pure_loop/asm_pure_loop.S b/tools/perf/tests/shell/coresight/asm_pure_loop/asm_pure_loop.S index 75cf084a927d..577760046772 100644 --- a/tools/perf/tests/shell/coresight/asm_pure_loop/asm_pure_loop.S +++ b/tools/perf/tests/shell/coresight/asm_pure_loop/asm_pure_loop.S @@ -26,3 +26,5 @@ skip: mov x0, #0 mov x8, #93 // __NR_exit syscall svc #0 + +.section .note.GNU-stack, "", @progbits diff --git a/tools/perf/tests/shell/coresight/memcpy_thread/memcpy_thread.c b/tools/perf/tests/shell/coresight/memcpy_thread/memcpy_thread.c index 5f886cd09e6b..7e879217be30 100644 --- a/tools/perf/tests/shell/coresight/memcpy_thread/memcpy_thread.c +++ b/tools/perf/tests/shell/coresight/memcpy_thread/memcpy_thread.c @@ -27,6 +27,8 @@ static void *thrfn(void *arg) } for (i = 0; i < len; i++) memcpy(dst, src, a->size * 1024); + + return NULL; } static pthread_t new_thr(void *(*fn) (void *arg), void *arg) diff --git a/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh b/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh index ddcc9bb850f5..1f765d69acc3 100755 --- a/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh +++ b/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh @@ -1,5 +1,5 @@ -#!/bin/sh -e -# CoreSight / Memcpy 16k 10 Threads +#!/bin/bash -e +# CoreSight / Memcpy 16k 10 Threads (exclusive) # SPDX-License-Identifier: GPL-2.0 # Carsten Haitzler <carsten.haitzler@arm.com>, 2021 diff --git a/tools/perf/tests/shell/coresight/thread_loop/thread_loop.c b/tools/perf/tests/shell/coresight/thread_loop/thread_loop.c index e05a559253ca..86f3f548b006 100644 --- a/tools/perf/tests/shell/coresight/thread_loop/thread_loop.c +++ b/tools/perf/tests/shell/coresight/thread_loop/thread_loop.c @@ -34,8 +34,8 @@ static void *thrfn(void *arg) } asm volatile( "loop:\n" - "add %[i], %[i], #1\n" - "cmp %[i], %[len]\n" + "add %w[i], %w[i], #1\n" + "cmp %w[i], %w[len]\n" "blt loop\n" : /* out */ : /* in */ [i] "r" (i), [len] "r" (len) diff --git a/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh b/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh index 2ce5e139b2fd..7f43a93a2ac2 100755 --- a/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh +++ b/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh @@ -1,5 +1,5 @@ -#!/bin/sh -e -# CoreSight / Thread Loop 10 Threads - Check TID +#!/bin/bash -e +# CoreSight / Thread Loop 10 Threads - Check TID (exclusive) # SPDX-License-Identifier: GPL-2.0 # Carsten Haitzler <carsten.haitzler@arm.com>, 2021 diff --git a/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh b/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh index 3ad9498753d7..a94d2079ed06 100755 --- a/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh +++ b/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh @@ -1,5 +1,5 @@ -#!/bin/sh -e -# CoreSight / Thread Loop 2 Threads - Check TID +#!/bin/bash -e +# CoreSight / Thread Loop 2 Threads - Check TID (exclusive) # SPDX-License-Identifier: GPL-2.0 # Carsten Haitzler <carsten.haitzler@arm.com>, 2021 diff --git a/tools/perf/tests/shell/coresight/unroll_loop_thread/unroll_loop_thread.c b/tools/perf/tests/shell/coresight/unroll_loop_thread/unroll_loop_thread.c index 0fc7bf1a25af..8f4e1c985ca3 100644 --- a/tools/perf/tests/shell/coresight/unroll_loop_thread/unroll_loop_thread.c +++ b/tools/perf/tests/shell/coresight/unroll_loop_thread/unroll_loop_thread.c @@ -20,7 +20,7 @@ static void *thrfn(void *arg) for (i = 0; i < 10000; i++) { asm volatile ( // force an unroll of thia add instruction so we can test long runs of code -#define SNIP1 "add %[in], %[in], #1\n" +#define SNIP1 "add %w[in], %w[in], #1\n" // 10 #define SNIP2 SNIP1 SNIP1 SNIP1 SNIP1 SNIP1 SNIP1 SNIP1 SNIP1 SNIP1 SNIP1 // 100 @@ -36,6 +36,8 @@ static void *thrfn(void *arg) : /* clobber */ ); } + + return NULL; } static pthread_t new_thr(void *(*fn) (void *arg), void *arg) diff --git a/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh b/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh index 4fbb4a29aad3..cb3e97a0a89f 100755 --- a/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh +++ b/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh @@ -1,5 +1,5 @@ -#!/bin/sh -e -# CoreSight / Unroll Loop Thread 10 +#!/bin/bash -e +# CoreSight / Unroll Loop Thread 10 (exclusive) # SPDX-License-Identifier: GPL-2.0 # Carsten Haitzler <carsten.haitzler@arm.com>, 2021 diff --git a/tools/perf/tests/shell/diff.sh b/tools/perf/tests/shell/diff.sh index 14b87af88703..fe05fdebcab5 100755 --- a/tools/perf/tests/shell/diff.sh +++ b/tools/perf/tests/shell/diff.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf diff tests # SPDX-License-Identifier: GPL-2.0 @@ -39,13 +39,13 @@ make_data() { file="$1" if ! perf record -o "${file}" ${testprog} 2> /dev/null then - echo "Workload record [Failed record]" + echo "Workload record [Failed record]" >&2 echo 1 return fi if ! perf report -i "${file}" -q | grep -q "${testsym}" then - echo "Workload record [Failed missing output]" + echo "Workload record [Failed missing output]" >&2 echo 1 return fi @@ -55,12 +55,12 @@ make_data() { test_two_files() { echo "Basic two file diff test" err=$(make_data "${perfdata1}") - if [ $err != 0 ] + if [ "$err" != 0 ] then return fi err=$(make_data "${perfdata2}") - if [ $err != 0 ] + if [ "$err" != 0 ] then return fi @@ -77,12 +77,12 @@ test_two_files() { test_three_files() { echo "Basic three file diff test" err=$(make_data "${perfdata1}") - if [ $err != 0 ] + if [ "$err" != 0 ] then return fi err=$(make_data "${perfdata2}") - if [ $err != 0 ] + if [ "$err" != 0 ] then return fi diff --git a/tools/perf/tests/shell/drm_pmu.sh b/tools/perf/tests/shell/drm_pmu.sh new file mode 100755 index 000000000000..e629fe0e8463 --- /dev/null +++ b/tools/perf/tests/shell/drm_pmu.sh @@ -0,0 +1,78 @@ +#!/bin/bash +# DRM PMU +# SPDX-License-Identifier: GPL-2.0 + +set -e + +output=$(mktemp /tmp/perf.drm_pmu.XXXXXX.txt) + +cleanup() { + rm -f "${output}" + + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +# Array to store file descriptors and device names +declare -A device_fds + +# Open all devices and store file descriptors. Opening the device will create a +# /proc/$$/fdinfo file containing the DRM statistics. +fd_count=3 # Start with file descriptor 3 +for device in /dev/dri/* +do + if [[ ! -c "$device" ]] + then + continue + fi + major=$(stat -c "%Hr" "$device") + if [[ "$major" != 226 ]] + then + continue + fi + echo "Opening $device" + eval "exec $fd_count<\"$device\"" + echo "fdinfo for: $device (FD: $fd_count)" + cat "/proc/$$/fdinfo/$fd_count" + echo + device_fds["$device"]="$fd_count" + fd_count=$((fd_count + 1)) +done + +if [[ ${#device_fds[@]} -eq 0 ]] +then + echo "No DRM devices found [Skip]" + cleanup + exit 2 +fi + +# For each DRM event +err=0 +for p in $(perf list --raw-dump drm-) +do + echo -n "Testing perf stat of $p. " + perf stat -e "$p" --pid=$$ true > "$output" 2>&1 + if ! grep -q "$p" "$output" + then + echo "Missing DRM event in: [Failed]" + cat "$output" + err=1 + else + echo "[OK]" + fi +done + +# Close all file descriptors +for fd in "${device_fds[@]}"; do + eval "exec $fd<&-" +done + +# Finished +cleanup +exit $err diff --git a/tools/perf/tests/shell/evlist.sh b/tools/perf/tests/shell/evlist.sh new file mode 100755 index 000000000000..140f099e75c1 --- /dev/null +++ b/tools/perf/tests/shell/evlist.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# perf evlist tests +# SPDX-License-Identifier: GPL-2.0 + +set -e + +err=0 +perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) + +cleanup() { + rm -f "${perfdata}" + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +test_evlist_simple() { + echo "Simple evlist test" + if ! perf record -e cycles -o "${perfdata}" true 2> /dev/null + then + echo "Simple evlist [Failed record]" + err=1 + return + fi + if ! perf evlist -i "${perfdata}" | grep -q "cycles" + then + echo "Simple evlist [Failed to list event]" + err=1 + return + fi + echo "Simple evlist test [Success]" +} + +test_evlist_group() { + echo "Group evlist test" + if ! perf record -e "{cycles,instructions}" -o "${perfdata}" true 2> /dev/null + then + echo "Group evlist [Skipped event group recording failed]" + return + fi + + if ! perf evlist -i "${perfdata}" -g | grep -q "{.*cycles.*,.*instructions.*}" + then + echo "Group evlist [Failed to list event group]" + err=1 + return + fi + echo "Group evlist test [Success]" +} + +test_evlist_verbose() { + echo "Event configuration evlist test" + if ! perf record -e cycles -o "${perfdata}" true 2> /dev/null + then + echo "Event configuration evlist [Failed record]" + err=1 + return + fi + + if ! perf evlist -i "${perfdata}" -v | grep -q "config:" + then + echo "Event configuration evlist [Failed to list verbose info]" + err=1 + return + fi + echo "Event configuration evlist test [Success]" +} + +test_evlist_simple +test_evlist_group +test_evlist_verbose + +cleanup +exit $err diff --git a/tools/perf/tests/shell/ftrace.sh b/tools/perf/tests/shell/ftrace.sh index a6ee740f0d7e..7f8aafcbb761 100755 --- a/tools/perf/tests/shell/ftrace.sh +++ b/tools/perf/tests/shell/ftrace.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf ftrace tests # SPDX-License-Identifier: GPL-2.0 @@ -67,12 +67,9 @@ test_ftrace_latency() { test_ftrace_profile() { echo "perf ftrace profile test" - perf ftrace profile sleep 0.1 > "${output}" + perf ftrace profile --graph-opts depth=5 sleep 0.1 > "${output}" grep ^# "${output}" - grep sleep "${output}" - grep schedule "${output}" - grep execve "${output}" - time_re="[[:space:]]+10[[:digit:]]{4}\.[[:digit:]]{3}" + time_re="[[:space:]]+1[[:digit:]]{5}\.[[:digit:]]{3}" # 100283.000 100283.000 100283.000 1 __x64_sys_clock_nanosleep # Check for one *clock_nanosleep line with a Count of just 1 that takes a bit more than 0.1 seconds # Strip the _x64_sys part to work with other architectures diff --git a/tools/perf/tests/shell/header.sh b/tools/perf/tests/shell/header.sh new file mode 100755 index 000000000000..e1628ac0a614 --- /dev/null +++ b/tools/perf/tests/shell/header.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# perf header tests +# SPDX-License-Identifier: GPL-2.0 + +set -e + +err=0 +perfdata=$(mktemp /tmp/__perf_test_header.perf.data.XXXXX) +script_output=$(mktemp /tmp/__perf_test_header.perf.data.XXXXX.script) + +cleanup() { + rm -f "${perfdata}" + rm -f "${perfdata}".old + rm -f "${script_output}" + + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +check_header_output() { + declare -a fields=( + "captured" + "hostname" + "os release" + "arch" + "cpuid" + "nrcpus" + "event" + "cmdline" + "perf version" + "sibling (cores|dies|threads)" + "sibling threads" + "total memory" + ) + for i in "${fields[@]}" + do + if ! grep -q -E "$i" "${script_output}" + then + echo "Failed to find expected $i in output" + err=1 + fi + done +} + +test_file() { + echo "Test perf header file" + + perf record -o "${perfdata}" -- perf test -w noploop + perf report --header-only -I -i "${perfdata}" > "${script_output}" + check_header_output + + echo "Test perf header file [Done]" +} + +test_pipe() { + echo "Test perf header pipe" + + perf record -o - -- perf test -w noploop | perf report --header-only -I -i - > "${script_output}" + check_header_output + + echo "Test perf header pipe [Done]" +} + +test_file +test_pipe + +cleanup +exit $err diff --git a/tools/perf/tests/shell/jitdump-python.sh b/tools/perf/tests/shell/jitdump-python.sh new file mode 100755 index 000000000000..ae86203b14a2 --- /dev/null +++ b/tools/perf/tests/shell/jitdump-python.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# python profiling with jitdump +# SPDX-License-Identifier: GPL-2.0 + +SHELLDIR=$(dirname $0) +# shellcheck source=lib/setup_python.sh +. "${SHELLDIR}"/lib/setup_python.sh + +OUTPUT=$(${PYTHON} -Xperf_jit -c 'import os, sys; print(os.getpid(), sys.is_stack_trampoline_active())' 2> /dev/null) +PID=${OUTPUT% *} +HAS_PERF_JIT=${OUTPUT#* } + +rm -f /tmp/jit-${PID}.dump 2> /dev/null +if [ "${HAS_PERF_JIT}" != "True" ]; then + echo "SKIP: python JIT dump is not available" + exit 2 +fi + +PERF_DATA=$(mktemp /tmp/__perf_test.perf.data.XXXXXX) + +cleanup() { + echo "Cleaning up files..." + rm -f ${PERF_DATA} ${PERF_DATA}.jit /tmp/jit-${PID}.dump /tmp/jitted-${PID}-*.so 2> /dev/null + + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected termination" + cleanup + exit 1 +} + +trap trap_cleanup EXIT TERM INT + +echo "Run python with -Xperf_jit" +cat <<EOF | perf record -k 1 -g --call-graph dwarf -o "${PERF_DATA}" \ + -- ${PYTHON} -Xperf_jit +def foo(n): + result = 0 + for _ in range(n): + result += 1 + return result + +def bar(n): + foo(n) + +def baz(n): + bar(n) + +if __name__ == "__main__": + baz(1000000) +EOF + +# extract PID of the target process from the data +_PID=$(perf report -i "${PERF_DATA}" -F pid -q -g none | cut -d: -f1 -s) +PID=$(echo -n $_PID) # remove newlines + +echo "Generate JIT-ed DSOs using perf inject" +DEBUGINFOD_URLS='' perf inject -i "${PERF_DATA}" -j -o "${PERF_DATA}.jit" + +echo "Add JIT-ed DSOs to the build-ID cache" +for F in /tmp/jitted-${PID}-*.so; do + perf buildid-cache -a "${F}" +done + +echo "Check the symbol containing the function/module name" +NUM=$(perf report -i "${PERF_DATA}.jit" -s sym | grep -cE 'py::(foo|bar|baz):<stdin>') + +echo "Found ${NUM} matching lines" + +echo "Remove JIT-ed DSOs from the build-ID cache" +for F in /tmp/jitted-${PID}-*.so; do + perf buildid-cache -r "${F}" +done + +cleanup + +if [ "${NUM}" -eq 0 ]; then + exit 1 +fi diff --git a/tools/perf/tests/shell/kallsyms.sh b/tools/perf/tests/shell/kallsyms.sh new file mode 100755 index 000000000000..d0eb99753f47 --- /dev/null +++ b/tools/perf/tests/shell/kallsyms.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# perf kallsyms tests +# SPDX-License-Identifier: GPL-2.0 + +err=0 + +test_kallsyms() { + echo "Basic perf kallsyms test" + + # Check if /proc/kallsyms is readable + if [ ! -r /proc/kallsyms ]; then + echo "Basic perf kallsyms test [Skipped: /proc/kallsyms not readable]" + err=2 + return + fi + + # Use a symbol that is definitely a function and present in all kernels, e.g. schedule + symbol="schedule" + + # Run perf kallsyms + # It prints "address symbol_name" + output=$(perf kallsyms $symbol 2>&1) + ret=$? + + if [ $ret -ne 0 ] || [ -z "$output" ]; then + # If empty or failed, it might be due to permissions (kptr_restrict) + # Check if we can grep the symbol from /proc/kallsyms directly + if grep -q "$symbol" /proc/kallsyms 2>/dev/null; then + # If it's in /proc/kallsyms but perf kallsyms returned empty/error, + # it likely means perf couldn't parse it or access it correctly (e.g. kptr_restrict=2). + echo "Basic perf kallsyms test [Skipped: $symbol found in /proc/kallsyms but perf kallsyms failed (output: '$output')]" + err=2 + return + else + echo "Basic perf kallsyms test [Skipped: $symbol not found in /proc/kallsyms]" + err=2 + return + fi + fi + + if echo "$output" | grep -q "not found"; then + echo "Basic perf kallsyms test [Failed: output '$output' does not contain $symbol]" + err=1 + return + fi + + if perf kallsyms ErlingHaaland | grep -vq "not found"; then + echo "Basic perf kallsyms test [Failed: ErlingHaaland found in the output]" + err=1 + return + fi + echo "Basic perf kallsyms test [Success]" +} + +test_kallsyms +exit $err diff --git a/tools/perf/tests/shell/kvm.sh b/tools/perf/tests/shell/kvm.sh new file mode 100755 index 000000000000..2fafde1a29cc --- /dev/null +++ b/tools/perf/tests/shell/kvm.sh @@ -0,0 +1,154 @@ +#!/bin/bash +# perf kvm tests +# SPDX-License-Identifier: GPL-2.0 + +set -e + +err=0 +perfdata=$(mktemp /tmp/__perf_kvm_test.perf.data.XXXXX) +qemu_pid_file=$(mktemp /tmp/__perf_kvm_test.qemu.pid.XXXXX) + +cleanup() { + rm -f "${perfdata}" + if [ -f "${qemu_pid_file}" ]; then + if [ -s "${qemu_pid_file}" ]; then + qemu_pid=$(cat "${qemu_pid_file}") + if [ -n "${qemu_pid}" ]; then + kill "${qemu_pid}" 2>/dev/null || true + fi + fi + rm -f "${qemu_pid_file}" + fi + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +skip() { + echo "Skip: $1" + cleanup + exit 2 +} + +test_kvm_stat() { + echo "Testing perf kvm stat" + + echo "Recording kvm events for pid ${qemu_pid}..." + if ! perf kvm stat record -p "${qemu_pid}" -o "${perfdata}" sleep 1; then + echo "Failed to record kvm events" + err=1 + return + fi + + echo "Reporting kvm events..." + if ! perf kvm -i "${perfdata}" stat report 2>&1 | grep -q "VM-EXIT"; then + echo "Failed to find VM-EXIT in report" + perf kvm -i "${perfdata}" stat report 2>&1 + err=1 + return + fi + + echo "perf kvm stat test [Success]" +} + +test_kvm_record_report() { + echo "Testing perf kvm record/report" + + echo "Recording kvm profile for pid ${qemu_pid}..." + # Use --host to avoid needing guest symbols/mounts for this simple test + # We just want to verify the command runs and produces data + # We run in background and kill it because 'perf kvm record' appends options + # after the command, which breaks 'sleep' (e.g. it gets '-e cycles'). + perf kvm --host record -p "${qemu_pid}" -o "${perfdata}" & + rec_pid=$! + sleep 1 + kill -INT "${rec_pid}" + wait "${rec_pid}" || true + + echo "Reporting kvm profile..." + # Check for some standard output from report + if ! perf kvm -i "${perfdata}" report --stdio 2>&1 | grep -q "Event count"; then + echo "Failed to report kvm profile" + perf kvm -i "${perfdata}" report --stdio 2>&1 + err=1 + return + fi + + echo "perf kvm record/report test [Success]" +} + +test_kvm_buildid_list() { + echo "Testing perf kvm buildid-list" + + # We reuse the perf.data from the previous record test + if ! perf kvm --host -i "${perfdata}" buildid-list 2>&1 | grep -q "."; then + echo "Failed to list buildids" + perf kvm --host -i "${perfdata}" buildid-list 2>&1 + err=1 + return + fi + + echo "perf kvm buildid-list test [Success]" +} + +setup_qemu() { + # Find qemu + if [ "$(uname -m)" = "x86_64" ]; then + qemu="qemu-system-x86_64" + elif [ "$(uname -m)" = "aarch64" ]; then + qemu="qemu-system-aarch64" + elif [ "$(uname -m)" = "s390x" ]; then + qemu="qemu-system-s390x" + elif [ "$(uname -m)" = "ppc64le" ]; then + qemu="qemu-system-ppc64" + else + qemu="qemu-system-$(uname -m)" + fi + + if ! which -s "$qemu"; then + skip "$qemu not found" + fi + + if [ ! -r /dev/kvm ] || [ ! -w /dev/kvm ]; then + skip "/dev/kvm not accessible" + fi + + if ! perf kvm stat record -a sleep 0.01 >/dev/null 2>&1; then + skip "No permission to record kvm events" + fi + + echo "Starting $qemu..." + # Start qemu in background, detached, with pidfile + # We use -display none -daemonize and a monitor to keep it alive/controllable if needed + # We don't need a real kernel, just KVM active. + if ! $qemu -enable-kvm -display none -daemonize -pidfile "${qemu_pid_file}" -monitor none; then + echo "Failed to start qemu" + err=1 + return + fi + + # Wait a bit for qemu to start + sleep 1 + qemu_pid=$(cat "${qemu_pid_file}") + + if ! kill -0 "${qemu_pid}" 2>/dev/null; then + echo "Qemu process failed to stay alive" + err=1 + return + fi +} + +setup_qemu +if [ $err -eq 0 ]; then + test_kvm_stat + test_kvm_record_report + test_kvm_buildid_list +fi + +cleanup +exit $err diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/shell/lib/attr.py index e890c261ad26..bfccc727d9b2 100644 --- a/tools/perf/tests/attr.py +++ b/tools/perf/tests/shell/lib/attr.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -from __future__ import print_function - +import configparser import os import sys import glob @@ -13,11 +12,6 @@ import re import shutil import subprocess -try: - import configparser -except ImportError: - import ConfigParser as configparser - def data_equal(a, b): # Allow multiple values in assignment separated by '|' a_list = a.split('|') @@ -246,6 +240,23 @@ class Test(object): return False return True + def restore_sample_rate(self, value=10000): + try: + # Check value of sample_rate + with open("/proc/sys/kernel/perf_event_max_sample_rate", "r") as fIn: + curr_value = fIn.readline() + # If too low restore to reasonable value + if not curr_value or int(curr_value) < int(value): + with open("/proc/sys/kernel/perf_event_max_sample_rate", "w") as fOut: + fOut.write(str(value)) + + except IOError as e: + log.warning("couldn't restore sample_rate value: I/O error %s" % e) + except ValueError as e: + log.warning("couldn't restore sample_rate value: Value error %s" % e) + except TypeError as e: + log.warning("couldn't restore sample_rate value: Type error %s" % e) + def load_events(self, path, events): parser_event = configparser.ConfigParser() parser_event.read(path) @@ -283,6 +294,7 @@ class Test(object): if self.skip_test_kernel_until(): raise Notest(self, "new kernel skip") + self.restore_sample_rate() cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir, self.perf, self.command, tempdir, self.args) ret = os.WEXITSTATUS(os.system(cmd)) diff --git a/tools/perf/tests/shell/lib/coresight.sh b/tools/perf/tests/shell/lib/coresight.sh index 11ed2c25ed91..184d62e7e5bd 100644 --- a/tools/perf/tests/shell/lib/coresight.sh +++ b/tools/perf/tests/shell/lib/coresight.sh @@ -18,7 +18,7 @@ BIN="$DIR/$TEST" # If the test tool/binary does not exist and is executable then skip the test if ! test -x "$BIN"; then exit 2; fi # If CoreSight is not available, skip the test -perf list cs_etm | grep -q cs_etm || exit 2 +perf list pmu | grep -q cs_etm || exit 2 DATD="." # If the data dir env is set then make the data dir use that instead of ./ if test -n "$PERF_TEST_CORESIGHT_DATADIR"; then diff --git a/tools/perf/tests/shell/lib/perf_has_symbol.sh b/tools/perf/tests/shell/lib/perf_has_symbol.sh index 561c93b75d77..0b35cce0b13d 100644 --- a/tools/perf/tests/shell/lib/perf_has_symbol.sh +++ b/tools/perf/tests/shell/lib/perf_has_symbol.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # SPDX-License-Identifier: GPL-2.0 perf_has_symbol() diff --git a/tools/perf/tests/shell/lib/perf_json_output_lint.py b/tools/perf/tests/shell/lib/perf_json_output_lint.py index abc1fd737782..dafbde56cc76 100644 --- a/tools/perf/tests/shell/lib/perf_json_output_lint.py +++ b/tools/perf/tests/shell/lib/perf_json_output_lint.py @@ -19,6 +19,7 @@ ap.add_argument('--per-cluster', action='store_true') ap.add_argument('--per-die', action='store_true') ap.add_argument('--per-node', action='store_true') ap.add_argument('--per-socket', action='store_true') +ap.add_argument('--metric-only', action='store_true') ap.add_argument('--file', type=argparse.FileType('r'), default=sys.stdin) args = ap.parse_args() @@ -42,9 +43,12 @@ def isint(num): def is_counter_value(num): return isfloat(num) or num == '<not counted>' or num == '<not supported>' +def is_metric_value(num): + return isfloat(num) or num == 'none' + def check_json_output(expected_items): checks = { - 'aggregate-number': lambda x: isfloat(x), + 'counters': lambda x: isfloat(x), 'core': lambda x: True, 'counter-value': lambda x: is_counter_value(x), 'cgroup': lambda x: True, @@ -56,7 +60,8 @@ def check_json_output(expected_items): 'event-runtime': lambda x: isfloat(x), 'interval': lambda x: isfloat(x), 'metric-unit': lambda x: True, - 'metric-value': lambda x: isfloat(x), + 'metric-value': lambda x: is_metric_value(x), + 'metric-threshold': lambda x: x in ['unknown', 'good', 'less good', 'nearly bad', 'bad'], 'metricgroup': lambda x: True, 'node': lambda x: True, 'pcnt-running': lambda x: isfloat(x), @@ -68,18 +73,24 @@ def check_json_output(expected_items): for item in json.loads(input): if expected_items != -1: count = len(item) - if count != expected_items and count >= 1 and count <= 6 and 'metric-value' in item: + if count not in expected_items and count >= 1 and count <= 7 and 'metric-value' in item: # Events that generate >1 metric may have isolated metric # values and possibly other prefixes like interval, core, - # aggregate-number, or event-runtime/pcnt-running from multiplexing. + # counters, or event-runtime/pcnt-running from multiplexing. pass - elif count != expected_items and count >= 1 and count <= 5 and 'metricgroup' in item: + elif count not in expected_items and count >= 1 and count <= 5 and 'metricgroup' in item: pass - elif count != expected_items: + elif count - 1 in expected_items and 'metric-threshold' in item: + pass + elif count in expected_items and 'insn per cycle' in item: + pass + elif count not in expected_items: raise RuntimeError(f'wrong number of fields. counted {count} expected {expected_items}' f' in \'{item}\'') for key, value in item.items(): if key not in checks: + if args.metric_only: + continue raise RuntimeError(f'Unexpected key: key={key} value={value}') if not checks[key](value): raise RuntimeError(f'Check failed for: key={key} value={value}') @@ -87,11 +98,13 @@ def check_json_output(expected_items): try: if args.no_args or args.system_wide or args.event: - expected_items = 7 + expected_items = [5, 7] elif args.interval or args.per_thread or args.system_wide_no_aggr: - expected_items = 8 + expected_items = [6, 8] elif args.per_core or args.per_socket or args.per_node or args.per_die or args.per_cluster or args.per_cache: - expected_items = 9 + expected_items = [7, 9] + elif args.metric_only: + expected_items = [1, 2] else: # If no option is specified, don't check the number of items. expected_items = -1 diff --git a/tools/perf/tests/shell/lib/perf_metric_validation.py b/tools/perf/tests/shell/lib/perf_metric_validation.py index 0b94216c9c46..dea8ef1977bf 100644 --- a/tools/perf/tests/shell/lib/perf_metric_validation.py +++ b/tools/perf/tests/shell/lib/perf_metric_validation.py @@ -35,7 +35,8 @@ class TestError: class Validator: - def __init__(self, rulefname, reportfname='', t=5, debug=False, datafname='', fullrulefname='', workload='true', metrics=''): + def __init__(self, rulefname, reportfname='', t=5, debug=False, datafname='', fullrulefname='', + workload='true', metrics='', cputype='cpu'): self.rulefname = rulefname self.reportfname = reportfname self.rules = None @@ -43,6 +44,7 @@ class Validator: self.metrics = self.__set_metrics(metrics) self.skiplist = set() self.tolerance = t + self.cputype = cputype self.workloads = [x for x in workload.split(",") if x] self.wlidx = 0 # idx of current workloads @@ -377,7 +379,7 @@ class Validator: def _run_perf(self, metric, workload: str): tool = 'perf' - command = [tool, 'stat', '-j', '-M', f"{metric}", "-a"] + command = [tool, 'stat', '--cputype', self.cputype, '-j', '-M', f"{metric}", "-a"] wl = workload.split() command.extend(wl) print(" ".join(command)) @@ -443,6 +445,8 @@ class Validator: if 'MetricName' not in m: print("Warning: no metric name") continue + if 'Unit' in m and m['Unit'] != self.cputype: + continue name = m['MetricName'].lower() self.metrics.add(name) if 'ScaleUnit' in m and (m['ScaleUnit'] == '1%' or m['ScaleUnit'] == '100%'): @@ -578,6 +582,8 @@ def main() -> None: parser.add_argument( "-wl", help="Workload to run while data collection", default="true") parser.add_argument("-m", help="Metric list to validate", default="") + parser.add_argument("-cputype", help="Only test metrics for the given CPU/PMU type", + default="cpu") args = parser.parse_args() outpath = Path(args.output_dir) reportf = Path.joinpath(outpath, 'perf_report.json') @@ -586,7 +592,7 @@ def main() -> None: validator = Validator(args.rule, reportf, debug=args.debug, datafname=datafile, fullrulefname=fullrule, workload=args.wl, - metrics=args.m) + metrics=args.m, cputype=args.cputype) ret = validator.test() return ret diff --git a/tools/perf/tests/shell/lib/probe_vfs_getname.sh b/tools/perf/tests/shell/lib/probe_vfs_getname.sh index 5c33ec7a5a63..88cd0e26d5f6 100644 --- a/tools/perf/tests/shell/lib/probe_vfs_getname.sh +++ b/tools/perf/tests/shell/lib/probe_vfs_getname.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Arnaldo Carvalho de Melo <acme@kernel.org>, 2017 perf probe -l 2>&1 | grep -q probe:vfs_getname @@ -13,14 +13,28 @@ cleanup_probe_vfs_getname() { add_probe_vfs_getname() { add_probe_verbose=$1 if [ $had_vfs_getname -eq 1 ] ; then - result_filename_re="[[:space:]]+([[:digit:]]+)[[:space:]]+result->uptr.*" - line=$(perf probe -L getname_flags 2>&1 | grep -E "$result_filename_re" | sed -r "s/$result_filename_re/\1/") + result_initname_re="[[:space:]]+([[:digit:]]+)[[:space:]]+initname.*" + line=$(perf probe -L getname_flags 2>&1 | grep -E "$result_initname_re" | sed -r "s/$result_initname_re/\1/") + + # Search the old regular expressions so that this will + # pass on older kernels as well. + if [ -z "$line" ] ; then + result_filename_re="[[:space:]]+([[:digit:]]+)[[:space:]]+result->uptr.*" + line=$(perf probe -L getname_flags 2>&1 | grep -E "$result_filename_re" | sed -r "s/$result_filename_re/\1/") + fi + if [ -z "$line" ] ; then result_aname_re="[[:space:]]+([[:digit:]]+)[[:space:]]+result->aname = NULL;" line=$(perf probe -L getname_flags 2>&1 | grep -E "$result_aname_re" | sed -r "s/$result_aname_re/\1/") fi + + if [ -z "$line" ] ; then + echo "Could not find probeable line" + return 2 + fi + perf probe -q "vfs_getname=getname_flags:${line} pathname=result->name:string" || \ - perf probe $add_probe_verbose "vfs_getname=getname_flags:${line} pathname=filename:ustring" + perf probe $add_probe_verbose "vfs_getname=getname_flags:${line} pathname=filename:ustring" || return 1 fi } diff --git a/tools/perf/tests/shell/lib/setup_python.sh b/tools/perf/tests/shell/lib/setup_python.sh index c2fce1793538..a58e5536f2ed 100644 --- a/tools/perf/tests/shell/lib/setup_python.sh +++ b/tools/perf/tests/shell/lib/setup_python.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # SPDX-License-Identifier: GPL-2.0 if [ "x$PYTHON" = "x" ] diff --git a/tools/perf/tests/shell/lib/stat_output.sh b/tools/perf/tests/shell/lib/stat_output.sh index 9a176ceae4a3..3c36e80fe422 100644 --- a/tools/perf/tests/shell/lib/stat_output.sh +++ b/tools/perf/tests/shell/lib/stat_output.sh @@ -148,6 +148,19 @@ check_per_socket() echo "[Success]" } +check_metric_only() +{ + echo -n "Checking $1 output: metric only " + if [ "$(uname -m)" = "s390x" ] && ! grep '^facilities' /proc/cpuinfo | grep -qw 67 + then + echo "[Skip] CPU-measurement counter facility not installed" + return + fi + perf stat --metric-only $2 -M page_faults_per_second true + commachecker --metric-only + echo "[Success]" +} + # The perf stat options for per-socket, per-core, per-die # and -A ( no_aggr mode ) uses the info fetched from this # directory: "/sys/devices/system/cpu/cpu*/topology". For diff --git a/tools/perf/tests/shell/lib/waiting.sh b/tools/perf/tests/shell/lib/waiting.sh index bdd5a7c71591..3a152892e077 100644 --- a/tools/perf/tests/shell/lib/waiting.sh +++ b/tools/perf/tests/shell/lib/waiting.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # SPDX-License-Identifier: GPL-2.0 tenths=date\ +%s%1N diff --git a/tools/perf/tests/shell/list.sh b/tools/perf/tests/shell/list.sh index 8a868ae64560..0c04b3159cef 100755 --- a/tools/perf/tests/shell/list.sh +++ b/tools/perf/tests/shell/list.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf list tests # SPDX-License-Identifier: GPL-2.0 @@ -24,8 +24,11 @@ trap trap_cleanup EXIT TERM INT test_list_json() { echo "Json output test" + # Generate perf list json output into list_output file. perf list -j -o "${list_output}" - $PYTHON -m json.tool "${list_output}" + # Validate the json using python, redirect the json copy to /dev/null as + # otherwise the test may block writing to stdout. + $PYTHON -m json.tool "${list_output}" /dev/null echo "Json output test [Success]" } diff --git a/tools/perf/tests/shell/lock_contention.sh b/tools/perf/tests/shell/lock_contention.sh index c1ec5762215b..6dd90519f45c 100755 --- a/tools/perf/tests/shell/lock_contention.sh +++ b/tools/perf/tests/shell/lock_contention.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # kernel lock contention analysis test # SPDX-License-Identifier: GPL-2.0 @@ -7,18 +7,24 @@ set -e err=0 perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) result=$(mktemp /tmp/__perf_test.result.XXXXX) +errout=$(mktemp /tmp/__perf_test.errout.XXXXX) cleanup() { rm -f ${perfdata} rm -f ${result} - trap - EXIT TERM INT + rm -f ${errout} + trap - EXIT TERM INT ERR } trap_cleanup() { + if (( $? == 139 )); then #SIGSEGV + err=1 + fi + echo "Unexpected signal in ${FUNCNAME[1]}" cleanup exit ${err} } -trap trap_cleanup EXIT TERM INT +trap trap_cleanup EXIT TERM INT ERR check() { if [ "$(id -u)" != 0 ]; then @@ -27,7 +33,7 @@ check() { exit fi - if ! perf list | grep -q lock:contention_begin; then + if ! perf list tracepoint | grep -q lock:contention_begin; then echo "[Skip] No lock contention tracepoints" err=2 exit @@ -44,7 +50,7 @@ check() { test_record() { echo "Testing perf lock record and perf lock contention" - perf lock record -o ${perfdata} -- perf bench sched messaging > /dev/null 2>&1 + perf lock record -o ${perfdata} -- perf bench sched messaging -p > /dev/null 2>&1 # the output goes to the stderr and we expect only 1 output (-E 1) perf lock contention -i ${perfdata} -E 1 -q 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then @@ -64,7 +70,7 @@ test_bpf() fi # the perf lock contention output goes to the stderr - perf lock con -a -b -E 1 -q -- perf bench sched messaging > /dev/null 2> ${result} + perf lock con -a -b -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)" err=1 @@ -75,10 +81,12 @@ test_bpf() test_record_concurrent() { echo "Testing perf lock record and perf lock contention at the same time" - perf lock record -o- -- perf bench sched messaging 2> /dev/null | \ + perf lock record -o- -- perf bench sched messaging -p 2> ${errout} | \ perf lock contention -i- -E 1 -q 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] Recorded result count is not 1:" "$(cat "${result}" | wc -l)" + cat ${errout} + cat ${result} err=1 exit fi @@ -99,7 +107,7 @@ test_aggr_task() fi # the perf lock contention output goes to the stderr - perf lock con -a -b -t -E 1 -q -- perf bench sched messaging > /dev/null 2> ${result} + perf lock con -a -b -t -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)" err=1 @@ -122,7 +130,7 @@ test_aggr_addr() fi # the perf lock contention output goes to the stderr - perf lock con -a -b -l -E 1 -q -- perf bench sched messaging > /dev/null 2> ${result} + perf lock con -a -b -l -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)" err=1 @@ -140,7 +148,7 @@ test_aggr_cgroup() fi # the perf lock contention output goes to the stderr - perf lock con -a -b -g -E 1 -q -- perf bench sched messaging > /dev/null 2> ${result} + perf lock con -a -b --lock-cgroup -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)" err=1 @@ -162,7 +170,7 @@ test_type_filter() return fi - perf lock con -a -b -Y spinlock -q -- perf bench sched messaging > /dev/null 2> ${result} + perf lock con -a -b -Y spinlock -q -- perf bench sched messaging -p > /dev/null 2> ${result} if [ "$(grep -c -v spinlock "${result}")" != "0" ]; then echo "[Fail] BPF result should not have non-spinlocks:" "$(cat "${result}")" err=1 @@ -194,7 +202,7 @@ test_lock_filter() return fi - perf lock con -a -b -L tasklist_lock -q -- perf bench sched messaging > /dev/null 2> ${result} + perf lock con -a -b -L tasklist_lock -q -- perf bench sched messaging -p > /dev/null 2> ${result} if [ "$(grep -c -v "${test_lock_filter_type}" "${result}")" != "0" ]; then echo "[Fail] BPF result should not have non-${test_lock_filter_type} locks:" "$(cat "${result}")" err=1 @@ -222,7 +230,7 @@ test_stack_filter() return fi - perf lock con -a -b -S unix_stream -E 1 -q -- perf bench sched messaging > /dev/null 2> ${result} + perf lock con -a -b -S unix_stream -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result should have a lock from unix_stream:" "$(cat "${result}")" err=1 @@ -250,7 +258,7 @@ test_aggr_task_stack_filter() return fi - perf lock con -a -b -t -S unix_stream -E 1 -q -- perf bench sched messaging > /dev/null 2> ${result} + perf lock con -a -b -t -S unix_stream -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result should have a task from unix_stream:" "$(cat "${result}")" err=1 @@ -266,7 +274,7 @@ test_cgroup_filter() return fi - perf lock con -a -b -g -E 1 -F wait_total -q -- perf bench sched messaging > /dev/null 2> ${result} + perf lock con -a -b --lock-cgroup -E 1 -F wait_total -q -- perf bench sched messaging -p > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result should have a cgroup result:" "$(cat "${result}")" err=1 @@ -274,7 +282,7 @@ test_cgroup_filter() fi cgroup=$(cat "${result}" | awk '{ print $3 }') - perf lock con -a -b -g -E 1 -G "${cgroup}" -q -- perf bench sched messaging > /dev/null 2> ${result} + perf lock con -a -b --lock-cgroup -E 1 -G "${cgroup}" -q -- perf bench sched messaging -p > /dev/null 2> ${result} if [ "$(cat "${result}" | wc -l)" != "1" ]; then echo "[Fail] BPF result should have a result with cgroup filter:" "$(cat "${cgroup}")" err=1 @@ -309,7 +317,7 @@ test_csv_output() fi # the perf lock contention output goes to the stderr - perf lock con -a -b -E 1 -x , --output ${result} -- perf bench sched messaging > /dev/null 2>&1 + perf lock con -a -b -E 1 -x , --output ${result} -- perf bench sched messaging -p > /dev/null 2>&1 output=$(grep -v "^#" ${result} | tr -d -c , | wc -c) if [ "${header}" != "${output}" ]; then echo "[Fail] BPF result does not match the number of commas: ${header} != ${output}" @@ -333,4 +341,5 @@ test_aggr_task_stack_filter test_cgroup_filter test_csv_output +cleanup exit ${err} diff --git a/tools/perf/tests/shell/perf-report-hierarchy.sh b/tools/perf/tests/shell/perf-report-hierarchy.sh new file mode 100755 index 000000000000..e3c6f9a24f33 --- /dev/null +++ b/tools/perf/tests/shell/perf-report-hierarchy.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# perf report --hierarchy +# SPDX-License-Identifier: GPL-2.0 +# Arnaldo Carvalho de Melo <acme@redhat.com> + +set -e + +temp_dir=$(mktemp -d /tmp/perf-test-report.XXXXXXXXXX) + +cleanup() +{ + trap - EXIT TERM INT + sane=$(echo "${temp_dir}" | cut -b 1-21) + if [ "${sane}" = "/tmp/perf-test-report" ] ; then + echo "--- Cleaning up ---" + rm -rf "${temp_dir:?}/"* + rmdir "${temp_dir}" + fi +} + +trap_cleanup() +{ + cleanup + exit 1 +} + +trap trap_cleanup EXIT TERM INT + +test_report_hierarchy() +{ + echo "perf report --hierarchy" + + perf_data="${temp_dir}/perf-report-hierarchy-perf.data" + perf record -o "${perf_data}" uname + perf report --hierarchy -i "${perf_data}" > /dev/null + echo "perf report --hierarchy test [Success]" +} + +test_report_hierarchy + +cleanup + +exit 0 diff --git a/tools/perf/tests/shell/perftool-testsuite_probe.sh b/tools/perf/tests/shell/perftool-testsuite_probe.sh index a0fec33a0358..3863df16c19b 100755 --- a/tools/perf/tests/shell/perftool-testsuite_probe.sh +++ b/tools/perf/tests/shell/perftool-testsuite_probe.sh @@ -1,7 +1,8 @@ #!/bin/bash -# perftool-testsuite_probe +# perftool-testsuite_probe (exclusive) # SPDX-License-Identifier: GPL-2.0 +[ "$(id -u)" = 0 ] || exit 2 test -d "$(dirname "$0")/base_probe" || exit 2 cd "$(dirname "$0")/base_probe" || exit 2 status=0 diff --git a/tools/perf/tests/shell/perftool-testsuite_report.sh b/tools/perf/tests/shell/perftool-testsuite_report.sh index 973012ce92a7..a8cf75b4e77e 100755 --- a/tools/perf/tests/shell/perftool-testsuite_report.sh +++ b/tools/perf/tests/shell/perftool-testsuite_report.sh @@ -1,5 +1,5 @@ #!/bin/bash -# perftool-testsuite_report +# perftool-testsuite_report (exclusive) # SPDX-License-Identifier: GPL-2.0 test -d "$(dirname "$0")/base_report" || exit 2 diff --git a/tools/perf/tests/shell/pipe_test.sh b/tools/perf/tests/shell/pipe_test.sh index d4c8005ce9b9..e459aa99a951 100755 --- a/tools/perf/tests/shell/pipe_test.sh +++ b/tools/perf/tests/shell/pipe_test.sh @@ -13,6 +13,7 @@ skip_test_missing_symbol ${sym} data=$(mktemp /tmp/perf.data.XXXXXX) data2=$(mktemp /tmp/perf.data2.XXXXXX) prog="perf test -w noploop" +[ "$(uname -m)" = "s390x" ] && prog="$prog 3" err=0 set -e diff --git a/tools/perf/tests/shell/probe_vfs_getname.sh b/tools/perf/tests/shell/probe_vfs_getname.sh index 554e12e83c55..5fe5682c28ce 100755 --- a/tools/perf/tests/shell/probe_vfs_getname.sh +++ b/tools/perf/tests/shell/probe_vfs_getname.sh @@ -1,5 +1,5 @@ -#!/bin/sh -# Add vfs_getname probe to get syscall args filenames +#!/bin/bash +# Add vfs_getname probe to get syscall args filenames (exclusive) # SPDX-License-Identifier: GPL-2.0 # Arnaldo Carvalho de Melo <acme@kernel.org>, 2017 @@ -8,11 +8,18 @@ . "$(dirname $0)"/lib/probe.sh skip_if_no_perf_probe || exit 2 +[ "$(id -u)" = 0 ] || exit 2 # shellcheck source=lib/probe_vfs_getname.sh . "$(dirname $0)"/lib/probe_vfs_getname.sh -add_probe_vfs_getname || skip_if_no_debuginfo +add_probe_vfs_getname err=$? + +if [ $err -eq 1 ] ; then + skip_if_no_debuginfo + err=$? +fi + cleanup_probe_vfs_getname exit $err diff --git a/tools/perf/tests/shell/python-use.sh b/tools/perf/tests/shell/python-use.sh new file mode 100755 index 000000000000..fd2ee5390060 --- /dev/null +++ b/tools/perf/tests/shell/python-use.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# 'import perf' in python +# SPDX-License-Identifier: GPL-2.0 +# Just test if we can load the python binding. +set -e + +shelldir=$(dirname "$0") +# shellcheck source=lib/setup_python.sh +. "${shelldir}"/lib/setup_python.sh + +MODULE_DIR=$(dirname "$(which perf)")/python + +if [ -d "$MODULE_DIR" ] +then + CMD=$(cat <<EOF +import sys +sys.path.insert(0, '$MODULE_DIR') +import perf +print('success!') +EOF + ) +else + CMD=$(cat <<EOF +import perf +print('success!') +EOF + ) +fi + +echo -e "Testing 'import perf' with:\n$CMD" + +if ! echo "$CMD" | $PYTHON | grep -q "success!" +then + exit 1 +fi +exit 0 diff --git a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh index f38c8ead0b03..ab99bef556bf 100755 --- a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh +++ b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh @@ -1,5 +1,5 @@ -#!/bin/sh -# probe libc's inet_pton & backtrace it with ping +#!/bin/bash +# probe libc's inet_pton & backtrace it with ping (exclusive) # Installs a probe on libc's inet_pton function, that will use uprobes, # then use 'perf trace' on a ping to localhost asking for just one packet @@ -18,12 +18,13 @@ libc=$(grep -w libc /proc/self/maps | head -1 | sed -r 's/.*[[:space:]](\/.*)/\1/g') nm -Dg $libc 2>/dev/null | grep -F -q inet_pton || exit 254 -event_pattern='probe_libc:inet_pton(\_[[:digit:]]+)?' +event_pattern='probe_libc:inet_pton(_[[:digit:]]+)?' add_libc_inet_pton_event() { event_name=$(perf probe -f -x $libc -a inet_pton 2>&1 | tail -n +2 | head -n -5 | \ - grep -P -o "$event_pattern(?=[[:space:]]\(on inet_pton in $libc\))") + awk -v ep="$event_pattern" -v l="$libc" '$0 ~ ep && $0 ~ \ + ("\\(on inet_pton in " l "\\)") {print $1}') if [ $? -ne 0 ] || [ -z "$event_name" ] ; then printf "FAIL: could not add event\n" @@ -40,20 +41,11 @@ trace_libc_inet_pton_backtrace() { case "$(uname -m)" in s390x) eventattr='call-graph=dwarf,max-stack=4' - echo "(__GI_)?getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" >> $expected - echo "main\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$" >> $expected - ;; - ppc64|ppc64le) - eventattr='max-stack=4' - # Add gaih_inet to expected backtrace only if it is part of libc. - if nm $libc | grep -F -q gaih_inet.; then - echo "gaih_inet.*\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected - fi - echo "getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected - echo ".*(\+0x[[:xdigit:]]+|\[unknown\])[[:space:]]\(.*/bin/ping.*\)$" >> $expected + echo "((__GI_)?getaddrinfo|text_to_binary_address)\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" >> $expected + echo "(gaih_inet|main)\+0x[[:xdigit:]]+[[:space:]]\(inlined|.*/bin/ping.*\)$" >> $expected ;; *) - eventattr='max-stack=3' + eventattr='max-stack=4' echo ".*(\+0x[[:xdigit:]]+|\[unknown\])[[:space:]]\(.*/bin/ping.*\)$" >> $expected ;; esac @@ -76,14 +68,25 @@ trace_libc_inet_pton_backtrace() { fi perf script -i $perf_data | tac | grep -m1 ^ping -B9 | tac > $perf_script - exec 3<$perf_script exec 4<$expected - while read line <&3 && read -r pattern <&4; do + while read -r pattern <&4; do + echo "Pattern: $pattern" [ -z "$pattern" ] && break - echo $line - echo "$line" | grep -E -q "$pattern" - if [ $? -ne 0 ] ; then - printf "FAIL: expected backtrace entry \"%s\" got \"%s\"\n" "$pattern" "$line" + + found=0 + + # Search lines in the perf script result + exec 3<$perf_script + while read line <&3; do + [ -z "$line" ] && break + echo " Matching: $line" + ! echo "$line" | grep -E -q "$pattern" + found=$? + [ $found -eq 1 ] && break + done + + if [ $found -ne 1 ] ; then + printf "FAIL: Didn't find the expected backtrace entry \"%s\"\n" "$pattern" return 1 fi done @@ -103,6 +106,7 @@ delete_libc_inet_pton_event() { # Check for IPv6 interface existence ip a sh lo | grep -F -q inet6 || exit 2 +[ "$(id -u)" = 0 ] || exit 2 skip_if_no_perf_probe && \ add_libc_inet_pton_event && \ diff --git a/tools/perf/tests/shell/record+script_probe_vfs_getname.sh b/tools/perf/tests/shell/record+script_probe_vfs_getname.sh index 9a61928e3c9a..002f7037f182 100755 --- a/tools/perf/tests/shell/record+script_probe_vfs_getname.sh +++ b/tools/perf/tests/shell/record+script_probe_vfs_getname.sh @@ -1,5 +1,5 @@ -#!/bin/sh -# Use vfs_getname probe to get syscall args filenames +#!/bin/bash +# Use vfs_getname probe to get syscall args filenames (exclusive) # Uses the 'perf test shell' library to add probe:vfs_getname to the system # then use it with 'perf record' using 'touch' to write to a temp file, then @@ -13,6 +13,7 @@ . "$(dirname "$0")/lib/probe.sh" skip_if_no_perf_probe || exit 2 +[ "$(id -u)" = 0 ] || exit 2 # shellcheck source=lib/probe_vfs_getname.sh . "$(dirname "$0")/lib/probe_vfs_getname.sh" @@ -34,8 +35,14 @@ perf_script_filenames() { grep -E " +touch +[0-9]+ +\[[0-9]+\] +[0-9]+\.[0-9]+: +probe:vfs_getname[_0-9]*: +\([[:xdigit:]]+\) +pathname=\"${file}\"" } -add_probe_vfs_getname || skip_if_no_debuginfo +add_probe_vfs_getname err=$? + +if [ $err -eq 1 ] ; then + skip_if_no_debuginfo + err=$? +fi + if [ $err -ne 0 ] ; then exit $err fi diff --git a/tools/perf/tests/shell/record+zstd_comp_decomp.sh b/tools/perf/tests/shell/record+zstd_comp_decomp.sh index 8929046e9057..f6b82223834e 100755 --- a/tools/perf/tests/shell/record+zstd_comp_decomp.sh +++ b/tools/perf/tests/shell/record+zstd_comp_decomp.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Zstd perf.data compression/decompression # SPDX-License-Identifier: GPL-2.0 diff --git a/tools/perf/tests/shell/record.sh b/tools/perf/tests/shell/record.sh index 048078ee2eca..0f5841c479e7 100755 --- a/tools/perf/tests/shell/record.sh +++ b/tools/perf/tests/shell/record.sh @@ -1,5 +1,5 @@ #!/bin/bash -# perf record tests +# perf record tests (exclusive) # SPDX-License-Identifier: GPL-2.0 set -e @@ -12,11 +12,14 @@ shelldir=$(dirname "$0") . "${shelldir}"/lib/perf_has_symbol.sh testsym="test_loop" +testsym2="brstack" skip_test_missing_symbol ${testsym} +skip_test_missing_symbol ${testsym2} err=0 perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) +script_output=$(mktemp /tmp/__perf_test.perf.data.XXXXX.script) testprog="perf test -w thloop" cpu_pmu_dir="/sys/bus/event_source/devices/cpu*" br_cntr_file="/caps/branch_counter_nr" @@ -33,13 +36,15 @@ default_fd_limit=$(ulimit -Sn) min_fd_limit=$(($(getconf _NPROCESSORS_ONLN) * 16)) cleanup() { - rm -rf "${perfdata}" - rm -rf "${perfdata}".old + rm -f "${perfdata}" + rm -f "${perfdata}".old + rm -f "${script_output}" trap - EXIT TERM INT } trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" cleanup exit 1 } @@ -93,7 +98,7 @@ test_per_thread() { test_register_capture() { echo "Register capture test" - if ! perf list | grep -q 'br_inst_retired.near_call' + if ! perf list pmu | grep -q 'br_inst_retired.near_call' then echo "Register capture test [Skipped missing event]" return @@ -228,6 +233,200 @@ test_cgroup() { echo "Cgroup sampling test [Success]" } +test_uid() { + echo "Uid sampling test" + if ! perf record -aB --synth=no --uid "$(id -u)" -o "${perfdata}" ${testprog} \ + > "${script_output}" 2>&1 + then + if grep -q "libbpf.*EPERM" "${script_output}" + then + echo "Uid sampling [Skipped permissions]" + return + else + echo "Uid sampling [Failed to record]" + err=1 + # cat "${script_output}" + return + fi + fi + if ! perf report -i "${perfdata}" -q | grep -q "${testsym}" + then + echo "Uid sampling [Failed missing output]" + err=1 + return + fi + echo "Uid sampling test [Success]" +} + +test_leader_sampling() { + echo "Basic leader sampling test" + if ! perf record -o "${perfdata}" -e "{cycles,cycles}:Su" -- \ + perf test -w brstack 2> /dev/null + then + echo "Leader sampling [Failed record]" + err=1 + return + fi + perf script -i "${perfdata}" | grep brstack > $script_output + # Check if the two instruction counts are equal in each record. + # However, the throttling code doesn't consider event grouping. During throttling, only the + # leader is stopped, causing the slave's counts significantly higher. To temporarily solve this, + # let's set the tolerance rate to 80%. + # TODO: Revert the code for tolerance once the throttling mechanism is fixed. + index=0 + valid_counts=0 + invalid_counts=0 + tolerance_rate=0.8 + while IFS= read -r line + do + cycles=$(echo $line | awk '{for(i=1;i<=NF;i++) if($i=="cycles:") print $(i-1)}') + if [ $(($index%2)) -ne 0 ] && [ ${cycles}x != ${prev_cycles}x ] + then + invalid_counts=$(($invalid_counts+1)) + else + valid_counts=$(($valid_counts+1)) + fi + index=$(($index+1)) + prev_cycles=$cycles + done < "${script_output}" + total_counts=$(bc <<< "$invalid_counts+$valid_counts") + if (( $(bc <<< "$total_counts <= 0") )) + then + echo "Leader sampling [No sample generated]" + err=1 + return + fi + isok=$(bc <<< "scale=2; if (($invalid_counts/$total_counts) < (1-$tolerance_rate)) { 0 } else { 1 };") + if [ $isok -eq 1 ] + then + echo "Leader sampling [Failed inconsistent cycles count]" + err=1 + else + echo "Basic leader sampling test [Success]" + fi +} + +test_topdown_leader_sampling() { + echo "Topdown leader sampling test" + if ! perf stat -e "{slots,topdown-retiring}" true 2> /dev/null + then + echo "Topdown leader sampling [Skipped event parsing failed]" + return + fi + if ! perf record -o "${perfdata}" -e "{instructions,slots,topdown-retiring}:S" true 2> /dev/null + then + echo "Topdown leader sampling [Failed topdown events not reordered correctly]" + err=1 + return + fi + echo "Topdown leader sampling test [Success]" +} + +test_precise_max() { + local -i skipped=0 + + echo "precise_max attribute test" + # Just to make sure event cycles is supported for sampling + if perf record -o "${perfdata}" -e "cycles" true 2> /dev/null + then + if ! perf record -o "${perfdata}" -e "cycles:P" true 2> /dev/null + then + echo "precise_max attribute [Failed cycles:P event]" + err=1 + return + fi + else + echo "precise_max attribute [Skipped no cycles:P event]" + ((skipped+=1)) + fi + # On s390 event instructions is not supported for perf record + if perf record -o "${perfdata}" -e "instructions" true 2> /dev/null + then + # On AMD, cycles and instructions events are treated differently + if ! perf record -o "${perfdata}" -e "instructions:P" true 2> /dev/null + then + echo "precise_max attribute [Failed instructions:P event]" + err=1 + return + fi + else + echo "precise_max attribute [Skipped no instructions:P event]" + ((skipped+=1)) + fi + if [ $skipped -eq 2 ] + then + echo "precise_max attribute [Skipped no hardware events]" + else + echo "precise_max attribute test [Success]" + fi +} + +test_callgraph() { + echo "Callgraph test" + + case $(uname -m) + in s390x) + cmd_flags="--call-graph dwarf -e cpu-clock";; + *) + cmd_flags="-g";; + esac + + if ! perf record -o "${perfdata}" $cmd_flags perf test -w brstack + then + echo "Callgraph test [Failed missing output]" + err=1 + return + fi + + if ! perf report -i "${perfdata}" 2>&1 | grep "${testsym2}" + then + echo "Callgraph test [Failed missing symbol]" + err=1 + return + fi + + echo "Callgraph test [Success]" +} + +test_ratio_to_prev() { + echo "ratio-to-prev test" + if ! perf record -o /dev/null -e "{instructions, cycles/period=100000,ratio-to-prev=0.5/}" \ + true 2> /dev/null + then + echo "ratio-to-prev [Skipped not supported]" + return + fi + if ! perf record -o /dev/null -e "instructions, cycles/period=100000,ratio-to-prev=0.5/" \ + true |& grep -q 'Invalid use of ratio-to-prev term without preceding element in group' + then + echo "ratio-to-prev test [Failed elements must be in same group]" + err=1 + return + fi + if ! perf record -o /dev/null -e "{instructions,dummy,cycles/period=100000,ratio-to-prev=0.5/}" \ + true |& grep -q 'must have same PMU' + then + echo "ratio-to-prev test [Failed elements must have same PMU]" + err=1 + return + fi + if ! perf record -o /dev/null -e "{instructions,cycles/ratio-to-prev=0.5/}" \ + true |& grep -q 'Event period term or count (-c) must be set when using ratio-to-prev term.' + then + echo "ratio-to-prev test [Failed period must be set]" + err=1 + return + fi + if ! perf record -o /dev/null -e "{cycles/ratio-to-prev=0.5/}" \ + true |& grep -q 'Invalid use of ratio-to-prev term without preceding element in group' + then + echo "ratio-to-prev test [Failed need 2+ events]" + err=1 + return + fi + echo "Basic ratio-to-prev record test [Success]" +} + # raise the limit of file descriptors to minimum if [[ $default_fd_limit -lt $min_fd_limit ]]; then ulimit -Sn $min_fd_limit @@ -239,6 +438,12 @@ test_system_wide test_workload test_branch_counter test_cgroup +test_uid +test_leader_sampling +test_topdown_leader_sampling +test_precise_max +test_callgraph +test_ratio_to_prev # restore the default value ulimit -Sn $default_fd_limit diff --git a/tools/perf/tests/shell/record_bpf_filter.sh b/tools/perf/tests/shell/record_bpf_filter.sh index 1b58ccc1fd88..383574cb3bd3 100755 --- a/tools/perf/tests/shell/record_bpf_filter.sh +++ b/tools/perf/tests/shell/record_bpf_filter.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf record sample filtering (by BPF) tests # SPDX-License-Identifier: GPL-2.0 @@ -89,7 +89,7 @@ test_bpf_filter_fail() { test_bpf_filter_group() { echo "Group bpf-filter test" - if ! perf record -e task-clock --filter 'period > 1000 || ip > 0' \ + if ! perf record -e task-clock --filter 'period > 1000, ip > 0' \ -o /dev/null true 2>/dev/null then echo "Group bpf-filter test [Failed should succeed]" @@ -97,7 +97,7 @@ test_bpf_filter_group() { return fi - if ! perf record -e task-clock --filter 'cpu > 0 || ip > 0' \ + if ! perf record -e task-clock --filter 'period > 1000 , cpu > 0 || ip > 0' \ -o /dev/null true 2>&1 | grep -q PERF_SAMPLE_CPU then echo "Group bpf-filter test [Failed forbidden CPU]" diff --git a/tools/perf/tests/shell/record_lbr.sh b/tools/perf/tests/shell/record_lbr.sh index 32314641217e..78a02e90ece1 100755 --- a/tools/perf/tests/shell/record_lbr.sh +++ b/tools/perf/tests/shell/record_lbr.sh @@ -1,10 +1,15 @@ #!/bin/bash -# perf record LBR tests +# perf record LBR tests (exclusive) # SPDX-License-Identifier: GPL-2.0 set -e -if [ ! -f /sys/devices/cpu/caps/branches ] && [ ! -f /sys/devices/cpu_core/caps/branches ] +ParanoidAndNotRoot() { + [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] +} + +if [ ! -f /sys/bus/event_source/devices/cpu/caps/branches ] && + [ ! -f /sys/bus/event_source/devices/cpu_core/caps/branches ] then echo "Skip: only x86 CPUs support LBR" exit 2 @@ -22,6 +27,7 @@ cleanup() { } trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" cleanup exit 1 } @@ -93,7 +99,7 @@ lbr_test() { return fi - zero_nr=$(echo "$out" | grep -c 'branch stack: nr:0' || true) + zero_nr=$(echo "$out" | grep -A3 'branch stack: nr:0' | grep thread | grep -cv swapper || true) r=$(($zero_nr * 100 / $bs_nr)) if [ $r -gt $threshold ]; then echo "$test [Failed empty br stack ratio exceed $threshold%: $r%]" @@ -122,8 +128,11 @@ lbr_test "-j ind_call" "any indirect call" 2 lbr_test "-j ind_jmp" "any indirect jump" 100 lbr_test "-j call" "direct calls" 2 lbr_test "-j ind_call,u" "any indirect user call" 100 -lbr_test "-a -b" "system wide any branch" 2 -lbr_test "-a -j any_call" "system wide any call" 2 +if ! ParanoidAndNotRoot 1 +then + lbr_test "-a -b" "system wide any branch" 2 + lbr_test "-a -j any_call" "system wide any call" 2 +fi # Parallel parallel_lbr_test "-b" "parallel any branch" 100 & @@ -140,10 +149,16 @@ parallel_lbr_test "-j call" "parallel direct calls" 100 & pid6=$! parallel_lbr_test "-j ind_call,u" "parallel any indirect user call" 100 & pid7=$! -parallel_lbr_test "-a -b" "parallel system wide any branch" 100 & -pid8=$! -parallel_lbr_test "-a -j any_call" "parallel system wide any call" 100 & -pid9=$! +if ParanoidAndNotRoot 1 +then + pid8= + pid9= +else + parallel_lbr_test "-a -b" "parallel system wide any branch" 100 & + pid8=$! + parallel_lbr_test "-a -j any_call" "parallel system wide any call" 100 & + pid9=$! +fi for pid in $pid1 $pid2 $pid3 $pid4 $pid5 $pid6 $pid7 $pid8 $pid9 do diff --git a/tools/perf/tests/shell/record_offcpu.sh b/tools/perf/tests/shell/record_offcpu.sh index 67c925f3a15a..860a2d6f4b75 100755 --- a/tools/perf/tests/shell/record_offcpu.sh +++ b/tools/perf/tests/shell/record_offcpu.sh @@ -1,5 +1,5 @@ -#!/bin/sh -# perf record offcpu profiling tests +#!/bin/bash +# perf record offcpu profiling tests (exclusive) # SPDX-License-Identifier: GPL-2.0 set -e @@ -7,6 +7,9 @@ set -e err=0 perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) +ts=$(printf "%u" $((~0 << 32))) # OFF_CPU_TIMESTAMP +dummy_timestamp=${ts%???} # remove the last 3 digits to match perf script + cleanup() { rm -f ${perfdata} rm -f ${perfdata}.old @@ -19,6 +22,9 @@ trap_cleanup() { } trap trap_cleanup EXIT TERM INT +test_above_thresh="Threshold test (above threshold)" +test_below_thresh="Threshold test (below threshold)" + test_offcpu_priv() { echo "Checking off-cpu privilege" @@ -88,6 +94,63 @@ test_offcpu_child() { echo "Child task off-cpu test [Success]" } +# task blocks longer than the --off-cpu-thresh, perf should collect a direct sample +test_offcpu_above_thresh() { + echo "${test_above_thresh}" + + # collect direct off-cpu samples for tasks blocked for more than 999ms + if ! perf record -e dummy --off-cpu --off-cpu-thresh 999 -o ${perfdata} -- sleep 1 2> /dev/null + then + echo "${test_above_thresh} [Failed record]" + err=1 + return + fi + # direct sample's timestamp should be lower than the dummy_timestamp of the at-the-end sample + # check if a direct sample exists + if ! perf script --time "0, ${dummy_timestamp}" -i ${perfdata} -F event | grep -q "offcpu-time" + then + echo "${test_above_thresh} [Failed missing direct samples]" + err=1 + return + fi + # there should only be one direct sample, and its period should be higher than off-cpu-thresh + if ! perf script --time "0, ${dummy_timestamp}" -i ${perfdata} -F period | \ + awk '{ if (int($1) > 999000000) exit 0; else exit 1; }' + then + echo "${test_above_thresh} [Failed off-cpu time too short]" + err=1 + return + fi + echo "${test_above_thresh} [Success]" +} + +# task blocks shorter than the --off-cpu-thresh, perf should collect an at-the-end sample +test_offcpu_below_thresh() { + echo "${test_below_thresh}" + + # collect direct off-cpu samples for tasks blocked for more than 1.2s + if ! perf record -e dummy --off-cpu --off-cpu-thresh 1200 -o ${perfdata} -- sleep 1 2> /dev/null + then + echo "${test_below_thresh} [Failed record]" + err=1 + return + fi + # see if there's an at-the-end sample + if ! perf script --time "${dummy_timestamp}," -i ${perfdata} -F event | grep -q 'offcpu-time' + then + echo "${test_below_thresh} [Failed at-the-end samples cannot be found]" + err=1 + return + fi + # plus there shouldn't be any direct samples + if perf script --time "0, ${dummy_timestamp}" -i ${perfdata} -F event | grep -q 'offcpu-time' + then + echo "${test_below_thresh} [Failed direct samples are found when they shouldn't be]" + err=1 + return + fi + echo "${test_below_thresh} [Success]" +} test_offcpu_priv @@ -99,5 +162,13 @@ if [ $err = 0 ]; then test_offcpu_child fi +if [ $err = 0 ]; then + test_offcpu_above_thresh +fi + +if [ $err = 0 ]; then + test_offcpu_below_thresh +fi + cleanup exit $err diff --git a/tools/perf/tests/shell/record_sideband.sh b/tools/perf/tests/shell/record_sideband.sh index ac70ac27d590..2182551873be 100755 --- a/tools/perf/tests/shell/record_sideband.sh +++ b/tools/perf/tests/shell/record_sideband.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf record sideband tests # SPDX-License-Identifier: GPL-2.0 diff --git a/tools/perf/tests/shell/record_weak_term.sh b/tools/perf/tests/shell/record_weak_term.sh new file mode 100755 index 000000000000..811b00ffb47a --- /dev/null +++ b/tools/perf/tests/shell/record_weak_term.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# record weak terms +# SPDX-License-Identifier: GPL-2.0 +# Test that command line options override weak terms from sysfs or inbuilt json. +set -e + +shelldir=$(dirname "$0") +# shellcheck source=lib/setup_python.sh +. "${shelldir}"/lib/setup_python.sh + +# Find the first event with a specified period, such as +# "cpu_core/event=0x24,period=200003,umask=0xff/" +event=$(perf list --json | $PYTHON -c ' +import json, sys +for e in json.load(sys.stdin): + if "EventName" not in e or "/modifier" in e["EventName"]: + continue + if "Encoding" in e and "period=" in e["Encoding"]: + print(e["EventName"]) + break +') +if [[ "$event" = "" ]] +then + echo "Skip: No sysfs/json events with inbuilt period." + exit 2 +fi + +echo "Testing that for $event the period is overridden with 1000" +perf list --detail "$event" +if ! perf record -c 1000 -vv -e "$event" -o /dev/null true 2>&1 | \ + grep -q -F '{ sample_period, sample_freq } 1000' +then + echo "Fail: Unexpected verbose output and sample period" + exit 1 +fi +echo "Success" +exit 0 diff --git a/tools/perf/tests/shell/sched.sh b/tools/perf/tests/shell/sched.sh new file mode 100755 index 000000000000..b9b81eaf856e --- /dev/null +++ b/tools/perf/tests/shell/sched.sh @@ -0,0 +1,116 @@ +#!/bin/bash +# perf sched tests +# SPDX-License-Identifier: GPL-2.0 + +set -e + +if [ "$(id -u)" != 0 ]; then + echo "[Skip] No root permission" + exit 2 +fi + +err=0 +perfdata=$(mktemp /tmp/__perf_test_sched.perf.data.XXXXX) +PID1=0 +PID2=0 + +cleanup() { + rm -f "${perfdata}" + rm -f "${perfdata}".old + + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +start_noploops() { + # Start two noploop workloads on CPU0 to trigger scheduling. + perf test -w noploop 10 & + PID1=$! + taskset -pc 0 $PID1 + perf test -w noploop 10 & + PID2=$! + taskset -pc 0 $PID2 + + if ! grep -q 'Cpus_allowed_list:\s*0$' "/proc/$PID1/status" + then + echo "Sched [Error taskset did not work for the 1st noploop ($PID1)]" + grep Cpus_allowed /proc/$PID1/status + err=1 + fi + + if ! grep -q 'Cpus_allowed_list:\s*0$' "/proc/$PID2/status" + then + echo "Sched [Error taskset did not work for the 2nd noploop ($PID2)]" + grep Cpus_allowed /proc/$PID2/status + err=1 + fi +} + +cleanup_noploops() { + kill "$PID1" "$PID2" +} + +test_sched_record() { + echo "Sched record" + + start_noploops + + perf sched record --no-inherit -o "${perfdata}" sleep 1 + + cleanup_noploops +} + +test_sched_latency() { + echo "Sched latency" + + if ! perf sched latency -i "${perfdata}" | grep -q perf-noploop + then + echo "Sched latency [Failed missing output]" + err=1 + fi +} + +test_sched_script() { + echo "Sched script" + + if ! perf sched script -i "${perfdata}" | grep -q perf-noploop + then + echo "Sched script [Failed missing output]" + err=1 + fi +} + +test_sched_map() { + echo "Sched map" + + if ! perf sched map -i "${perfdata}" | grep -q perf-noploop + then + echo "Sched map [Failed missing output]" + err=1 + fi +} + +test_sched_timehist() { + echo "Sched timehist" + + if ! perf sched timehist -i "${perfdata}" | grep -q perf-noploop + then + echo "Sched timehist [Failed missing output]" + err=1 + fi +} + +test_sched_record +test_sched_latency +test_sched_script +test_sched_map +test_sched_timehist + +cleanup +exit $err diff --git a/tools/perf/tests/shell/script.sh b/tools/perf/tests/shell/script.sh index d3e2958d2242..7007f1cdf761 100755 --- a/tools/perf/tests/shell/script.sh +++ b/tools/perf/tests/shell/script.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf script tests # SPDX-License-Identifier: GPL-2.0 diff --git a/tools/perf/tests/shell/script_dlfilter.sh b/tools/perf/tests/shell/script_dlfilter.sh new file mode 100755 index 000000000000..45c97d4a7d5f --- /dev/null +++ b/tools/perf/tests/shell/script_dlfilter.sh @@ -0,0 +1,107 @@ +#!/bin/bash +# perf script --dlfilter tests +# SPDX-License-Identifier: GPL-2.0 + +set -e + +shelldir=$(dirname "$0") +# shellcheck source=lib/setup_python.sh +. "${shelldir}"/lib/setup_python.sh + +# skip if there's no compiler +if ! [ -x "$(command -v cc)" ]; then + echo "failed: no compiler, install gcc" + exit 2 +fi + +err=0 +perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) +dlfilter_c=$(mktemp /tmp/__perf_test.dlfilter.test.c.XXXXX) +dlfilter_so=$(mktemp /tmp/__perf_test.dlfilter.so.XXXXX) + +cleanup() { + rm -f "${perfdata}" + rm -f "${dlfilter_c}" + rm -f "${dlfilter_so}" + rm -f "${dlfilter_so}.o" + + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +cat <<EOF > "${dlfilter_c}" +#include <perf/perf_dlfilter.h> +#include <string.h> +#include <stdio.h> + +struct perf_dlfilter_fns perf_dlfilter_fns; + +int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx) +{ + const struct perf_dlfilter_al *al; + + if (!sample->ip) + return 0; + + al = perf_dlfilter_fns.resolve_ip(ctx); + if (!al || !al->sym || strcmp(al->sym, "test_loop")) + return 1; + + return 0; +} +EOF + +test_dlfilter() { + echo "Basic --dlfilter test" + # Generate perf.data file + if ! perf record -o "${perfdata}" perf test -w thloop 1 2> /dev/null + then + echo "Basic --dlfilter test [Failed record]" + err=1 + return + fi + + # Build the dlfilter + if ! cc -c -I tools/perf/include -fpic -x c "${dlfilter_c}" -o "${dlfilter_so}.o" + then + echo "Basic --dlfilter test [Failed to build dlfilter object]" + err=1 + return + fi + + if ! cc -shared -o "${dlfilter_so}" "${dlfilter_so}.o" + then + echo "Basic --dlfilter test [Failed to link dlfilter shared object]" + err=1 + return + fi + + # Check that the output contains "test_loop" and nothing else + if ! perf script -i "${perfdata}" --dlfilter "${dlfilter_so}" | grep -q "test_loop" + then + echo "Basic --dlfilter test [Failed missing output]" + err=1 + return + fi + + # The filter should filter out everything except test_loop, so ensure no other symbols are present + # This is a simple check; we could be more rigorous + if perf script -i "${perfdata}" --dlfilter "${dlfilter_so}" | grep -v "test_loop" | grep -q "perf" + then + echo "Basic --dlfilter test [Failed filtering]" + err=1 + return + fi + + echo "Basic --dlfilter test [Success]" +} + +test_dlfilter +cleanup +exit $err diff --git a/tools/perf/tests/shell/stat+csv_output.sh b/tools/perf/tests/shell/stat+csv_output.sh index fc2d8cc6e5e0..cd6fff597091 100755 --- a/tools/perf/tests/shell/stat+csv_output.sh +++ b/tools/perf/tests/shell/stat+csv_output.sh @@ -44,6 +44,7 @@ function commachecker() ;; "--per-die") exp=8 ;; "--per-cluster") exp=8 ;; "--per-cache") exp=8 + ;; "--metric-only") exp=1 esac while read line @@ -75,6 +76,7 @@ check_interval "CSV" "$perf_cmd" check_event "CSV" "$perf_cmd" check_per_thread "CSV" "$perf_cmd" check_per_node "CSV" "$perf_cmd" +check_metric_only "CSV" "$perf_cmd" if [ $skip_test -ne 1 ] then check_system_wide_no_aggr "CSV" "$perf_cmd" diff --git a/tools/perf/tests/shell/stat+csv_summary.sh b/tools/perf/tests/shell/stat+csv_summary.sh index 323123ff4d19..9a4353db3825 100755 --- a/tools/perf/tests/shell/stat+csv_summary.sh +++ b/tools/perf/tests/shell/stat+csv_summary.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf stat csv summary test # SPDX-License-Identifier: GPL-2.0 diff --git a/tools/perf/tests/shell/stat+event_uniquifying.sh b/tools/perf/tests/shell/stat+event_uniquifying.sh new file mode 100755 index 000000000000..b5dec6b6da36 --- /dev/null +++ b/tools/perf/tests/shell/stat+event_uniquifying.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# perf stat events uniquifying +# SPDX-License-Identifier: GPL-2.0 + +set -e + +err=0 +stat_output=$(mktemp /tmp/__perf_test.stat_output.XXXXX) + +cleanup() { + rm -f "${stat_output}" + + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +test_event_uniquifying() { + echo "Uniquification of PMU sysfs events test" + + # Read events from perf list with and without -v. With -v the duplicate PMUs + # aren't deduplicated. Note, json events are listed by perf list without a + # PMU. + read -ra pmu_events <<< "$(perf list --raw pmu)" + read -ra pmu_v_events <<< "$(perf list -v --raw pmu)" + # For all non-deduplicated events. + for pmu_v_event in "${pmu_v_events[@]}"; do + # If the event matches an event in the deduplicated events then it musn't + # be an event with duplicate PMUs, continue the outer loop. + for pmu_event in "${pmu_events[@]}"; do + if [[ "$pmu_v_event" == "$pmu_event" ]]; then + continue 2 + fi + done + # Strip the suffix from the non-deduplicated event's PMU. + event=$(echo "$pmu_v_event" | sed -E 's/_[0-9]+//') + for pmu_event in "${pmu_events[@]}"; do + if [[ "$event" == "$pmu_event" ]]; then + echo "Testing event ${event} is uniquified to ${pmu_v_event}" + if ! perf stat -e "$event" -A -o ${stat_output} -- true; then + echo "Error running perf stat for event '$event' [Skip]" + if [ $err = 0 ]; then + err=2 + fi + continue + fi + # Ensure the non-deduplicated event appears in the output. + if ! grep -q "${pmu_v_event}" "${stat_output}"; then + echo "Uniquification of PMU sysfs events test [Failed]" + cat "${stat_output}" + err=1 + fi + break + fi + done + done +} + +test_event_uniquifying +cleanup +exit $err diff --git a/tools/perf/tests/shell/stat+json_output.sh b/tools/perf/tests/shell/stat+json_output.sh index 6b630d33c328..85d1ad7186c6 100755 --- a/tools/perf/tests/shell/stat+json_output.sh +++ b/tools/perf/tests/shell/stat+json_output.sh @@ -173,6 +173,19 @@ check_per_socket() echo "[Success]" } +check_metric_only() +{ + echo -n "Checking json output: metric only " + if [ "$(uname -m)" = "s390x" ] && ! grep '^facilities' /proc/cpuinfo | grep -qw 67 + then + echo "[Skip] CPU-measurement counter facility not installed" + return + fi + perf stat -j --metric-only -M page_faults_per_second -o "${stat_output}" true + $PYTHON $pythonchecker --metric-only --file "${stat_output}" + echo "[Success]" +} + # The perf stat options for per-socket, per-core, per-die # and -A ( no_aggr mode ) uses the info fetched from this # directory: "/sys/devices/system/cpu/cpu*/topology". For @@ -207,6 +220,7 @@ check_interval check_event check_per_thread check_per_node +check_metric_only if [ $skip_test -ne 1 ] then check_system_wide_no_aggr diff --git a/tools/perf/tests/shell/stat+shadow_stat.sh b/tools/perf/tests/shell/stat+shadow_stat.sh index 0c7d79a230ea..cabbbf17c662 100755 --- a/tools/perf/tests/shell/stat+shadow_stat.sh +++ b/tools/perf/tests/shell/stat+shadow_stat.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf stat metrics (shadow stat) test # SPDX-License-Identifier: GPL-2.0 @@ -14,7 +14,7 @@ perf stat -a -e cycles sleep 1 2>&1 | grep -e cpu_core && exit 2 test_global_aggr() { - perf stat -a --no-big-num -e cycles,instructions sleep 1 2>&1 | \ + perf stat -a --no-big-num -M insn_per_cycle sleep 1 2>&1 | \ grep -e cycles -e instructions | \ while read num evt _ ipc rest do @@ -53,7 +53,7 @@ test_global_aggr() test_no_aggr() { - perf stat -a -A --no-big-num -e cycles,instructions sleep 1 2>&1 | \ + perf stat -a -A --no-big-num -M insn_per_cycle sleep 1 2>&1 | \ grep ^CPU | \ while read cpu num evt _ ipc rest do diff --git a/tools/perf/tests/shell/stat+std_output.sh b/tools/perf/tests/shell/stat+std_output.sh index cbf2894b2c84..9c4b92ecf448 100755 --- a/tools/perf/tests/shell/stat+std_output.sh +++ b/tools/perf/tests/shell/stat+std_output.sh @@ -12,8 +12,8 @@ set -e stat_output=$(mktemp /tmp/__perf_test.stat_output.std.XXXXX) event_name=(cpu-clock task-clock context-switches cpu-migrations page-faults stalled-cycles-frontend stalled-cycles-backend cycles instructions branches branch-misses) -event_metric=("CPUs utilized" "CPUs utilized" "/sec" "/sec" "/sec" "frontend cycles idle" "backend cycles idle" "GHz" "insn per cycle" "/sec" "of all branches") -skip_metric=("stalled cycles per insn" "tma_" "retiring" "frontend_bound" "bad_speculation" "backend_bound") +event_metric=("CPUs_utilized" "CPUs_utilized" "cs/sec" "migrations/sec" "faults/sec" "frontend_cycles_idle" "backend_cycles_idle" "GHz" "insn_per_cycle" "/sec" "branch_miss_rate") +skip_metric=("tma_" "TopdownL1") cleanup() { rm -f "${stat_output}" @@ -30,6 +30,7 @@ trap trap_cleanup EXIT TERM INT function commachecker() { local prefix=1 + local -i metric_only=0 case "$1" in "--interval") prefix=2 @@ -41,6 +42,7 @@ function commachecker() ;; "--per-die") prefix=3 ;; "--per-cache") prefix=3 ;; "--per-cluster") prefix=3 + ;; "--metric-only") metric_only=1 esac while read line @@ -60,6 +62,9 @@ function commachecker() x=${main_body%#*} [ "$x" = "" ] && continue + # Check metric only - if it has a non-empty result + [ $metric_only -eq 1 ] && return 0 + # Skip metrics without event name y=${main_body#*#} for i in "${!skip_metric[@]}"; do @@ -84,6 +89,12 @@ function commachecker() exit 1; } done < "${stat_output}" + + if [ $metric_only -ne 1 ] + then + echo "Missing metric only output in:" + cat "${stat_output}" + fi return 0 } @@ -95,6 +106,7 @@ check_system_wide "STD" "$perf_cmd" check_interval "STD" "$perf_cmd" check_per_thread "STD" "$perf_cmd" check_per_node "STD" "$perf_cmd" +check_metric_only "STD" "$perf_cmd" if [ $skip_test -ne 1 ] then check_system_wide_no_aggr "STD" "$perf_cmd" diff --git a/tools/perf/tests/shell/stat.sh b/tools/perf/tests/shell/stat.sh index 3f1e67795490..0b2f0f88ca16 100755 --- a/tools/perf/tests/shell/stat.sh +++ b/tools/perf/tests/shell/stat.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf stat tests # SPDX-License-Identifier: GPL-2.0 @@ -16,9 +16,46 @@ test_default_stat() { echo "Basic stat command test [Success]" } +test_null_stat() { + echo "Null stat command test" + if ! perf stat --null true 2>&1 | grep -E -q "Performance counter stats for 'true':" + then + echo "Null stat command test [Failed]" + err=1 + return + fi + echo "Null stat command test [Success]" +} + +find_offline_cpu() { + for i in $(seq 1 4096) + do + if [[ ! -f /sys/devices/system/cpu/cpu$i/online || \ + $(cat /sys/devices/system/cpu/cpu$i/online) == "0" ]] + then + echo $i + return + fi + done + echo "Failed to find offline CPU" + exit 1 +} + +test_offline_cpu_stat() { + cpu=$(find_offline_cpu) + echo "Offline CPU stat command test (cpu $cpu)" + if ! perf stat "-C$cpu" -e cycles true 2>&1 | grep -E -q "No supported events found." + then + echo "Offline CPU stat command test [Failed]" + err=1 + return + fi + echo "Offline CPU stat command test [Success]" +} + test_stat_record_report() { echo "stat record and report test" - if ! perf stat record -o - true | perf stat report -i - 2>&1 | \ + if ! perf stat record -e task-clock -o - true | perf stat report -i - 2>&1 | \ grep -E -q "Performance counter stats for 'pipe':" then echo "stat record and report test [Failed]" @@ -30,7 +67,7 @@ test_stat_record_report() { test_stat_record_script() { echo "stat record and script test" - if ! perf stat record -o - true | perf script -i - 2>&1 | \ + if ! perf stat record -e task-clock -o - true | perf script -i - 2>&1 | \ grep -E -q "CPU[[:space:]]+THREAD[[:space:]]+VAL[[:space:]]+ENA[[:space:]]+RUN[[:space:]]+TIME[[:space:]]+EVENT" then echo "stat record and script test [Failed]" @@ -67,19 +104,54 @@ test_topdown_groups() { echo "Topdown event group test [Skipped event parsing failed]" return fi - if perf stat -e '{slots,topdown-retiring}' true 2>&1 | grep -E -q "<not supported>" - then - echo "Topdown event group test [Failed events not supported]" - err=1 - return - fi - if perf stat -e '{topdown-retiring,slots}' true 2>&1 | grep -E -q "<not supported>" + td_err=0 + do_topdown_group_test() { + events=$1 + failure=$2 + if perf stat -e "$events" true 2>&1 | grep -E -q "<not supported>" + then + echo "Topdown event group test [Failed $failure for '$events']" + td_err=1 + return + fi + } + do_topdown_group_test "{slots,topdown-retiring}" "events not supported" + do_topdown_group_test "{instructions,r400,r8000}" "raw format slots not reordered first" + filler_events=("instructions" "cycles" + "context-switches" "faults") + for ((i = 0; i < ${#filler_events[@]}; i+=2)) + do + filler1=${filler_events[i]} + filler2=${filler_events[i+1]} + do_topdown_group_test "$filler1,topdown-retiring,slots" \ + "slots not reordered first in no-group case" + do_topdown_group_test "slots,$filler1,topdown-retiring" \ + "topdown metrics event not reordered in no-group case" + do_topdown_group_test "{$filler1,topdown-retiring,slots}" \ + "slots not reordered first in single group case" + do_topdown_group_test "{$filler1,slots},topdown-retiring" \ + "topdown metrics event not move into slots group" + do_topdown_group_test "topdown-retiring,{$filler1,slots}" \ + "topdown metrics event not move into slots group last" + do_topdown_group_test "{$filler1,slots},{topdown-retiring}" \ + "topdown metrics group not merge into slots group" + do_topdown_group_test "{topdown-retiring},{$filler1,slots}" \ + "topdown metrics group not merge into slots group last" + do_topdown_group_test "{$filler1,slots},$filler2,topdown-retiring" \ + "non-adjacent topdown metrics group not move into slots group" + do_topdown_group_test "$filler2,topdown-retiring,{$filler1,slots}" \ + "non-adjacent topdown metrics group not move into slots group last" + do_topdown_group_test "{$filler1,slots},{$filler2,topdown-retiring}" \ + "metrics group not merge into slots group" + do_topdown_group_test "{$filler1,topdown-retiring},{$filler2,slots}" \ + "metrics group not merge into slots group last" + done + if test "$td_err" -eq 0 then - echo "Topdown event group test [Failed slots not reordered first]" - err=1 - return + echo "Topdown event group test [Success]" + else + err="$td_err" fi - echo "Topdown event group test [Success]" } test_topdown_weak_groups() { @@ -117,16 +189,18 @@ test_cputype() { # Find a known PMU for cputype. pmu="" - for i in cpu cpu_atom armv8_pmuv3_0 + devs="/sys/bus/event_source/devices" + for i in $devs/cpu $devs/cpu_atom $devs/armv8_pmuv3_0 $devs/armv8_cortex_* do - if test -d "/sys/devices/$i" + i_base=$(basename "$i") + if test -d "$i" then - pmu="$i" + pmu="$i_base" break fi - if perf stat -e "$i/instructions/" true > /dev/null 2>&1 + if perf stat -e "$i_base/instructions/" true > /dev/null 2>&1 then - pmu="$i" + pmu="$i_base" break fi done @@ -146,11 +220,42 @@ test_cputype() { echo "cputype test [Success]" } +test_hybrid() { + # Test the default stat command on hybrid devices opens one cycles event for + # each CPU type. + echo "hybrid test" + + # Count the number of core PMUs, assume minimum of 1 + pmus=$(ls /sys/bus/event_source/devices/*/cpus 2>/dev/null | wc -l) + if [ "$pmus" -lt 1 ] + then + pmus=1 + fi + + # Run default Perf stat + cycles_events=$(perf stat -a -- sleep 0.1 2>&1 | grep -E "/cpu-cycles/[uH]*| cpu-cycles[:uH]* " -c) + + # The expectation is that default output will have a cycles events on each + # hybrid PMU. In situations with no cycles PMU events, like virtualized, this + # can fall back to task-clock and so the end count may be 0. Fail if neither + # condition holds. + if [ "$pmus" -ne "$cycles_events" ] && [ "0" -ne "$cycles_events" ] + then + echo "hybrid test [Found $pmus PMUs but $cycles_events cycles events. Failed]" + err=1 + return + fi + echo "hybrid test [Success]" +} + test_default_stat +test_null_stat +test_offline_cpu_stat test_stat_record_report test_stat_record_script test_stat_repeat_weak_groups test_topdown_groups test_topdown_weak_groups test_cputype +test_hybrid exit $err diff --git a/tools/perf/tests/shell/stat_all_metricgroups.sh b/tools/perf/tests/shell/stat_all_metricgroups.sh index 55ef9c9ded2d..1400880ec01f 100755 --- a/tools/perf/tests/shell/stat_all_metricgroups.sh +++ b/tools/perf/tests/shell/stat_all_metricgroups.sh @@ -1,9 +1,7 @@ -#!/bin/sh +#!/bin/bash # perf all metricgroups test # SPDX-License-Identifier: GPL-2.0 -set -e - ParanoidAndNotRoot() { [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] @@ -14,11 +12,40 @@ if ParanoidAndNotRoot 0 then system_wide_flag="" fi - +err=0 for m in $(perf list --raw-dump metricgroups) do echo "Testing $m" - perf stat -M "$m" $system_wide_flag sleep 0.01 + result=$(perf stat -M "$m" $system_wide_flag sleep 0.01 2>&1) + result_err=$? + if [[ $result_err -gt 0 ]] + then + if [[ "$result" =~ \ + "Access to performance monitoring and observability operations is limited" ]] + then + echo "Permission failure" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] + then + echo "Permissions - need system wide mode" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + elif [[ "$m" == @(Default2|Default3|Default4) ]] + then + echo "Ignoring failures in $m that may contain unsupported legacy events" + else + echo "Metric group $m failed" + echo $result + err=1 # Fail + fi + fi done -exit 0 +exit $err diff --git a/tools/perf/tests/shell/stat_all_metrics.sh b/tools/perf/tests/shell/stat_all_metrics.sh index 54774525e18a..3dabb39c7cc8 100755 --- a/tools/perf/tests/shell/stat_all_metrics.sh +++ b/tools/perf/tests/shell/stat_all_metrics.sh @@ -2,42 +2,115 @@ # perf all metrics test # SPDX-License-Identifier: GPL-2.0 +ParanoidAndNotRoot() +{ + [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] +} + +test_prog="sleep 0.01" +system_wide_flag="-a" +if ParanoidAndNotRoot 0 +then + system_wide_flag="" + test_prog="perf test -w noploop" +fi + err=0 for m in $(perf list --raw-dump metrics); do echo "Testing $m" - result=$(perf stat -M "$m" true 2>&1) - if [[ "$result" =~ ${m:0:50} ]] || [[ "$result" =~ "<not supported>" ]] + result=$(perf stat -M "$m" $system_wide_flag -- $test_prog 2>&1) + result_err=$? + if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] then + # No error result and metric shown. continue fi - # Failed so try system wide. - result=$(perf stat -M "$m" -a sleep 0.01 2>&1) - if [[ "$result" =~ ${m:0:50} ]] + if [[ "$result" =~ "Cannot resolve IDs for" || "$result" =~ "No supported events found" ]] then + if [[ $(perf list --raw-dump $m) == "Default"* ]] + then + echo "[Ignored $m] failed but as a Default metric this can be expected" + echo $result + continue + fi + echo "[Failed $m] Metric contains missing events" + echo $result + err=1 # Fail continue - fi - # Failed again, possibly the workload was too small so retry with something - # longer. - result=$(perf stat -M "$m" perf bench internals synthesize 2>&1) - if [[ "$result" =~ ${m:0:50} ]] + elif [[ "$result" =~ \ + "Access to performance monitoring and observability operations is limited" ]] then + echo "[Skipped $m] Permission failure" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi continue - fi - echo "Metric '$m' not printed in:" - echo "$result" - if [[ "$err" != "1" ]] + elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] + then + echo "[Skipped $m] Permissions - need system wide mode" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "<not supported>" ]] + then + if [[ $(perf list --raw-dump $m) == "Default"* ]] + then + echo "[Ignored $m] failed but as a Default metric this can be expected" + echo $result + continue + fi + echo "[Skipped $m] Not supported events" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "<not counted>" ]] + then + echo "[Skipped $m] Not counted events" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] then - err=2 - if [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] + echo "[Skipped $m] FP issues" + echo $result + if [[ $err -eq 0 ]] then - echo "Skip, not fail, for FP issues" - elif [[ "$result" =~ "PMM" ]] + err=2 # Skip + fi + continue + elif [[ "$result" =~ "PMM" ]] + then + echo "[Skipped $m] Optane memory issues" + echo $result + if [[ $err -eq 0 ]] then - echo "Skip, not fail, for Optane memory issues" - else - err=1 + err=2 # Skip fi + continue + fi + + # Failed, possibly the workload was too small so retry with something longer. + result=$(perf stat -M "$m" $system_wide_flag -- perf bench internals synthesize 2>&1) + result_err=$? + if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] + then + # No error result and metric shown. + continue fi + echo "[Failed $m] has non-zero error '$result_err' or not printed in:" + echo "$result" + err=1 done exit "$err" diff --git a/tools/perf/tests/shell/stat_all_pfm.sh b/tools/perf/tests/shell/stat_all_pfm.sh index 4d004f777a6e..c08c186af2c4 100755 --- a/tools/perf/tests/shell/stat_all_pfm.sh +++ b/tools/perf/tests/shell/stat_all_pfm.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf all libpfm4 events test # SPDX-License-Identifier: GPL-2.0 diff --git a/tools/perf/tests/shell/stat_all_pmu.sh b/tools/perf/tests/shell/stat_all_pmu.sh index d2a3506e0d19..9c466c0efa85 100755 --- a/tools/perf/tests/shell/stat_all_pmu.sh +++ b/tools/perf/tests/shell/stat_all_pmu.sh @@ -1,23 +1,71 @@ -#!/bin/sh -# perf all PMU test +#!/bin/bash +# perf all PMU test (exclusive) # SPDX-License-Identifier: GPL-2.0 -set -e +err=0 +result="" + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + echo "$result" + exit 1 +} +trap trap_cleanup EXIT TERM INT # Test all PMU events; however exclude parameterized ones (name contains '?') -for p in $(perf list --raw-dump pmu | sed 's/[[:graph:]]\+?[[:graph:]]\+[[:space:]]//g'); do - echo "Testing $p" - result=$(perf stat -e "$p" true 2>&1) - if ! echo "$result" | grep -q "$p" && ! echo "$result" | grep -q "<not supported>" ; then - # We failed to see the event and it is supported. Possibly the workload was - # too small so retry with something longer. - result=$(perf stat -e "$p" perf bench internals synthesize 2>&1) - if ! echo "$result" | grep -q "$p" ; then - echo "Event '$p' not printed in:" - echo "$result" - exit 1 +for p in $(perf list --raw-dump pmu | sed 's/[[:graph:]]\+?[[:graph:]]\+[[:space:]]//g') +do + echo -n "Testing $p -- " + output=$(perf stat -e "$p" true 2>&1) + stat_result=$? + if echo "$output" | grep -q "$p" + then + # Event seen in output. + if [ $stat_result -eq 0 ] && ! echo "$output" | grep -q "<not supported>" + then + # Event supported. + echo "supported" + continue + elif echo "$output" | grep -q "<not supported>" + then + # Event not supported, so ignore. + echo "not supported" + continue + elif echo "$output" | grep -q "No permission to enable" + then + # No permissions, so ignore. + echo "no permission to enable" + continue + elif echo "$output" | grep -q "Bad event name" + then + # Non-existent event. + echo "Error: Bad event name" + echo "$output" + err=1 + continue fi fi + + if echo "$output" | grep -q "Access to performance monitoring and observability operations is limited." + then + # Access is limited, so ignore. + echo "access limited" + continue + fi + + # We failed to see the event and it is supported. Possibly the workload was + # too small so retry with something longer. + output=$(perf stat -e "$p" perf bench internals synthesize 2>&1) + if echo "$output" | grep -q "$p" + then + # Event seen in output. + echo "supported" + continue + fi + echo "Error: event '$p' not printed in:" + echo "$output" + err=1 done -exit 0 +trap - EXIT TERM INT +exit $err diff --git a/tools/perf/tests/shell/stat_bpf_counters.sh b/tools/perf/tests/shell/stat_bpf_counters.sh index f250b7d6f773..f43e28a136d3 100755 --- a/tools/perf/tests/shell/stat_bpf_counters.sh +++ b/tools/perf/tests/shell/stat_bpf_counters.sh @@ -1,10 +1,10 @@ -#!/bin/sh -# perf stat --bpf-counters test +#!/bin/bash +# perf stat --bpf-counters test (exclusive) # SPDX-License-Identifier: GPL-2.0 set -e -workload="perf test -w brstack" +workload="perf test -w sqrtloop" # check whether $2 is within +/- 20% of $1 compare_number() diff --git a/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh b/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh index e75d0780dc78..ff2e06c408bc 100755 --- a/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh +++ b/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf stat --bpf-counters --for-each-cgroup test # SPDX-License-Identifier: GPL-2.0 @@ -58,22 +58,9 @@ check_system_wide_counted() fi } -check_cpu_list_counted() -{ - check_cpu_list_counted_output=$(perf stat -C 0,1 --bpf-counters --for-each-cgroup ${test_cgroups} -e cpu-clock -x, taskset -c 1 sleep 1 2>&1) - if echo ${check_cpu_list_counted_output} | grep -q -F "<not "; then - echo "Some CPU events are not counted" - if [ "${verbose}" = "1" ]; then - echo ${check_cpu_list_counted_output} - fi - exit 1 - fi -} - check_bpf_counter find_cgroups check_system_wide_counted -check_cpu_list_counted exit 0 diff --git a/tools/perf/tests/shell/stat_metrics_values.sh b/tools/perf/tests/shell/stat_metrics_values.sh index 279f19c5919a..30566f0b5427 100755 --- a/tools/perf/tests/shell/stat_metrics_values.sh +++ b/tools/perf/tests/shell/stat_metrics_values.sh @@ -16,11 +16,16 @@ workload="perf bench futex hash -r 2 -s" # Add -debug, save data file and full rule file echo "Launch python validation script $pythonvalidator" echo "Output will be stored in: $tmpdir" -$PYTHON $pythonvalidator -rule $rulefile -output_dir $tmpdir -wl "${workload}" -ret=$? -rm -rf $tmpdir -if [ $ret -ne 0 ]; then - echo "Metric validation return with erros. Please check metrics reported with errors." -fi +for cputype in /sys/bus/event_source/devices/cpu_*; do + cputype=$(basename "$cputype") + echo "Testing metrics for: $cputype" + $PYTHON $pythonvalidator -rule $rulefile -output_dir $tmpdir -wl "${workload}" \ + -cputype "${cputype}" + ret=$? + rm -rf $tmpdir + if [ $ret -ne 0 ]; then + echo "Metric validation return with errors. Please check metrics reported with errors." + fi +done exit $ret diff --git a/tools/perf/tests/shell/test_arm_callgraph_fp.sh b/tools/perf/tests/shell/test_arm_callgraph_fp.sh index 9caa36130175..9172dd68a81d 100755 --- a/tools/perf/tests/shell/test_arm_callgraph_fp.sh +++ b/tools/perf/tests/shell/test_arm_callgraph_fp.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Check Arm64 callgraphs are complete in fp mode # SPDX-License-Identifier: GPL-2.0 diff --git a/tools/perf/tests/shell/test_arm_coresight.sh b/tools/perf/tests/shell/test_arm_coresight.sh index 3302ea0b9672..1c750b67d141 100755 --- a/tools/perf/tests/shell/test_arm_coresight.sh +++ b/tools/perf/tests/shell/test_arm_coresight.sh @@ -1,5 +1,5 @@ -#!/bin/sh -# Check Arm CoreSight trace data recording and synthesized samples +#!/bin/bash +# Check Arm CoreSight trace data recording and synthesized samples (exclusive) # Uses the 'perf record' to record trace data with Arm CoreSight sinks; # then verify if there have any branch samples and instruction samples @@ -12,7 +12,7 @@ glb_err=0 skip_if_no_cs_etm_event() { - perf list | grep -q 'cs_etm//' && return 0 + perf list pmu | grep -q 'cs_etm//' && return 0 # cs_etm event doesn't exist return 2 diff --git a/tools/perf/tests/shell/test_arm_coresight_disasm.sh b/tools/perf/tests/shell/test_arm_coresight_disasm.sh new file mode 100755 index 000000000000..0dfb4fadf531 --- /dev/null +++ b/tools/perf/tests/shell/test_arm_coresight_disasm.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# Check Arm CoreSight disassembly script completes without errors (exclusive) +# SPDX-License-Identifier: GPL-2.0 + +# The disassembly script reconstructs ranges of instructions and gives these to objdump to +# decode. objdump doesn't like ranges that go backwards, but these are a good indication +# that decoding has gone wrong either in OpenCSD, Perf or in the range reconstruction in +# the script. Test all 3 parts are working correctly by running the script. + +skip_if_no_cs_etm_event() { + perf list pmu | grep -q 'cs_etm//' && return 0 + + # cs_etm event doesn't exist + return 2 +} + +skip_if_no_cs_etm_event || exit 2 + +# Assume an error unless we reach the very end +set -e +glb_err=1 + +perfdata_dir=$(mktemp -d /tmp/__perf_test.perf.data.XXXXX) +perfdata=${perfdata_dir}/perf.data +file=$(mktemp /tmp/temporary_file.XXXXX) +# Relative path works whether it's installed or running from repo +script_path=$(dirname "$0")/../../scripts/python/arm-cs-trace-disasm.py + +cleanup_files() +{ + set +e + rm -rf ${perfdata_dir} + rm -f ${file} + trap - EXIT TERM INT + exit $glb_err +} + +trap cleanup_files EXIT TERM INT + +# Ranges start and end on branches, so check for some likely branch instructions +sep="\s\|\s" +branch_search="\sbl${sep}b${sep}b.ne${sep}b.eq${sep}cbz\s" + +## Test kernel ## +if [ -e /proc/kcore ]; then + echo "Testing kernel disassembly" + perf record -o ${perfdata} -e cs_etm//k --kcore -- touch $file > /dev/null 2>&1 + perf script -i ${perfdata} -s python:${script_path} -- \ + -d --stop-sample=30 2> /dev/null > ${file} + grep -q -e ${branch_search} ${file} + echo "Found kernel branches" +else + # kcore is required for correct kernel decode due to runtime code patching + echo "No kcore, skipping kernel test" +fi + +## Test user ## +echo "Testing userspace disassembly" +perf record -o ${perfdata} -e cs_etm//u -- touch $file > /dev/null 2>&1 +perf script -i ${perfdata} -s python:${script_path} -- \ + -d --stop-sample=30 2> /dev/null > ${file} +grep -q -e ${branch_search} ${file} +echo "Found userspace branches" + +glb_err=0 diff --git a/tools/perf/tests/shell/test_arm_spe.sh b/tools/perf/tests/shell/test_arm_spe.sh index 03d5c7d12ee5..bb76ea88aa14 100755 --- a/tools/perf/tests/shell/test_arm_spe.sh +++ b/tools/perf/tests/shell/test_arm_spe.sh @@ -1,5 +1,5 @@ -#!/bin/sh -# Check Arm SPE trace data recording and synthesized samples +#!/bin/bash +# Check Arm SPE trace data recording and synthesized samples (exclusive) # Uses the 'perf record' to record trace data of Arm SPE events; # then verify if any SPE event samples are generated by SPE with @@ -9,7 +9,7 @@ # German Gomez <german.gomez@arm.com>, 2021 skip_if_no_arm_spe_event() { - perf list | grep -E -q 'arm_spe_[0-9]+//' && return 0 + perf list pmu | grep -E -q 'arm_spe_[0-9]+//' && return 0 # arm_spe event doesn't exist return 2 @@ -107,7 +107,37 @@ arm_spe_system_wide_test() { arm_spe_report "SPE system-wide testing" $err } +arm_spe_discard_test() { + echo "SPE discard mode" + + for f in /sys/bus/event_source/devices/arm_spe_*; do + if [ -e "$f/format/discard" ]; then + cpu=$(cut -c -1 "$f/cpumask") + break + fi + done + + if [ -z $cpu ]; then + arm_spe_report "SPE discard mode not present" 2 + return + fi + + # Test can use wildcard SPE instance and Perf will only open the event + # on instances that have that format flag. But make sure the target + # runs on an instance with discard mode otherwise we're not testing + # anything. + perf record -o ${perfdata} -e arm_spe/discard/ -N -B --no-bpf-event \ + -- taskset --cpu-list $cpu true + + if perf report -i ${perfdata} --stats | grep 'AUX events\|AUXTRACE events'; then + arm_spe_report "SPE discard mode found unexpected data" 1 + else + arm_spe_report "SPE discard mode" 0 + fi +} + arm_spe_snapshot_test arm_spe_system_wide_test +arm_spe_discard_test exit $glb_err diff --git a/tools/perf/tests/shell/test_arm_spe_fork.sh b/tools/perf/tests/shell/test_arm_spe_fork.sh index 1a7e6a82d0e3..5bcca51c03ac 100755 --- a/tools/perf/tests/shell/test_arm_spe_fork.sh +++ b/tools/perf/tests/shell/test_arm_spe_fork.sh @@ -1,11 +1,11 @@ -#!/bin/sh +#!/bin/bash # Check Arm SPE doesn't hang when there are forks # SPDX-License-Identifier: GPL-2.0 # German Gomez <german.gomez@arm.com>, 2022 skip_if_no_arm_spe_event() { - perf list | grep -E -q 'arm_spe_[0-9]+//' && return 0 + perf list pmu | grep -E -q 'arm_spe_[0-9]+//' && return 0 return 2 } diff --git a/tools/perf/tests/shell/test_bpf_metadata.sh b/tools/perf/tests/shell/test_bpf_metadata.sh new file mode 100755 index 000000000000..be67d56e0f09 --- /dev/null +++ b/tools/perf/tests/shell/test_bpf_metadata.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# BPF metadata collection test +# +# SPDX-License-Identifier: GPL-2.0 + +set -e + +err=0 +perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) + +cleanup() { + rm -f "${perfdata}" + rm -f "${perfdata}".old + trap - EXIT TERM INT +} + +trap_cleanup() { + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +test_bpf_metadata() { + echo "Checking BPF metadata collection" + + if ! perf check -q feature libbpf-strings ; then + echo "Basic BPF metadata test [skipping - not supported]" + err=0 + return + fi + + # This is a basic invocation of perf record + # that invokes the perf_sample_filter BPF program. + if ! perf record -e task-clock --filter 'ip > 0' \ + -o "${perfdata}" sleep 1 2> /dev/null + then + echo "Basic BPF metadata test [Failed record]" + err=1 + return + fi + + # The BPF programs that ship with "perf" all have the following + # variable defined at compile time: + # + # const char bpf_metadata_perf_version[] SEC(".rodata") = <...>; + # + # This invocation looks for a PERF_RECORD_BPF_METADATA event, + # and checks that its content contains the string given by + # "perf version". + VERS=$(perf version | awk '{print $NF}') + if ! perf script --show-bpf-events -i "${perfdata}" | awk ' + /PERF_RECORD_BPF_METADATA.*perf_sample_filter/ { + header = 1; + } + /^ *entry/ { + if (header) { header = 0; entry = 1; } + } + $0 !~ /^ *entry/ { + entry = 0; + } + /perf_version/ { + if (entry) print $NF; + } + ' | grep -qF "$VERS" + then + echo "Basic BPF metadata test [Failed invalid output]" + err=1 + return + fi + echo "Basic BPF metadata test [Success]" +} + +test_bpf_metadata + +cleanup +exit $err diff --git a/tools/perf/tests/shell/test_brstack.sh b/tools/perf/tests/shell/test_brstack.sh index 5f14d0cb013f..85233d435be6 100755 --- a/tools/perf/tests/shell/test_brstack.sh +++ b/tools/perf/tests/shell/test_brstack.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Check branch stack sampling # SPDX-License-Identifier: GPL-2.0 @@ -17,37 +17,116 @@ fi skip_test_missing_symbol brstack_bench +err=0 TMPDIR=$(mktemp -d /tmp/__perf_test.program.XXXXX) TESTPROG="perf test -w brstack" cleanup() { rm -rf $TMPDIR + trap - EXIT TERM INT } -trap cleanup EXIT TERM INT +trap_cleanup() { + set +e + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +is_arm64() { + [ "$(uname -m)" = "aarch64" ]; +} + +check_branches() { + if ! tr -s ' ' '\n' < "$TMPDIR/perf.script" | grep -E -m1 -q "$1"; then + echo "Branches missing $1" + err=1 + fi +} test_user_branches() { echo "Testing user branch stack sampling" - perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u -- ${TESTPROG} > /dev/null 2>&1 - perf script -i $TMPDIR/perf.data --fields brstacksym | xargs -n1 > $TMPDIR/perf.script + perf record -o "$TMPDIR/perf.data" --branch-filter any,save_type,u -- ${TESTPROG} > "$TMPDIR/record.txt" 2>&1 + perf script -i "$TMPDIR/perf.data" --fields brstacksym > "$TMPDIR/perf.script" # example of branch entries: # brstack_foo+0x14/brstack_bar+0x40/P/-/-/0/CALL - set -x - grep -E -m1 "^brstack_bench\+[^ ]*/brstack_foo\+[^ ]*/IND_CALL/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack_foo\+[^ ]*/brstack_bar\+[^ ]*/CALL/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack_bench\+[^ ]*/brstack_foo\+[^ ]*/CALL/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack_bench\+[^ ]*/brstack_bar\+[^ ]*/CALL/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack_bar\+[^ ]*/brstack_foo\+[^ ]*/RET/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack_foo\+[^ ]*/brstack_bench\+[^ ]*/RET/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack_bench\+[^ ]*/brstack_bench\+[^ ]*/COND/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack\+[^ ]*/brstack\+[^ ]*/UNCOND/.*$" $TMPDIR/perf.script - set +x - + expected=( + "^brstack_bench\+[^ ]*/brstack_foo\+[^ ]*/IND_CALL/.*$" + "^brstack_foo\+[^ ]*/brstack_bar\+[^ ]*/CALL/.*$" + "^brstack_bench\+[^ ]*/brstack_foo\+[^ ]*/CALL/.*$" + "^brstack_bench\+[^ ]*/brstack_bar\+[^ ]*/CALL/.*$" + "^brstack_bar\+[^ ]*/brstack_foo\+[^ ]*/RET/.*$" + "^brstack_foo\+[^ ]*/brstack_bench\+[^ ]*/RET/.*$" + "^brstack_bench\+[^ ]*/brstack_bench\+[^ ]*/COND/.*$" + "^brstack\+[^ ]*/brstack\+[^ ]*/UNCOND/.*$" + ) + for x in "${expected[@]}" + do + check_branches "$x" + done + + # Dump addresses only this time + perf script -i "$TMPDIR/perf.data" --fields brstack | \ + tr ' ' '\n' > "$TMPDIR/perf.script" + + # There should be no kernel addresses with the u option, in either + # source or target addresses. + if grep -E -m1 "0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then + echo "ERROR: Kernel address found in user mode" + err=1 + fi # some branch types are still not being tested: - # IND COND_CALL COND_RET SYSCALL SYSRET IRQ SERROR NO_TX + # IND COND_CALL COND_RET SYSRET SERROR NO_TX +} + +test_trap_eret_branches() { + echo "Testing trap & eret branches" + if ! is_arm64; then + echo "skip: not arm64" + else + perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u,k -- \ + perf test -w traploop 1000 + perf script -i $TMPDIR/perf.data --fields brstacksym | \ + tr ' ' '\n' > $TMPDIR/perf.script + + # BRBINF<n>.TYPE == TRAP are mapped to PERF_BR_IRQ by the BRBE driver + check_branches "^trap_bench\+[^ ]+/[^ ]/IRQ/" + check_branches "^[^ ]+/trap_bench\+[^ ]+/ERET/" + fi +} + +test_kernel_branches() { + echo "Testing that k option only includes kernel source addresses" + + if ! perf record --branch-filter any,k -o- -- true > /dev/null; then + echo "skip: not enough privileges" + else + perf record -o $TMPDIR/perf.data --branch-filter any,k -- \ + perf bench syscall basic --loop 1000 + perf script -i $TMPDIR/perf.data --fields brstack | \ + tr ' ' '\n' > $TMPDIR/perf.script + + # Example of branch entries: + # "0xffffffff93bda241/0xffffffff93bda20f/M/-/-/..." + # Source addresses come first and target address can be either + # userspace or kernel even with k option, as long as the source + # is in kernel. + + #Look for source addresses with top bit set + if ! grep -E -m1 "^0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then + echo "ERROR: Kernel branches missing" + err=1 + fi + # Look for no source addresses without top bit set + if grep -E -m1 "^0x[0-7][0-9a-f]{0,15}" $TMPDIR/perf.script; then + echo "ERROR: User branches found with kernel filter" + err=1 + fi + fi } # first argument <arg0> is the argument passed to "--branch-stack <arg0>,save_type,u" @@ -57,26 +136,67 @@ test_filter() { test_filter_expect=$2 echo "Testing branch stack filtering permutation ($test_filter_filter,$test_filter_expect)" - - perf record -o $TMPDIR/perf.data --branch-filter $test_filter_filter,save_type,u -- ${TESTPROG} > /dev/null 2>&1 - perf script -i $TMPDIR/perf.data --fields brstack | xargs -n1 > $TMPDIR/perf.script + perf record -o "$TMPDIR/perf.data" --branch-filter "$test_filter_filter,save_type,u" -- ${TESTPROG} > "$TMPDIR/record.txt" 2>&1 + perf script -i "$TMPDIR/perf.data" --fields brstack > "$TMPDIR/perf.script" # fail if we find any branch type that doesn't match any of the expected ones # also consider UNKNOWN branch types (-) - if grep -E -vm1 "^[^ ]*/($test_filter_expect|-|( *))/.*$" $TMPDIR/perf.script; then - return 1 + if [ ! -s "$TMPDIR/perf.script" ] + then + echo "Empty script output" + err=1 + return + fi + # Look for lines not matching test_filter_expect ignoring issues caused + # by empty output + tr -s ' ' '\n' < "$TMPDIR/perf.script" | grep '.' | \ + grep -E -vm1 "^[^ ]*/($test_filter_expect|-|( *))/.*$" \ + > "$TMPDIR/perf.script-filtered" || true + if [ -s "$TMPDIR/perf.script-filtered" ] + then + echo "Unexpected branch filter in script output" + cat "$TMPDIR/perf.script" + err=1 + return fi } +test_syscall() { + echo "Testing syscalls" + # skip if perf doesn't have enough privileges + if ! perf record --branch-filter any,k -o- -- true > /dev/null; then + echo "skip: not enough privileges" + else + perf record -o $TMPDIR/perf.data --branch-filter \ + any_call,save_type,u,k -c 10000 -- \ + perf bench syscall basic --loop 1000 + perf script -i $TMPDIR/perf.data --fields brstacksym | \ + tr ' ' '\n' > $TMPDIR/perf.script + + check_branches "getppid[^ ]*/SYSCALL/" + fi +} set -e test_user_branches +test_syscall +test_kernel_branches +test_trap_eret_branches + +any_call="CALL|IND_CALL|COND_CALL|SYSCALL|IRQ" -test_filter "any_call" "CALL|IND_CALL|COND_CALL|SYSCALL|IRQ" +if is_arm64; then + any_call="$any_call|FAULT_DATA|FAULT_INST" +fi + +test_filter "any_call" "$any_call" test_filter "call" "CALL|SYSCALL" test_filter "cond" "COND" test_filter "any_ret" "RET|COND_RET|SYSRET|ERET" test_filter "call,cond" "CALL|SYSCALL|COND" -test_filter "any_call,cond" "CALL|IND_CALL|COND_CALL|IRQ|SYSCALL|COND" -test_filter "cond,any_call,any_ret" "COND|CALL|IND_CALL|COND_CALL|SYSCALL|IRQ|RET|COND_RET|SYSRET|ERET" +test_filter "any_call,cond" "$any_call|COND" +test_filter "any_call,cond,any_ret" "$any_call|COND|RET|COND_RET" + +cleanup +exit $err diff --git a/tools/perf/tests/shell/test_data_symbol.sh b/tools/perf/tests/shell/test_data_symbol.sh index 3dfa91832aa8..d61b5659a46d 100755 --- a/tools/perf/tests/shell/test_data_symbol.sh +++ b/tools/perf/tests/shell/test_data_symbol.sh @@ -1,12 +1,10 @@ #!/bin/bash -# Test data symbol +# Test data symbol (exclusive) # SPDX-License-Identifier: GPL-2.0 # Leo Yan <leo.yan@linaro.org>, 2022 shelldir=$(dirname "$0") -# shellcheck source=lib/waiting.sh -. "${shelldir}"/lib/waiting.sh # shellcheck source=lib/perf_has_symbol.sh . "${shelldir}"/lib/perf_has_symbol.sh @@ -18,7 +16,7 @@ skip_if_no_mem_event() { skip_if_no_mem_event || exit 2 -skip_test_missing_symbol buf1 +skip_test_missing_symbol workload_datasym_buf1 TEST_PROGRAM="perf test -w datasym" PERF_DATA=$(mktemp /tmp/__perf_test.perf.data.XXXXX) @@ -26,18 +24,19 @@ ERR_FILE=$(mktemp /tmp/__perf_test.stderr.XXXXX) check_result() { # The memory report format is as below: - # 99.92% ... [.] buf1+0x38 + # 99.92% ... [.] workload_datasym_buf1+0x38 result=$(perf mem report -i ${PERF_DATA} -s symbol_daddr -q 2>&1 | - awk '/buf1/ { print $4 }') + awk '/workload_datasym_buf1/ { print $4 }') - # Testing is failed if has no any sample for "buf1" + # Testing is failed if has no any sample for "workload_datasym_buf1" [ -z "$result" ] && return 1 while IFS= read -r line; do - # The "data1" and "data2" fields in structure "buf1" have - # offset "0x0" and "0x38", returns failure if detect any - # other offset value. - if [ "$line" != "buf1+0x0" ] && [ "$line" != "buf1+0x38" ]; then + # The "data1" and "data2" fields in structure + # "workload_datasym_buf1" have offset "0x0" and "0x38", returns + # failure if detect any other offset value. + if [ "$line" != "workload_datasym_buf1+0x0" ] && \ + [ "$line" != "workload_datasym_buf1+0x38" ]; then return 1 fi done <<< "$result" @@ -55,24 +54,38 @@ trap cleanup_files exit term int echo "Recording workload..." -# perf mem/c2c internally uses IBS PMU on AMD CPU which doesn't support -# user/kernel filtering and per-process monitoring, spin program on -# specific CPU and test in per-CPU mode. is_amd=$(grep -E -c 'vendor_id.*AuthenticAMD' /proc/cpuinfo) if (($is_amd >= 1)); then - perf mem record -vvv -o ${PERF_DATA} -C 0 -- taskset -c 0 $TEST_PROGRAM 2>"${ERR_FILE}" & -else - perf mem record -vvv --all-user -o ${PERF_DATA} -- $TEST_PROGRAM 2>"${ERR_FILE}" & -fi - -PERFPID=$! - -wait_for_perf_to_start ${PERFPID} "${ERR_FILE}" + mem_events="$(perf mem record -v -e list 2>&1)" + if ! [[ "$mem_events" =~ ^mem\-ldst.*ibs_op/(.*)/.*available ]]; then + echo "ERROR: mem-ldst event is not matching" + exit 1 + fi + + # --ldlat on AMD: + # o Zen4 and earlier uarch does not support ldlat + # o Even on supported platforms, it's disabled (--ldlat=0) by default. + ldlat=${BASH_REMATCH[1]} + if [[ -n $ldlat ]]; then + if ! [[ "$ldlat" =~ ldlat=0 ]]; then + echo "ERROR: ldlat not initialized to 0?" + exit 1 + fi -sleep 1 + mem_events="$(perf mem record -v --ldlat=150 -e list 2>&1)" + if ! [[ "$mem_events" =~ ^mem-ldst.*ibs_op/ldlat=150/.*available ]]; then + echo "ERROR: --ldlat not honored?" + exit 1 + fi + fi -kill $PERFPID -wait $PERFPID + # perf mem/c2c internally uses IBS PMU on AMD CPU which doesn't + # support user/kernel filtering and per-process monitoring on older + # kernels, spin program on specific CPU and test in per-CPU mode. + perf mem record -vvv -o ${PERF_DATA} -C 0 -- taskset -c 0 $TEST_PROGRAM 2>"${ERR_FILE}" +else + perf mem record -vvv --all-user -o ${PERF_DATA} -- $TEST_PROGRAM 2>"${ERR_FILE}" +fi check_result exit $? diff --git a/tools/perf/tests/shell/test_event_open_fallback.sh b/tools/perf/tests/shell/test_event_open_fallback.sh new file mode 100755 index 000000000000..9420a7557c13 --- /dev/null +++ b/tools/perf/tests/shell/test_event_open_fallback.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# Perf event open fallback test +# SPDX-License-Identifier: GPL-2.0 + +skip_cnt=0 +ok_cnt=0 +err_cnt=0 + +perf_record() +{ + perf record -o /dev/null "$@" -- true 1>/dev/null 2>&1 +} + +test_decrease_precise_ip() +{ + echo "Decrease precise ip test" + + perf list pmu | grep -q 'cycles' || return 2 + + if ! perf_record -e cycles; then + return 2 + fi + + # It should reduce precision level down to 0 if needed. + if ! perf_record -e cycles:P; then + return 1 + fi + return 0 +} + +test_decrease_precise_ip_complicated() +{ + echo "Decrease precise ip test (complicated case)" + + perf list pmu | grep -q 'mem-loads-aux' || return 2 + + if ! perf_record -e '{mem-loads-aux:S,mem-loads:PS}'; then + return 1 + fi + return 0 +} + +count_result() +{ + if [ "$1" -eq 2 ] ; then + skip_cnt=$((skip_cnt + 1)) + return + fi + if [ "$1" -eq 0 ] ; then + ok_cnt=$((ok_cnt + 1)) + return + fi + err_cnt=$((err_cnt + 1)) +} + +ret=0 +test_decrease_precise_ip || ret=$? ; count_result $ret ; ret=0 +test_decrease_precise_ip_complicated || ret=$? ; count_result $ret ; ret=0 + +cleanup + +if [ ${err_cnt} -gt 0 ] ; then + exit 1 +fi + +if [ ${ok_cnt} -gt 0 ] ; then + exit 0 +fi + +# Skip +exit 2 diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh index 723ec501f99a..8ee761f03c38 100755 --- a/tools/perf/tests/shell/test_intel_pt.sh +++ b/tools/perf/tests/shell/test_intel_pt.sh @@ -1,11 +1,11 @@ -#!/bin/sh -# Miscellaneous Intel PT testing +#!/bin/bash +# Miscellaneous Intel PT testing (exclusive) # SPDX-License-Identifier: GPL-2.0 set -e # Skip if no Intel PT -perf list | grep -q 'intel_pt//' || exit 2 +perf list pmu | grep -q 'intel_pt//' || exit 2 shelldir=$(dirname "$0") # shellcheck source=lib/waiting.sh @@ -288,6 +288,11 @@ test_jitdump() jitdump_incl_dir="${script_dir}/../../util" jitdump_h="${jitdump_incl_dir}/jitdump.h" + if ! perf check feature -q libelf ; then + echo "SKIP: libelf is needed for jitdump" + return 2 + fi + if [ ! -e "${jitdump_h}" ] ; then echo "SKIP: Include file jitdump.h not found" return 2 @@ -644,6 +649,33 @@ test_pipe() return 0 } +test_pause_resume() +{ + echo "--- Test with pause / resume ---" + if ! perf_record_no_decode -o "${perfdatafile}" -e intel_pt/aux-action=start-paused/u uname ; then + echo "SKIP: pause / resume is not supported" + return 2 + fi + if ! perf_record_no_bpf -o "${perfdatafile}" \ + -e intel_pt/aux-action=start-paused/u \ + -e instructions/period=50000,aux-action=resume,name=Resume/u \ + -e instructions/period=100000,aux-action=pause,name=Pause/u uname ; then + echo "perf record with pause / resume failed" + return 1 + fi + if ! perf script -i "${perfdatafile}" --itrace=b -Fperiod,event | \ + awk 'BEGIN {paused=1;branches=0} + /Resume/ {paused=0} + /branches/ {if (paused) exit 1;branches=1} + /Pause/ {paused=1} + END {if (!branches) exit 1}' ; then + echo "perf record with pause / resume failed" + return 1 + fi + echo OK + return 0 +} + count_result() { if [ "$1" -eq 2 ] ; then @@ -672,6 +704,7 @@ test_power_event || ret=$? ; count_result $ret ; ret=0 test_no_tnt || ret=$? ; count_result $ret ; ret=0 test_event_trace || ret=$? ; count_result $ret ; ret=0 test_pipe || ret=$? ; count_result $ret ; ret=0 +test_pause_resume || ret=$? ; count_result $ret ; ret=0 cleanup diff --git a/tools/perf/tests/shell/test_stat_intel_tpebs.sh b/tools/perf/tests/shell/test_stat_intel_tpebs.sh index c60b29add980..a330ecdb7ba5 100755 --- a/tools/perf/tests/shell/test_stat_intel_tpebs.sh +++ b/tools/perf/tests/shell/test_stat_intel_tpebs.sh @@ -1,19 +1,85 @@ #!/bin/bash -# test Intel TPEBS counting mode +# test Intel TPEBS counting mode (exclusive) # SPDX-License-Identifier: GPL-2.0 set -e -grep -q GenuineIntel /proc/cpuinfo || { echo Skipping non-Intel; exit 2; } -# Use this event for testing because it should exist in all platforms -event=cache-misses:R +ParanoidAndNotRoot() { + [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] +} -# Without this cmd option, default value or zero is returned -echo "Testing without --record-tpebs" -result=$(perf stat -e "$event" true 2>&1) -[[ "$result" =~ $event ]] || exit 1 +if ! grep -q GenuineIntel /proc/cpuinfo +then + echo "Skipping non-Intel" + exit 2 +fi -# In platforms that do not support TPEBS, it should execute without error. -echo "Testing with --record-tpebs" -result=$(perf stat -e "$event" --record-tpebs -a sleep 0.01 2>&1) -[[ "$result" =~ "perf record" && "$result" =~ $event ]] || exit 1 +if ParanoidAndNotRoot 0 +then + echo "Skipping paranoid >0 and not root" + exit 2 +fi + +stat_output=$(mktemp /tmp/__perf_stat_tpebs_output.XXXXX) + +cleanup() { + rm -rf "${stat_output}" + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cat "${stat_output}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +# Event to be used in tests +event=cache-misses + +if ! perf record -e "${event}:p" -a -o /dev/null sleep 0.01 > "${stat_output}" 2>&1 +then + echo "Missing ${event} support" + cleanup + exit 2 +fi + +test_with_record_tpebs() { + echo "Testing with --record-tpebs" + if ! perf stat -e "${event}:R" --record-tpebs -a sleep 0.01 > "${stat_output}" 2>&1 + then + echo "Testing with --record-tpebs [Failed perf stat]" + cat "${stat_output}" + exit 1 + fi + + # Expected output: + # $ perf stat --record-tpebs -e cache-misses:R -a sleep 0.01 + # Events enabled + # [ perf record: Woken up 2 times to write data ] + # [ perf record: Captured and wrote 0.056 MB - ] + # + # Performance counter stats for 'system wide': + # + # 0 cache-misses:R + # + # 0.013963299 seconds time elapsed + if ! grep "perf record" "${stat_output}" + then + echo "Testing with --record-tpebs [Failed missing perf record]" + cat "${stat_output}" + exit 1 + fi + if ! grep "${event}:R" "${stat_output}" && ! grep "/${event}/R" "${stat_output}" + then + echo "Testing with --record-tpebs [Failed missing event name]" + cat "${stat_output}" + exit 1 + fi + echo "Testing with --record-tpebs [Success]" +} + +test_with_record_tpebs +cleanup +exit 0 diff --git a/tools/perf/tests/shell/test_task_analyzer.sh b/tools/perf/tests/shell/test_task_analyzer.sh index 7d76fc63d995..e194fcf61df3 100755 --- a/tools/perf/tests/shell/test_task_analyzer.sh +++ b/tools/perf/tests/shell/test_task_analyzer.sh @@ -1,5 +1,5 @@ #!/bin/bash -# perf script task-analyzer tests +# perf script task-analyzer tests (exclusive) # SPDX-License-Identifier: GPL-2.0 tmpdir=$(mktemp -d /tmp/perf-script-task-analyzer-XXXXX) 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 33387c329f92..7adf9755d6de 100755 --- a/tools/perf/tests/shell/test_uprobe_from_different_cu.sh +++ b/tools/perf/tests/shell/test_uprobe_from_different_cu.sh @@ -4,12 +4,11 @@ set -e -# Skip if there's no probe command. -if ! perf | grep probe -then - echo "Skip: probe command isn't present" - exit 2 -fi +# shellcheck source=lib/probe.sh +. "$(dirname $0)"/lib/probe.sh + +skip_if_no_perf_probe || exit 2 +[ "$(id -u)" == 0 ] || exit 2 # skip if there's no gcc if ! [ -x "$(command -v gcc)" ]; then diff --git a/tools/perf/tests/shell/timechart.sh b/tools/perf/tests/shell/timechart.sh new file mode 100755 index 000000000000..b14b3472c284 --- /dev/null +++ b/tools/perf/tests/shell/timechart.sh @@ -0,0 +1,67 @@ +#!/bin/bash +# perf timechart tests +# SPDX-License-Identifier: GPL-2.0 + +set -e + +err=0 +perfdata=$(mktemp /tmp/__perf_timechart_test.perf.data.XXXXX) +output=$(mktemp /tmp/__perf_timechart_test.output.XXXXX.svg) + +cleanup() { + rm -f "${perfdata}" + rm -f "${output}" + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +test_timechart() { + echo "Basic perf timechart test" + + # Try to record timechart data. + # perf timechart record uses system-wide recording and specific tracepoints. + # If it fails (e.g. permissions, missing tracepoints), skip the test. + if ! perf timechart record -o "${perfdata}" true > /dev/null 2>&1; then + echo "Basic perf timechart test [Skipped: perf timechart record failed (permissions/events?)]" + return + fi + + # Generate the timechart + if ! perf timechart -i "${perfdata}" -o "${output}" > /dev/null 2>&1; then + echo "Basic perf timechart test [Failed: perf timechart command failed]" + err=1 + return + fi + + # Check if output file exists and is not empty + if [ ! -s "${output}" ]; then + echo "Basic perf timechart test [Failed: output file is empty or missing]" + err=1 + return + fi + + # Check if it looks like an SVG + if ! grep -q "svg" "${output}"; then + echo "Basic perf timechart test [Failed: output doesn't look like SVG]" + err=1 + return + fi + + echo "Basic perf timechart test [Success]" +} + +if ! perf check feature -q libtraceevent ; then + echo "perf timechart is not supported. Skip." + cleanup + exit 2 +fi + +test_timechart +cleanup +exit $err diff --git a/tools/perf/tests/shell/top.sh b/tools/perf/tests/shell/top.sh new file mode 100755 index 000000000000..768ebcf7a89c --- /dev/null +++ b/tools/perf/tests/shell/top.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# perf top tests +# SPDX-License-Identifier: GPL-2.0 + +set -e + +err=0 +log_file=$(mktemp /tmp/perf.top.log.XXXXX) + +cleanup() { + rm -f "${log_file}" + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +test_basic_perf_top() { + echo "Basic perf top test" + + # Start a workload that spins to generate samples + # thloop runs for the specified number of seconds + perf test -w thloop 20 & + PID=$! + + # Allow it to start + sleep 0.1 + + # Run perf top for 5 seconds, monitoring that PID + # Use --stdio to avoid TUI and redirect output + # Use -d 1 to avoid flooding output + # Use -e cpu-clock to ensure we get samples + # Use sleep to keep stdin open but silent, preventing EOF loop or interactive spam + if ! sleep 10 | timeout 5s perf top --stdio -d 1 -e cpu-clock -p $PID > "${log_file}" 2>&1; then + retval=$? + if [ $retval -ne 124 ] && [ $retval -ne 0 ]; then + echo "Basic perf top test [Failed: perf top failed to start or run (ret=$retval)]" + head -n 50 "${log_file}" + kill $PID + wait $PID 2>/dev/null || true + err=1 + return + fi + fi + + kill $PID + wait $PID 2>/dev/null || true + + # Check for some sample data (percentage) + if ! grep -E -q "[0-9]+\.[0-9]+%" "${log_file}"; then + echo "Basic perf top test [Failed: no sample percentage found]" + head -n 50 "${log_file}" + err=1 + return + fi + + # Check for the symbol + if ! grep -q "test_loop" "${log_file}"; then + echo "Basic perf top test [Failed: test_loop symbol not found]" + head -n 50 "${log_file}" + err=1 + return + fi + + echo "Basic perf top test [Success]" +} + +test_basic_perf_top +cleanup +exit $err diff --git a/tools/perf/tests/shell/trace+probe_vfs_getname.sh b/tools/perf/tests/shell/trace+probe_vfs_getname.sh index 3146a1eece07..7a0b1145d0cd 100755 --- a/tools/perf/tests/shell/trace+probe_vfs_getname.sh +++ b/tools/perf/tests/shell/trace+probe_vfs_getname.sh @@ -1,5 +1,5 @@ -#!/bin/sh -# Check open filename arg using perf trace + vfs_getname +#!/bin/bash +# Check open filename arg using perf trace + vfs_getname (exclusive) # Uses the 'perf test shell' library to add probe:vfs_getname to the system # then use it with 'perf trace' using 'touch' to write to a temp file, then @@ -15,18 +15,24 @@ skip_if_no_perf_probe || exit 2 skip_if_no_perf_trace || exit 2 +[ "$(id -u)" = 0 ] || exit 2 . "$(dirname $0)"/lib/probe_vfs_getname.sh trace_open_vfs_getname() { - evts="$(echo "$(perf list syscalls:sys_enter_open* 2>/dev/null | grep -E 'open(at)? ' | sed -r 's/.*sys_enter_([a-z]+) +\[.*$/\1/')" | sed ':a;N;s:\n:,:g')" + evts="$(echo "$(perf list tracepoint 2>/dev/null | grep -E 'syscalls:sys_enter_open(at)? ' | sed -r 's/.*sys_enter_([a-z]+) +\[.*$/\1/')" | sed ':a;N;s:\n:,:g')" perf trace -e $evts touch $file 2>&1 | \ grep -E " +[0-9]+\.[0-9]+ +\( +[0-9]+\.[0-9]+ ms\): +touch/[0-9]+ open(at)?\((dfd: +CWD, +)?filename: +\"?${file}\"?, +flags: CREAT\|NOCTTY\|NONBLOCK\|WRONLY, +mode: +IRUGO\|IWUGO\) += +[0-9]+$" } - -add_probe_vfs_getname || skip_if_no_debuginfo +add_probe_vfs_getname err=$? + +if [ $err -eq 1 ] ; then + skip_if_no_debuginfo + err=$? +fi + if [ $err -ne 0 ] ; then exit $err fi diff --git a/tools/perf/tests/shell/trace_btf_enum.sh b/tools/perf/tests/shell/trace_btf_enum.sh index 5a3b8a5a9b5c..03e9f680a4a6 100755 --- a/tools/perf/tests/shell/trace_btf_enum.sh +++ b/tools/perf/tests/shell/trace_btf_enum.sh @@ -1,55 +1,72 @@ -#!/bin/sh +#!/bin/bash # perf trace enum augmentation tests # SPDX-License-Identifier: GPL-2.0 err=0 -set -e syscall="landlock_add_rule" -non_syscall="timer:hrtimer_init,timer:hrtimer_start" +non_syscall="timer:hrtimer_start" TESTPROG="perf test -w landlock" # shellcheck source=lib/probe.sh . "$(dirname $0)"/lib/probe.sh skip_if_no_perf_trace || exit 2 +[ "$(id -u)" = 0 ] || exit 2 check_vmlinux() { echo "Checking if vmlinux exists" - if ! ls /sys/kernel/btf/vmlinux 1>/dev/null 2>&1 + if [ ! -f /sys/kernel/btf/vmlinux ] then echo "trace+enum test [Skipped missing vmlinux BTF support]" err=2 fi } +check_permissions() { + if perf trace -e $syscall $TESTPROG 2>&1 | grep -q "Operation not permitted" + then + echo "trace+enum test [Skipped permissions]" + err=2 + fi +} + trace_landlock() { echo "Tracing syscall ${syscall}" - # test flight just to see if landlock_add_rule and libbpf are available - $TESTPROG + # test flight just to see if landlock_add_rule is available + if ! perf trace $TESTPROG 2>&1 | grep -q landlock + then + echo "No landlock system call found, skipping to non-syscall tracing." + return + fi - if perf trace -e $syscall $TESTPROG 2>&1 | \ - grep -q -E ".*landlock_add_rule\(ruleset_fd: 11, rule_type: (LANDLOCK_RULE_PATH_BENEATH|LANDLOCK_RULE_NET_PORT), rule_attr: 0x[a-f0-9]+, flags: 45\) = -1.*" + output="$(perf trace -e $syscall $TESTPROG 2>&1)" + if echo "$output" | grep -q -E ".*landlock_add_rule\(ruleset_fd: 11, rule_type: (LANDLOCK_RULE_PATH_BENEATH|LANDLOCK_RULE_NET_PORT), rule_attr: 0x[a-f0-9]+, flags: 45\) = -1.*" then err=0 else + printf "[syscall failure] Failed to trace syscall $syscall, output:\n$output\n" err=1 fi } trace_non_syscall() { - echo "Tracing non-syscall tracepoint ${non-syscall}" - if perf trace -e $non_syscall --max-events=1 2>&1 | \ - grep -q -E '.*timer:hrtimer_.*\(.*mode: HRTIMER_MODE_.*\)$' + echo "Tracing non-syscall tracepoint ${non_syscall}" + output="$(perf trace -e $non_syscall --max-events=1 2>&1)" + if echo "$output" | grep -q -E '.*timer:hrtimer_.*\(.*mode: HRTIMER_MODE_.*\)$' then err=0 else + printf "[tracepoint failure] Failed to trace tracepoint $non_syscall, output:\n$output\n" err=1 fi } check_vmlinux +if [ $err = 0 ]; then + check_permissions +fi if [ $err = 0 ]; then trace_landlock diff --git a/tools/perf/tests/shell/trace_btf_general.sh b/tools/perf/tests/shell/trace_btf_general.sh new file mode 100755 index 000000000000..ef2da806be6b --- /dev/null +++ b/tools/perf/tests/shell/trace_btf_general.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# perf trace BTF general tests +# SPDX-License-Identifier: GPL-2.0 + +err=0 + +# shellcheck source=lib/probe.sh +. "$(dirname $0)"/lib/probe.sh + +file1=$(mktemp /tmp/file1_XXXX) +file2=$(echo $file1 | sed 's/file1/file2/g') + +buffer="buffer content" +perf_config_tmp=$(mktemp /tmp/.perfconfig_XXXXX) + +trap cleanup EXIT TERM INT HUP + +check_vmlinux() { + echo "Checking if vmlinux BTF exists" + if [ ! -f /sys/kernel/btf/vmlinux ] + then + echo "Skipped due to missing vmlinux BTF" + return 2 + fi + return 0 +} + +trace_test_string() { + echo "Testing perf trace's string augmentation" + output="$(perf trace --sort-events -e renameat* --max-events=1 -- mv ${file1} ${file2} 2>&1)" + if ! echo "$output" | grep -q -E "^mv/[0-9]+ renameat(2)?\(.*, \"${file1}\", .*, \"${file2}\", .*\) += +[0-9]+$" + then + printf "String augmentation test failed, output:\n$output\n" + err=1 + fi +} + +trace_test_buffer() { + echo "Testing perf trace's buffer augmentation" + # echo will insert a newline (\10) at the end of the buffer + output="$(perf trace --sort-events -e write --max-events=1 -- echo "${buffer}" 2>&1)" + if ! echo "$output" | grep -q -E "^echo/[0-9]+ write\([0-9]+, ${buffer}.*, [0-9]+\) += +[0-9]+$" + then + printf "Buffer augmentation test failed, output:\n$output\n" + err=1 + fi +} + +trace_test_struct_btf() { + echo "Testing perf trace's struct augmentation" + output="$(perf trace --sort-events -e clock_nanosleep --force-btf --max-events=1 -- sleep 1 2>&1)" + if ! echo "$output" | grep -q -E "^sleep/[0-9]+ clock_nanosleep\(0, 0, \{1,.*\}, 0x[0-9a-f]+\) += +[0-9]+$" + then + printf "BTF struct augmentation test failed, output:\n$output\n" + err=1 + fi +} + +cleanup() { + rm -rf ${file1} ${file2} ${perf_config_tmp} +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} + +# don't overwrite user's perf config +trace_config() { + export PERF_CONFIG=${perf_config_tmp} + perf config trace.show_arg_names=false trace.show_duration=false \ + trace.show_timestamp=false trace.args_alignment=0 +} + +skip_if_no_perf_trace || exit 2 +check_vmlinux || exit 2 +[ "$(id -u)" = 0 ] || exit 2 + +trace_config + +trace_test_string + +if [ $err = 0 ]; then + trace_test_buffer +fi + +if [ $err = 0 ]; then + trace_test_struct_btf +fi + +cleanup + +exit $err diff --git a/tools/perf/tests/shell/trace_exit_race.sh b/tools/perf/tests/shell/trace_exit_race.sh new file mode 100755 index 000000000000..db300cde94fb --- /dev/null +++ b/tools/perf/tests/shell/trace_exit_race.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# perf trace exit race +# SPDX-License-Identifier: GPL-2.0 + +# Check that the last events of a perf trace'd subprocess are not +# lost. Specifically, trace the exiting syscall of "true" 10 times and ensure +# the output contains 10 correct lines. + +# shellcheck source=lib/probe.sh +. "$(dirname $0)"/lib/probe.sh + +skip_if_no_perf_trace || exit 2 +[ "$(id -u)" = 0 ] || exit 2 + +if [ "$1" = "-v" ]; then + verbose="1" +fi + +iter=10 +regexp=" +[0-9]+\.[0-9]+ [0-9]+ syscalls:sys_enter_exit_group\(\)$" + +trace_shutdown_race() { + for _ in $(seq $iter); do + perf trace --no-comm -e syscalls:sys_enter_exit_group true 2>>$file + done + result="$(grep -c -E "$regexp" $file)" + [ $result = $iter ] +} + + +file=$(mktemp /tmp/temporary_file.XXXXX) + +# Do not use whatever ~/.perfconfig file, it may change the output +# via trace.{show_timestamp,show_prefix,etc} +export PERF_CONFIG=/dev/null + +trace_shutdown_race +err=$? + +if [ $err != 0 ] && [ "${verbose}" = "1" ]; then + lines_not_matching=$(mktemp /tmp/temporary_file.XXXXX) + if grep -v -E "$regexp" $file > $lines_not_matching ; then + echo "Lines not matching the expected regexp: '$regexp':" + cat $lines_not_matching + else + echo "Missing output, expected $iter but only got $result" + fi + rm -f $lines_not_matching +fi + +rm -f ${file} +exit $err diff --git a/tools/perf/tests/shell/trace_record_replay.sh b/tools/perf/tests/shell/trace_record_replay.sh new file mode 100755 index 000000000000..88d30a03dcec --- /dev/null +++ b/tools/perf/tests/shell/trace_record_replay.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# perf trace record and replay +# SPDX-License-Identifier: GPL-2.0 + +# Check that perf trace works with record and replay + +# shellcheck source=lib/probe.sh +. "$(dirname $0)"/lib/probe.sh + +skip_if_no_perf_trace || exit 2 +[ "$(id -u)" = 0 ] || exit 2 + +file=$(mktemp /tmp/temporary_file.XXXXX) + +perf trace record -o ${file} sleep 1 || exit 1 +if ! perf trace -i ${file} 2>&1 | grep nanosleep; then + echo "Failed: cannot find *nanosleep syscall" + exit 1 +fi + +rm -f ${file} diff --git a/tools/perf/tests/shell/trace_summary.sh b/tools/perf/tests/shell/trace_summary.sh new file mode 100755 index 000000000000..22e2651d5919 --- /dev/null +++ b/tools/perf/tests/shell/trace_summary.sh @@ -0,0 +1,77 @@ +#!/bin/bash +# perf trace summary (exclusive) +# SPDX-License-Identifier: GPL-2.0 + +# Check that perf trace works with various summary mode + +# shellcheck source=lib/probe.sh +. "$(dirname $0)"/lib/probe.sh + +skip_if_no_perf_trace || exit 2 +[ "$(id -u)" = 0 ] || exit 2 + +OUTPUT=$(mktemp /tmp/perf_trace_test.XXXXX) + +test_perf_trace() { + args=$1 + workload="true" + search="^\s*(open|read|close).*[0-9]+%$" + + echo "testing: perf trace ${args} -- ${workload}" + perf trace ${args} -- ${workload} >${OUTPUT} 2>&1 + if [ $? -ne 0 ]; then + echo "Error: perf trace ${args} failed unexpectedly" + cat ${OUTPUT} + rm -f ${OUTPUT} + exit 1 + fi + + count=$(grep -E -c -m 3 "${search}" ${OUTPUT}) + if [ "${count}" != "3" ]; then + echo "Error: cannot find enough pattern ${search} in the output" + cat ${OUTPUT} + rm -f ${OUTPUT} + exit 1 + fi +} + +# summary only for a process +test_perf_trace "-s" + +# normal output with summary at the end +test_perf_trace "-S" + +# summary only with an explicit summary mode +test_perf_trace "-s --summary-mode=thread" + +# summary with normal output - total summary mode +test_perf_trace "-S --summary-mode=total" + +# summary only for system wide - per-thread summary +test_perf_trace "-as --summary-mode=thread --no-bpf-summary" + +# summary only for system wide - total summary mode +test_perf_trace "-as --summary-mode=total --no-bpf-summary" + +if ! perf check feature -q bpf; then + echo "Skip --bpf-summary tests as perf built without libbpf" + rm -f ${OUTPUT} + exit 2 +fi + +# summary only for system wide - per-thread summary with BPF +test_perf_trace "-as --summary-mode=thread --bpf-summary" + +# summary only for system wide - total summary mode with BPF +test_perf_trace "-as --summary-mode=total --bpf-summary" + +# summary with normal output for system wide - total summary mode with BPF +test_perf_trace "-aS --summary-mode=total --bpf-summary" + +# summary only for system wide - cgroup summary mode with BPF +test_perf_trace "-as --summary-mode=cgroup --bpf-summary" + +# summary with normal output for system wide - cgroup summary mode with BPF +test_perf_trace "-aS --summary-mode=cgroup --bpf-summary" + +rm -f ${OUTPUT} diff --git a/tools/perf/tests/sigtrap.c b/tools/perf/tests/sigtrap.c index e6fd934b027a..a67c756f90b8 100644 --- a/tools/perf/tests/sigtrap.c +++ b/tools/perf/tests/sigtrap.c @@ -56,6 +56,7 @@ static struct perf_event_attr make_event_attr(void) #ifdef HAVE_BPF_SKEL #include <bpf/btf.h> +#include <util/btf.h> static struct btf *btf; @@ -73,21 +74,6 @@ static void btf__exit(void) btf = NULL; } -static const struct btf_member *__btf_type__find_member_by_name(int type_id, const char *member_name) -{ - const struct btf_type *t = btf__type_by_id(btf, type_id); - const struct btf_member *m; - int i; - - for (i = 0, m = btf_members(t); i < btf_vlen(t); i++, m++) { - const char *current_member_name = btf__name_by_offset(btf, m->name_off); - if (!strcmp(current_member_name, member_name)) - return m; - } - - return NULL; -} - static bool attr_has_sigtrap(void) { int id; @@ -101,7 +87,7 @@ static bool attr_has_sigtrap(void) if (id < 0) return false; - return __btf_type__find_member_by_name(id, "sigtrap") != NULL; + return __btf_type__find_member_by_name(btf, id, "sigtrap") != NULL; } static bool kernel_with_sleepable_spinlocks(void) @@ -119,7 +105,7 @@ static bool kernel_with_sleepable_spinlocks(void) return false; // Only RT has a "lock" member for "struct spinlock" - member = __btf_type__find_member_by_name(id, "lock"); + member = __btf_type__find_member_by_name(btf, id, "lock"); if (member == NULL) return false; diff --git a/tools/perf/tests/stat.c b/tools/perf/tests/stat.c index 6468cc0d0204..d60983657bad 100644 --- a/tools/perf/tests/stat.c +++ b/tools/perf/tests/stat.c @@ -27,7 +27,7 @@ static int process_stat_config_event(const struct perf_tool *tool __maybe_unused struct machine *machine __maybe_unused) { struct perf_record_stat_config *config = &event->stat_config; - struct perf_stat_config stat_config = {}; + struct perf_stat_config test_stat_config = {}; #define HAS(term, val) \ has_term(config, PERF_STAT_CONFIG_TERM__##term, val) @@ -39,25 +39,27 @@ static int process_stat_config_event(const struct perf_tool *tool __maybe_unused #undef HAS - perf_event__read_stat_config(&stat_config, config); + perf_event__read_stat_config(&test_stat_config, config); - TEST_ASSERT_VAL("wrong aggr_mode", stat_config.aggr_mode == AGGR_CORE); - TEST_ASSERT_VAL("wrong scale", stat_config.scale == 1); - TEST_ASSERT_VAL("wrong interval", stat_config.interval == 1); + TEST_ASSERT_VAL("wrong aggr_mode", test_stat_config.aggr_mode == AGGR_CORE); + TEST_ASSERT_VAL("wrong scale", test_stat_config.scale == 1); + TEST_ASSERT_VAL("wrong interval", test_stat_config.interval == 1); return 0; } static int test__synthesize_stat_config(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { - struct perf_stat_config stat_config = { + struct perf_stat_config test_stat_config = { .aggr_mode = AGGR_CORE, .scale = 1, .interval = 1, }; TEST_ASSERT_VAL("failed to synthesize stat_config", - !perf_event__synthesize_stat_config(NULL, &stat_config, process_stat_config_event, NULL)); + !perf_event__synthesize_stat_config(NULL, &test_stat_config, + process_stat_config_event, + NULL)); return 0; } diff --git a/tools/perf/tests/subcmd-help.c b/tools/perf/tests/subcmd-help.c new file mode 100644 index 000000000000..2280b4c0e5e7 --- /dev/null +++ b/tools/perf/tests/subcmd-help.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "tests.h" +#include <linux/compiler.h> +#include <subcmd/help.h> + +static int test__load_cmdnames(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + struct cmdnames cmds = {}; + + add_cmdname(&cmds, "aaa", 3); + add_cmdname(&cmds, "foo", 3); + add_cmdname(&cmds, "xyz", 3); + + TEST_ASSERT_VAL("cannot find cmd", is_in_cmdlist(&cmds, "aaa") == 1); + TEST_ASSERT_VAL("wrong cmd", is_in_cmdlist(&cmds, "bar") == 0); + TEST_ASSERT_VAL("case sensitive", is_in_cmdlist(&cmds, "XYZ") == 0); + + clean_cmdnames(&cmds); + return TEST_OK; +} + +static int test__uniq_cmdnames(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + struct cmdnames cmds = {}; + + /* uniq() assumes it's sorted */ + add_cmdname(&cmds, "aaa", 3); + add_cmdname(&cmds, "aaa", 3); + add_cmdname(&cmds, "bbb", 3); + + TEST_ASSERT_VAL("invalid original size", cmds.cnt == 3); + /* uniquify command names (to remove second 'aaa') */ + uniq(&cmds); + TEST_ASSERT_VAL("invalid final size", cmds.cnt == 2); + + TEST_ASSERT_VAL("cannot find cmd", is_in_cmdlist(&cmds, "aaa") == 1); + TEST_ASSERT_VAL("cannot find cmd", is_in_cmdlist(&cmds, "bbb") == 1); + TEST_ASSERT_VAL("wrong cmd", is_in_cmdlist(&cmds, "ccc") == 0); + + clean_cmdnames(&cmds); + return TEST_OK; +} + +static int test__exclude_cmdnames(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + struct cmdnames cmds1 = {}; + struct cmdnames cmds2 = {}; + + add_cmdname(&cmds1, "aaa", 3); + add_cmdname(&cmds1, "bbb", 3); + add_cmdname(&cmds1, "ccc", 3); + add_cmdname(&cmds1, "ddd", 3); + add_cmdname(&cmds1, "eee", 3); + add_cmdname(&cmds1, "fff", 3); + add_cmdname(&cmds1, "ggg", 3); + add_cmdname(&cmds1, "hhh", 3); + add_cmdname(&cmds1, "iii", 3); + add_cmdname(&cmds1, "jjj", 3); + + add_cmdname(&cmds2, "bbb", 3); + add_cmdname(&cmds2, "eee", 3); + add_cmdname(&cmds2, "jjj", 3); + + TEST_ASSERT_VAL("invalid original size", cmds1.cnt == 10); + TEST_ASSERT_VAL("invalid original size", cmds2.cnt == 3); + + /* remove duplicate command names in cmds1 */ + exclude_cmds(&cmds1, &cmds2); + + TEST_ASSERT_VAL("invalid excluded size", cmds1.cnt == 7); + TEST_ASSERT_VAL("invalid excluded size", cmds2.cnt == 3); + + /* excluded commands should not belong to cmds1 */ + TEST_ASSERT_VAL("cannot find cmd", is_in_cmdlist(&cmds1, "aaa") == 1); + TEST_ASSERT_VAL("wrong cmd", is_in_cmdlist(&cmds1, "bbb") == 0); + TEST_ASSERT_VAL("cannot find cmd", is_in_cmdlist(&cmds1, "ccc") == 1); + TEST_ASSERT_VAL("cannot find cmd", is_in_cmdlist(&cmds1, "ddd") == 1); + TEST_ASSERT_VAL("wrong cmd", is_in_cmdlist(&cmds1, "eee") == 0); + TEST_ASSERT_VAL("cannot find cmd", is_in_cmdlist(&cmds1, "fff") == 1); + TEST_ASSERT_VAL("cannot find cmd", is_in_cmdlist(&cmds1, "ggg") == 1); + TEST_ASSERT_VAL("cannot find cmd", is_in_cmdlist(&cmds1, "hhh") == 1); + TEST_ASSERT_VAL("cannot find cmd", is_in_cmdlist(&cmds1, "iii") == 1); + TEST_ASSERT_VAL("wrong cmd", is_in_cmdlist(&cmds1, "jjj") == 0); + + /* they should be only in cmds2 */ + TEST_ASSERT_VAL("cannot find cmd", is_in_cmdlist(&cmds2, "bbb") == 1); + TEST_ASSERT_VAL("cannot find cmd", is_in_cmdlist(&cmds2, "eee") == 1); + TEST_ASSERT_VAL("cannot find cmd", is_in_cmdlist(&cmds2, "jjj") == 1); + + clean_cmdnames(&cmds1); + clean_cmdnames(&cmds2); + return TEST_OK; +} + +static struct test_case tests__subcmd_help[] = { + TEST_CASE("Load subcmd names", load_cmdnames), + TEST_CASE("Uniquify subcmd names", uniq_cmdnames), + TEST_CASE("Exclude duplicate subcmd names", exclude_cmdnames), + { .name = NULL, } +}; + +struct test_suite suite__subcmd_help = { + .desc = "libsubcmd help tests", + .test_cases = tests__subcmd_help, +}; diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c index 290716783ac6..4a2ad7176fa0 100644 --- a/tools/perf/tests/sw-clock.c +++ b/tools/perf/tests/sw-clock.c @@ -104,12 +104,14 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) while ((event = perf_mmap__read_event(&md->core)) != NULL) { struct perf_sample sample; + perf_sample__init(&sample, /*all=*/false); if (event->header.type != PERF_RECORD_SAMPLE) goto next_event; err = evlist__parse_sample(evlist, event, &sample); if (err < 0) { pr_debug("Error during parse sample\n"); + perf_sample__exit(&sample); goto out_delete_evlist; } @@ -117,6 +119,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) nr_samples++; next_event: perf_mmap__consume(&md->core); + perf_sample__exit(&sample); } perf_mmap__read_done(&md->core); diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index 5cab17a1942e..15791fcb76b2 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c @@ -131,9 +131,11 @@ static int process_sample_event(struct evlist *evlist, pid_t next_tid, prev_tid; int cpu, err; + perf_sample__init(&sample, /*all=*/false); if (evlist__parse_sample(evlist, event, &sample)) { pr_debug("evlist__parse_sample failed\n"); - return -1; + err = -1; + goto out; } evsel = evlist__id2evsel(evlist, sample.id); @@ -145,7 +147,7 @@ static int process_sample_event(struct evlist *evlist, cpu, prev_tid, next_tid); err = check_cpu(switch_tracking, cpu); if (err) - return err; + goto out; /* * Check for no missing sched_switch events i.e. that the * evsel->core.system_wide flag has worked. @@ -153,7 +155,8 @@ static int process_sample_event(struct evlist *evlist, if (switch_tracking->tids[cpu] != -1 && switch_tracking->tids[cpu] != prev_tid) { pr_debug("Missing sched_switch events\n"); - return -1; + err = -1; + goto out; } switch_tracking->tids[cpu] = next_tid; } @@ -169,7 +172,10 @@ static int process_sample_event(struct evlist *evlist, switch_tracking->cycles_after_comm_4 = 1; } - return 0; + err = 0; +out: + perf_sample__exit(&sample); + return err; } static int process_event(struct evlist *evlist, union perf_event *event, @@ -258,7 +264,7 @@ static int compar(const void *a, const void *b) const struct event_node *nodeb = b; s64 cmp = nodea->event_time - nodeb->event_time; - return cmp; + return cmp < 0 ? -1 : (cmp > 0 ? 1 : 0); } static int process_events(struct evlist *evlist, @@ -326,7 +332,7 @@ out_free_nodes: static int test__switch_tracking(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { const char *sched_switch = "sched:sched_switch"; - const char *cycles = "cycles:u"; + const char *cycles = "cpu-cycles:u"; struct switch_tracking switch_tracking = { .tids = NULL, }; struct record_opts opts = { .mmap_pages = UINT_MAX, @@ -345,7 +351,7 @@ static int test__switch_tracking(struct test_suite *test __maybe_unused, int sub const char *comm; int err = -1; - threads = thread_map__new(-1, getpid(), UINT_MAX); + threads = thread_map__new_by_tid(getpid()); if (!threads) { pr_debug("thread_map__new failed!\n"); goto out_err; @@ -583,4 +589,4 @@ out_err: goto out; } -DEFINE_SUITE("Track with sched_switch", switch_tracking); +DEFINE_SUITE_EXCLUSIVE("Track with sched_switch", switch_tracking); diff --git a/tools/perf/tests/symbols.c b/tools/perf/tests/symbols.c index ee20a366f32f..f4ffe5804f40 100644 --- a/tools/perf/tests/symbols.c +++ b/tools/perf/tests/symbols.c @@ -5,6 +5,7 @@ #include <limits.h> #include "debug.h" #include "dso.h" +#include "env.h" #include "machine.h" #include "thread.h" #include "symbol.h" @@ -13,15 +14,18 @@ #include "tests.h" struct test_info { + struct perf_env host_env; struct machine *machine; struct thread *thread; }; static int init_test_info(struct test_info *ti) { - ti->machine = machine__new_host(); + perf_env__init(&ti->host_env); + ti->machine = machine__new_host(&ti->host_env); if (!ti->machine) { pr_debug("machine__new_host() failed!\n"); + perf_env__exit(&ti->host_env); return TEST_FAIL; } @@ -29,6 +33,7 @@ static int init_test_info(struct test_info *ti) ti->thread = machine__findnew_thread(ti->machine, 100, 100); if (!ti->thread) { pr_debug("machine__findnew_thread() failed!\n"); + perf_env__exit(&ti->host_env); return TEST_FAIL; } @@ -39,6 +44,7 @@ static void exit_test_info(struct test_info *ti) { thread__put(ti->thread); machine__delete(ti->machine); + perf_env__exit(&ti->host_env); } struct dso_map { @@ -96,8 +102,8 @@ static int create_map(struct test_info *ti, char *filename, struct map **map_p) dso__put(dso); /* Create a dummy map at 0x100000 */ - *map_p = map__new(ti->machine, 0x100000, 0xffffffff, 0, NULL, - PROT_EXEC, 0, NULL, filename, ti->thread); + *map_p = map__new(ti->machine, 0x100000, 0xffffffff, 0, &dso_id_empty, + PROT_EXEC, /*flags=*/0, filename, ti->thread); if (!*map_p) { pr_debug("Failed to create map!"); return TEST_FAIL; diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index d33d0952025c..4053ff2813bb 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c @@ -46,7 +46,6 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _ struct evsel *evsel; struct evlist *evlist; struct target target = { - .uid = UINT_MAX, .uses_mmap = true, }; const char *argv[] = { "true", NULL }; @@ -152,4 +151,11 @@ out_delete_evlist: return err; } -DEFINE_SUITE("Number of exit events of a simple workload", task_exit); +struct test_case tests__task_exit[] = { + TEST_CASE_EXCLUSIVE("Number of exit events of a simple workload", task_exit), + { .name = NULL, } +}; +struct test_suite suite__task_exit = { + .desc = "Number of exit events of a simple workload", + .test_cases = tests__task_exit, +}; diff --git a/tools/perf/tests/tests-scripts.c b/tools/perf/tests/tests-scripts.c index ed114b044293..f18c4cd337c8 100644 --- a/tools/perf/tests/tests-scripts.c +++ b/tools/perf/tests/tests-scripts.c @@ -85,7 +85,7 @@ static char *shell_test__description(int dir_fd, const char *name) if (io.fd < 0) return NULL; - /* Skip first line - should be #!/bin/sh Shebang */ + /* Skip first line - should be #!/bin/bash Shebang */ if (io__get_char(&io) != '#') goto err_out; if (io__get_char(&io) != '!') @@ -174,7 +174,8 @@ static void append_script(int dir_fd, const char *name, char *desc, char filename[PATH_MAX], link[128]; struct test_suite *test_suite, **result_tmp; struct test_case *tests; - size_t len; + ssize_t len; + char *exclusive; snprintf(link, sizeof(link), "/proc/%d/fd/%d", getpid(), dir_fd); len = readlink(link, filename, sizeof(filename)); @@ -191,9 +192,13 @@ 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'; + } tests[0].desc = strdup_check(desc); tests[0].run_case = shell_test__run; - test_suite = zalloc(sizeof(*test_suite)); if (!test_suite) { pr_err("Out of memory while building script test suite list\n"); @@ -255,6 +260,7 @@ static void append_scripts_in_dir(int dir_fd, continue; /* Skip scripts that have a separate driver. */ fd = openat(dir_fd, ent->d_name, O_PATH); append_scripts_in_dir(fd, result, result_sz); + close(fd); } for (i = 0; i < n_dirs; i++) /* Clean up */ zfree(&entlist[i]); diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 6ea2be86b7bf..cb67ddbd0375 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -3,6 +3,7 @@ #define TESTS_H #include <stdbool.h> +#include "util/debug.h" enum { TEST_OK = 0, @@ -36,6 +37,7 @@ struct test_case { const char *desc; const char *skip_reason; test_fnptr run_case; + bool exclusive; }; struct test_suite { @@ -62,6 +64,23 @@ struct test_suite { .skip_reason = _reason, \ } +#define TEST_CASE_EXCLUSIVE(description, _name) \ + { \ + .name = #_name, \ + .desc = description, \ + .run_case = test__##_name, \ + .exclusive = true, \ + } + +#define TEST_CASE_REASON_EXCLUSIVE(description, _name, _reason) \ + { \ + .name = #_name, \ + .desc = description, \ + .run_case = test__##_name, \ + .skip_reason = _reason, \ + .exclusive = true, \ + } + #define DEFINE_SUITE(description, _name) \ struct test_case tests__##_name[] = { \ TEST_CASE(description, _name), \ @@ -72,6 +91,16 @@ struct test_suite { .test_cases = tests__##_name, \ } +#define DEFINE_SUITE_EXCLUSIVE(description, _name) \ + struct test_case tests__##_name[] = { \ + TEST_CASE_EXCLUSIVE(description, _name),\ + { .name = NULL, } \ + }; \ + struct test_suite suite__##_name = { \ + .desc = description, \ + .test_cases = tests__##_name, \ + } + /* Tests */ DECLARE_SUITE(vmlinux_matches_kallsyms); DECLARE_SUITE(openat_syscall_event); @@ -83,13 +112,14 @@ DECLARE_SUITE(perf_evsel__tp_sched_test); DECLARE_SUITE(syscall_openat_tp_fields); DECLARE_SUITE(pmu); DECLARE_SUITE(pmu_events); +DECLARE_SUITE(hwmon_pmu); +DECLARE_SUITE(tool_pmu); DECLARE_SUITE(attr); DECLARE_SUITE(dso_data); DECLARE_SUITE(dso_data_cache); DECLARE_SUITE(dso_data_reopen); DECLARE_SUITE(parse_events); DECLARE_SUITE(hists_link); -DECLARE_SUITE(python_use); DECLARE_SUITE(bp_signal); DECLARE_SUITE(bp_signal_overflow); DECLARE_SUITE(bp_accounting); @@ -130,12 +160,13 @@ DECLARE_SUITE(bitmap_print); DECLARE_SUITE(perf_hooks); DECLARE_SUITE(unit_number__scnprint); DECLARE_SUITE(mem2node); -DECLARE_SUITE(maps__merge_in); +DECLARE_SUITE(maps); DECLARE_SUITE(time_utils); DECLARE_SUITE(jit_write_elf); DECLARE_SUITE(api_io); DECLARE_SUITE(demangle_java); DECLARE_SUITE(demangle_ocaml); +DECLARE_SUITE(demangle_rust); DECLARE_SUITE(pfm); DECLARE_SUITE(parse_metric); DECLARE_SUITE(pe_file_parsing); @@ -146,6 +177,8 @@ DECLARE_SUITE(sigtrap); DECLARE_SUITE(event_groups); DECLARE_SUITE(symbols); DECLARE_SUITE(util); +DECLARE_SUITE(subcmd_help); +DECLARE_SUITE(kallsyms_split); /* * PowerPC and S390 do not support creation of instruction breakpoints using the @@ -206,6 +239,7 @@ DECLARE_WORKLOAD(sqrtloop); DECLARE_WORKLOAD(brstack); DECLARE_WORKLOAD(datasym); DECLARE_WORKLOAD(landlock); +DECLARE_WORKLOAD(traploop); extern const char *dso_to_test; extern const char *test_objdump_path; diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c index 1fe521466bf4..54209592168d 100644 --- a/tools/perf/tests/thread-map.c +++ b/tools/perf/tests/thread-map.c @@ -115,7 +115,7 @@ static int test__thread_map_remove(struct test_suite *test __maybe_unused, int s TEST_ASSERT_VAL("failed to allocate map string", asprintf(&str, "%d,%d", getpid(), getppid()) >= 0); - threads = thread_map__new_str(str, NULL, 0, false); + threads = thread_map__new_str(str, /*tid=*/NULL, /*all_threads=*/false); free(str); TEST_ASSERT_VAL("failed to allocate thread_map", diff --git a/tools/perf/tests/tool_pmu.c b/tools/perf/tests/tool_pmu.c new file mode 100644 index 000000000000..1e900ef92e37 --- /dev/null +++ b/tools/perf/tests/tool_pmu.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +#include "debug.h" +#include "evlist.h" +#include "parse-events.h" +#include "tests.h" +#include "tool_pmu.h" + +static int do_test(enum tool_pmu_event ev, bool with_pmu) +{ + struct evlist *evlist = evlist__new(); + struct evsel *evsel; + struct parse_events_error err; + int ret; + char str[128]; + bool found = false; + + if (!evlist) { + pr_err("evlist allocation failed\n"); + return TEST_FAIL; + } + + if (with_pmu) + snprintf(str, sizeof(str), "tool/%s/", tool_pmu__event_to_str(ev)); + else + snprintf(str, sizeof(str), "%s", tool_pmu__event_to_str(ev)); + + parse_events_error__init(&err); + ret = parse_events(evlist, str, &err); + if (ret) { + if (!tool_pmu__event_to_str(ev)) { + ret = TEST_OK; + goto out; + } + + pr_debug("FAILED %s:%d failed to parse event '%s', err %d\n", + __FILE__, __LINE__, str, ret); + parse_events_error__print(&err, str); + ret = TEST_FAIL; + goto out; + } + + ret = TEST_OK; + if (with_pmu ? (evlist->core.nr_entries != 1) : (evlist->core.nr_entries < 1)) { + pr_debug("FAILED %s:%d Unexpected number of events for '%s' of %d\n", + __FILE__, __LINE__, str, evlist->core.nr_entries); + ret = TEST_FAIL; + goto out; + } + + evlist__for_each_entry(evlist, evsel) { + if (perf_pmu__is_tool(evsel->pmu)) { + if (evsel->core.attr.config != ev) { + pr_debug("FAILED %s:%d Unexpected config for '%s', %lld != %d\n", + __FILE__, __LINE__, str, evsel->core.attr.config, ev); + ret = TEST_FAIL; + goto out; + } + found = true; + } + } + + if (!found && tool_pmu__event_to_str(ev)) { + pr_debug("FAILED %s:%d Didn't find tool event '%s' in parsed evsels\n", + __FILE__, __LINE__, str); + ret = TEST_FAIL; + } + +out: + parse_events_error__exit(&err); + evlist__delete(evlist); + return ret; +} + +static int test__tool_pmu_without_pmu(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + int i; + + tool_pmu__for_each_event(i) { + int ret = do_test(i, /*with_pmu=*/false); + + if (ret != TEST_OK) + return ret; + } + return TEST_OK; +} + +static int test__tool_pmu_with_pmu(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + int i; + + tool_pmu__for_each_event(i) { + int ret = do_test(i, /*with_pmu=*/true); + + if (ret != TEST_OK) + return ret; + } + return TEST_OK; +} + +static struct test_case tests__tool_pmu[] = { + TEST_CASE("Parsing without PMU name", tool_pmu_without_pmu), + TEST_CASE("Parsing with PMU name", tool_pmu_with_pmu), + { .name = NULL, } +}; + +struct test_suite suite__tool_pmu = { + .desc = "Tool PMU", + .test_cases = tests__tool_pmu, +}; diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c index a8cb5ba898ab..ec01150d208d 100644 --- a/tools/perf/tests/topology.c +++ b/tools/perf/tests/topology.c @@ -43,6 +43,7 @@ static int session_write_header(char *path) session->evlist = evlist__new_default(); TEST_ASSERT_VAL("can't get evlist", session->evlist); + session->evlist->session = session; perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY); perf_header__set_feat(&session->header, HEADER_NRCPUS); @@ -69,9 +70,11 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) int i; struct aggr_cpu_id id; struct perf_cpu cpu; + struct perf_env *env; session = perf_session__new(&data, NULL); TEST_ASSERT_VAL("can't get session", !IS_ERR(session)); + env = perf_session__env(session); cpu__setup_cpunode_map(); /* On platforms with large numbers of CPUs process_cpu_topology() @@ -95,9 +98,7 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) * condition is true (see do_core_id_test in header.c). So always * run this test on those platforms. */ - if (!session->header.env.cpu - && strncmp(session->header.env.arch, "s390", 4) - && strncmp(session->header.env.arch, "aarch64", 7)) + if (!env->cpu && strncmp(env->arch, "s390", 4) && strncmp(env->arch, "aarch64", 7)) return TEST_SKIP; /* @@ -106,20 +107,20 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) * physical_package_id will be set to -1. Hence skip this * test if physical_package_id returns -1 for cpu from perf_cpu_map. */ - if (!strncmp(session->header.env.arch, "ppc64le", 7)) { + if (!strncmp(env->arch, "ppc64le", 7)) { if (cpu__get_socket_id(perf_cpu_map__cpu(map, 0)) == -1) return TEST_SKIP; } - TEST_ASSERT_VAL("Session header CPU map not set", session->header.env.cpu); + TEST_ASSERT_VAL("Session header CPU map not set", env->cpu); - for (i = 0; i < session->header.env.nr_cpus_avail; i++) { + for (i = 0; i < env->nr_cpus_avail; i++) { cpu.cpu = i; if (!perf_cpu_map__has(map, cpu)) continue; pr_debug("CPU %d, core %d, socket %d\n", i, - session->header.env.cpu[i].core_id, - session->header.env.cpu[i].socket_id); + env->cpu[i].core_id, + env->cpu[i].socket_id); } // Test that CPU ID contains socket, die, core and CPU @@ -129,13 +130,12 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) cpu.cpu == id.cpu.cpu); TEST_ASSERT_VAL("Cpu map - Core ID doesn't match", - session->header.env.cpu[cpu.cpu].core_id == id.core); + env->cpu[cpu.cpu].core_id == id.core); TEST_ASSERT_VAL("Cpu map - Socket ID doesn't match", - session->header.env.cpu[cpu.cpu].socket_id == - id.socket); + env->cpu[cpu.cpu].socket_id == id.socket); TEST_ASSERT_VAL("Cpu map - Die ID doesn't match", - session->header.env.cpu[cpu.cpu].die_id == id.die); + env->cpu[cpu.cpu].die_id == id.die); TEST_ASSERT_VAL("Cpu map - Node ID is set", id.node == -1); TEST_ASSERT_VAL("Cpu map - Thread IDX is set", id.thread_idx == -1); } @@ -144,14 +144,13 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) perf_cpu_map__for_each_cpu(cpu, i, map) { id = aggr_cpu_id__core(cpu, NULL); TEST_ASSERT_VAL("Core map - Core ID doesn't match", - session->header.env.cpu[cpu.cpu].core_id == id.core); + env->cpu[cpu.cpu].core_id == id.core); TEST_ASSERT_VAL("Core map - Socket ID doesn't match", - session->header.env.cpu[cpu.cpu].socket_id == - id.socket); + env->cpu[cpu.cpu].socket_id == id.socket); TEST_ASSERT_VAL("Core map - Die ID doesn't match", - session->header.env.cpu[cpu.cpu].die_id == id.die); + env->cpu[cpu.cpu].die_id == id.die); TEST_ASSERT_VAL("Core map - Node ID is set", id.node == -1); TEST_ASSERT_VAL("Core map - Thread IDX is set", id.thread_idx == -1); } @@ -160,11 +159,10 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) perf_cpu_map__for_each_cpu(cpu, i, map) { id = aggr_cpu_id__die(cpu, NULL); TEST_ASSERT_VAL("Die map - Socket ID doesn't match", - session->header.env.cpu[cpu.cpu].socket_id == - id.socket); + env->cpu[cpu.cpu].socket_id == id.socket); TEST_ASSERT_VAL("Die map - Die ID doesn't match", - session->header.env.cpu[cpu.cpu].die_id == id.die); + env->cpu[cpu.cpu].die_id == id.die); TEST_ASSERT_VAL("Die map - Node ID is set", id.node == -1); TEST_ASSERT_VAL("Die map - Core is set", id.core == -1); @@ -176,8 +174,7 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) perf_cpu_map__for_each_cpu(cpu, i, map) { id = aggr_cpu_id__socket(cpu, NULL); TEST_ASSERT_VAL("Socket map - Socket ID doesn't match", - session->header.env.cpu[cpu.cpu].socket_id == - id.socket); + env->cpu[cpu.cpu].socket_id == id.socket); TEST_ASSERT_VAL("Socket map - Node ID is set", id.node == -1); TEST_ASSERT_VAL("Socket map - Die ID is set", id.die == -1); diff --git a/tools/perf/tests/util.c b/tools/perf/tests/util.c index 6366db5cbf8c..b273d287e164 100644 --- a/tools/perf/tests/util.c +++ b/tools/perf/tests/util.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "tests.h" #include "util/debug.h" +#include "util/sha1.h" #include <linux/compiler.h> #include <stdlib.h> @@ -16,6 +17,48 @@ static int test_strreplace(char needle, const char *haystack, return ret == 0; } +#define MAX_LEN 512 + +/* Test sha1() for all lengths from 0 to MAX_LEN inclusively. */ +static int test_sha1(void) +{ + u8 data[MAX_LEN]; + size_t digests_size = (MAX_LEN + 1) * SHA1_DIGEST_SIZE; + u8 *digests; + u8 digest_of_digests[SHA1_DIGEST_SIZE]; + /* + * The correctness of this value was verified by running this test with + * sha1() replaced by OpenSSL's SHA1(). + */ + static const u8 expected_digest_of_digests[SHA1_DIGEST_SIZE] = { + 0x74, 0xcd, 0x4c, 0xb9, 0xd8, 0xa6, 0xd5, 0x95, 0x22, 0x8b, + 0x7e, 0xd6, 0x8b, 0x7e, 0x46, 0x95, 0x31, 0x9b, 0xa2, 0x43, + }; + size_t i; + + digests = malloc(digests_size); + TEST_ASSERT_VAL("failed to allocate digests", digests != NULL); + + /* Generate MAX_LEN bytes of data. */ + for (i = 0; i < MAX_LEN; i++) + data[i] = i; + + /* Calculate a SHA-1 for each length 0 through MAX_LEN inclusively. */ + for (i = 0; i <= MAX_LEN; i++) + sha1(data, i, &digests[i * SHA1_DIGEST_SIZE]); + + /* Calculate digest of all digests calculated above. */ + sha1(digests, digests_size, digest_of_digests); + + free(digests); + + /* Check for the expected result. */ + TEST_ASSERT_VAL("wrong output from sha1()", + memcmp(digest_of_digests, expected_digest_of_digests, + SHA1_DIGEST_SIZE) == 0); + return 0; +} + static int test__util(struct test_suite *t __maybe_unused, int subtest __maybe_unused) { TEST_ASSERT_VAL("empty string", test_strreplace(' ', "", "123", "")); @@ -25,7 +68,7 @@ static int test__util(struct test_suite *t __maybe_unused, int subtest __maybe_u TEST_ASSERT_VAL("replace long", test_strreplace('a', "abcabc", "longlong", "longlongbclonglongbc")); - return 0; + return test_sha1(); } DEFINE_SUITE("util", util); diff --git a/tools/perf/tests/workloads/Build b/tools/perf/tests/workloads/Build index 5af17206f04d..fb1012cc4fc3 100644 --- a/tools/perf/tests/workloads/Build +++ b/tools/perf/tests/workloads/Build @@ -7,8 +7,10 @@ perf-test-y += sqrtloop.o perf-test-y += brstack.o perf-test-y += datasym.o perf-test-y += landlock.o +perf-test-y += traploop.o CFLAGS_sqrtloop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE CFLAGS_leafloop.o = -g -O0 -fno-inline -fno-omit-frame-pointer -U_FORTIFY_SOURCE CFLAGS_brstack.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE CFLAGS_datasym.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE +CFLAGS_traploop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE diff --git a/tools/perf/tests/workloads/datasym.c b/tools/perf/tests/workloads/datasym.c index 8e08fc75a973..1d0b7d64e1ba 100644 --- a/tools/perf/tests/workloads/datasym.c +++ b/tools/perf/tests/workloads/datasym.c @@ -1,3 +1,6 @@ +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> #include <linux/compiler.h> #include "../tests.h" @@ -7,16 +10,33 @@ typedef struct _buf { char data2; } buf __attribute__((aligned(64))); -static buf buf1 = { +/* volatile to try to avoid the compiler seeing reserved as unused. */ +static volatile buf workload_datasym_buf1 = { /* to have this in the data section */ .reserved[0] = 1, }; -static int datasym(int argc __maybe_unused, const char **argv __maybe_unused) +static volatile sig_atomic_t done; + +static void sighandler(int sig __maybe_unused) +{ + done = 1; +} + +static int datasym(int argc, const char **argv) { - for (;;) { - buf1.data1++; - if (buf1.data1 == 123) { + int sec = 1; + + if (argc > 0) + sec = atoi(argv[0]); + + signal(SIGINT, sighandler); + signal(SIGALRM, sighandler); + alarm(sec); + + while (!done) { + workload_datasym_buf1.data1++; + if (workload_datasym_buf1.data1 == 123) { /* * Add some 'noise' in the loop to work around errata * 1694299 on Arm N1. @@ -30,9 +50,9 @@ static int datasym(int argc __maybe_unused, const char **argv __maybe_unused) * longer a continuous repeating pattern that interacts * badly with the bias. */ - buf1.data1++; + workload_datasym_buf1.data1++; } - buf1.data2 += buf1.data1; + workload_datasym_buf1.data2 += workload_datasym_buf1.data1; } return 0; } diff --git a/tools/perf/tests/workloads/landlock.c b/tools/perf/tests/workloads/landlock.c index e2b5ef647c09..1f285b7b6236 100644 --- a/tools/perf/tests/workloads/landlock.c +++ b/tools/perf/tests/workloads/landlock.c @@ -10,7 +10,7 @@ * 'perf test' workload) we just add the required types and defines here instead * of including linux/landlock, that isn't available in older systems. * - * We are not interested in the the result of the syscall, just in intercepting + * We are not interested in the result of the syscall, just in intercepting * its arguments. */ diff --git a/tools/perf/tests/workloads/noploop.c b/tools/perf/tests/workloads/noploop.c index 940ea5910a84..656e472e6188 100644 --- a/tools/perf/tests/workloads/noploop.c +++ b/tools/perf/tests/workloads/noploop.c @@ -1,4 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#include <pthread.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> @@ -16,6 +17,7 @@ static int noploop(int argc, const char **argv) { int sec = 1; + pthread_setname_np(pthread_self(), "perf-noploop"); if (argc > 0) sec = atoi(argv[0]); diff --git a/tools/perf/tests/workloads/thloop.c b/tools/perf/tests/workloads/thloop.c index 457b29f91c3e..bd8168f883fb 100644 --- a/tools/perf/tests/workloads/thloop.c +++ b/tools/perf/tests/workloads/thloop.c @@ -31,21 +31,52 @@ static void *thfunc(void *arg) static int thloop(int argc, const char **argv) { - int sec = 1; - pthread_t th; + int nt = 2, sec = 1, err = 1; + pthread_t *thread_list = NULL; if (argc > 0) sec = atoi(argv[0]); + if (sec <= 0) { + fprintf(stderr, "Error: seconds (%d) must be >= 1\n", sec); + return 1; + } + + if (argc > 1) + nt = atoi(argv[1]); + + if (nt <= 0) { + fprintf(stderr, "Error: thread count (%d) must be >= 1\n", nt); + return 1; + } + signal(SIGINT, sighandler); signal(SIGALRM, sighandler); - alarm(sec); - pthread_create(&th, NULL, thfunc, test_loop); - test_loop(); - pthread_join(th, NULL); + thread_list = calloc(nt, sizeof(pthread_t)); + if (thread_list == NULL) { + fprintf(stderr, "Error: malloc failed for %d threads\n", nt); + goto out; + } + for (int i = 1; i < nt; i++) { + int ret = pthread_create(&thread_list[i], NULL, thfunc, test_loop); - return 0; + if (ret) { + fprintf(stderr, "Error: failed to create thread %d\n", i); + done = 1; // Ensure started threads terminate. + goto out; + } + } + alarm(sec); + test_loop(); + err = 0; +out: + for (int i = 1; i < nt; i++) { + if (thread_list && thread_list[i]) + pthread_join(thread_list[i], /*retval=*/NULL); + } + free(thread_list); + return err; } DEFINE_WORKLOAD(thloop); diff --git a/tools/perf/tests/workloads/traploop.c b/tools/perf/tests/workloads/traploop.c new file mode 100644 index 000000000000..68dec399a735 --- /dev/null +++ b/tools/perf/tests/workloads/traploop.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <stdlib.h> +#include "../tests.h" + +#define BENCH_RUNS 999999 + +#ifdef __aarch64__ +static void trap_bench(void) +{ + unsigned long val; + + asm("mrs %0, ID_AA64ISAR0_EL1" : "=r" (val)); /* TRAP + ERET */ +} +#else +static void trap_bench(void) { } +#endif + +static int traploop(int argc, const char **argv) +{ + int num_loops = BENCH_RUNS; + + if (argc > 0) + num_loops = atoi(argv[0]); + + for (int i = 0; i < num_loops; i++) + trap_bench(); + + return 0; +} + +DEFINE_WORKLOAD(traploop); |
