1 // SPDX-License-Identifier: GPL-2.0 2 #define _GNU_SOURCE 3 #include <pthread.h> 4 #include <sched.h> 5 #include <sys/socket.h> 6 #include <test_progs.h> 7 #include "bpf/libbpf_internal.h" 8 #include "test_perf_branches.skel.h" 9 10 static void check_good_sample(struct test_perf_branches *skel) 11 { 12 int written_global = skel->bss->written_global_out; 13 int required_size = skel->bss->required_size_out; 14 int written_stack = skel->bss->written_stack_out; 15 int pbe_size = sizeof(struct perf_branch_entry); 16 int duration = 0; 17 18 if (CHECK(!skel->bss->run_cnt, "invalid run_cnt", 19 "checked sample validity before prog run")) 20 return; 21 22 if (CHECK(!skel->bss->valid, "output not valid", 23 "no valid sample from prog")) 24 return; 25 26 /* 27 * It's hard to validate the contents of the branch entries b/c it 28 * would require some kind of disassembler and also encoding the 29 * valid jump instructions for supported architectures. So just check 30 * the easy stuff for now. 31 */ 32 CHECK(required_size <= 0, "read_branches_size", "err %d\n", required_size); 33 CHECK(written_stack < 0, "read_branches_stack", "err %d\n", written_stack); 34 CHECK(written_stack % pbe_size != 0, "read_branches_stack", 35 "stack bytes written=%d not multiple of struct size=%d\n", 36 written_stack, pbe_size); 37 CHECK(written_global < 0, "read_branches_global", "err %d\n", written_global); 38 CHECK(written_global % pbe_size != 0, "read_branches_global", 39 "global bytes written=%d not multiple of struct size=%d\n", 40 written_global, pbe_size); 41 CHECK(written_global < written_stack, "read_branches_size", 42 "written_global=%d < written_stack=%d\n", written_global, written_stack); 43 } 44 45 static void check_bad_sample(struct test_perf_branches *skel) 46 { 47 int written_global = skel->bss->written_global_out; 48 int required_size = skel->bss->required_size_out; 49 int written_stack = skel->bss->written_stack_out; 50 int duration = 0; 51 52 if (CHECK(!skel->bss->run_cnt, "invalid run_cnt", 53 "checked sample validity before prog run")) 54 return; 55 56 if (CHECK(!skel->bss->valid, "output not valid", 57 "no valid sample from prog")) 58 return; 59 60 CHECK((required_size != -EINVAL && required_size != -ENOENT), 61 "read_branches_size", "err %d\n", required_size); 62 CHECK((written_stack != -EINVAL && written_stack != -ENOENT), 63 "read_branches_stack", "written %d\n", written_stack); 64 CHECK((written_global != -EINVAL && written_global != -ENOENT), 65 "read_branches_global", "written %d\n", written_global); 66 } 67 68 static void test_perf_branches_common(int perf_fd, 69 void (*cb)(struct test_perf_branches *)) 70 { 71 struct test_perf_branches *skel; 72 int err, i, duration = 0; 73 bool detached = false; 74 struct bpf_link *link; 75 volatile int j = 0; 76 cpu_set_t cpu_set; 77 78 skel = test_perf_branches__open_and_load(); 79 if (CHECK(!skel, "test_perf_branches_load", 80 "perf_branches skeleton failed\n")) 81 return; 82 83 /* attach perf_event */ 84 link = bpf_program__attach_perf_event(skel->progs.perf_branches, perf_fd); 85 if (!ASSERT_OK_PTR(link, "attach_perf_event")) 86 goto out_destroy_skel; 87 88 /* generate some branches on cpu 0 */ 89 CPU_ZERO(&cpu_set); 90 CPU_SET(0, &cpu_set); 91 err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set); 92 if (CHECK(err, "set_affinity", "cpu #0, err %d\n", err)) 93 goto out_destroy; 94 95 /* Spin the loop for a while by using a high iteration count, and by 96 * checking whether the specific run count marker has been explicitly 97 * incremented at least once by the backing perf_event BPF program. 98 */ 99 for (i = 0; i < 100000000 && !*(volatile int *)&skel->bss->run_cnt; ++i) 100 ++j; 101 102 test_perf_branches__detach(skel); 103 detached = true; 104 105 cb(skel); 106 out_destroy: 107 bpf_link__destroy(link); 108 out_destroy_skel: 109 if (!detached) 110 test_perf_branches__detach(skel); 111 test_perf_branches__destroy(skel); 112 } 113 114 static void test_perf_branches_hw(void) 115 { 116 struct perf_event_attr attr = {0}; 117 int duration = 0; 118 int pfd; 119 120 /* create perf event */ 121 attr.size = sizeof(attr); 122 attr.type = PERF_TYPE_HARDWARE; 123 attr.config = PERF_COUNT_HW_CPU_CYCLES; 124 attr.freq = 1; 125 attr.sample_freq = 1000; 126 attr.sample_type = PERF_SAMPLE_BRANCH_STACK; 127 attr.branch_sample_type = PERF_SAMPLE_BRANCH_USER | PERF_SAMPLE_BRANCH_ANY; 128 pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); 129 130 /* 131 * Some setups don't support LBR (virtual machines, !x86, AMD Milan Zen 132 * 3 which only supports BRS), so skip test in this case. 133 */ 134 if (pfd < 0) { 135 if (errno == ENOENT || errno == EOPNOTSUPP || errno == EINVAL) { 136 printf("%s:SKIP:no PERF_SAMPLE_BRANCH_STACK\n", 137 __func__); 138 test__skip(); 139 return; 140 } 141 if (CHECK(pfd < 0, "perf_event_open", "err %d errno %d\n", 142 pfd, errno)) 143 return; 144 } 145 146 test_perf_branches_common(pfd, check_good_sample); 147 148 close(pfd); 149 } 150 151 /* 152 * Tests negative case -- run bpf_read_branch_records() on improperly configured 153 * perf event. 154 */ 155 static void test_perf_branches_no_hw(void) 156 { 157 struct perf_event_attr attr = {0}; 158 int duration = 0; 159 int pfd; 160 161 /* create perf event */ 162 attr.size = sizeof(attr); 163 attr.type = PERF_TYPE_SOFTWARE; 164 attr.config = PERF_COUNT_SW_CPU_CLOCK; 165 attr.freq = 1; 166 attr.sample_freq = 1000; 167 pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); 168 if (CHECK(pfd < 0, "perf_event_open", "err %d\n", pfd)) 169 return; 170 171 test_perf_branches_common(pfd, check_bad_sample); 172 173 close(pfd); 174 } 175 176 void test_perf_branches(void) 177 { 178 if (test__start_subtest("perf_branches_hw")) 179 test_perf_branches_hw(); 180 if (test__start_subtest("perf_branches_no_hw")) 181 test_perf_branches_no_hw(); 182 } 183