// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2021 Facebook */ #include #include "get_branch_snapshot.skel.h" static int *pfd_array; static int cpu_cnt; static bool is_hypervisor(void) { char *line = NULL; bool ret = false; size_t len; FILE *fp; fp = fopen("/proc/cpuinfo", "r"); if (!fp) return false; while (getline(&line, &len, fp) != -1) { if (!strncmp(line, "flags", 5)) { if (strstr(line, "hypervisor") != NULL) ret = true; break; } } free(line); fclose(fp); return ret; } static int create_perf_events(void) { struct perf_event_attr attr = {0}; int cpu; /* create perf event */ attr.size = sizeof(attr); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_CPU_CYCLES; attr.sample_type = PERF_SAMPLE_BRANCH_STACK; attr.branch_sample_type = PERF_SAMPLE_BRANCH_KERNEL | PERF_SAMPLE_BRANCH_USER | PERF_SAMPLE_BRANCH_ANY; cpu_cnt = libbpf_num_possible_cpus(); pfd_array = malloc(sizeof(int) * cpu_cnt); if (!pfd_array) { cpu_cnt = 0; return 1; } for (cpu = 0; cpu < cpu_cnt; cpu++) { pfd_array[cpu] = syscall(__NR_perf_event_open, &attr, -1, cpu, -1, PERF_FLAG_FD_CLOEXEC); if (pfd_array[cpu] < 0) break; } return cpu == 0; } static void close_perf_events(void) { int cpu, fd; for (cpu = 0; cpu < cpu_cnt; cpu++) { fd = pfd_array[cpu]; if (fd < 0) break; close(fd); } free(pfd_array); } void serial_test_get_branch_snapshot(void) { struct get_branch_snapshot *skel = NULL; int err; /* Skip the test before we fix LBR snapshot for hypervisor. */ if (is_hypervisor()) { test__skip(); return; } if (create_perf_events()) { test__skip(); /* system doesn't support LBR */ goto cleanup; } skel = get_branch_snapshot__open_and_load(); if (!ASSERT_OK_PTR(skel, "get_branch_snapshot__open_and_load")) goto cleanup; err = kallsyms_find("bpf_testmod_loop_test", &skel->bss->address_low); if (!ASSERT_OK(err, "kallsyms_find")) goto cleanup; /* Just a guess for the end of this function, as module functions * in /proc/kallsyms could come in any order. */ skel->bss->address_high = skel->bss->address_low + 128; err = get_branch_snapshot__attach(skel); if (!ASSERT_OK(err, "get_branch_snapshot__attach")) goto cleanup; trigger_module_test_read(100); if (skel->bss->total_entries < 16) { /* too few entries for the hit/waste test */ test__skip(); goto cleanup; } ASSERT_GT(skel->bss->test1_hits, 6, "find_looptest_in_lbr"); /* Given we stop LBR in software, we will waste a few entries. * But we should try to waste as few as possible entries. We are at * about 7 on x86_64 systems. * Add a check for < 10 so that we get heads-up when something * changes and wastes too many entries. */ ASSERT_LT(skel->bss->wasted_entries, 10, "check_wasted_entries"); cleanup: get_branch_snapshot__destroy(skel); close_perf_events(); }