On Mon, Feb 10, 2020 at 12:09 PM Daniel Xu <dxu@xxxxxxxxx> wrote: > > Add a selftest to test: > > * default bpf_read_branch_records() behavior > * BPF_F_GET_BRANCH_RECORDS_SIZE flag behavior > * error path on non branch record perf events > * using helper to write to stack > * using helper to write to map > > On host with hardware counter support: > > # ./test_progs -t perf_branches > #27/1 perf_branches_hw:OK > #27/2 perf_branches_no_hw:OK > #27 perf_branches:OK > Summary: 1/2 PASSED, 0 SKIPPED, 0 FAILED > > On host without hardware counter support (VM): > > # ./test_progs -t perf_branches > #27/1 perf_branches_hw:OK > #27/2 perf_branches_no_hw:OK > #27 perf_branches:OK > Summary: 1/2 PASSED, 1 SKIPPED, 0 FAILED > > Also sync tools/include/uapi/linux/bpf.h. > > Signed-off-by: Daniel Xu <dxu@xxxxxxxxx> > --- > tools/include/uapi/linux/bpf.h | 25 ++- > .../selftests/bpf/prog_tests/perf_branches.c | 182 ++++++++++++++++++ > .../selftests/bpf/progs/test_perf_branches.c | 74 +++++++ > 3 files changed, 280 insertions(+), 1 deletion(-) > create mode 100644 tools/testing/selftests/bpf/prog_tests/perf_branches.c > create mode 100644 tools/testing/selftests/bpf/progs/test_perf_branches.c > [...] > + /* generate some branches on cpu 0 */ > + CPU_ZERO(&cpu_set); > + CPU_SET(0, &cpu_set); > + err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set); > + if (CHECK(err, "set_affinity", "cpu #0, err %d\n", err)) > + goto out_free_pb; > + /* spin the loop for a while (random high number) */ > + for (i = 0; i < 1000000; ++i) > + ++j; > + test_perf_branches__detach here? > + /* read perf buffer */ > + err = perf_buffer__poll(pb, 500); > + if (CHECK(err < 0, "perf_buffer__poll", "err %d\n", err)) > + goto out_free_pb; > + > + if (CHECK(!ok, "ok", "not ok\n")) > + goto out_free_pb; > + [...] > diff --git a/tools/testing/selftests/bpf/progs/test_perf_branches.c b/tools/testing/selftests/bpf/progs/test_perf_branches.c > new file mode 100644 > index 000000000000..60327d512400 > --- /dev/null > +++ b/tools/testing/selftests/bpf/progs/test_perf_branches.c > @@ -0,0 +1,74 @@ > +// SPDX-License-Identifier: GPL-2.0 > +// Copyright (c) 2019 Facebook > + > +#include <stddef.h> > +#include <linux/ptrace.h> > +#include <linux/bpf.h> > +#include <bpf/bpf_helpers.h> > +#include "bpf_trace_helpers.h" > + > +struct fake_perf_branch_entry { > + __u64 _a; > + __u64 _b; > + __u64 _c; > +}; > + > +struct output { > + int required_size; > + int written_stack; > + int written_map; > +}; > + > +struct { > + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); > + __uint(key_size, sizeof(int)); > + __uint(value_size, sizeof(int)); > +} perf_buf_map SEC(".maps"); > + > +typedef struct fake_perf_branch_entry fpbe_t[30]; > + > +struct { > + __uint(type, BPF_MAP_TYPE_ARRAY); > + __uint(max_entries, 1); > + __type(key, __u32); > + __type(value, fpbe_t); > +} scratch_map SEC(".maps"); Can you please use global variables instead of array and perf_event_array? Would make BPF side clearer and userspace simpler. struct output member will just become variables. [...]