diff options
Diffstat (limited to 'tools/perf/tests')
132 files changed, 2965 insertions, 1033 deletions
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index ec4e1f034742..3e8394be15ae 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -5,10 +5,10 @@ perf-test-y += tests-scripts.o perf-test-y += parse-events.o perf-test-y += dso-data.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 @@ -56,6 +56,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 @@ -68,6 +69,7 @@ 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 ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc)) perf-test-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o @@ -80,14 +82,40 @@ 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/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 8dcf74d3c0a3..85142dfb3e01 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -4,8 +4,12 @@ * * 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> @@ -42,6 +46,8 @@ static bool dont_fork; /* 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"; @@ -60,11 +66,9 @@ 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, @@ -126,6 +130,7 @@ static struct test_suite *generic_tests[] = { &suite__maps__merge_in, &suite__demangle_java, &suite__demangle_ocaml, + &suite__demangle_rust, &suite__parse_metric, &suite__pe_file_parsing, &suite__expand_cgroup_events, @@ -135,6 +140,7 @@ static struct test_suite *generic_tests[] = { &suite__event_groups, &suite__symbols, &suite__util, + &suite__subcmd_help, NULL, }; @@ -151,58 +157,116 @@ static struct test_workload *workloads[] = { #define workloads__for_each(workload) \ for (unsigned i = 0; i < ARRAY_SIZE(workloads) && ({ workload = workloads[i]; 1; }); i++) -static int num_subtests(const struct test_suite *t) +#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 bool has_subtests(const struct test_suite *t) +static void check_leaks(void) { - return num_subtests(t) > 1; + 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 int test_suite__num_test_cases(const struct test_suite *t) +{ + 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 subtest) +static bool test_exclusive(const struct test_suite *t, int test_case) { - if (subtest <= 0) + if (test_case <= 0) return t->test_cases[0].exclusive; - return t->test_cases[subtest].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; @@ -214,7 +278,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; } @@ -229,14 +293,24 @@ 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); } @@ -248,9 +322,11 @@ static int run_test_child(struct child_process *process) 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) { - fprintf(stderr, "\n---- unexpected signal (%d) ----\n", err); + /* Received signal. */ err = err > 0 ? -err : -1; goto err_out; } @@ -260,9 +336,10 @@ static int run_test_child(struct child_process *process) pr_debug("--- start ---\n"); pr_debug("test child forked, pid %d\n", getpid()); - err = test_function(child->test, child->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++) @@ -272,15 +349,16 @@ err_out: #define TEST_RUNNING -3 -static int print_test_result(struct test_suite *t, int i, int subtest, int result, int width, - int running) +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: @@ -290,7 +368,7 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resul 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); @@ -312,7 +390,7 @@ static void finish_test(struct child_test **child_tests, int running_test, int c { struct child_test *child_test = child_tests[running_test]; struct test_suite *t; - int i, subi, err; + int curr_suite, curr_test_case, err; bool err_done = false; struct strbuf err_output = STRBUF_INIT; int last_running = -1; @@ -323,15 +401,15 @@ static void finish_test(struct child_test **child_tests, int running_test, int c return; } t = child_test->test; - i = child_test->test_num; - subi = child_test->subtest; + 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 @@ -340,10 +418,11 @@ static void finish_test(struct child_test **child_tests, int running_test, int c 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] = { @@ -368,7 +447,8 @@ static void finish_test(struct child_test **child_tests, int running_test, int c */ fprintf(debug_file(), PERF_COLOR_DELETE_LINE); } - print_test_result(t, i, subi, TEST_RUNNING, width, running); + print_test_result(t, curr_suite, curr_test_case, TEST_RUNNING, + width, running); last_running = running; } } @@ -406,14 +486,14 @@ static void finish_test(struct child_test **child_tests, int running_test, int c fprintf(stderr, "%s", err_output.buf); strbuf_release(&err_output); - print_test_result(t, i, subi, ret, width, /*running=*/0); + print_test_result(t, curr_suite, curr_test_case, ret, width, /*running=*/0); if (err > 0) close(err); zfree(&child_tests[running_test]); } -static int start_test(struct test_suite *test, int i, int subi, struct child_test **child, - int width, int pass) +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; @@ -421,17 +501,18 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes if (dont_fork) { if (pass == 1) { pr_debug("--- start ---\n"); - err = test_function(test, subi)(test, subi); + err = test_function(test, curr_test_case)(test, curr_test_case); pr_debug("---- end ----\n"); - print_test_result(test, i, subi, err, width, /*running=*/0); + print_test_result(test, curr_suite, curr_test_case, err, width, + /*running=*/0); } return 0; } - if (pass == 1 && !sequential && test_exclusive(test, subi)) { + 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, subi))) { + if (pass != 1 && (sequential || !test_exclusive(test, curr_test_case))) { /* Sequential and non-exclusive tests were run on the first pass. */ return 0; } @@ -440,8 +521,8 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes 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) { @@ -481,20 +562,16 @@ static int __cmd_test(struct test_suite **suites, int argc, const char *argv[], int err = 0; for (struct test_suite **t = suites; *t; t++) { - int len = strlen(test_description(*t, -1)); + 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)); @@ -508,11 +585,11 @@ static int __cmd_test(struct test_suite **suites, int argc, const char *argv[], for (size_t x = 0; x < num_tests; x++) { struct child_test *child_test = child_tests[x]; - if (!child_test) + if (!child_test || child_test->process.pid <= 0) continue; pr_debug3("Killing %d pid %d\n", - child_test->test_num + 1, + child_test->suite_num + 1, child_test->process.pid); kill(child_test->process.pid, err); } @@ -528,50 +605,51 @@ static int __cmd_test(struct test_suite **suites, int argc, const char *argv[], */ for (int pass = 1; pass <= 2; pass++) { int child_test_num = 0; - int i = 0; + int curr_suite = 0; - for (struct test_suite **t = suites; *t; t++) { - int curr = i++; + 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, argc, argv)) { + if (!perf_test__matches(test_description(*t, -1), curr_suite, argc, argv)) { /* * Test suite shouldn't be run based on - * description. See if subtest should. + * description. See if any test case should. */ bool skip = true; - for (int subi = 0, subn = num_subtests(*t); subi < subn; subi++) { - if (perf_test__matches(test_description(*t, subi), - curr, argc, argv)) + 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; } - if (intlist__find(skiplist, i)) { - pr_info("%3d: %-*s:", curr + 1, width, test_description(*t, -1)); + 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; } - if (!has_subtests(*t)) { - err = start_test(*t, curr, -1, &child_tests[child_test_num++], - width, pass); - if (err) - goto err_out; - continue; - } - for (int subi = 0, subn = num_subtests(*t); subi < subn; subi++) { - if (!perf_test__matches(test_description(*t, subi), - curr, argc, argv)) - continue; - - err = start_test(*t, curr, subi, &child_tests[child_test_num++], - width, pass); - if (err) - goto err_out; + 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; + } } } if (!sequential) { @@ -592,25 +670,24 @@ err_out: return err; } -static int perf_test__list(struct test_suite **suites, int argc, const char **argv) +static int perf_test__list(FILE *fp, struct test_suite **suites, int argc, const char **argv) { - int i = 0; + int curr_suite = 0; - for (struct test_suite **t = suites; *t; 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; @@ -667,27 +744,24 @@ static struct test_suite **build_suites(void) if (suites[2] == NULL) suites[2] = create_script_test_suites(); -#define for_each_test(t) \ +#define for_each_suite(suite) \ for (size_t i = 0, j = 0; i < ARRAY_SIZE(suites); i++, j = 0) \ - while ((t = suites[i][j++]) != NULL) + while ((suite = suites[i][j++]) != NULL) - for_each_test(t) + for_each_suite(t) num_suites++; result = calloc(num_suites + 1, sizeof(struct test_suite *)); for (int pass = 1; pass <= 2; pass++) { - for_each_test(t) { + for_each_suite(t) { bool exclusive = false; + int curr_test_case; - if (!has_subtests(t)) { - exclusive = test_exclusive(t, -1); - } else { - for (int subi = 0, subn = num_subtests(t); subi < subn; subi++) { - if (test_exclusive(t, subi)) { - exclusive = true; - break; - } + 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)) @@ -695,7 +769,7 @@ static struct test_suite **build_suites(void) } } return result; -#undef for_each_test +#undef for_each_suite } int cmd_test(int argc, const char **argv) @@ -715,6 +789,8 @@ int cmd_test(int argc, const char **argv) "Do not fork for testcase"), OPT_BOOLEAN('S', "sequential", &sequential, "Run the tests one after another rather than in parallel"), + 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"), @@ -738,7 +814,7 @@ int cmd_test(int argc, const char **argv) argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0); if (argc >= 1 && !strcmp(argv[0], "list")) { suites = build_suites(); - ret = perf_test__list(suites, argc - 1, argv + 1); + ret = perf_test__list(stdout, suites, argc - 1, argv + 1); free(suites); return ret; } diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 27c82cfb7e7d..9c2091310191 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include <errno.h> +#include <linux/kconfig.h> #include <linux/kernel.h> #include <linux/types.h> #include <inttypes.h> @@ -8,6 +9,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> @@ -176,16 +178,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; @@ -389,19 +479,25 @@ static int process_sample_event(struct machine *machine, 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); thread__put(thread); +out: + perf_sample__exit(&sample); return ret; } @@ -555,11 +651,12 @@ static int do_test_code_reading(bool try_kcore) struct dso *dso; const char *events[] = { "cycles", "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 +750,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; @@ -702,6 +792,7 @@ out_err: perf_cpu_map__put(cpus); perf_thread_map__put(threads); machine__delete(machine); + perf_env__exit(&host_env); 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 93c94408bdc8..0fb3e5a4a0ed 100644 --- a/tools/perf/tests/demangle-java-test.c +++ b/tools/perf/tests/demangle-java-test.c @@ -3,10 +3,9 @@ #include <stdlib.h> #include <stdio.h> #include <linux/kernel.h> -#include "tests.h" -#include "session.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) { @@ -18,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 < ARRAY_SIZE(test_cases); i++) { - buf = java_demangle_sym(test_cases[i].mangled, 0); + 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 deefe5003bfc..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; 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/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 41ff1affdfcd..726cf8d4da28 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -75,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_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); @@ -245,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 index f8bcee9660d5..151f02701c8c 100644 --- a/tools/perf/tests/hwmon_pmu.c +++ b/tools/perf/tests/hwmon_pmu.c @@ -13,17 +13,23 @@ static const struct test_event { const char *name; const char *alias; - long config; + union hwmon_pmu_event_key key; } test_events[] = { { "temp_test_hwmon_event1", "temp1", - 0xA0001, + .key = { + .num = 1, + .type = 10 + }, }, { "temp_test_hwmon_event2", "temp2", - 0xA0002, + .key = { + .num = 2, + .type = 10 + }, }, }; @@ -65,7 +71,7 @@ static struct perf_pmu *test_pmu_get(char *dir, size_t sz) { "temp2_label", "test hwmon event2\n", }, { "temp2_input", "50000\n", }, }; - int dirfd, file; + int hwmon_dirfd = -1, test_dirfd = -1, file; struct perf_pmu *hwm = NULL; ssize_t len; @@ -76,19 +82,25 @@ static struct perf_pmu *test_pmu_get(char *dir, size_t sz) dir[0] = '\0'; return NULL; } - dirfd = open(dir, O_DIRECTORY); - if (dirfd < 0) { + 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(dirfd, "hwmon1234", 0755) < 0) { + if (mkdirat(test_dirfd, "hwmon1234", 0755) < 0) { pr_err("Failed to mkdir hwmon directory\n"); goto err_out; } - file = openat(dirfd, "hwmon1234/name", O_WRONLY | O_CREAT, 0600); - if (!file) { + 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; } @@ -104,8 +116,8 @@ static struct perf_pmu *test_pmu_get(char *dir, size_t sz) for (size_t i = 0; i < ARRAY_SIZE(test_items); i++) { const struct test_item *item = &test_items[i]; - file = openat(dirfd, item->name, O_WRONLY | O_CREAT, 0600); - if (!file) { + 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; } @@ -119,16 +131,18 @@ static struct perf_pmu *test_pmu_get(char *dir, size_t sz) } /* Make the PMU reading the files created above. */ - hwm = perf_pmus__add_test_hwmon_pmu(dirfd, "hwmon1234", test_hwmon_name); + 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 (dirfd >= 0) - close(dirfd); } + if (test_dirfd >= 0) + close(test_dirfd); + if (hwmon_dirfd >= 0) + close(hwmon_dirfd); return hwm; } @@ -176,11 +190,11 @@ static int do_test(size_t i, bool with_pmu, bool with_alias) strcmp(evsel->pmu->name, "hwmon_a_test_hwmon_pmu")) continue; - if (evsel->core.attr.config != (u64)test_events[i].config) { + 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].config); + test_events[i].key.type_and_num); ret = TEST_FAIL; goto out; } diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index 5a3b2bed07f3..eafb49eb0b56 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(); diff --git a/tools/perf/tests/make b/tools/perf/tests/make index a7fcbd589752..c574a678c28a 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -81,23 +81,21 @@ 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_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" @@ -122,10 +120,10 @@ make_static := LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX3 # 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_BACKTRACE=1 -make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 +make_minimal += NO_LIBNUMA=1 NO_LIBBIONIC=1 NO_LIBDW=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_SDT=1 NO_JVMTI=1 NO_LIBZSTD=1 +make_minimal += NO_LIBCAP=1 NO_CAPSTONE=1 # $(run) contains all available tests run := make_pure @@ -153,17 +151,16 @@ run += make_no_gtk2 run += make_no_ui run += make_no_demangle run += make_no_libelf +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/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 012c8ae439fd..3c89d3001887 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 (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 3943da441979..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, @@ -111,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); 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 82a19674a38f..bb8004397650 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -54,8 +54,6 @@ static bool test_perf_config(const struct perf_evsel *evsel, __u64 expected_conf return (evsel->attr.config & PERF_HW_EVENT_MASK) == expected_config; } -#ifdef HAVE_LIBTRACEEVENT - #if defined(__s390x__) /* Return true if kvm module is available and loaded. Test this * and return success when trace point kvm_s390_create_vm @@ -112,7 +110,6 @@ static int test__checkevent_tracepoint_multi(struct evlist *evlist) } return TEST_OK; } -#endif /* HAVE_LIBTRACEEVENT */ static int test__checkevent_raw(struct evlist *evlist) { @@ -311,7 +308,6 @@ static int test__checkevent_breakpoint_rw(struct evlist *evlist) return TEST_OK; } -#ifdef HAVE_LIBTRACEEVENT static int test__checkevent_tracepoint_modifier(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); @@ -340,7 +336,6 @@ test__checkevent_tracepoint_multi_modifier(struct evlist *evlist) return test__checkevent_tracepoint_multi(evlist); } -#endif /* HAVE_LIBTRACEEVENT */ static int test__checkevent_raw_modifier(struct evlist *evlist) { @@ -629,7 +624,6 @@ static int test__checkevent_pmu(struct evlist *evlist) return TEST_OK; } -#ifdef HAVE_LIBTRACEEVENT static int test__checkevent_list(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); @@ -671,7 +665,6 @@ static int test__checkevent_list(struct evlist *evlist) return TEST_OK; } -#endif static int test__checkevent_pmu_name(struct evlist *evlist) { @@ -726,20 +719,20 @@ static int test__checkevent_pmu_partial_time_callgraph(struct evlist *evlist) static int test__checkevent_pmu_events(struct evlist *evlist) { - struct evsel *evsel = evlist__first(evlist); + struct evsel *evsel; - 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_VAL("wrong number of entries", 1 <= evlist->core.nr_entries); + evlist__for_each_entry(evlist, evsel) { + 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); + } return TEST_OK; } @@ -971,7 +964,6 @@ static int test__group2(struct evlist *evlist) return TEST_OK; } -#ifdef HAVE_LIBTRACEEVENT static int test__group3(struct evlist *evlist __maybe_unused) { struct evsel *evsel, *group1_leader = NULL, *group2_leader = NULL; @@ -1078,7 +1070,6 @@ static int test__group3(struct evlist *evlist __maybe_unused) } return TEST_OK; } -#endif static int test__group4(struct evlist *evlist __maybe_unused) { @@ -1813,7 +1804,6 @@ static int test__term_equal_legacy(struct evlist *evlist) return TEST_OK; } -#ifdef HAVE_LIBTRACEEVENT static int count_tracepoints(void) { struct dirent *events_ent; @@ -1867,7 +1857,6 @@ static int test__all_tracepoints(struct evlist *evlist) return test__checkevent_tracepoint_multi(evlist); } -#endif /* HAVE_LIBTRACEVENT */ struct evlist_test { const char *name; @@ -1876,7 +1865,6 @@ struct evlist_test { }; static const struct evlist_test test__events[] = { -#ifdef HAVE_LIBTRACEEVENT { .name = "syscalls:sys_enter_openat", .check = test__checkevent_tracepoint, @@ -1887,7 +1875,6 @@ static const struct evlist_test test__events[] = { .check = test__checkevent_tracepoint_multi, /* 1 */ }, -#endif { .name = "r1a", .check = test__checkevent_raw, @@ -1938,7 +1925,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, @@ -1949,7 +1935,6 @@ static const struct evlist_test test__events[] = { .check = test__checkevent_tracepoint_multi_modifier, /* 3 */ }, -#endif { .name = "r1a:kp", .check = test__checkevent_raw_modifier, @@ -1995,13 +1980,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, @@ -2032,13 +2015,11 @@ static const struct evlist_test test__events[] = { .check = test__group2, /* 9 */ }, -#ifdef HAVE_LIBTRACEEVENT { .name = "group1{syscalls:sys_enter_openat:H,cycles:kppp},group2{cycles,1:3}:G,instructions:u", .check = test__group3, /* 0 */ }, -#endif { .name = "{cycles:u,instructions:kp}:p", .check = test__group4, @@ -2049,13 +2030,11 @@ static const struct evlist_test test__events[] = { .check = test__group5, /* 2 */ }, -#ifdef HAVE_LIBTRACEEVENT { .name = "*:*", .check = test__all_tracepoints, /* 3 */ }, -#endif { .name = "{cycles,cache-misses:G}:H", .check = test__group_gh1, @@ -2111,7 +2090,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, @@ -2265,13 +2244,11 @@ 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 }; static const struct evlist_test test__events_pmu[] = { diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c index 2c28fb50dc24..66a5275917e2 100644 --- a/tools/perf/tests/parse-metric.c +++ b/tools/perf/tests/parse-metric.c @@ -45,15 +45,14 @@ static void load_runtime_stat(struct evlist *evlist, struct value *vals) } } -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 +68,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 +91,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 +104,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..0b3c37e66871 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -45,7 +45,6 @@ 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, @@ -70,6 +69,7 @@ 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]; + perf_sample__init(&sample, /*all=*/false); if (evlist == NULL) /* Fallback for kernels lacking PERF_COUNT_SW_DUMMY */ evlist = evlist__new_default(); @@ -330,6 +330,7 @@ found_exit: out_delete_evlist: 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..d4437410c99f 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(); @@ -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/pmu-events.c b/tools/perf/tests/pmu-events.c index db004d26fcb0..95fd9f671a22 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -38,7 +38,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]; }; @@ -51,7 +53,6 @@ static const struct perf_pmu_test_event bp_l1_btb_correct = { .topic = "branch", }, .alias_str = "event=0x8a", - .alias_long_desc = "L1 BTB Correction", }; static const struct perf_pmu_test_event bp_l2_btb_correct = { @@ -63,7 +64,6 @@ static const struct perf_pmu_test_event bp_l2_btb_correct = { .topic = "branch", }, .alias_str = "event=0x8b", - .alias_long_desc = "L2 BTB Correction", }; static const struct perf_pmu_test_event segment_reg_loads_any = { @@ -75,7 +75,6 @@ static const struct perf_pmu_test_event segment_reg_loads_any = { .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 = { @@ -87,7 +86,6 @@ static const struct perf_pmu_test_event dispatch_blocked_any = { .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 = { @@ -99,7 +97,6 @@ static const struct perf_pmu_test_event eist_trans = { .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 = { @@ -131,11 +128,9 @@ 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 +140,9 @@ 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 +152,9 @@ 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 +164,9 @@ 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 +176,9 @@ 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 +188,9 @@ 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 +200,9 @@ 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", }; @@ -244,7 +227,6 @@ static const struct perf_pmu_test_event sys_ddr_pmu_write_cycles = { .compat = "v8", }, .alias_str = "event=0x2b", - .alias_long_desc = "ddr write-cycles event", .matching_pmu = "uncore_sys_ddr_pmu0", }; @@ -258,7 +240,6 @@ static const struct perf_pmu_test_event sys_ccn_pmu_read_cycles = { .compat = "0x01", }, .alias_str = "config=0x2c", - .alias_long_desc = "ccn read-cycles event", .matching_pmu = "uncore_sys_ccn_pmu4", }; @@ -272,7 +253,6 @@ static const struct perf_pmu_test_event sys_cmn_pmu_hnf_cache_miss = { .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", }; @@ -553,11 +533,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 +573,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 +612,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 +626,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 +638,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 +671,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 +773,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 +846,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 +870,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")) { @@ -927,7 +897,7 @@ static int test__parsing_callback(const struct pmu_metric *pm, 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 +919,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 6a681e3fb552..4a9f8e090cf4 100644 --- a/tools/perf/tests/pmu.c +++ b/tools/perf/tests/pmu.c @@ -452,9 +452,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) @@ -463,41 +463,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 @@ -505,7 +508,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 @@ -513,19 +516,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/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..7045ec72ba4c --- /dev/null +++ b/tools/perf/tests/shell/amd-ibs-swfilt.sh @@ -0,0 +1,67 @@ +#!/bin/bash +# AMD IBS software filtering + +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" + +# 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 + +# 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 + +# 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 +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 + +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 + +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 diff --git a/tools/perf/tests/shell/annotate.sh b/tools/perf/tests/shell/annotate.sh index 1590a37363de..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 --no-demangle -i "${perfdata}" --stdio 2> /dev/null | head -250 > "${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 --no-demangle -i "${perfdata}" "${testsym}" 2> /dev/null | \ - head -250 | 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 --no-demangle -i "${perfdata}" --objdump=objdump 2> /dev/null | \ - head -250 | 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/base_probe/test_adding_blacklisted.sh b/tools/perf/tests/shell/base_probe/test_adding_blacklisted.sh index bead723e34af..8226449ac5c3 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 # @@ -22,7 +22,7 @@ TEST_RESULT=0 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 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..df288cf90cd6 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 # @@ -33,7 +33,7 @@ fi check_kprobes_available if [ $? -ne 0 ]; then print_overall_skipped - exit 0 + exit 2 fi @@ -169,7 +169,7 @@ print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "force-adding probes :: second pr (( 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=$? @@ -205,7 +205,7 @@ 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 +../common/check_all_patterns_found.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" diff --git a/tools/perf/tests/shell/base_probe/test_basic.sh b/tools/perf/tests/shell/base_probe/test_basic.sh index 09669ec479f2..9d8b5afbeddd 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 # @@ -19,7 +19,7 @@ TEST_RESULT=0 if ! check_kprobes_available; then print_overall_skipped - exit 0 + exit 2 fi 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..92f7254eb32a 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 # @@ -19,9 +19,12 @@ TEST_RESULT=0 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 @@ -75,5 +78,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..20435b6bf6bc 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 # @@ -20,9 +20,12 @@ TEST_RESULT=0 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 +54,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..8634e7e0dda6 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 # @@ -15,6 +15,8 @@ # include working environment . ../common/init.sh +TEST_RESULT=0 + test -d "$HEADER_TAR_DIR" || mkdir -p "$HEADER_TAR_DIR" SW_EVENT="cpu-clock" @@ -26,7 +28,21 @@ PERF_EXIT_CODE=$? 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 ================== + +../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..adfd8713b8f8 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 # @@ -183,6 +183,58 @@ 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=$? + +../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=$? + +../common/check_all_patterns_found.pl "# Overhead Latency Command" < $LOGS_DIR/latency_default.log +CHECK_EXIT_CODE=$? +../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=$? + +../common/check_all_patterns_found.pl "# Latency Overhead Command" < $LOGS_DIR/latency_latency.log +CHECK_EXIT_CODE=$? +../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=$? + +../common/check_all_patterns_found.pl "# Latency Parallelism / Command / Symbol" < $LOGS_DIR/parallelism_hierarchy.log +CHECK_EXIT_CODE=$? +../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..d2eb213da01d 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 diff --git a/tools/perf/tests/shell/common/init.sh b/tools/perf/tests/shell/common/init.sh index 075f17623c8e..26c7525651e0 100644 --- a/tools/perf/tests/shell/common/init.sh +++ b/tools/perf/tests/shell/common/init.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 c63bc8c73e26..0301904b9637 100755 --- a/tools/perf/tests/shell/coresight/asm_pure_loop.sh +++ b/tools/perf/tests/shell/coresight/asm_pure_loop.sh @@ -1,4 +1,4 @@ -#!/bin/sh -e +#!/bin/bash -e # CoreSight / ASM Pure Loop (exclusive) # SPDX-License-Identifier: GPL-2.0 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_16k_10.sh b/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh index 8e29630957c8..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,4 +1,4 @@ -#!/bin/sh -e +#!/bin/bash -e # CoreSight / Memcpy 16k 10 Threads (exclusive) # SPDX-License-Identifier: GPL-2.0 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 0c4c82a1c8e1..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,4 +1,4 @@ -#!/bin/sh -e +#!/bin/bash -e # CoreSight / Thread Loop 10 Threads - Check TID (exclusive) # SPDX-License-Identifier: GPL-2.0 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 d3aea9fc6ced..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,4 +1,4 @@ -#!/bin/sh -e +#!/bin/bash -e # CoreSight / Thread Loop 2 Threads - Check TID (exclusive) # SPDX-License-Identifier: GPL-2.0 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 7429d3a2ae43..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,4 +1,4 @@ -#!/bin/sh -e +#!/bin/bash -e # CoreSight / Unroll Loop Thread 10 (exclusive) # SPDX-License-Identifier: GPL-2.0 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/ftrace.sh b/tools/perf/tests/shell/ftrace.sh index 2df05052c324..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,11 +67,8 @@ test_ftrace_latency() { test_ftrace_profile() { echo "perf ftrace profile test" - perf ftrace profile -m 16M 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:]]+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 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/lib/attr.py b/tools/perf/tests/shell/lib/attr.py index 3db9a7d78715..bfccc727d9b2 100644 --- a/tools/perf/tests/shell/lib/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('|') 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 8ddb85586131..c6750ef06c0f 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() @@ -44,7 +45,7 @@ def is_counter_value(num): 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, @@ -64,21 +65,25 @@ def check_json_output(expected_items): 'socket': lambda x: True, 'thread': lambda x: True, 'unit': lambda x: True, + 'insn per cycle': lambda x: isfloat(x), + 'GHz': lambda x: True, # FIXME: it seems unintended for --metric-only } input = '[\n' + ','.join(Lines) + '\n]' for item in json.loads(input): if expected_items != -1: count = len(item) - if count != expected_items and count >= 1 and count <= 7 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 + 1 and 'metric-threshold' in item: + elif count - 1 in expected_items and 'metric-threshold' in item: pass - elif count != expected_items: + 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(): @@ -90,11 +95,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..c2ec7881ec1d 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 -e instructions,cycles 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 76a9846cff22..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 diff --git a/tools/perf/tests/shell/lock_contention.sh b/tools/perf/tests/shell/lock_contention.sh index 30d195d4c62f..d33d9e4392b0 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 @@ -44,7 +44,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 +64,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,7 +75,7 @@ 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> /dev/null | \ 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)" @@ -99,7 +99,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 +122,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 +140,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 -g -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 +162,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 +194,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 +222,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 +250,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 +266,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 -g -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 +274,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 -g -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 +309,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}" 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/probe_vfs_getname.sh b/tools/perf/tests/shell/probe_vfs_getname.sh index 0c5aacc446b3..5fe5682c28ce 100755 --- a/tools/perf/tests/shell/probe_vfs_getname.sh +++ b/tools/perf/tests/shell/probe_vfs_getname.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Add vfs_getname probe to get syscall args filenames (exclusive) # SPDX-License-Identifier: GPL-2.0 @@ -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/record+probe_libc_inet_pton.sh b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh index 47a26f25db9f..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" @@ -43,17 +44,8 @@ trace_libc_inet_pton_backtrace() { echo "((__GI_)?getaddrinfo|text_to_binary_address)\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" >> $expected echo "(gaih_inet|main)\+0x[[:xdigit:]]+[[:space:]]\(inlined|.*/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 - ;; *) - 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 5940fdc1df37..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,4 +1,4 @@ -#!/bin/sh +#!/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 @@ -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 0fc7a909ae9b..b1ad24fb3b33 100755 --- a/tools/perf/tests/shell/record.sh +++ b/tools/perf/tests/shell/record.sh @@ -12,8 +12,10 @@ 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) @@ -34,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 } @@ -229,31 +233,77 @@ 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 "{instructions,instructions}:Su" -- \ + 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 - perf script -i "${perfdata}" > $script_output + valid_counts=0 + invalid_counts=0 + tolerance_rate=0.8 while IFS= read -r line do - # Check if the two instruction counts are equal in each record - instructions=$(echo $line | awk '{for(i=1;i<=NF;i++) if($i=="instructions:") print $(i-1)}') - if [ $(($index%2)) -ne 0 ] && [ ${instructions}x != ${prev_instructions}x ] + 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 - echo "Leader sampling [Failed inconsistent instructions count]" - err=1 - return + invalid_counts=$(($invalid_counts+1)) + else + valid_counts=$(($valid_counts+1)) fi index=$(($index+1)) - prev_instructions=$instructions - done < $script_output - echo "Basic leader sampling test [Success]" + 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() { @@ -273,27 +323,69 @@ test_topdown_leader_sampling() { } test_precise_max() { + local -i skipped=0 + echo "precise_max attribute test" - if ! perf stat -e "cycles,instructions" true 2> /dev/null + # 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]" - return + else + echo "precise_max attribute test [Success]" fi - # Just to make sure it doesn't fail - if ! perf record -o "${perfdata}" -e "cycles:P" true 2> /dev/null +} + +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 "precise_max attribute [Failed cycles:P event]" + echo "Callgraph test [Failed missing output]" err=1 return fi - # On AMD, cycles and instructions events are treated differently - if ! perf record -o "${perfdata}" -e "instructions:P" true 2> /dev/null + + if ! perf report -i "${perfdata}" 2>&1 | grep "${testsym2}" then - echo "precise_max attribute [Failed instructions:P event]" + echo "Callgraph test [Failed missing symbol]" err=1 return fi - echo "precise_max attribute test [Success]" + + echo "Callgraph test [Success]" } # raise the limit of file descriptors to minimum @@ -307,9 +399,11 @@ test_system_wide test_workload test_branch_counter test_cgroup +test_uid test_leader_sampling test_topdown_leader_sampling test_precise_max +test_callgraph # 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 8d750ee631f8..6fcb5e52b9b4 100755 --- a/tools/perf/tests/shell/record_lbr.sh +++ b/tools/perf/tests/shell/record_lbr.sh @@ -4,7 +4,8 @@ set -e -if [ ! -f /sys/devices/cpu/caps/branches ] && [ ! -f /sys/devices/cpu_core/caps/branches ] +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 @@ -93,7 +94,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%]" diff --git a/tools/perf/tests/shell/record_offcpu.sh b/tools/perf/tests/shell/record_offcpu.sh index 678947fe69ee..860a2d6f4b75 100755 --- a/tools/perf/tests/shell/record_offcpu.sh +++ b/tools/perf/tests/shell/record_offcpu.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf record offcpu profiling tests (exclusive) # SPDX-License-Identifier: GPL-2.0 @@ -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/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/stat+csv_output.sh b/tools/perf/tests/shell/stat+csv_output.sh index fc2d8cc6e5e0..7a6f6e177402 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=2 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..bf54bd6c3e2e --- /dev/null +++ b/tools/perf/tests/shell/stat+event_uniquifying.sh @@ -0,0 +1,77 @@ +#!/bin/bash +# perf stat events uniquifying +# SPDX-License-Identifier: GPL-2.0 + +set -e + +stat_output=$(mktemp /tmp/__perf_test.stat_output.XXXXX) +perf_tool=perf +err=0 + +test_event_uniquifying() { + # We use `clockticks` in `uncore_imc` to verify the uniquify behavior. + pmu="uncore_imc" + event="clockticks" + + # If the `-A` option is added, the event should be uniquified. + # + # $perf list -v clockticks + # + # List of pre-defined events (to be used in -e or -M): + # + # uncore_imc_0/clockticks/ [Kernel PMU event] + # uncore_imc_1/clockticks/ [Kernel PMU event] + # uncore_imc_2/clockticks/ [Kernel PMU event] + # uncore_imc_3/clockticks/ [Kernel PMU event] + # uncore_imc_4/clockticks/ [Kernel PMU event] + # uncore_imc_5/clockticks/ [Kernel PMU event] + # + # ... + # + # $perf stat -e clockticks -A -- true + # + # Performance counter stats for 'system wide': + # + # CPU0 3,773,018 uncore_imc_0/clockticks/ + # CPU0 3,609,025 uncore_imc_1/clockticks/ + # CPU0 0 uncore_imc_2/clockticks/ + # CPU0 3,230,009 uncore_imc_3/clockticks/ + # CPU0 3,049,897 uncore_imc_4/clockticks/ + # CPU0 0 uncore_imc_5/clockticks/ + # + # 0.002029828 seconds time elapsed + + echo "stat event uniquifying test" + uniquified_event_array=() + + # Skip if the machine does not have `uncore_imc` device. + if ! ${perf_tool} list pmu | grep -q ${pmu}; then + echo "Target does not support PMU ${pmu} [Skipped]" + err=2 + return + fi + + # Check how many uniquified events. + while IFS= read -r line; do + uniquified_event=$(echo "$line" | awk '{print $1}') + uniquified_event_array+=("${uniquified_event}") + done < <(${perf_tool} list -v ${event} | grep ${pmu}) + + perf_command="${perf_tool} stat -e $event -A -o ${stat_output} -- true" + $perf_command + + # Check the output contains all uniquified events. + for uniquified_event in "${uniquified_event_array[@]}"; do + if ! cat "${stat_output}" | grep -q "${uniquified_event}"; then + echo "Event is not uniquified [Failed]" + echo "${perf_command}" + cat "${stat_output}" + err=1 + break + fi + done +} + +test_event_uniquifying +rm -f "${stat_output}" +exit $err diff --git a/tools/perf/tests/shell/stat+json_output.sh b/tools/perf/tests/shell/stat+json_output.sh index 6b630d33c328..98fb65274ac4 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 -e instructions,cycles -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..8824f445d343 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 diff --git a/tools/perf/tests/shell/stat+std_output.sh b/tools/perf/tests/shell/stat+std_output.sh index cbf2894b2c84..6fee67693ba7 100755 --- a/tools/perf/tests/shell/stat+std_output.sh +++ b/tools/perf/tests/shell/stat+std_output.sh @@ -13,7 +13,7 @@ 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") +skip_metric=("stalled cycles per insn" "tma_" "retiring" "frontend_bound" "bad_speculation" "backend_bound" "TopdownL1" "percent of slots") 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,8 @@ function commachecker() exit 1; } done < "${stat_output}" + + [ $metric_only -eq 1 ] && exit 1 return 0 } @@ -95,6 +102,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 7a8adf81e4b3..8a100a7f2dc1 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 @@ -67,43 +67,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 'instructions,topdown-retiring,slots' true 2>&1 | grep -E -q "<not supported>" - then - echo "Topdown event group test [Failed slots not reordered first in no-group case]" - err=1 - return - fi - if perf stat -e '{instructions,topdown-retiring,slots}' true 2>&1 | grep -E -q "<not supported>" - then - echo "Topdown event group test [Failed slots not reordered first in single group case]" - err=1 - return - fi - if perf stat -e '{instructions,slots},topdown-retiring' true 2>&1 | grep -E -q "<not supported>" - then - echo "Topdown event group test [Failed topdown metrics event not move into slots group]" - err=1 - return - fi - if perf stat -e '{instructions,slots},{topdown-retiring}' true 2>&1 | grep -E -q "<not supported>" - then - echo "Topdown event group test [Failed topdown metrics group not merge into slots group]" - err=1 - return - fi - if perf stat -e '{instructions,r400,r8000}' 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 raw format 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() { @@ -187,7 +198,11 @@ test_hybrid() { # Run default Perf stat cycles_events=$(perf stat -- true 2>&1 | grep -E "/cycles/[uH]*| cycles[:uH]* " -c) - if [ "$pmus" -ne "$cycles_events" ] + # 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 diff --git a/tools/perf/tests/shell/stat_all_metrics.sh b/tools/perf/tests/shell/stat_all_metrics.sh index 73e9347e88a9..6fa585a1e34c 100755 --- a/tools/perf/tests/shell/stat_all_metrics.sh +++ b/tools/perf/tests/shell/stat_all_metrics.sh @@ -7,80 +7,96 @@ 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" $system_wide_flag -- sleep 0.01 2>&1) + result=$(perf stat -M "$m" $system_wide_flag -- $test_prog 2>&1) result_err=$? - if [[ $result_err -gt 0 ]] + if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] then - if [[ "$result" =~ \ - "Access to performance monitoring and observability operations is limited" ]] + # No error result and metric shown. + continue + fi + if [[ "$result" =~ "Cannot resolve IDs for" ]] + then + echo "Metric contains missing events" + echo $result + err=1 # Fail + continue + elif [[ "$result" =~ \ + "Access to performance monitoring and observability operations is limited" ]] + then + echo "Permission failure" + echo $result + if [[ $err -eq 0 ]] then - echo "Permission failure" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue - elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] + err=2 # Skip + fi + continue + elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] + then + echo "Permissions - need system wide mode" + echo $result + if [[ $err -eq 0 ]] then - echo "Permissions - need system wide mode" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue - elif [[ "$result" =~ "<not supported>" ]] + err=2 # Skip + fi + continue + elif [[ "$result" =~ "<not supported>" ]] + then + echo "Not supported events" + echo $result + if [[ $err -eq 0 ]] then - echo "Not supported events" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue - elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] + err=2 # Skip + fi + continue + elif [[ "$result" =~ "<not counted>" ]] + then + echo "Not counted events" + echo $result + if [[ $err -eq 0 ]] then - echo "FP issues" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue - elif [[ "$result" =~ "PMM" ]] + err=2 # Skip + fi + continue + elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] + then + echo "FP issues" + echo $result + if [[ $err -eq 0 ]] then - echo "Optane memory issues" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue + err=2 # Skip fi - fi - - if [[ "$result" =~ ${m:0:50} ]] + continue + elif [[ "$result" =~ "PMM" ]] then + echo "Optane memory issues" + echo $result + if [[ $err -eq 0 ]] + then + 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) - if [[ "$result" =~ ${m:0:50} ]] + result_err=$? + if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] then + # No error result and metric shown. continue fi - echo "Metric '$m' not printed in:" + echo "Metric '$m' has non-zero error '$result_err' or not printed in:" echo "$result" err=1 done 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 8b148b300be1..9c466c0efa85 100755 --- a/tools/perf/tests/shell/stat_all_pmu.sh +++ b/tools/perf/tests/shell/stat_all_pmu.sh @@ -2,7 +2,6 @@ # perf all PMU test (exclusive) # SPDX-License-Identifier: GPL-2.0 -set -e err=0 result="" @@ -16,34 +15,55 @@ 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 -n "Testing $p -- " + output=$(perf stat -e "$p" true 2>&1) + stat_result=$? + if echo "$output" | grep -q "$p" then # Event seen in output. - continue - fi - if echo "$result" | grep -q "<not supported>" - then - # Event not supported, so ignore. - continue + 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 "$result" | grep -q "Access to performance monitoring and observability operations is limited." + + 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. - result=$(perf stat -e "$p" perf bench internals synthesize 2>&1) - if echo "$result" | grep -q "$p" + 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 "$result" + echo "$output" err=1 done diff --git a/tools/perf/tests/shell/stat_bpf_counters.sh b/tools/perf/tests/shell/stat_bpf_counters.sh index 95d2ad5d17c6..f43e28a136d3 100755 --- a/tools/perf/tests/shell/stat_bpf_counters.sh +++ b/tools/perf/tests/shell/stat_bpf_counters.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf stat --bpf-counters test (exclusive) # SPDX-License-Identifier: GPL-2.0 diff --git a/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh b/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh index 2ec69060c42f..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 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 573af9235b72..1c750b67d141 100755 --- a/tools/perf/tests/shell/test_arm_coresight.sh +++ b/tools/perf/tests/shell/test_arm_coresight.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Check Arm CoreSight trace data recording and synthesized samples (exclusive) # Uses the 'perf record' to record trace data with Arm CoreSight sinks; diff --git a/tools/perf/tests/shell/test_arm_coresight_disasm.sh b/tools/perf/tests/shell/test_arm_coresight_disasm.sh index be2d26303f94..0dfb4fadf531 100755 --- a/tools/perf/tests/shell/test_arm_coresight_disasm.sh +++ b/tools/perf/tests/shell/test_arm_coresight_disasm.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Check Arm CoreSight disassembly script completes without errors (exclusive) # SPDX-License-Identifier: GPL-2.0 diff --git a/tools/perf/tests/shell/test_arm_spe.sh b/tools/perf/tests/shell/test_arm_spe.sh index 3258368634f7..bb76ea88aa14 100755 --- a/tools/perf/tests/shell/test_arm_spe.sh +++ b/tools/perf/tests/shell/test_arm_spe.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Check Arm SPE trace data recording and synthesized samples (exclusive) # Uses the 'perf record' to record trace data of Arm SPE events; @@ -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 8efeef9fb956..5bcca51c03ac 100755 --- a/tools/perf/tests/shell/test_arm_spe_fork.sh +++ b/tools/perf/tests/shell/test_arm_spe_fork.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Check Arm SPE doesn't hang when there are forks # SPDX-License-Identifier: GPL-2.0 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..69e3c2055134 --- /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; + } + ' | egrep "$VERS" > /dev/null + 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..9138fa83bf36 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,35 +17,50 @@ 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 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 + if ! tr -s ' ' '\n' < "$TMPDIR/perf.script" | grep -E -m1 -q "$x" + then + echo "Branches missing $x" + err=1 + fi + done # some branch types are still not being tested: # IND COND_CALL COND_RET SYSCALL SYSRET IRQ SERROR NO_TX } @@ -57,14 +72,28 @@ 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 } @@ -80,3 +109,6 @@ 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" + +cleanup +exit $err diff --git a/tools/perf/tests/shell/test_data_symbol.sh b/tools/perf/tests/shell/test_data_symbol.sh index c86da0235059..d61b5659a46d 100755 --- a/tools/perf/tests/shell/test_data_symbol.sh +++ b/tools/perf/tests/shell/test_data_symbol.sh @@ -5,8 +5,6 @@ # 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_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh index e6f0070975f6..8ee761f03c38 100755 --- a/tools/perf/tests/shell/test_intel_pt.sh +++ b/tools/perf/tests/shell/test_intel_pt.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Miscellaneous Intel PT testing (exclusive) # SPDX-License-Identifier: GPL-2.0 @@ -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 f95fc64bf0a7..a330ecdb7ba5 100755 --- a/tools/perf/tests/shell/test_stat_intel_tpebs.sh +++ b/tools/perf/tests/shell/test_stat_intel_tpebs.sh @@ -3,20 +3,83 @@ # 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 ] +} -# Hybrid platforms output like "cpu_atom/cache-misses/R", rather than as above -alt_name=/cache-misses/R +if ! grep -q GenuineIntel /proc/cpuinfo +then + echo "Skipping non-Intel" + exit 2 +fi -# 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 || "$result" =~ $alt_name ]] || exit 1 +if ParanoidAndNotRoot 0 +then + echo "Skipping paranoid >0 and not root" + 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 || "$result" =~ $alt_name ]] || exit 1 +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/trace+probe_vfs_getname.sh b/tools/perf/tests/shell/trace+probe_vfs_getname.sh index 708a13f00635..7a0b1145d0cd 100755 --- a/tools/perf/tests/shell/trace+probe_vfs_getname.sh +++ b/tools/perf/tests/shell/trace+probe_vfs_getname.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/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 @@ -15,6 +15,7 @@ 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 @@ -24,9 +25,14 @@ trace_open_vfs_getname() { 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..572001d75d78 100755 --- a/tools/perf/tests/shell/trace_btf_enum.sh +++ b/tools/perf/tests/shell/trace_btf_enum.sh @@ -1,22 +1,22 @@ -#!/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 @@ -26,25 +26,31 @@ check_vmlinux() { 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 } 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 index fbb0adc33a88..db300cde94fb 100755 --- a/tools/perf/tests/shell/trace_exit_race.sh +++ b/tools/perf/tests/shell/trace_exit_race.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # perf trace exit race # SPDX-License-Identifier: GPL-2.0 @@ -10,6 +10,7 @@ . "$(dirname $0)"/lib/probe.sh skip_if_no_perf_trace || exit 2 +[ "$(id -u)" = 0 ] || exit 2 if [ "$1" = "-v" ]; then verbose="1" 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..5be294014d3b 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, @@ -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 8e328bbd509d..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 }; diff --git a/tools/perf/tests/tests-scripts.c b/tools/perf/tests/tests-scripts.c index cf3ae0c1d871..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,7 @@ 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); @@ -260,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 cb58b43aa063..97e62db8764a 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, @@ -71,6 +72,15 @@ struct test_suite { .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), \ @@ -81,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); @@ -147,6 +167,7 @@ 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); @@ -157,6 +178,7 @@ DECLARE_SUITE(sigtrap); DECLARE_SUITE(event_groups); DECLARE_SUITE(symbols); DECLARE_SUITE(util); +DECLARE_SUITE(subcmd_help); /* * PowerPC and S390 do not support creation of instruction breakpoints using the 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 index 187942b749b7..1e900ef92e37 100644 --- a/tools/perf/tests/tool_pmu.c +++ b/tools/perf/tests/tool_pmu.c @@ -27,7 +27,7 @@ static int do_test(enum tool_pmu_event ev, bool with_pmu) parse_events_error__init(&err); ret = parse_events(evlist, str, &err); if (ret) { - if (tool_pmu__skip_event(tool_pmu__event_to_str(ev))) { + if (!tool_pmu__event_to_str(ev)) { ret = TEST_OK; goto out; } @@ -59,7 +59,7 @@ static int do_test(enum tool_pmu_event ev, bool with_pmu) } } - if (!found && !tool_pmu__skip_event(tool_pmu__event_to_str(ev))) { + 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; 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/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]); |