xref: /linux/tools/testing/selftests/bpf/prog_tests/perf_branches.c (revision db6b35cffe59c619ea3772b21d7c7c8a7b885dc1)
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