diff options
Diffstat (limited to 'tools/perf/tests')
24 files changed, 1243 insertions, 301 deletions
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 650aec19d490..803ca426f8e6 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -64,6 +64,7 @@ perf-y += parse-metric.o perf-y += pe-file-parsing.o perf-y += expand-cgroup.o perf-y += perf-time-to-tsc.o +perf-y += dlfilter-test.o $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build $(call rule_mkdir) diff --git a/tools/perf/tests/bitmap.c b/tools/perf/tests/bitmap.c index 96c137360918..12b805efdca0 100644 --- a/tools/perf/tests/bitmap.c +++ b/tools/perf/tests/bitmap.c @@ -14,7 +14,7 @@ static unsigned long *get_bitmap(const char *str, int nbits) unsigned long *bm = NULL; int i; - bm = bitmap_alloc(nbits); + bm = bitmap_zalloc(nbits); if (map && bm) { for (i = 0; i < map->nr; i++) diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c index c72adbd67386..dbf5f5215abe 100644 --- a/tools/perf/tests/bpf.c +++ b/tools/perf/tests/bpf.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <errno.h> #include <stdio.h> +#include <stdlib.h> #include <sys/epoll.h> #include <sys/types.h> #include <sys/stat.h> @@ -151,7 +152,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void), } evlist__splice_list_tail(evlist, &parse_state.list); - evlist->nr_groups = parse_state.nr_groups; + evlist->core.nr_groups = parse_state.nr_groups; evlist__config(evlist, &opts, NULL); @@ -276,6 +277,7 @@ static int __test__bpf(int idx) } out: + free(obj_buf); bpf__clear(); return ret; } diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index c4b888f18e9c..da7dc5e45d0c 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -26,6 +26,7 @@ #include <linux/kernel.h> #include <linux/string.h> #include <subcmd/exec-cmd.h> +#include <linux/zalloc.h> static bool dont_fork; @@ -360,6 +361,10 @@ static struct test generic_tests[] = { .is_supported = test__tsc_is_supported, }, { + .desc = "dlfilter C API", + .func = test__dlfilter, + }, + { .func = NULL, }, }; @@ -510,8 +515,8 @@ static const char *shell_test__description(char *description, size_t size, return description ? strim(description + 1) : NULL; } -#define for_each_shell_test(dir, base, ent) \ - while ((ent = readdir(dir)) != NULL) \ +#define for_each_shell_test(entlist, nr, base, ent) \ + for (int __i = 0; __i < nr && (ent = entlist[__i]); __i++) \ if (!is_directory(base, ent) && ent->d_name[0] != '.') static const char *shell_tests__dir(char *path, size_t size) @@ -538,8 +543,9 @@ static const char *shell_tests__dir(char *path, size_t size) static int shell_tests__max_desc_width(void) { - DIR *dir; + struct dirent **entlist; struct dirent *ent; + int n_dirs, e; char path_dir[PATH_MAX]; const char *path = shell_tests__dir(path_dir, sizeof(path_dir)); int width = 0; @@ -547,11 +553,11 @@ static int shell_tests__max_desc_width(void) if (path == NULL) return -1; - dir = opendir(path); - if (!dir) + n_dirs = scandir(path, &entlist, NULL, alphasort); + if (n_dirs == -1) return -1; - for_each_shell_test(dir, path, ent) { + for_each_shell_test(entlist, n_dirs, path, ent) { char bf[256]; const char *desc = shell_test__description(bf, sizeof(bf), path, ent->d_name); @@ -563,7 +569,9 @@ static int shell_tests__max_desc_width(void) } } - closedir(dir); + for (e = 0; e < n_dirs; e++) + zfree(&entlist[e]); + free(entlist); return width; } @@ -578,7 +586,10 @@ static int shell_test__run(struct test *test, int subdir __maybe_unused) char script[PATH_MAX]; struct shell_test *st = test->priv; - path__join(script, sizeof(script), st->dir, st->file); + path__join(script, sizeof(script) - 3, st->dir, st->file); + + if (verbose) + strncat(script, " -v", sizeof(script) - strlen(script) - 1); err = system(script); if (!err) @@ -587,10 +598,12 @@ static int shell_test__run(struct test *test, int subdir __maybe_unused) return WEXITSTATUS(err) == 2 ? TEST_SKIP : TEST_FAIL; } -static int run_shell_tests(int argc, const char *argv[], int i, int width) +static int run_shell_tests(int argc, const char *argv[], int i, int width, + struct intlist *skiplist) { - DIR *dir; + struct dirent **entlist; struct dirent *ent; + int n_dirs, e; char path_dir[PATH_MAX]; struct shell_test st = { .dir = shell_tests__dir(path_dir, sizeof(path_dir)), @@ -599,14 +612,14 @@ static int run_shell_tests(int argc, const char *argv[], int i, int width) if (st.dir == NULL) return -1; - dir = opendir(st.dir); - if (!dir) { + n_dirs = scandir(st.dir, &entlist, NULL, alphasort); + if (n_dirs == -1) { pr_err("failed to open shell test directory: %s\n", st.dir); return -1; } - for_each_shell_test(dir, st.dir, ent) { + for_each_shell_test(entlist, n_dirs, st.dir, ent) { int curr = i++; char desc[256]; struct test test = { @@ -620,10 +633,18 @@ static int run_shell_tests(int argc, const char *argv[], int i, int width) st.file = ent->d_name; pr_info("%2d: %-*s:", i, width, test.desc); + + if (intlist__find(skiplist, i)) { + color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n"); + continue; + } + test_and_print(&test, false, -1); } - closedir(dir); + for (e = 0; e < n_dirs; e++) + zfree(&entlist[e]); + free(entlist); return 0; } @@ -717,24 +738,25 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) } } - return run_shell_tests(argc, argv, i, width); + return run_shell_tests(argc, argv, i, width, skiplist); } static int perf_test__list_shell(int argc, const char **argv, int i) { - DIR *dir; + struct dirent **entlist; struct dirent *ent; + int n_dirs, e; char path_dir[PATH_MAX]; const char *path = shell_tests__dir(path_dir, sizeof(path_dir)); if (path == NULL) return -1; - dir = opendir(path); - if (!dir) + n_dirs = scandir(path, &entlist, NULL, alphasort); + if (n_dirs == -1) return -1; - for_each_shell_test(dir, path, ent) { + for_each_shell_test(entlist, n_dirs, path, ent) { int curr = i++; char bf[256]; struct test t = { @@ -745,9 +767,12 @@ static int perf_test__list_shell(int argc, const char **argv, int i) continue; pr_info("%2d: %s\n", i, t.desc); + } - closedir(dir); + for (e = 0; e < n_dirs; e++) + zfree(&entlist[e]); + free(entlist); return 0; } diff --git a/tools/perf/tests/dlfilter-test.c b/tools/perf/tests/dlfilter-test.c new file mode 100644 index 000000000000..bc03b5df6828 --- /dev/null +++ b/tools/perf/tests/dlfilter-test.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test dlfilter C API. A perf.data file is synthesized and then processed + * by perf script with a dlfilter named dlfilter-test-api-v0.so. Also a C file + * is compiled to provide a dso to match the synthesized perf.data file. + */ + +#include <linux/compiler.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/perf_event.h> +#include <internal/lib.h> +#include <subcmd/exec-cmd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <inttypes.h> +#include <libgen.h> +#include <string.h> +#include <errno.h> +#include "debug.h" +#include "tool.h" +#include "event.h" +#include "header.h" +#include "machine.h" +#include "dso.h" +#include "map.h" +#include "symbol.h" +#include "synthetic-events.h" +#include "util.h" +#include "archinsn.h" +#include "dlfilter.h" +#include "tests.h" + +#define MAP_START 0x400000 + +struct test_data { + struct perf_tool tool; + struct machine *machine; + int fd; + u64 foo; + u64 bar; + u64 ip; + u64 addr; + char perf[PATH_MAX]; + char perf_data_file_name[PATH_MAX]; + char c_file_name[PATH_MAX]; + char prog_file_name[PATH_MAX]; + char dlfilters[PATH_MAX]; +}; + +static int test_result(const char *msg, int ret) +{ + pr_debug("%s\n", msg); + return ret; +} + +static int process(struct perf_tool *tool, union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine __maybe_unused) +{ + struct test_data *td = container_of(tool, struct test_data, tool); + int fd = td->fd; + + if (writen(fd, event, event->header.size) != event->header.size) + return -1; + + return 0; +} + +#define MAXCMD 4096 +#define REDIRECT_TO_DEV_NULL " >/dev/null 2>&1" + +static __printf(1, 2) int system_cmd(const char *fmt, ...) +{ + char cmd[MAXCMD + sizeof(REDIRECT_TO_DEV_NULL)]; + int ret; + + va_list args; + + va_start(args, fmt); + ret = vsnprintf(cmd, MAXCMD, fmt, args); + va_end(args); + + if (ret <= 0 || ret >= MAXCMD) + return -1; + + if (!verbose) + strcat(cmd, REDIRECT_TO_DEV_NULL); + + pr_debug("Command: %s\n", cmd); + ret = system(cmd); + if (ret) + pr_debug("Failed with return value %d\n", ret); + + return ret; +} + +static bool have_gcc(void) +{ + pr_debug("Checking for gcc\n"); + return !system_cmd("gcc --version"); +} + +static int write_attr(struct test_data *td, u64 sample_type, u64 *id) +{ + struct perf_event_attr attr = { + .size = sizeof(attr), + .type = PERF_TYPE_HARDWARE, + .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS, + .sample_type = sample_type, + .sample_period = 1, + }; + + return perf_event__synthesize_attr(&td->tool, &attr, 1, id, process); +} + +static int write_comm(int fd, pid_t pid, pid_t tid, const char *comm_str) +{ + struct perf_record_comm comm; + ssize_t sz = sizeof(comm); + + comm.header.type = PERF_RECORD_COMM; + comm.header.misc = PERF_RECORD_MISC_USER; + comm.header.size = sz; + + comm.pid = pid; + comm.tid = tid; + strncpy(comm.comm, comm_str, 16); + + if (writen(fd, &comm, sz) != sz) { + pr_debug("%s failed\n", __func__); + return -1; + } + + return 0; +} + +static int write_mmap(int fd, pid_t pid, pid_t tid, u64 start, u64 len, u64 pgoff, + const char *filename) +{ + char buf[PERF_SAMPLE_MAX_SIZE]; + struct perf_record_mmap *mmap = (struct perf_record_mmap *)buf; + size_t fsz = roundup(strlen(filename) + 1, 8); + ssize_t sz = sizeof(*mmap) - sizeof(mmap->filename) + fsz; + + mmap->header.type = PERF_RECORD_MMAP; + mmap->header.misc = PERF_RECORD_MISC_USER; + mmap->header.size = sz; + + mmap->pid = pid; + mmap->tid = tid; + mmap->start = start; + mmap->len = len; + mmap->pgoff = pgoff; + strncpy(mmap->filename, filename, sizeof(mmap->filename)); + + if (writen(fd, mmap, sz) != sz) { + pr_debug("%s failed\n", __func__); + return -1; + } + + return 0; +} + +static int write_sample(struct test_data *td, u64 sample_type, u64 id, pid_t pid, pid_t tid) +{ + char buf[PERF_SAMPLE_MAX_SIZE]; + union perf_event *event = (union perf_event *)buf; + struct perf_sample sample = { + .ip = td->ip, + .addr = td->addr, + .id = id, + .time = 1234567890, + .cpu = 31, + .pid = pid, + .tid = tid, + .period = 543212345, + .stream_id = 101, + }; + int err; + + event->header.type = PERF_RECORD_SAMPLE; + event->header.misc = PERF_RECORD_MISC_USER; + event->header.size = perf_event__sample_event_size(&sample, sample_type, 0); + err = perf_event__synthesize_sample(event, sample_type, 0, &sample); + if (err) + return test_result("perf_event__synthesize_sample() failed", TEST_FAIL); + + err = process(&td->tool, event, &sample, td->machine); + if (err) + return test_result("Failed to write sample", TEST_FAIL); + + return TEST_OK; +} + +static void close_fd(int fd) +{ + if (fd >= 0) + close(fd); +} + +static const char *prog = "int bar(){};int foo(){bar();};int main(){foo();return 0;}"; + +static int write_prog(char *file_name) +{ + int fd = creat(file_name, 0644); + ssize_t n = strlen(prog); + bool err = fd < 0 || writen(fd, prog, n) != n; + + close_fd(fd); + return err ? -1 : 0; +} + +static int get_dlfilters_path(char *buf, size_t sz) +{ + char perf[PATH_MAX]; + char path[PATH_MAX]; + char *perf_path; + char *exec_path; + + perf_exe(perf, sizeof(perf)); + perf_path = dirname(perf); + snprintf(path, sizeof(path), "%s/dlfilters/dlfilter-test-api-v0.so", perf_path); + if (access(path, R_OK)) { + exec_path = get_argv_exec_path(); + if (!exec_path) + return -1; + snprintf(path, sizeof(path), "%s/dlfilters/dlfilter-test-api-v0.so", exec_path); + free(exec_path); + if (access(path, R_OK)) + return -1; + } + strlcpy(buf, dirname(path), sz); + return 0; +} + +static int check_filter_desc(struct test_data *td) +{ + char *long_desc = NULL; + char *desc = NULL; + int ret; + + if (get_filter_desc(td->dlfilters, "dlfilter-test-api-v0.so", &desc, &long_desc) && + long_desc && !strcmp(long_desc, "Filter used by the 'dlfilter C API' perf test") && + desc && !strcmp(desc, "dlfilter to test v0 C API")) + ret = 0; + else + ret = -1; + + free(desc); + free(long_desc); + return ret; +} + +static int get_ip_addr(struct test_data *td) +{ + struct map *map; + struct symbol *sym; + + map = dso__new_map(td->prog_file_name); + if (!map) + return -1; + + sym = map__find_symbol_by_name(map, "foo"); + if (sym) + td->foo = sym->start; + + sym = map__find_symbol_by_name(map, "bar"); + if (sym) + td->bar = sym->start; + + map__put(map); + + td->ip = MAP_START + td->foo; + td->addr = MAP_START + td->bar; + + return td->foo && td->bar ? 0 : -1; +} + +static int do_run_perf_script(struct test_data *td, int do_early) +{ + return system_cmd("%s script -i %s " + "--dlfilter %s/dlfilter-test-api-v0.so " + "--dlarg first " + "--dlarg %d " + "--dlarg %" PRIu64 " " + "--dlarg %" PRIu64 " " + "--dlarg %d " + "--dlarg last", + td->perf, td->perf_data_file_name, td->dlfilters, + verbose, td->ip, td->addr, do_early); +} + +static int run_perf_script(struct test_data *td) +{ + int do_early; + int err; + + for (do_early = 0; do_early < 3; do_early++) { + err = do_run_perf_script(td, do_early); + if (err) + return err; + } + return 0; +} + +#define TEST_SAMPLE_TYPE (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ + PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_TIME | \ + PERF_SAMPLE_ADDR | PERF_SAMPLE_CPU | \ + PERF_SAMPLE_PERIOD | PERF_SAMPLE_STREAM_ID) + +static int test__dlfilter_test(struct test_data *td) +{ + u64 sample_type = TEST_SAMPLE_TYPE; + pid_t pid = 12345; + pid_t tid = 12346; + u64 id = 99; + int err; + + if (get_dlfilters_path(td->dlfilters, PATH_MAX)) + return test_result("dlfilters not found", TEST_SKIP); + + if (check_filter_desc(td)) + return test_result("Failed to get expected filter description", TEST_FAIL); + + if (!have_gcc()) + return test_result("gcc not found", TEST_SKIP); + + pr_debug("dlfilters path: %s\n", td->dlfilters); + + if (write_prog(td->c_file_name)) + return test_result("Failed to write test C file", TEST_FAIL); + + if (verbose > 1) + system_cmd("cat %s ; echo", td->c_file_name); + + if (system_cmd("gcc -g -o %s %s", td->prog_file_name, td->c_file_name)) + return TEST_FAIL; + + if (verbose > 2) + system_cmd("objdump -x -dS %s", td->prog_file_name); + + if (get_ip_addr(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; + + 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); + + 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 (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; +} + +static void unlink_path(const char *path) +{ + if (*path) + unlink(path); +} + +static void test_data__free(struct test_data *td) +{ + machine__delete(td->machine); + close_fd(td->fd); + if (verbose <= 2) { + unlink_path(td->c_file_name); + unlink_path(td->prog_file_name); + unlink_path(td->perf_data_file_name); + } +} + +int test__dlfilter(struct test *test __maybe_unused, int subtest __maybe_unused) +{ + struct test_data td = {.fd = -1}; + int pid = getpid(); + int err; + + perf_exe(td.perf, sizeof(td.perf)); + + snprintf(td.perf_data_file_name, PATH_MAX, "/tmp/dlfilter-test-%u-perf-data", pid); + snprintf(td.c_file_name, PATH_MAX, "/tmp/dlfilter-test-%u-prog.c", pid); + snprintf(td.prog_file_name, PATH_MAX, "/tmp/dlfilter-test-%u-prog", pid); + + err = test__dlfilter_test(&td); + test_data__free(&td); + return err; +} diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 627c1aaf1c9e..43e1b01e5afc 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c @@ -308,10 +308,20 @@ int test__dso_data_cache(struct test *test __maybe_unused, int subtest __maybe_u return 0; } +static long new_limit(int count) +{ + int fd = open("/dev/null", O_RDONLY); + long ret = fd; + if (count > 0) + ret = new_limit(--count); + close(fd); + return ret; +} + int test__dso_data_reopen(struct test *test __maybe_unused, int subtest __maybe_unused) { struct machine machine; - long nr_end, nr = open_files_cnt(); + long nr_end, nr = open_files_cnt(), lim = new_limit(3); int fd, fd_extra; #define dso_0 (dsos[0]) @@ -334,7 +344,7 @@ int test__dso_data_reopen(struct test *test __maybe_unused, int subtest __maybe_ /* Make sure we are able to open 3 fds anyway */ TEST_ASSERT_VAL("failed to set file limit", - !set_fd_limit((nr + 3))); + !set_fd_limit((lim))); TEST_ASSERT_VAL("failed to create dsos\n", !dsos__create(3, TEST_FILE_SIZE)); diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c index 83638097c3bc..a288035eb362 100644 --- a/tools/perf/tests/dwarf-unwind.c +++ b/tools/perf/tests/dwarf-unwind.c @@ -17,10 +17,6 @@ #include "callchain.h" #include "util/synthetic-events.h" -#if defined (__x86_64__) || defined (__i386__) || defined (__powerpc__) -#include "arch-tests.h" -#endif - /* For bsearch. We try to unwind functions in shared object. */ #include <stdlib.h> diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index 656218179222..44a50527f9d9 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c @@ -88,6 +88,7 @@ int test__event_update(struct test *test __maybe_unused, int subtest __maybe_unu struct evsel *evsel; struct event_name tmp; struct evlist *evlist = evlist__new_default(); + char *unit = strdup("KRAVA"); TEST_ASSERT_VAL("failed to get evlist", evlist); @@ -98,7 +99,7 @@ int test__event_update(struct test *test __maybe_unused, int subtest __maybe_unu perf_evlist__id_add(&evlist->core, &evsel->core, 0, 0, 123); - evsel->unit = strdup("KRAVA"); + evsel->unit = unit; TEST_ASSERT_VAL("failed to synthesize attr update unit", !perf_event__synthesize_event_update_unit(NULL, evsel, process_event_unit)); @@ -118,6 +119,7 @@ int test__event_update(struct test *test __maybe_unused, int subtest __maybe_unu TEST_ASSERT_VAL("failed to synthesize attr update cpus", !perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus)); - perf_cpu_map__put(evsel->core.own_cpus); + free(unit); + evlist__delete(evlist); return 0; } diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index b74cf80d1f10..4e09f0a312af 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c @@ -5,6 +5,7 @@ #include "tests.h" #include "debug.h" #include "pmu.h" +#include "pmu-hybrid.h" #include <errno.h> #include <linux/kernel.h> @@ -44,7 +45,7 @@ static int perf_evsel__roundtrip_cache_name_test(void) for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); - if (evsel->idx != idx) + if (evsel->core.idx != idx) continue; ++idx; @@ -84,9 +85,9 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names, err = 0; evlist__for_each_entry(evlist, evsel) { - if (strcmp(evsel__name(evsel), names[evsel->idx / distance])) { + if (strcmp(evsel__name(evsel), names[evsel->core.idx / distance])) { --err; - pr_debug("%s != %s\n", evsel__name(evsel), names[evsel->idx / distance]); + pr_debug("%s != %s\n", evsel__name(evsel), names[evsel->core.idx / distance]); } } @@ -102,7 +103,7 @@ int test__perf_evsel__roundtrip_name_test(struct test *test __maybe_unused, int { int err = 0, ret = 0; - if (perf_pmu__has_hybrid()) + if (perf_pmu__has_hybrid() && perf_pmu__hybrid_mounted("cpu_atom")) return perf_evsel__name_array_test(evsel__hw_names, 2); err = perf_evsel__name_array_test(evsel__hw_names, 1); diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c index 98da8a8757ab..33e43cce9064 100644 --- a/tools/perf/tests/llvm.c +++ b/tools/perf/tests/llvm.c @@ -67,12 +67,11 @@ test_llvm__fetch_bpf_obj(void **p_obj_buf, /* * Skip this test if user's .perfconfig doesn't set [llvm] section - * and clang is not found in $PATH, and this is not perf test -v + * and clang is not found in $PATH */ - if (!force && (verbose <= 0 && - !llvm_param.user_set_param && + if (!force && (!llvm_param.user_set_param && llvm__search_clang())) { - pr_debug("No clang and no verbosive, skip this test\n"); + pr_debug("No clang, skip this test\n"); return TEST_SKIP; } diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 94bd5d215d94..da013e90a945 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -84,9 +84,11 @@ 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_with_babeltrace:= LIBBABELTRACE=1 +make_with_coresight := CORESIGHT=1 make_no_sdt := NO_SDT=1 make_no_syscall_tbl := NO_SYSCALL_TABLE=1 make_with_clangllvm := LIBCLANGLLVM=1 @@ -148,11 +150,13 @@ run += make_no_libaudit run += make_no_libbionic run += make_no_auxtrace run += make_no_libbpf +run += make_libbpf_dynamic run += make_no_libbpf_DEBUG run += make_no_libcrypto run += make_no_sdt run += make_no_syscall_tbl run += make_with_babeltrace +run += make_with_coresight run += make_with_clangllvm run += make_with_libpfm4 run += make_help @@ -266,6 +270,9 @@ test_make_install_info_O := $(test_ok) test_make_install_pdf := $(test_ok) test_make_install_pdf_O := $(test_ok) +test_make_libbpf_dynamic := ldd $(PERF_O)/perf | grep -q libbpf +test_make_libbpf_dynamic_O := ldd $$TMP_O/perf | grep -q libbpf + test_make_python_perf_so_O := test -f $$TMP_O/python/perf.so test_make_perf_o_O := test -f $$TMP_O/perf.o test_make_util_map_o_O := test -f $$TMP_O/util/map.o diff --git a/tools/perf/tests/maps.c b/tools/perf/tests/maps.c index edcbc70ff9d6..1ac72919fa35 100644 --- a/tools/perf/tests/maps.c +++ b/tools/perf/tests/maps.c @@ -116,5 +116,7 @@ int test__maps__merge_in(struct test *t __maybe_unused, int subtest __maybe_unus ret = check_maps(merged3, ARRAY_SIZE(merged3), &maps); TEST_ASSERT_VAL("merge check failed", !ret); + + maps__exit(&maps); return TEST_OK; } diff --git a/tools/perf/tests/mem2node.c b/tools/perf/tests/mem2node.c index a258bd51f1a4..e4d0d58b97f8 100644 --- a/tools/perf/tests/mem2node.c +++ b/tools/perf/tests/mem2node.c @@ -27,7 +27,7 @@ static unsigned long *get_bitmap(const char *str, int nbits) unsigned long *bm = NULL; int i; - bm = bitmap_alloc(nbits); + bm = bitmap_zalloc(nbits); if (map && bm) { for (i = 0; i < map->nr; i++) { diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 73ae8f7aa066..d38757db2dc2 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -139,7 +139,7 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse " doesn't map to an evsel\n", sample.id); goto out_delete_evlist; } - nr_events[evsel->idx]++; + nr_events[evsel->core.idx]++; perf_mmap__consume(&md->core); } perf_mmap__read_done(&md->core); @@ -147,10 +147,10 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse out_init: err = 0; evlist__for_each_entry(evlist, evsel) { - if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { + if (nr_events[evsel->core.idx] != expected_nr_events[evsel->core.idx]) { pr_debug("expected %d %s events, got %d\n", - expected_nr_events[evsel->idx], - evsel__name(evsel), nr_events[evsel->idx]); + expected_nr_events[evsel->core.idx], + evsel__name(evsel), nr_events[evsel->core.idx]); err = -1; goto out_delete_evlist; } diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 0f113b2b36a3..fd3556cc9ad4 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -6,8 +6,10 @@ #include "tests.h" #include "debug.h" #include "pmu.h" +#include "pmu-hybrid.h" #include <dirent.h> #include <errno.h> +#include "fncache.h" #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> @@ -49,7 +51,7 @@ static int test__checkevent_tracepoint(struct evlist *evlist) struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->core.nr_groups); TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type); TEST_ASSERT_VAL("wrong sample_type", PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type); @@ -62,7 +64,7 @@ static int test__checkevent_tracepoint_multi(struct evlist *evlist) struct evsel *evsel; TEST_ASSERT_VAL("wrong number of entries", evlist->core.nr_entries > 1); - TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->core.nr_groups); evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_VAL("wrong type", @@ -668,7 +670,7 @@ static int test__group1(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* instructions:k */ evsel = leader = evlist__first(evlist); @@ -698,7 +700,7 @@ static int test__group1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 2); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -710,7 +712,7 @@ static int test__group2(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* faults + :ku modifier */ evsel = leader = evlist__first(evlist); @@ -739,7 +741,7 @@ static int test__group2(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -765,7 +767,7 @@ static int test__group3(struct evlist *evlist __maybe_unused) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->core.nr_groups); /* group1 syscalls:sys_enter_openat:H */ evsel = leader = evlist__first(evlist); @@ -798,7 +800,7 @@ static int test__group3(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 3); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -831,7 +833,7 @@ static int test__group3(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -857,7 +859,7 @@ static int test__group4(struct evlist *evlist __maybe_unused) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* cycles:u + p */ evsel = leader = evlist__first(evlist); @@ -889,7 +891,7 @@ static int test__group4(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 2); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -901,7 +903,7 @@ static int test__group5(struct evlist *evlist __maybe_unused) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->core.nr_groups); /* cycles + G */ evsel = leader = evlist__first(evlist); @@ -931,7 +933,7 @@ static int test__group5(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read); @@ -963,7 +965,7 @@ static int test__group5(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); /* cycles */ @@ -987,7 +989,7 @@ static int test__group_gh1(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* cycles + :H group modifier */ evsel = leader = evlist__first(evlist); @@ -1016,7 +1018,7 @@ static int test__group_gh1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); return 0; @@ -1027,7 +1029,7 @@ static int test__group_gh2(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* cycles + :G group modifier */ evsel = leader = evlist__first(evlist); @@ -1056,7 +1058,7 @@ static int test__group_gh2(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); return 0; @@ -1067,7 +1069,7 @@ static int test__group_gh3(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* cycles:G + :u group modifier */ evsel = leader = evlist__first(evlist); @@ -1096,7 +1098,7 @@ static int test__group_gh3(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); return 0; @@ -1107,7 +1109,7 @@ static int test__group_gh4(struct evlist *evlist) struct evsel *evsel, *leader; TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); - TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); + TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->core.nr_groups); /* cycles:G + :uG group modifier */ evsel = leader = evlist__first(evlist); @@ -1136,7 +1138,7 @@ static int test__group_gh4(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong group_idx", evsel__group_idx(evsel) == 1); return 0; @@ -1160,7 +1162,7 @@ static int test__leader_sample1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); /* cache-misses - not sampling */ @@ -1174,7 +1176,7 @@ static int test__leader_sample1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); /* branch-misses - not sampling */ @@ -1189,7 +1191,7 @@ static int test__leader_sample1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); return 0; @@ -1213,7 +1215,7 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); /* branch-misses - not sampling */ @@ -1228,7 +1230,7 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read); return 0; @@ -1259,7 +1261,7 @@ static int test__pinned_group(struct evlist *evlist) TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong pinned", evsel->core.attr.pinned); /* cache-misses - can not be pinned, but will go on with the leader */ @@ -1303,7 +1305,7 @@ static int test__exclusive_group(struct evlist *evlist) TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong exclusive", evsel->core.attr.exclusive); /* cache-misses - can not be pinned, but will go on with the leader */ @@ -1530,12 +1532,12 @@ static int test__hybrid_hw_group_event(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0x3c == evsel->core.attr.config); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); evsel = evsel__next(evsel); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0xc0 == evsel->core.attr.config); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); return 0; } @@ -1546,12 +1548,12 @@ static int test__hybrid_sw_hw_group_event(struct evlist *evlist) evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); evsel = evsel__next(evsel); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0x3c == evsel->core.attr.config); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); return 0; } @@ -1563,11 +1565,11 @@ static int test__hybrid_hw_sw_group_event(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0x3c == evsel->core.attr.config); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); evsel = evsel__next(evsel); TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); return 0; } @@ -1579,14 +1581,14 @@ static int test__hybrid_group_modifier1(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0x3c == evsel->core.attr.config); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); evsel = evsel__next(evsel); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0xc0 == evsel->core.attr.config); - TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); + TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); return 0; @@ -1596,6 +1598,13 @@ static int test__hybrid_raw1(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); + if (!perf_pmu__hybrid_mounted("cpu_atom")) { + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); + TEST_ASSERT_VAL("wrong config", 0x1a == evsel->core.attr.config); + return 0; + } + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0x1a == evsel->core.attr.config); @@ -1620,13 +1629,9 @@ static int test__hybrid_cache_event(struct evlist *evlist) { struct evsel *evsel = evlist__first(evlist); - TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); + TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", 0x2 == (evsel->core.attr.config & 0xffffffff)); - - evsel = evsel__next(evsel); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->core.attr.type); - TEST_ASSERT_VAL("wrong config", 0x10002 == (evsel->core.attr.config & 0xffffffff)); return 0; } @@ -2028,7 +2033,7 @@ static struct evlist_test test__hybrid_events[] = { .id = 7, }, { - .name = "cpu_core/LLC-loads/,cpu_atom/LLC-load-misses/", + .name = "cpu_core/LLC-loads/", .check = test__hybrid_cache_event, .id = 8, }, @@ -2190,9 +2195,91 @@ static int test_pmu_events(void) return ret; } +static bool test_alias(char **event, char **alias) +{ + char path[PATH_MAX]; + DIR *dir; + struct dirent *dent; + const char *sysfs = sysfs__mountpoint(); + char buf[128]; + FILE *file; + + if (!sysfs) + return false; + + snprintf(path, PATH_MAX, "%s/bus/event_source/devices/", sysfs); + dir = opendir(path); + if (!dir) + return false; + + while ((dent = readdir(dir))) { + if (!strcmp(dent->d_name, ".") || + !strcmp(dent->d_name, "..")) + continue; + + snprintf(path, PATH_MAX, "%s/bus/event_source/devices/%s/alias", + sysfs, dent->d_name); + + if (!file_available(path)) + continue; + + file = fopen(path, "r"); + if (!file) + continue; + + if (!fgets(buf, sizeof(buf), file)) { + fclose(file); + continue; + } + + /* Remove the last '\n' */ + buf[strlen(buf) - 1] = 0; + + fclose(file); + *event = strdup(dent->d_name); + *alias = strdup(buf); + closedir(dir); + + if (*event == NULL || *alias == NULL) { + free(*event); + free(*alias); + return false; + } + + return true; + } + + closedir(dir); + return false; +} + +static int test__checkevent_pmu_events_alias(struct evlist *evlist) +{ + struct evsel *evsel1 = evlist__first(evlist); + struct evsel *evsel2 = evlist__last(evlist); + + TEST_ASSERT_VAL("wrong type", evsel1->core.attr.type == evsel2->core.attr.type); + TEST_ASSERT_VAL("wrong config", evsel1->core.attr.config == evsel2->core.attr.config); + return 0; +} + +static int test_pmu_events_alias(char *event, char *alias) +{ + struct evlist_test e = { .id = 0, }; + char name[2 * NAME_MAX + 20]; + + snprintf(name, sizeof(name), "%s/event=1/,%s/event=1/", + event, alias); + + e.name = name; + e.check = test__checkevent_pmu_events_alias; + return test_event(&e); +} + int test__parse_events(struct test *test __maybe_unused, int subtest __maybe_unused) { int ret1, ret2 = 0; + char *event, *alias; #define TEST_EVENTS(tests) \ do { \ @@ -2217,6 +2304,15 @@ do { \ return ret; } + if (test_alias(&event, &alias)) { + int ret = test_pmu_events_alias(event, alias); + + free(event); + free(alias); + if (ret) + return ret; + } + ret1 = test_terms(test__terms, ARRAY_SIZE(test__terms)); if (!ret2) ret2 = ret1; diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c index 85d75b9b25a1..7c56bc1f4cff 100644 --- a/tools/perf/tests/perf-time-to-tsc.c +++ b/tools/perf/tests/perf-time-to-tsc.c @@ -21,6 +21,7 @@ #include "mmap.h" #include "tests.h" #include "pmu.h" +#include "pmu-hybrid.h" #define CHECK__(x) { \ while ((x) < 0) { \ @@ -93,7 +94,7 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe * For hybrid "cycles:u", it creates two events. * Init the second evsel here. */ - if (perf_pmu__has_hybrid()) { + if (perf_pmu__has_hybrid() && perf_pmu__hybrid_mounted("cpu_atom")) { evsel = evsel__next(evsel); evsel->core.attr.comm = 1; evsel->core.attr.disabled = 1; diff --git a/tools/perf/tests/pfm.c b/tools/perf/tests/pfm.c index d4b0ef74defc..e8fd0da0762b 100644 --- a/tools/perf/tests/pfm.c +++ b/tools/perf/tests/pfm.c @@ -96,7 +96,7 @@ static int test__pfm_events(void) count_pfm_events(&evlist->core), table[i].nr_events); TEST_ASSERT_EQUAL(table[i].events, - evlist->nr_groups, + evlist->core.nr_groups, 0); evlist__delete(evlist); @@ -155,6 +155,16 @@ static int test__pfm_group(void) .nr_events = 3, .nr_groups = 1, }, + { + .events = "instructions}", + .nr_events = 1, + .nr_groups = 0, + }, + { + .events = "{{instructions}}", + .nr_events = 0, + .nr_groups = 0, + }, }; for (i = 0; i < ARRAY_SIZE(table); i++) { @@ -170,7 +180,7 @@ static int test__pfm_group(void) count_pfm_events(&evlist->core), table[i].nr_events); TEST_ASSERT_EQUAL(table[i].events, - evlist->nr_groups, + evlist->core.nr_groups, table[i].nr_groups); evlist__delete(evlist); diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c index b8aff8fb50d8..43743cf719ef 100644 --- a/tools/perf/tests/pmu-events.c +++ b/tools/perf/tests/pmu-events.c @@ -28,110 +28,190 @@ struct perf_pmu_test_event { * be set in the alias. */ const char *alias_long_desc; + + /* PMU which we should match against */ + const char *matching_pmu; }; -static struct perf_pmu_test_event test_cpu_events[] = { - { - .event = { - .name = "bp_l1_btb_correct", - .event = "event=0x8a", - .desc = "L1 BTB Correction", - .topic = "branch", - }, - .alias_str = "event=0x8a", - .alias_long_desc = "L1 BTB Correction", +struct perf_pmu_test_pmu { + struct perf_pmu pmu; + struct perf_pmu_test_event const *aliases[10]; +}; + +static const struct perf_pmu_test_event bp_l1_btb_correct = { + .event = { + .name = "bp_l1_btb_correct", + .event = "event=0x8a", + .desc = "L1 BTB Correction", + .topic = "branch", }, - { - .event = { - .name = "bp_l2_btb_correct", - .event = "event=0x8b", - .desc = "L2 BTB Correction", - .topic = "branch", - }, - .alias_str = "event=0x8b", - .alias_long_desc = "L2 BTB Correction", + .alias_str = "event=0x8a", + .alias_long_desc = "L1 BTB Correction", +}; + +static const struct perf_pmu_test_event bp_l2_btb_correct = { + .event = { + .name = "bp_l2_btb_correct", + .event = "event=0x8b", + .desc = "L2 BTB Correction", + .topic = "branch", }, - { - .event = { - .name = "segment_reg_loads.any", - .event = "umask=0x80,period=200000,event=0x6", - .desc = "Number of segment register loads", - .topic = "other", - }, - .alias_str = "umask=0x80,(null)=0x30d40,event=0x6", - .alias_long_desc = "Number of segment register loads", + .alias_str = "event=0x8b", + .alias_long_desc = "L2 BTB Correction", +}; + +static const struct perf_pmu_test_event segment_reg_loads_any = { + .event = { + .name = "segment_reg_loads.any", + .event = "umask=0x80,period=200000,event=0x6", + .desc = "Number of segment register loads", + .topic = "other", }, - { - .event = { - .name = "dispatch_blocked.any", - .event = "umask=0x20,period=200000,event=0x9", - .desc = "Memory cluster signals to block micro-op dispatch for any reason", - .topic = "other", - }, - .alias_str = "umask=0x20,(null)=0x30d40,event=0x9", - .alias_long_desc = "Memory cluster signals to block micro-op dispatch for any reason", + .alias_str = "umask=0x80,(null)=0x30d40,event=0x6", + .alias_long_desc = "Number of segment register loads", +}; + +static const struct perf_pmu_test_event dispatch_blocked_any = { + .event = { + .name = "dispatch_blocked.any", + .event = "umask=0x20,period=200000,event=0x9", + .desc = "Memory cluster signals to block micro-op dispatch for any reason", + .topic = "other", }, - { - .event = { - .name = "eist_trans", - .event = "umask=0x0,period=200000,event=0x3a", - .desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", - .topic = "other", - }, - .alias_str = "umask=0,(null)=0x30d40,event=0x3a", - .alias_long_desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", + .alias_str = "umask=0x20,(null)=0x30d40,event=0x9", + .alias_long_desc = "Memory cluster signals to block micro-op dispatch for any reason", +}; + +static const struct perf_pmu_test_event eist_trans = { + .event = { + .name = "eist_trans", + .event = "umask=0x0,period=200000,event=0x3a", + .desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", + .topic = "other", }, - { - .event = { - .name = "l3_cache_rd", - .event = "event=0x40", - .desc = "L3 cache access, read", - .long_desc = "Attributable Level 3 cache access, read", - .topic = "cache", - }, - .alias_str = "event=0x40", - .alias_long_desc = "Attributable Level 3 cache access, read", + .alias_str = "umask=0,(null)=0x30d40,event=0x3a", + .alias_long_desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", +}; + +static const struct perf_pmu_test_event l3_cache_rd = { + .event = { + .name = "l3_cache_rd", + .event = "event=0x40", + .desc = "L3 cache access, read", + .long_desc = "Attributable Level 3 cache access, read", + .topic = "cache", }, - { /* sentinel */ - .event = { - .name = NULL, - }, + .alias_str = "event=0x40", + .alias_long_desc = "Attributable Level 3 cache access, read", +}; + +static const struct perf_pmu_test_event *core_events[] = { + &bp_l1_btb_correct, + &bp_l2_btb_correct, + &segment_reg_loads_any, + &dispatch_blocked_any, + &eist_trans, + &l3_cache_rd, + NULL +}; + +static const struct perf_pmu_test_event uncore_hisi_ddrc_flux_wcmd = { + .event = { + .name = "uncore_hisi_ddrc.flux_wcmd", + .event = "event=0x2", + .desc = "DDRC write commands. Unit: hisi_sccl,ddrc ", + .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", }; -static struct perf_pmu_test_event test_uncore_events[] = { - { - .event = { - .name = "uncore_hisi_ddrc.flux_wcmd", - .event = "event=0x2", - .desc = "DDRC write commands. Unit: hisi_sccl,ddrc ", - .topic = "uncore", - .long_desc = "DDRC write commands", - .pmu = "hisi_sccl,ddrc", - }, - .alias_str = "event=0x2", - .alias_long_desc = "DDRC write commands", +static const struct perf_pmu_test_event unc_cbo_xsnp_response_miss_eviction = { + .event = { + .name = "unc_cbo_xsnp_response.miss_eviction", + .event = "umask=0x81,event=0x22", + .desc = "Unit: uncore_cbox 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", }, - { - .event = { - .name = "unc_cbo_xsnp_response.miss_eviction", - .event = "umask=0x81,event=0x22", - .desc = "Unit: uncore_cbox 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 = "umask=0x81,event=0x22", - .alias_long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", + .alias_str = "umask=0x81,event=0x22", + .alias_long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", + .matching_pmu = "uncore_cbox_0", +}; + +static const struct perf_pmu_test_event uncore_hisi_l3c_rd_hit_cpipe = { + .event = { + .name = "uncore_hisi_l3c.rd_hit_cpipe", + .event = "event=0x2", + .desc = "Total read hits. Unit: hisi_sccl,l3c ", + .topic = "uncore", + .long_desc = "Total read hits", + .pmu = "hisi_sccl,l3c", }, - { /* sentinel */ - .event = { - .name = NULL, - }, - } + .alias_str = "event=0x7", + .alias_long_desc = "Total read hits", + .matching_pmu = "hisi_sccl3_l3c7", +}; + +static const struct perf_pmu_test_event uncore_imc_free_running_cache_miss = { + .event = { + .name = "uncore_imc_free_running.cache_miss", + .event = "event=0x12", + .desc = "Total cache misses. Unit: uncore_imc_free_running ", + .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", +}; + +static const struct perf_pmu_test_event uncore_imc_cache_hits = { + .event = { + .name = "uncore_imc.cache_hits", + .event = "event=0x34", + .desc = "Total cache hits. Unit: uncore_imc ", + .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", +}; + +static const struct perf_pmu_test_event *uncore_events[] = { + &uncore_hisi_ddrc_flux_wcmd, + &unc_cbo_xsnp_response_miss_eviction, + &uncore_hisi_l3c_rd_hit_cpipe, + &uncore_imc_free_running_cache_miss, + &uncore_imc_cache_hits, + NULL }; -const int total_test_events_size = ARRAY_SIZE(test_uncore_events); +static const struct perf_pmu_test_event sys_ddr_pmu_write_cycles = { + .event = { + .name = "sys_ddr_pmu.write_cycles", + .event = "event=0x2b", + .desc = "ddr write-cycles event. Unit: uncore_sys_ddr_pmu ", + .topic = "uncore", + .pmu = "uncore_sys_ddr_pmu", + .compat = "v8", + }, + .alias_str = "event=0x2b", + .alias_long_desc = "ddr write-cycles event. Unit: uncore_sys_ddr_pmu ", + .matching_pmu = "uncore_sys_ddr_pmu", +}; + +static const struct perf_pmu_test_event *sys_events[] = { + &sys_ddr_pmu_write_cycles, + NULL +}; static bool is_same(const char *reference, const char *test) { @@ -161,99 +241,207 @@ static struct pmu_events_map *__test_pmu_get_events_map(void) return NULL; } -/* Verify generated events from pmu-events.c is as expected */ +static struct pmu_event *__test_pmu_get_sys_events_table(void) +{ + struct pmu_sys_events *tables = &pmu_sys_event_tables[0]; + + for ( ; tables->name; tables++) { + if (!strcmp("pme_test_soc_sys", tables->name)) + return tables->table; + } + + return NULL; +} + +static int compare_pmu_events(struct pmu_event *e1, const struct pmu_event *e2) +{ + if (!is_same(e1->desc, e2->desc)) { + pr_debug2("testing event e1 %s: mismatched desc, %s vs %s\n", + e1->name, e1->desc, e2->desc); + return -1; + } + + if (!is_same(e1->topic, e2->topic)) { + pr_debug2("testing event e1 %s: mismatched topic, %s vs %s\n", + e1->name, e1->topic, e2->topic); + return -1; + } + + if (!is_same(e1->long_desc, e2->long_desc)) { + pr_debug2("testing event e1 %s: mismatched long_desc, %s vs %s\n", + e1->name, e1->long_desc, e2->long_desc); + return -1; + } + + if (!is_same(e1->unit, e2->unit)) { + pr_debug2("testing event e1 %s: mismatched unit, %s vs %s\n", + e1->name, e1->unit, e2->unit); + return -1; + } + + if (!is_same(e1->perpkg, e2->perpkg)) { + pr_debug2("testing event e1 %s: mismatched perpkg, %s vs %s\n", + e1->name, e1->perpkg, e2->perpkg); + return -1; + } + + if (!is_same(e1->metric_expr, e2->metric_expr)) { + pr_debug2("testing event e1 %s: mismatched metric_expr, %s vs %s\n", + e1->name, e1->metric_expr, e2->metric_expr); + return -1; + } + + if (!is_same(e1->metric_name, e2->metric_name)) { + pr_debug2("testing event e1 %s: mismatched metric_name, %s vs %s\n", + e1->name, e1->metric_name, e2->metric_name); + return -1; + } + + if (!is_same(e1->deprecated, e2->deprecated)) { + pr_debug2("testing event e1 %s: mismatched deprecated, %s vs %s\n", + e1->name, e1->deprecated, e2->deprecated); + return -1; + } + + if (!is_same(e1->pmu, e2->pmu)) { + pr_debug2("testing event e1 %s: mismatched pmu string, %s vs %s\n", + e1->name, e1->pmu, e2->pmu); + return -1; + } + + if (!is_same(e1->compat, e2->compat)) { + pr_debug2("testing event e1 %s: mismatched compat string, %s vs %s\n", + e1->name, e1->compat, e2->compat); + return -1; + } + + return 0; +} + +static int compare_alias_to_test_event(struct perf_pmu_alias *alias, + struct perf_pmu_test_event const *test_event, + char const *pmu_name) +{ + struct pmu_event const *event = &test_event->event; + + /* An alias was found, ensure everything is in order */ + if (!is_same(alias->name, event->name)) { + pr_debug("testing aliases PMU %s: mismatched name, %s vs %s\n", + pmu_name, alias->name, event->name); + return -1; + } + + if (!is_same(alias->desc, event->desc)) { + pr_debug("testing aliases PMU %s: mismatched desc, %s vs %s\n", + pmu_name, alias->desc, event->desc); + return -1; + } + + if (!is_same(alias->long_desc, test_event->alias_long_desc)) { + pr_debug("testing aliases PMU %s: mismatched long_desc, %s vs %s\n", + pmu_name, alias->long_desc, + test_event->alias_long_desc); + return -1; + } + + if (!is_same(alias->topic, event->topic)) { + pr_debug("testing aliases PMU %s: mismatched topic, %s vs %s\n", + pmu_name, alias->topic, event->topic); + return -1; + } + + if (!is_same(alias->str, test_event->alias_str)) { + pr_debug("testing aliases PMU %s: mismatched str, %s vs %s\n", + pmu_name, alias->str, test_event->alias_str); + return -1; + } + + if (!is_same(alias->long_desc, test_event->alias_long_desc)) { + pr_debug("testing aliases PMU %s: mismatched long desc, %s vs %s\n", + pmu_name, alias->str, test_event->alias_long_desc); + return -1; + } + + + if (!is_same(alias->pmu_name, test_event->event.pmu)) { + pr_debug("testing aliases PMU %s: mismatched pmu_name, %s vs %s\n", + pmu_name, alias->pmu_name, test_event->event.pmu); + return -1; + } + + return 0; +} + +/* Verify generated events from pmu-events.c are as expected */ static int test_pmu_event_table(void) { + struct pmu_event *sys_event_tables = __test_pmu_get_sys_events_table(); struct pmu_events_map *map = __test_pmu_get_events_map(); struct pmu_event *table; int map_events = 0, expected_events; - /* ignore 2x sentinels */ - expected_events = ARRAY_SIZE(test_cpu_events) + - ARRAY_SIZE(test_uncore_events) - 2; + /* ignore 3x sentinels */ + expected_events = ARRAY_SIZE(core_events) + + ARRAY_SIZE(uncore_events) + + ARRAY_SIZE(sys_events) - 3; - if (!map) + if (!map || !sys_event_tables) return -1; for (table = map->table; table->name; table++) { - struct perf_pmu_test_event *test; - struct pmu_event *te; + struct perf_pmu_test_event const **test_event_table; bool found = false; if (table->pmu) - test = &test_uncore_events[0]; + test_event_table = &uncore_events[0]; else - test = &test_cpu_events[0]; + test_event_table = &core_events[0]; - te = &test->event; + for (; *test_event_table; test_event_table++) { + struct perf_pmu_test_event const *test_event = *test_event_table; + struct pmu_event const *event = &test_event->event; - for (; te->name; test++, te = &test->event) { - if (strcmp(table->name, te->name)) + if (strcmp(table->name, event->name)) continue; found = true; map_events++; - if (!is_same(table->desc, te->desc)) { - pr_debug2("testing event table %s: mismatched desc, %s vs %s\n", - table->name, table->desc, te->desc); + if (compare_pmu_events(table, event)) return -1; - } - if (!is_same(table->topic, te->topic)) { - pr_debug2("testing event table %s: mismatched topic, %s vs %s\n", - table->name, table->topic, - te->topic); - return -1; - } + pr_debug("testing event table %s: pass\n", table->name); + } - if (!is_same(table->long_desc, te->long_desc)) { - pr_debug2("testing event table %s: mismatched long_desc, %s vs %s\n", - table->name, table->long_desc, - te->long_desc); - return -1; - } + if (!found) { + pr_err("testing event table: could not find event %s\n", + table->name); + return -1; + } + } - if (!is_same(table->unit, te->unit)) { - pr_debug2("testing event table %s: mismatched unit, %s vs %s\n", - table->name, table->unit, - te->unit); - return -1; - } + for (table = sys_event_tables; table->name; table++) { + struct perf_pmu_test_event const **test_event_table; + bool found = false; - if (!is_same(table->perpkg, te->perpkg)) { - pr_debug2("testing event table %s: mismatched perpkg, %s vs %s\n", - table->name, table->perpkg, - te->perpkg); - return -1; - } + test_event_table = &sys_events[0]; - if (!is_same(table->metric_expr, te->metric_expr)) { - pr_debug2("testing event table %s: mismatched metric_expr, %s vs %s\n", - table->name, table->metric_expr, - te->metric_expr); - return -1; - } + for (; *test_event_table; test_event_table++) { + struct perf_pmu_test_event const *test_event = *test_event_table; + struct pmu_event const *event = &test_event->event; - if (!is_same(table->metric_name, te->metric_name)) { - pr_debug2("testing event table %s: mismatched metric_name, %s vs %s\n", - table->name, table->metric_name, - te->metric_name); - return -1; - } + if (strcmp(table->name, event->name)) + continue; + found = true; + map_events++; - if (!is_same(table->deprecated, te->deprecated)) { - pr_debug2("testing event table %s: mismatched deprecated, %s vs %s\n", - table->name, table->deprecated, - te->deprecated); + if (compare_pmu_events(table, event)) return -1; - } - pr_debug("testing event table %s: pass\n", table->name); + pr_debug("testing sys event table %s: pass\n", table->name); } - if (!found) { - pr_err("testing event table: could not find event %s\n", - table->name); + pr_debug("testing event table: could not find event %s\n", + table->name); return -1; } } @@ -279,27 +467,19 @@ static struct perf_pmu_alias *find_alias(const char *test_event, struct list_hea } /* Verify aliases are as expected */ -static int __test__pmu_event_aliases(char *pmu_name, int *count) +static int __test_core_pmu_event_aliases(char *pmu_name, int *count) { - struct perf_pmu_test_event *test; - struct pmu_event *te; + struct perf_pmu_test_event const **test_event_table; struct perf_pmu *pmu; LIST_HEAD(aliases); int res = 0; - bool use_uncore_table; struct pmu_events_map *map = __test_pmu_get_events_map(); struct perf_pmu_alias *a, *tmp; if (!map) return -1; - if (is_pmu_core(pmu_name)) { - test = &test_cpu_events[0]; - use_uncore_table = false; - } else { - test = &test_uncore_events[0]; - use_uncore_table = true; - } + test_event_table = &core_events[0]; pmu = zalloc(sizeof(*pmu)); if (!pmu) @@ -309,91 +489,202 @@ static int __test__pmu_event_aliases(char *pmu_name, int *count) pmu_add_cpu_aliases_map(&aliases, pmu, map); - for (te = &test->event; te->name; test++, te = &test->event) { - struct perf_pmu_alias *alias = find_alias(te->name, &aliases); + for (; *test_event_table; test_event_table++) { + struct perf_pmu_test_event const *test_event = *test_event_table; + struct pmu_event const *event = &test_event->event; + struct perf_pmu_alias *alias = find_alias(event->name, &aliases); if (!alias) { - bool uncore_match = pmu_uncore_alias_match(pmu_name, - te->pmu); - - if (use_uncore_table && !uncore_match) { - pr_debug3("testing aliases PMU %s: skip matching alias %s\n", - pmu_name, te->name); - continue; - } - - pr_debug2("testing aliases PMU %s: no alias, alias_table->name=%s\n", - pmu_name, te->name); + pr_debug("testing aliases core PMU %s: no alias, alias_table->name=%s\n", + pmu_name, event->name); res = -1; break; } - if (!is_same(alias->desc, te->desc)) { - pr_debug2("testing aliases PMU %s: mismatched desc, %s vs %s\n", - pmu_name, alias->desc, te->desc); + if (compare_alias_to_test_event(alias, test_event, pmu_name)) { res = -1; break; } - if (!is_same(alias->long_desc, test->alias_long_desc)) { - pr_debug2("testing aliases PMU %s: mismatched long_desc, %s vs %s\n", - pmu_name, alias->long_desc, - test->alias_long_desc); - res = -1; - break; - } + (*count)++; + pr_debug2("testing aliases core PMU %s: matched event %s\n", + pmu_name, alias->name); + } - if (!is_same(alias->str, test->alias_str)) { - pr_debug2("testing aliases PMU %s: mismatched str, %s vs %s\n", - pmu_name, alias->str, test->alias_str); - res = -1; - break; + list_for_each_entry_safe(a, tmp, &aliases, list) { + list_del(&a->list); + perf_pmu_free_alias(a); + } + free(pmu); + return res; +} + +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_alias *a, *tmp, *alias; + struct pmu_events_map *map; + LIST_HEAD(aliases); + int res = 0; + + map = __test_pmu_get_events_map(); + if (!map) + return -1; + pmu_add_cpu_aliases_map(&aliases, pmu, map); + pmu_add_sys_aliases(&aliases, pmu); + + /* Count how many aliases we generated */ + list_for_each_entry(alias, &aliases, list) + alias_count++; + + /* Count how many aliases we expect from the known table */ + for (table = &test_pmu->aliases[0]; *table; table++) + to_match_count++; + + 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); + res = -1; + goto out; + } + + list_for_each_entry(alias, &aliases, list) { + bool matched = false; + + for (table = &test_pmu->aliases[0]; *table; table++) { + struct perf_pmu_test_event const *test_event = *table; + struct pmu_event const *event = &test_event->event; + + if (!strcmp(event->name, alias->name)) { + if (compare_alias_to_test_event(alias, + test_event, + pmu_name)) { + continue; + } + matched = true; + matched_count++; + } } - if (!is_same(alias->topic, te->topic)) { - pr_debug2("testing aliases PMU %s: mismatched topic, %s vs %s\n", - pmu_name, alias->topic, te->topic); + if (matched == false) { + pr_debug("testing aliases uncore PMU %s: could not match alias %s\n", + pmu_name, alias->name); res = -1; - break; + goto out; } + } - (*count)++; - pr_debug2("testing aliases PMU %s: matched event %s\n", - pmu_name, alias->name); + 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); + res = -1; } +out: list_for_each_entry_safe(a, tmp, &aliases, list) { list_del(&a->list); perf_pmu_free_alias(a); } - free(pmu); return res; } +static struct perf_pmu_test_pmu test_pmus[] = { + { + .pmu = { + .name = (char *)"hisi_sccl1_ddrc2", + .is_uncore = 1, + }, + .aliases = { + &uncore_hisi_ddrc_flux_wcmd, + }, + }, + { + .pmu = { + .name = (char *)"uncore_cbox_0", + .is_uncore = 1, + }, + .aliases = { + &unc_cbo_xsnp_response_miss_eviction, + }, + }, + { + .pmu = { + .name = (char *)"hisi_sccl3_l3c7", + .is_uncore = 1, + }, + .aliases = { + &uncore_hisi_l3c_rd_hit_cpipe, + }, + }, + { + .pmu = { + .name = (char *)"uncore_imc_free_running_0", + .is_uncore = 1, + }, + .aliases = { + &uncore_imc_free_running_cache_miss, + }, + }, + { + .pmu = { + .name = (char *)"uncore_imc_0", + .is_uncore = 1, + }, + .aliases = { + &uncore_imc_cache_hits, + }, + }, + { + .pmu = { + .name = (char *)"uncore_sys_ddr_pmu0", + .is_uncore = 1, + .id = (char *)"v8", + }, + .aliases = { + &sys_ddr_pmu_write_cycles, + }, + }, +}; /* Test that aliases generated are as expected */ static int test_aliases(void) { struct perf_pmu *pmu = NULL; + unsigned long i; while ((pmu = perf_pmu__scan(pmu)) != NULL) { int count = 0; + if (!is_pmu_core(pmu->name)) + continue; + if (list_empty(&pmu->format)) { - pr_debug2("skipping testing PMU %s\n", pmu->name); + pr_debug2("skipping testing core PMU %s\n", pmu->name); continue; } - if (__test__pmu_event_aliases(pmu->name, &count)) { - pr_debug("testing PMU %s aliases: failed\n", pmu->name); + if (__test_core_pmu_event_aliases(pmu->name, &count)) { + pr_debug("testing core PMU %s aliases: failed\n", pmu->name); return -1; } - if (count == 0) - pr_debug3("testing PMU %s aliases: no events to match\n", + if (count == 0) { + pr_debug("testing core PMU %s aliases: no events to match\n", pmu->name); - else - pr_debug("testing PMU %s aliases: pass\n", pmu->name); + return -1; + } + + pr_debug("testing core PMU %s aliases: pass\n", pmu->name); + } + + for (i = 0; i < ARRAY_SIZE(test_pmus); i++) { + int res = __test_uncore_pmu_event_aliases(&test_pmus[i]); + + if (res) + return res; } return 0; diff --git a/tools/perf/tests/shell/lib/probe_vfs_getname.sh b/tools/perf/tests/shell/lib/probe_vfs_getname.sh index c2cc42daf924..5b17d916c555 100644 --- a/tools/perf/tests/shell/lib/probe_vfs_getname.sh +++ b/tools/perf/tests/shell/lib/probe_vfs_getname.sh @@ -19,6 +19,6 @@ add_probe_vfs_getname() { } skip_if_no_debuginfo() { - add_probe_vfs_getname -v 2>&1 | egrep -q "^(Failed to find the path for kernel|Debuginfo-analysis is not supported)" && return 2 + add_probe_vfs_getname -v 2>&1 | egrep -q "^(Failed to find the path for the kernel|Debuginfo-analysis is not supported)" && return 2 return 1 } diff --git a/tools/perf/tests/shell/pipe_test.sh b/tools/perf/tests/shell/pipe_test.sh new file mode 100755 index 000000000000..1b32b4f28391 --- /dev/null +++ b/tools/perf/tests/shell/pipe_test.sh @@ -0,0 +1,69 @@ +#!/bin/sh +# perf pipe recording and injection test +# SPDX-License-Identifier: GPL-2.0 + +# skip if there's no compiler +if ! [ -x "$(command -v cc)" ]; then + echo "failed: no compiler, install gcc" + exit 2 +fi + +file=$(mktemp /tmp/test.file.XXXXXX) +data=$(mktemp /tmp/perf.data.XXXXXX) + +cat <<EOF | cc -o ${file} -x c - +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> + +volatile int done; + +void sigalrm(int sig) { + done = 1; +} + +__attribute__((noinline)) void noploop(void) { + while (!done) + continue; +} + +int main(int argc, char *argv[]) { + int sec = 1; + + if (argc > 1) + sec = atoi(argv[1]); + + signal(SIGALRM, sigalrm); + alarm(sec); + + noploop(); + return 0; +} +EOF + + +if ! perf record -e task-clock:u -o - ${file} | perf report -i - --task | grep test.file; then + echo "cannot find the test file in the perf report" + exit 1 +fi + +if ! perf record -e task-clock:u -o - ${file} | perf inject -b | perf report -i - | grep noploop; then + echo "cannot find noploop function in pipe #1" + exit 1 +fi + +perf record -e task-clock:u -o - ${file} | perf inject -b -o ${data} +if ! perf report -i ${data} | grep noploop; then + echo "cannot find noploop function in pipe #2" + exit 1 +fi + +perf record -e task-clock:u -o ${data} ${file} +if ! perf inject -b -i ${data} | perf report -i - | grep noploop; then + echo "cannot find noploop function in pipe #3" + exit 1 +fi + + +rm -f ${file} ${data} ${data}.old +exit 0 diff --git a/tools/perf/tests/shell/record+zstd_comp_decomp.sh b/tools/perf/tests/shell/record+zstd_comp_decomp.sh index 045723b3d992..8a168cf8bacc 100755 --- a/tools/perf/tests/shell/record+zstd_comp_decomp.sh +++ b/tools/perf/tests/shell/record+zstd_comp_decomp.sh @@ -25,8 +25,8 @@ check_compressed_stats() { check_compressed_output() { $perf_tool inject -i $trace_file -o $trace_file.decomp && - $perf_tool report -i $trace_file --stdio | head -n -3 > $trace_file.comp.output && - $perf_tool report -i $trace_file.decomp --stdio | head -n -3 > $trace_file.decomp.output && + $perf_tool report -i $trace_file --stdio -F comm,dso,sym | head -n -3 > $trace_file.comp.output && + $perf_tool report -i $trace_file.decomp --stdio -F comm,dso,sym | head -n -3 > $trace_file.decomp.output && diff $trace_file.comp.output $trace_file.decomp.output } diff --git a/tools/perf/tests/shell/stat_bpf_counters.sh b/tools/perf/tests/shell/stat_bpf_counters.sh index 2f9948b3d943..2aed20dc2262 100755 --- a/tools/perf/tests/shell/stat_bpf_counters.sh +++ b/tools/perf/tests/shell/stat_bpf_counters.sh @@ -22,10 +22,24 @@ compare_number() } # skip if --bpf-counters is not supported -perf stat --bpf-counters true > /dev/null 2>&1 || exit 2 +if ! perf stat --bpf-counters true > /dev/null 2>&1; then + if [ "$1" == "-v" ]; then + echo "Skipping: --bpf-counters not supported" + perf --no-pager stat --bpf-counters true || true + fi + exit 2 +fi base_cycles=$(perf stat --no-big-num -e cycles -- perf bench sched messaging -g 1 -l 100 -t 2>&1 | awk '/cycles/ {print $1}') +if [ "$base_cycles" == "<not" ]; then + echo "Skipping: cycles event not counted" + exit 2 +fi bpf_cycles=$(perf stat --no-big-num --bpf-counters -e cycles -- perf bench sched messaging -g 1 -l 100 -t 2>&1 | awk '/cycles/ {print $1}') +if [ "$bpf_cycles" == "<not" ]; then + echo "Failed: cycles not counted with --bpf-counters" + exit 1 +fi compare_number $base_cycles $bpf_cycles exit 0 diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index b85f005308a3..fe1306f58495 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -127,20 +127,19 @@ int test__parse_metric(struct test *test, int subtest); int test__pe_file_parsing(struct test *test, int subtest); int test__expand_cgroup_events(struct test *test, int subtest); int test__perf_time_to_tsc(struct test *test, int subtest); +int test__dlfilter(struct test *test, int subtest); bool test__bp_signal_is_supported(void); bool test__bp_account_is_supported(void); bool test__wp_is_supported(void); bool test__tsc_is_supported(void); -#if defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT struct thread; struct perf_sample; int test__arch_unwind_sample(struct perf_sample *sample, struct thread *thread); #endif -#endif #if defined(__arm__) int test__vectors_page(struct test *test, int subtest); diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c index ec4e3b21b831..b9028e304ddd 100644 --- a/tools/perf/tests/topology.c +++ b/tools/perf/tests/topology.c @@ -38,7 +38,7 @@ static int session_write_header(char *path) .mode = PERF_DATA_MODE_WRITE, }; - session = perf_session__new(&data, false, NULL); + session = perf_session__new(&data, NULL); TEST_ASSERT_VAL("can't get session", !IS_ERR(session)); if (!perf_pmu__has_hybrid()) { @@ -61,6 +61,7 @@ static int session_write_header(char *path) TEST_ASSERT_VAL("failed to write header", !perf_session__write_header(session, session->evlist, data.file.fd, true)); + evlist__delete(session->evlist); perf_session__delete(session); return 0; @@ -76,7 +77,7 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) int i; struct aggr_cpu_id id; - session = perf_session__new(&data, false, NULL); + session = perf_session__new(&data, NULL); TEST_ASSERT_VAL("can't get session", !IS_ERR(session)); cpu__setup_cpunode_map(); |