Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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      * It's hard to validate the contents of the branch entries b/c it
0024      * would require some kind of disassembler and also encoding the
0025      * valid jump instructions for supported architectures. So just check
0026      * the easy stuff for now.
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     /* attach perf_event */
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     /* generate some branches on cpu 0 */
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     /* spin the loop for a while (random high number) */
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     /* create perf event */
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      * Some setups don't support branch records (virtual machines, !x86),
0120      * so skip test in this case.
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  * Tests negative case -- run bpf_read_branch_records() on improperly configured
0141  * perf event.
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     /* create perf event */
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 }