File Index
Files and directories
Sign in
FILE

perf_branches.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/bpf/prog_tests/perf_branches.c C
  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
 10static 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
 45static 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
 68static 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);
106out_destroy:
107	bpf_link__destroy(link);
108out_destroy_skel:
109	if (!detached)
110		test_perf_branches__detach(skel);
111	test_perf_branches__destroy(skel);
112}
113
114static 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 */
155static 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
176void 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}
~/ Read-only file preview.