0001
0002 #define _GNU_SOURCE
0003 #include <pthread.h>
0004 #include <sched.h>
0005 #include <sys/socket.h>
0006 #include <test_progs.h>
0007 #include "bpf/libbpf_internal.h"
0008 #include "test_perf_branches.skel.h"
0009
0010 static void check_good_sample(struct test_perf_branches *skel)
0011 {
0012 int written_global = skel->bss->written_global_out;
0013 int required_size = skel->bss->required_size_out;
0014 int written_stack = skel->bss->written_stack_out;
0015 int pbe_size = sizeof(struct perf_branch_entry);
0016 int duration = 0;
0017
0018 if (CHECK(!skel->bss->valid, "output not valid",
0019 "no valid sample from prog"))
0020 return;
0021
0022
0023
0024
0025
0026
0027
0028 CHECK(required_size <= 0, "read_branches_size", "err %d\n", required_size);
0029 CHECK(written_stack < 0, "read_branches_stack", "err %d\n", written_stack);
0030 CHECK(written_stack % pbe_size != 0, "read_branches_stack",
0031 "stack bytes written=%d not multiple of struct size=%d\n",
0032 written_stack, pbe_size);
0033 CHECK(written_global < 0, "read_branches_global", "err %d\n", written_global);
0034 CHECK(written_global % pbe_size != 0, "read_branches_global",
0035 "global bytes written=%d not multiple of struct size=%d\n",
0036 written_global, pbe_size);
0037 CHECK(written_global < written_stack, "read_branches_size",
0038 "written_global=%d < written_stack=%d\n", written_global, written_stack);
0039 }
0040
0041 static void check_bad_sample(struct test_perf_branches *skel)
0042 {
0043 int written_global = skel->bss->written_global_out;
0044 int required_size = skel->bss->required_size_out;
0045 int written_stack = skel->bss->written_stack_out;
0046 int duration = 0;
0047
0048 if (CHECK(!skel->bss->valid, "output not valid",
0049 "no valid sample from prog"))
0050 return;
0051
0052 CHECK((required_size != -EINVAL && required_size != -ENOENT),
0053 "read_branches_size", "err %d\n", required_size);
0054 CHECK((written_stack != -EINVAL && written_stack != -ENOENT),
0055 "read_branches_stack", "written %d\n", written_stack);
0056 CHECK((written_global != -EINVAL && written_global != -ENOENT),
0057 "read_branches_global", "written %d\n", written_global);
0058 }
0059
0060 static void test_perf_branches_common(int perf_fd,
0061 void (*cb)(struct test_perf_branches *))
0062 {
0063 struct test_perf_branches *skel;
0064 int err, i, duration = 0;
0065 bool detached = false;
0066 struct bpf_link *link;
0067 volatile int j = 0;
0068 cpu_set_t cpu_set;
0069
0070 skel = test_perf_branches__open_and_load();
0071 if (CHECK(!skel, "test_perf_branches_load",
0072 "perf_branches skeleton failed\n"))
0073 return;
0074
0075
0076 link = bpf_program__attach_perf_event(skel->progs.perf_branches, perf_fd);
0077 if (!ASSERT_OK_PTR(link, "attach_perf_event"))
0078 goto out_destroy_skel;
0079
0080
0081 CPU_ZERO(&cpu_set);
0082 CPU_SET(0, &cpu_set);
0083 err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set);
0084 if (CHECK(err, "set_affinity", "cpu #0, err %d\n", err))
0085 goto out_destroy;
0086
0087 for (i = 0; i < 1000000; ++i)
0088 ++j;
0089
0090 test_perf_branches__detach(skel);
0091 detached = true;
0092
0093 cb(skel);
0094 out_destroy:
0095 bpf_link__destroy(link);
0096 out_destroy_skel:
0097 if (!detached)
0098 test_perf_branches__detach(skel);
0099 test_perf_branches__destroy(skel);
0100 }
0101
0102 static void test_perf_branches_hw(void)
0103 {
0104 struct perf_event_attr attr = {0};
0105 int duration = 0;
0106 int pfd;
0107
0108
0109 attr.size = sizeof(attr);
0110 attr.type = PERF_TYPE_HARDWARE;
0111 attr.config = PERF_COUNT_HW_CPU_CYCLES;
0112 attr.freq = 1;
0113 attr.sample_freq = 1000;
0114 attr.sample_type = PERF_SAMPLE_BRANCH_STACK;
0115 attr.branch_sample_type = PERF_SAMPLE_BRANCH_USER | PERF_SAMPLE_BRANCH_ANY;
0116 pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC);
0117
0118
0119
0120
0121
0122 if (pfd < 0) {
0123 if (errno == ENOENT || errno == EOPNOTSUPP) {
0124 printf("%s:SKIP:no PERF_SAMPLE_BRANCH_STACK\n",
0125 __func__);
0126 test__skip();
0127 return;
0128 }
0129 if (CHECK(pfd < 0, "perf_event_open", "err %d errno %d\n",
0130 pfd, errno))
0131 return;
0132 }
0133
0134 test_perf_branches_common(pfd, check_good_sample);
0135
0136 close(pfd);
0137 }
0138
0139
0140
0141
0142
0143 static void test_perf_branches_no_hw(void)
0144 {
0145 struct perf_event_attr attr = {0};
0146 int duration = 0;
0147 int pfd;
0148
0149
0150 attr.size = sizeof(attr);
0151 attr.type = PERF_TYPE_SOFTWARE;
0152 attr.config = PERF_COUNT_SW_CPU_CLOCK;
0153 attr.freq = 1;
0154 attr.sample_freq = 1000;
0155 pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC);
0156 if (CHECK(pfd < 0, "perf_event_open", "err %d\n", pfd))
0157 return;
0158
0159 test_perf_branches_common(pfd, check_bad_sample);
0160
0161 close(pfd);
0162 }
0163
0164 void test_perf_branches(void)
0165 {
0166 if (test__start_subtest("perf_branches_hw"))
0167 test_perf_branches_hw();
0168 if (test__start_subtest("perf_branches_no_hw"))
0169 test_perf_branches_no_hw();
0170 }