Message ID | 20230314234237.3008956-3-namhyung@kernel.org (mailing list archive) |
---|---|
State | Handled Elsewhere |
Delegated to: | BPF |
Headers | show |
Series | perf record: Implement BPF sample filter (v5) | expand |
Em Tue, Mar 14, 2023 at 04:42:29PM -0700, Namhyung Kim escreveu: > The BPF program will be attached to a perf_event and be triggered when > it overflows. It'd iterate the filters map and compare the sample > value according to the expression. If any of them fails, the sample > would be dropped. > > Also it needs to have the corresponding sample data for the expression > so it compares data->sample_flags with the given value. To access the > sample data, it uses the bpf_cast_to_kern_ctx() kfunc which was added > in v6.2 kernel. > > Acked-by: Jiri Olsa <jolsa@kernel.org> > Signed-off-by: Namhyung Kim <namhyung@kernel.org> I'm noticing this while building on a debian:11 container: GENSKEL /tmp/build/perf/util/bpf_skel/bperf_leader.skel.h GENSKEL /tmp/build/perf/util/bpf_skel/bperf_follower.skel.h GENSKEL /tmp/build/perf/util/bpf_skel/func_latency.skel.h GENSKEL /tmp/build/perf/util/bpf_skel/bpf_prog_profiler.skel.h GENSKEL /tmp/build/perf/util/bpf_skel/kwork_trace.skel.h GENSKEL /tmp/build/perf/util/bpf_skel/sample_filter.skel.h libbpf: failed to find BTF for extern 'bpf_cast_to_kern_ctx' [21] section: -2 Error: failed to open BPF object file: No such file or directory make[2]: *** [Makefile.perf:1085: /tmp/build/perf/util/bpf_skel/sample_filter.skel.h] Error 254 make[2]: *** Deleting file '/tmp/build/perf/util/bpf_skel/sample_filter.skel.h' make[2]: *** Waiting for unfinished jobs.... make[1]: *** [Makefile.perf:236: sub-make] Error 2 make: *** [Makefile:70: all] Error 2 make: Leaving directory '/git/perf-6.3.0-rc1/tools/perf' + exit 1 [perfbuilder@five 11]$ - Arnaldo > --- > tools/perf/Makefile.perf | 2 +- > tools/perf/util/bpf-filter.c | 64 ++++++++++ > tools/perf/util/bpf-filter.h | 26 ++-- > tools/perf/util/bpf_skel/sample-filter.h | 24 ++++ > tools/perf/util/bpf_skel/sample_filter.bpf.c | 126 +++++++++++++++++++ > tools/perf/util/evsel.h | 7 +- > 6 files changed, 236 insertions(+), 13 deletions(-) > create mode 100644 tools/perf/util/bpf_skel/sample-filter.h > create mode 100644 tools/perf/util/bpf_skel/sample_filter.bpf.c > > diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf > index dc9dda09b076..ed6b6a070f79 100644 > --- a/tools/perf/Makefile.perf > +++ b/tools/perf/Makefile.perf > @@ -1050,7 +1050,7 @@ SKELETONS := $(SKEL_OUT)/bpf_prog_profiler.skel.h > SKELETONS += $(SKEL_OUT)/bperf_leader.skel.h $(SKEL_OUT)/bperf_follower.skel.h > SKELETONS += $(SKEL_OUT)/bperf_cgroup.skel.h $(SKEL_OUT)/func_latency.skel.h > SKELETONS += $(SKEL_OUT)/off_cpu.skel.h $(SKEL_OUT)/lock_contention.skel.h > -SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h > +SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h $(SKEL_OUT)/sample_filter.skel.h > > $(SKEL_TMP_OUT) $(LIBAPI_OUTPUT) $(LIBBPF_OUTPUT) $(LIBPERF_OUTPUT) $(LIBSUBCMD_OUTPUT) $(LIBSYMBOL_OUTPUT): > $(Q)$(MKDIR) -p $@ > diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c > index c72e35d51240..f20e1bc03778 100644 > --- a/tools/perf/util/bpf-filter.c > +++ b/tools/perf/util/bpf-filter.c > @@ -1,10 +1,74 @@ > /* SPDX-License-Identifier: GPL-2.0 */ > #include <stdlib.h> > > +#include <bpf/bpf.h> > +#include <linux/err.h> > +#include <internal/xyarray.h> > + > +#include "util/debug.h" > +#include "util/evsel.h" > + > #include "util/bpf-filter.h" > #include "util/bpf-filter-flex.h" > #include "util/bpf-filter-bison.h" > > +#include "bpf_skel/sample-filter.h" > +#include "bpf_skel/sample_filter.skel.h" > + > +#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) > + > +int perf_bpf_filter__prepare(struct evsel *evsel) > +{ > + int i, x, y, fd; > + struct sample_filter_bpf *skel; > + struct bpf_program *prog; > + struct bpf_link *link; > + struct perf_bpf_filter_expr *expr; > + > + skel = sample_filter_bpf__open_and_load(); > + if (!skel) { > + pr_err("Failed to load perf sample-filter BPF skeleton\n"); > + return -1; > + } > + > + i = 0; > + fd = bpf_map__fd(skel->maps.filters); > + list_for_each_entry(expr, &evsel->bpf_filters, list) { > + struct perf_bpf_filter_entry entry = { > + .op = expr->op, > + .flags = expr->sample_flags, > + .value = expr->val, > + }; > + bpf_map_update_elem(fd, &i, &entry, BPF_ANY); > + i++; > + } > + > + prog = skel->progs.perf_sample_filter; > + for (x = 0; x < xyarray__max_x(evsel->core.fd); x++) { > + for (y = 0; y < xyarray__max_y(evsel->core.fd); y++) { > + link = bpf_program__attach_perf_event(prog, FD(evsel, x, y)); > + if (IS_ERR(link)) { > + pr_err("Failed to attach perf sample-filter program\n"); > + return PTR_ERR(link); > + } > + } > + } > + evsel->bpf_skel = skel; > + return 0; > +} > + > +int perf_bpf_filter__destroy(struct evsel *evsel) > +{ > + struct perf_bpf_filter_expr *expr, *tmp; > + > + list_for_each_entry_safe(expr, tmp, &evsel->bpf_filters, list) { > + list_del(&expr->list); > + free(expr); > + } > + sample_filter_bpf__destroy(evsel->bpf_skel); > + return 0; > +} > + > struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, > enum perf_bpf_filter_op op, > unsigned long val) > diff --git a/tools/perf/util/bpf-filter.h b/tools/perf/util/bpf-filter.h > index 93a0d3de038c..eb8e1ac43cdf 100644 > --- a/tools/perf/util/bpf-filter.h > +++ b/tools/perf/util/bpf-filter.h > @@ -4,15 +4,7 @@ > > #include <linux/list.h> > > -enum perf_bpf_filter_op { > - PBF_OP_EQ, > - PBF_OP_NEQ, > - PBF_OP_GT, > - PBF_OP_GE, > - PBF_OP_LT, > - PBF_OP_LE, > - PBF_OP_AND, > -}; > +#include "bpf_skel/sample-filter.h" > > struct perf_bpf_filter_expr { > struct list_head list; > @@ -21,16 +13,30 @@ struct perf_bpf_filter_expr { > unsigned long val; > }; > > +struct evsel; > + > #ifdef HAVE_BPF_SKEL > struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, > enum perf_bpf_filter_op op, > unsigned long val); > int perf_bpf_filter__parse(struct list_head *expr_head, const char *str); > +int perf_bpf_filter__prepare(struct evsel *evsel); > +int perf_bpf_filter__destroy(struct evsel *evsel); > + > #else /* !HAVE_BPF_SKEL */ > + > static inline int perf_bpf_filter__parse(struct list_head *expr_head __maybe_unused, > const char *str __maybe_unused) > { > - return -ENOSYS; > + return -EOPNOTSUPP; > +} > +static inline int perf_bpf_filter__prepare(struct evsel *evsel __maybe_unused) > +{ > + return -EOPNOTSUPP; > +} > +static inline int perf_bpf_filter__destroy(struct evsel *evsel __maybe_unused) > +{ > + return -EOPNOTSUPP; > } > #endif /* HAVE_BPF_SKEL*/ > #endif /* PERF_UTIL_BPF_FILTER_H */ > diff --git a/tools/perf/util/bpf_skel/sample-filter.h b/tools/perf/util/bpf_skel/sample-filter.h > new file mode 100644 > index 000000000000..862060bfda14 > --- /dev/null > +++ b/tools/perf/util/bpf_skel/sample-filter.h > @@ -0,0 +1,24 @@ > +#ifndef PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H > +#define PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H > + > +#define MAX_FILTERS 32 > + > +/* supported filter operations */ > +enum perf_bpf_filter_op { > + PBF_OP_EQ, > + PBF_OP_NEQ, > + PBF_OP_GT, > + PBF_OP_GE, > + PBF_OP_LT, > + PBF_OP_LE, > + PBF_OP_AND > +}; > + > +/* BPF map entry for filtering */ > +struct perf_bpf_filter_entry { > + enum perf_bpf_filter_op op; > + __u64 flags; > + __u64 value; > +}; > + > +#endif /* PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H */ > \ No newline at end of file > diff --git a/tools/perf/util/bpf_skel/sample_filter.bpf.c b/tools/perf/util/bpf_skel/sample_filter.bpf.c > new file mode 100644 > index 000000000000..c07256279c3e > --- /dev/null > +++ b/tools/perf/util/bpf_skel/sample_filter.bpf.c > @@ -0,0 +1,126 @@ > +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > +// Copyright (c) 2023 Google > +#include "vmlinux.h" > +#include <bpf/bpf_helpers.h> > +#include <bpf/bpf_tracing.h> > +#include <bpf/bpf_core_read.h> > + > +#include "sample-filter.h" > + > +/* BPF map that will be filled by user space */ > +struct filters { > + __uint(type, BPF_MAP_TYPE_ARRAY); > + __type(key, int); > + __type(value, struct perf_bpf_filter_entry); > + __uint(max_entries, MAX_FILTERS); > +} filters SEC(".maps"); > + > +int dropped; > + > +void *bpf_cast_to_kern_ctx(void *) __ksym; > + > +/* new kernel perf_sample_data definition */ > +struct perf_sample_data___new { > + __u64 sample_flags; > +} __attribute__((preserve_access_index)); > + > +/* helper function to return the given perf sample data */ > +static inline __u64 perf_get_sample(struct bpf_perf_event_data_kern *kctx, > + struct perf_bpf_filter_entry *entry) > +{ > + struct perf_sample_data___new *data = (void *)kctx->data; > + > + if (!bpf_core_field_exists(data->sample_flags) || > + (data->sample_flags & entry->flags) == 0) > + return 0; > + > + switch (entry->flags) { > + case PERF_SAMPLE_IP: > + return kctx->data->ip; > + case PERF_SAMPLE_ID: > + return kctx->data->id; > + case PERF_SAMPLE_TID: > + return kctx->data->tid_entry.tid; > + case PERF_SAMPLE_CPU: > + return kctx->data->cpu_entry.cpu; > + case PERF_SAMPLE_TIME: > + return kctx->data->time; > + case PERF_SAMPLE_ADDR: > + return kctx->data->addr; > + case PERF_SAMPLE_PERIOD: > + return kctx->data->period; > + case PERF_SAMPLE_TRANSACTION: > + return kctx->data->txn; > + case PERF_SAMPLE_WEIGHT: > + return kctx->data->weight.full; > + case PERF_SAMPLE_PHYS_ADDR: > + return kctx->data->phys_addr; > + case PERF_SAMPLE_CODE_PAGE_SIZE: > + return kctx->data->code_page_size; > + case PERF_SAMPLE_DATA_PAGE_SIZE: > + return kctx->data->data_page_size; > + default: > + break; > + } > + return 0; > +} > + > +/* BPF program to be called from perf event overflow handler */ > +SEC("perf_event") > +int perf_sample_filter(void *ctx) > +{ > + struct bpf_perf_event_data_kern *kctx; > + struct perf_bpf_filter_entry *entry; > + __u64 sample_data; > + int i; > + > + kctx = bpf_cast_to_kern_ctx(ctx); > + > + for (i = 0; i < MAX_FILTERS; i++) { > + int key = i; /* needed for verifier :( */ > + > + entry = bpf_map_lookup_elem(&filters, &key); > + if (entry == NULL) > + break; > + sample_data = perf_get_sample(kctx, entry); > + > + switch (entry->op) { > + case PBF_OP_EQ: > + if (!(sample_data == entry->value)) > + goto drop; > + break; > + case PBF_OP_NEQ: > + if (!(sample_data != entry->value)) > + goto drop; > + break; > + case PBF_OP_GT: > + if (!(sample_data > entry->value)) > + goto drop; > + break; > + case PBF_OP_GE: > + if (!(sample_data >= entry->value)) > + goto drop; > + break; > + case PBF_OP_LT: > + if (!(sample_data < entry->value)) > + goto drop; > + break; > + case PBF_OP_LE: > + if (!(sample_data <= entry->value)) > + goto drop; > + break; > + case PBF_OP_AND: > + if (!(sample_data & entry->value)) > + goto drop; > + break; > + } > + } > + /* generate sample data */ > + return 1; > + > +drop: > + __sync_fetch_and_add(&dropped, 1); > + return 0; > +} > + > +char LICENSE[] SEC("license") = "Dual BSD/GPL"; > diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h > index c272c06565c0..68072ec655ce 100644 > --- a/tools/perf/util/evsel.h > +++ b/tools/perf/util/evsel.h > @@ -150,8 +150,10 @@ struct evsel { > */ > struct bpf_counter_ops *bpf_counter_ops; > > - /* for perf-stat -b */ > - struct list_head bpf_counter_list; > + union { > + struct list_head bpf_counter_list; /* for perf-stat -b */ > + struct list_head bpf_filters; /* for perf-record --filter */ > + }; > > /* for perf-stat --use-bpf */ > int bperf_leader_prog_fd; > @@ -159,6 +161,7 @@ struct evsel { > union { > struct bperf_leader_bpf *leader_skel; > struct bperf_follower_bpf *follower_skel; > + void *bpf_skel; > }; > unsigned long open_flags; > int precise_ip_original; > -- > 2.40.0.rc1.284.g88254d51c5-goog >
Em Wed, Mar 15, 2023 at 01:24:37PM -0300, Arnaldo Carvalho de Melo escreveu: > Em Tue, Mar 14, 2023 at 04:42:29PM -0700, Namhyung Kim escreveu: > > The BPF program will be attached to a perf_event and be triggered when > > it overflows. It'd iterate the filters map and compare the sample > > value according to the expression. If any of them fails, the sample > > would be dropped. > > > > Also it needs to have the corresponding sample data for the expression > > so it compares data->sample_flags with the given value. To access the > > sample data, it uses the bpf_cast_to_kern_ctx() kfunc which was added > > in v6.2 kernel. > > > > Acked-by: Jiri Olsa <jolsa@kernel.org> > > Signed-off-by: Namhyung Kim <namhyung@kernel.org> > > > I'm noticing this while building on a debian:11 container: > > GENSKEL /tmp/build/perf/util/bpf_skel/bperf_leader.skel.h > GENSKEL /tmp/build/perf/util/bpf_skel/bperf_follower.skel.h > GENSKEL /tmp/build/perf/util/bpf_skel/func_latency.skel.h > GENSKEL /tmp/build/perf/util/bpf_skel/bpf_prog_profiler.skel.h > GENSKEL /tmp/build/perf/util/bpf_skel/kwork_trace.skel.h > GENSKEL /tmp/build/perf/util/bpf_skel/sample_filter.skel.h > libbpf: failed to find BTF for extern 'bpf_cast_to_kern_ctx' [21] section: -2 > Error: failed to open BPF object file: No such file or directory > make[2]: *** [Makefile.perf:1085: /tmp/build/perf/util/bpf_skel/sample_filter.skel.h] Error 254 > make[2]: *** Deleting file '/tmp/build/perf/util/bpf_skel/sample_filter.skel.h' > make[2]: *** Waiting for unfinished jobs.... > make[1]: *** [Makefile.perf:236: sub-make] Error 2 > make: *** [Makefile:70: all] Error 2 > make: Leaving directory '/git/perf-6.3.0-rc1/tools/perf' > + exit 1 > [perfbuilder@five 11]$ Same thing on debian:10 libbpf: failed to find BTF for extern 'bpf_cast_to_kern_ctx' [21] section: -2 Error: failed to open BPF object file: No such file or directory make[2]: *** [Makefile.perf:1085: /tmp/build/perf/util/bpf_skel/sample_filter.skel.h] Error 254 make[2]: *** Deleting file '/tmp/build/perf/util/bpf_skel/sample_filter.skel.h' make[2]: *** Waiting for unfinished jobs.... make[1]: *** [Makefile.perf:236: sub-make] Error 2 make: *** [Makefile:70: all] Error 2 make: Leaving directory '/git/perf-6.3.0-rc1/tools/perf' + exit 1 [perfbuilder@five 10]$ Works with debian:experimental: [perfbuilder@five experimental]$ export BUILD_TARBALL=http://192.168.86.10/perf/perf-6.3.0-rc1.tar.xz [perfbuilder@five experimental]$ time dm . 1 147.54 debian:experimental : Ok gcc (Debian 12.2.0-14) 12.2.0 , Debian clang version 14.0.6 BUILD_TARBALL_HEAD=d34a77f6cd75d2a75c64e78f3d949a12903a7cf0 Both with: Debian clang version 14.0.6 Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/12 Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/12 Candidate multilib: .;@m64 Selected multilib: .;@m64 + rm -rf /tmp/build/perf + mkdir /tmp/build/perf + make ARCH= CROSS_COMPILE= EXTRA_CFLAGS= -C tools/perf O=/tmp/build/perf CC=clang and: COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Debian 12.2.0-14' --with-bugurl=file:///usr/share/doc/gcc-12/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-12 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-12-bTRWOB/gcc-12-12.2.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-12-bTRWOB/gcc-12-12.2.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 12.2.0 (Debian 12.2.0-14) + make ARCH= CROSS_COMPILE= EXTRA_CFLAGS= -C tools/perf O=/tmp/build/perf make: Entering directory '/git/perf-6.3.0-rc1/tools/perf' > > > --- > > tools/perf/Makefile.perf | 2 +- > > tools/perf/util/bpf-filter.c | 64 ++++++++++ > > tools/perf/util/bpf-filter.h | 26 ++-- > > tools/perf/util/bpf_skel/sample-filter.h | 24 ++++ > > tools/perf/util/bpf_skel/sample_filter.bpf.c | 126 +++++++++++++++++++ > > tools/perf/util/evsel.h | 7 +- > > 6 files changed, 236 insertions(+), 13 deletions(-) > > create mode 100644 tools/perf/util/bpf_skel/sample-filter.h > > create mode 100644 tools/perf/util/bpf_skel/sample_filter.bpf.c > > > > diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf > > index dc9dda09b076..ed6b6a070f79 100644 > > --- a/tools/perf/Makefile.perf > > +++ b/tools/perf/Makefile.perf > > @@ -1050,7 +1050,7 @@ SKELETONS := $(SKEL_OUT)/bpf_prog_profiler.skel.h > > SKELETONS += $(SKEL_OUT)/bperf_leader.skel.h $(SKEL_OUT)/bperf_follower.skel.h > > SKELETONS += $(SKEL_OUT)/bperf_cgroup.skel.h $(SKEL_OUT)/func_latency.skel.h > > SKELETONS += $(SKEL_OUT)/off_cpu.skel.h $(SKEL_OUT)/lock_contention.skel.h > > -SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h > > +SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h $(SKEL_OUT)/sample_filter.skel.h > > > > $(SKEL_TMP_OUT) $(LIBAPI_OUTPUT) $(LIBBPF_OUTPUT) $(LIBPERF_OUTPUT) $(LIBSUBCMD_OUTPUT) $(LIBSYMBOL_OUTPUT): > > $(Q)$(MKDIR) -p $@ > > diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c > > index c72e35d51240..f20e1bc03778 100644 > > --- a/tools/perf/util/bpf-filter.c > > +++ b/tools/perf/util/bpf-filter.c > > @@ -1,10 +1,74 @@ > > /* SPDX-License-Identifier: GPL-2.0 */ > > #include <stdlib.h> > > > > +#include <bpf/bpf.h> > > +#include <linux/err.h> > > +#include <internal/xyarray.h> > > + > > +#include "util/debug.h" > > +#include "util/evsel.h" > > + > > #include "util/bpf-filter.h" > > #include "util/bpf-filter-flex.h" > > #include "util/bpf-filter-bison.h" > > > > +#include "bpf_skel/sample-filter.h" > > +#include "bpf_skel/sample_filter.skel.h" > > + > > +#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) > > + > > +int perf_bpf_filter__prepare(struct evsel *evsel) > > +{ > > + int i, x, y, fd; > > + struct sample_filter_bpf *skel; > > + struct bpf_program *prog; > > + struct bpf_link *link; > > + struct perf_bpf_filter_expr *expr; > > + > > + skel = sample_filter_bpf__open_and_load(); > > + if (!skel) { > > + pr_err("Failed to load perf sample-filter BPF skeleton\n"); > > + return -1; > > + } > > + > > + i = 0; > > + fd = bpf_map__fd(skel->maps.filters); > > + list_for_each_entry(expr, &evsel->bpf_filters, list) { > > + struct perf_bpf_filter_entry entry = { > > + .op = expr->op, > > + .flags = expr->sample_flags, > > + .value = expr->val, > > + }; > > + bpf_map_update_elem(fd, &i, &entry, BPF_ANY); > > + i++; > > + } > > + > > + prog = skel->progs.perf_sample_filter; > > + for (x = 0; x < xyarray__max_x(evsel->core.fd); x++) { > > + for (y = 0; y < xyarray__max_y(evsel->core.fd); y++) { > > + link = bpf_program__attach_perf_event(prog, FD(evsel, x, y)); > > + if (IS_ERR(link)) { > > + pr_err("Failed to attach perf sample-filter program\n"); > > + return PTR_ERR(link); > > + } > > + } > > + } > > + evsel->bpf_skel = skel; > > + return 0; > > +} > > + > > +int perf_bpf_filter__destroy(struct evsel *evsel) > > +{ > > + struct perf_bpf_filter_expr *expr, *tmp; > > + > > + list_for_each_entry_safe(expr, tmp, &evsel->bpf_filters, list) { > > + list_del(&expr->list); > > + free(expr); > > + } > > + sample_filter_bpf__destroy(evsel->bpf_skel); > > + return 0; > > +} > > + > > struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, > > enum perf_bpf_filter_op op, > > unsigned long val) > > diff --git a/tools/perf/util/bpf-filter.h b/tools/perf/util/bpf-filter.h > > index 93a0d3de038c..eb8e1ac43cdf 100644 > > --- a/tools/perf/util/bpf-filter.h > > +++ b/tools/perf/util/bpf-filter.h > > @@ -4,15 +4,7 @@ > > > > #include <linux/list.h> > > > > -enum perf_bpf_filter_op { > > - PBF_OP_EQ, > > - PBF_OP_NEQ, > > - PBF_OP_GT, > > - PBF_OP_GE, > > - PBF_OP_LT, > > - PBF_OP_LE, > > - PBF_OP_AND, > > -}; > > +#include "bpf_skel/sample-filter.h" > > > > struct perf_bpf_filter_expr { > > struct list_head list; > > @@ -21,16 +13,30 @@ struct perf_bpf_filter_expr { > > unsigned long val; > > }; > > > > +struct evsel; > > + > > #ifdef HAVE_BPF_SKEL > > struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, > > enum perf_bpf_filter_op op, > > unsigned long val); > > int perf_bpf_filter__parse(struct list_head *expr_head, const char *str); > > +int perf_bpf_filter__prepare(struct evsel *evsel); > > +int perf_bpf_filter__destroy(struct evsel *evsel); > > + > > #else /* !HAVE_BPF_SKEL */ > > + > > static inline int perf_bpf_filter__parse(struct list_head *expr_head __maybe_unused, > > const char *str __maybe_unused) > > { > > - return -ENOSYS; > > + return -EOPNOTSUPP; > > +} > > +static inline int perf_bpf_filter__prepare(struct evsel *evsel __maybe_unused) > > +{ > > + return -EOPNOTSUPP; > > +} > > +static inline int perf_bpf_filter__destroy(struct evsel *evsel __maybe_unused) > > +{ > > + return -EOPNOTSUPP; > > } > > #endif /* HAVE_BPF_SKEL*/ > > #endif /* PERF_UTIL_BPF_FILTER_H */ > > diff --git a/tools/perf/util/bpf_skel/sample-filter.h b/tools/perf/util/bpf_skel/sample-filter.h > > new file mode 100644 > > index 000000000000..862060bfda14 > > --- /dev/null > > +++ b/tools/perf/util/bpf_skel/sample-filter.h > > @@ -0,0 +1,24 @@ > > +#ifndef PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H > > +#define PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H > > + > > +#define MAX_FILTERS 32 > > + > > +/* supported filter operations */ > > +enum perf_bpf_filter_op { > > + PBF_OP_EQ, > > + PBF_OP_NEQ, > > + PBF_OP_GT, > > + PBF_OP_GE, > > + PBF_OP_LT, > > + PBF_OP_LE, > > + PBF_OP_AND > > +}; > > + > > +/* BPF map entry for filtering */ > > +struct perf_bpf_filter_entry { > > + enum perf_bpf_filter_op op; > > + __u64 flags; > > + __u64 value; > > +}; > > + > > +#endif /* PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H */ > > \ No newline at end of file > > diff --git a/tools/perf/util/bpf_skel/sample_filter.bpf.c b/tools/perf/util/bpf_skel/sample_filter.bpf.c > > new file mode 100644 > > index 000000000000..c07256279c3e > > --- /dev/null > > +++ b/tools/perf/util/bpf_skel/sample_filter.bpf.c > > @@ -0,0 +1,126 @@ > > +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > > +// Copyright (c) 2023 Google > > +#include "vmlinux.h" > > +#include <bpf/bpf_helpers.h> > > +#include <bpf/bpf_tracing.h> > > +#include <bpf/bpf_core_read.h> > > + > > +#include "sample-filter.h" > > + > > +/* BPF map that will be filled by user space */ > > +struct filters { > > + __uint(type, BPF_MAP_TYPE_ARRAY); > > + __type(key, int); > > + __type(value, struct perf_bpf_filter_entry); > > + __uint(max_entries, MAX_FILTERS); > > +} filters SEC(".maps"); > > + > > +int dropped; > > + > > +void *bpf_cast_to_kern_ctx(void *) __ksym; > > + > > +/* new kernel perf_sample_data definition */ > > +struct perf_sample_data___new { > > + __u64 sample_flags; > > +} __attribute__((preserve_access_index)); > > + > > +/* helper function to return the given perf sample data */ > > +static inline __u64 perf_get_sample(struct bpf_perf_event_data_kern *kctx, > > + struct perf_bpf_filter_entry *entry) > > +{ > > + struct perf_sample_data___new *data = (void *)kctx->data; > > + > > + if (!bpf_core_field_exists(data->sample_flags) || > > + (data->sample_flags & entry->flags) == 0) > > + return 0; > > + > > + switch (entry->flags) { > > + case PERF_SAMPLE_IP: > > + return kctx->data->ip; > > + case PERF_SAMPLE_ID: > > + return kctx->data->id; > > + case PERF_SAMPLE_TID: > > + return kctx->data->tid_entry.tid; > > + case PERF_SAMPLE_CPU: > > + return kctx->data->cpu_entry.cpu; > > + case PERF_SAMPLE_TIME: > > + return kctx->data->time; > > + case PERF_SAMPLE_ADDR: > > + return kctx->data->addr; > > + case PERF_SAMPLE_PERIOD: > > + return kctx->data->period; > > + case PERF_SAMPLE_TRANSACTION: > > + return kctx->data->txn; > > + case PERF_SAMPLE_WEIGHT: > > + return kctx->data->weight.full; > > + case PERF_SAMPLE_PHYS_ADDR: > > + return kctx->data->phys_addr; > > + case PERF_SAMPLE_CODE_PAGE_SIZE: > > + return kctx->data->code_page_size; > > + case PERF_SAMPLE_DATA_PAGE_SIZE: > > + return kctx->data->data_page_size; > > + default: > > + break; > > + } > > + return 0; > > +} > > + > > +/* BPF program to be called from perf event overflow handler */ > > +SEC("perf_event") > > +int perf_sample_filter(void *ctx) > > +{ > > + struct bpf_perf_event_data_kern *kctx; > > + struct perf_bpf_filter_entry *entry; > > + __u64 sample_data; > > + int i; > > + > > + kctx = bpf_cast_to_kern_ctx(ctx); > > + > > + for (i = 0; i < MAX_FILTERS; i++) { > > + int key = i; /* needed for verifier :( */ > > + > > + entry = bpf_map_lookup_elem(&filters, &key); > > + if (entry == NULL) > > + break; > > + sample_data = perf_get_sample(kctx, entry); > > + > > + switch (entry->op) { > > + case PBF_OP_EQ: > > + if (!(sample_data == entry->value)) > > + goto drop; > > + break; > > + case PBF_OP_NEQ: > > + if (!(sample_data != entry->value)) > > + goto drop; > > + break; > > + case PBF_OP_GT: > > + if (!(sample_data > entry->value)) > > + goto drop; > > + break; > > + case PBF_OP_GE: > > + if (!(sample_data >= entry->value)) > > + goto drop; > > + break; > > + case PBF_OP_LT: > > + if (!(sample_data < entry->value)) > > + goto drop; > > + break; > > + case PBF_OP_LE: > > + if (!(sample_data <= entry->value)) > > + goto drop; > > + break; > > + case PBF_OP_AND: > > + if (!(sample_data & entry->value)) > > + goto drop; > > + break; > > + } > > + } > > + /* generate sample data */ > > + return 1; > > + > > +drop: > > + __sync_fetch_and_add(&dropped, 1); > > + return 0; > > +} > > + > > +char LICENSE[] SEC("license") = "Dual BSD/GPL"; > > diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h > > index c272c06565c0..68072ec655ce 100644 > > --- a/tools/perf/util/evsel.h > > +++ b/tools/perf/util/evsel.h > > @@ -150,8 +150,10 @@ struct evsel { > > */ > > struct bpf_counter_ops *bpf_counter_ops; > > > > - /* for perf-stat -b */ > > - struct list_head bpf_counter_list; > > + union { > > + struct list_head bpf_counter_list; /* for perf-stat -b */ > > + struct list_head bpf_filters; /* for perf-record --filter */ > > + }; > > > > /* for perf-stat --use-bpf */ > > int bperf_leader_prog_fd; > > @@ -159,6 +161,7 @@ struct evsel { > > union { > > struct bperf_leader_bpf *leader_skel; > > struct bperf_follower_bpf *follower_skel; > > + void *bpf_skel; > > }; > > unsigned long open_flags; > > int precise_ip_original; > > -- > > 2.40.0.rc1.284.g88254d51c5-goog > > > > -- > > - Arnaldo
On Wed, Mar 15, 2023 at 9:39 AM Arnaldo Carvalho de Melo <acme@kernel.org> wrote: > > Em Wed, Mar 15, 2023 at 01:24:37PM -0300, Arnaldo Carvalho de Melo escreveu: > > Em Tue, Mar 14, 2023 at 04:42:29PM -0700, Namhyung Kim escreveu: > > > The BPF program will be attached to a perf_event and be triggered when > > > it overflows. It'd iterate the filters map and compare the sample > > > value according to the expression. If any of them fails, the sample > > > would be dropped. > > > > > > Also it needs to have the corresponding sample data for the expression > > > so it compares data->sample_flags with the given value. To access the > > > sample data, it uses the bpf_cast_to_kern_ctx() kfunc which was added > > > in v6.2 kernel. > > > > > > Acked-by: Jiri Olsa <jolsa@kernel.org> > > > Signed-off-by: Namhyung Kim <namhyung@kernel.org> > > > > > > I'm noticing this while building on a debian:11 container: > > > > GENSKEL /tmp/build/perf/util/bpf_skel/bperf_leader.skel.h > > GENSKEL /tmp/build/perf/util/bpf_skel/bperf_follower.skel.h > > GENSKEL /tmp/build/perf/util/bpf_skel/func_latency.skel.h > > GENSKEL /tmp/build/perf/util/bpf_skel/bpf_prog_profiler.skel.h > > GENSKEL /tmp/build/perf/util/bpf_skel/kwork_trace.skel.h > > GENSKEL /tmp/build/perf/util/bpf_skel/sample_filter.skel.h > > libbpf: failed to find BTF for extern 'bpf_cast_to_kern_ctx' [21] section: -2 > > Error: failed to open BPF object file: No such file or directory > > make[2]: *** [Makefile.perf:1085: /tmp/build/perf/util/bpf_skel/sample_filter.skel.h] Error 254 > > make[2]: *** Deleting file '/tmp/build/perf/util/bpf_skel/sample_filter.skel.h' > > make[2]: *** Waiting for unfinished jobs.... > > make[1]: *** [Makefile.perf:236: sub-make] Error 2 > > make: *** [Makefile:70: all] Error 2 > > make: Leaving directory '/git/perf-6.3.0-rc1/tools/perf' > > + exit 1 > > [perfbuilder@five 11]$ > > Same thing on debian:10 Hmm.. I thought extern symbols with__ksym are runtime dependencies and it should build on old kernels too. BPF folks, any suggestions? Thanks, Namhyung > > libbpf: failed to find BTF for extern 'bpf_cast_to_kern_ctx' [21] section: -2 > Error: failed to open BPF object file: No such file or directory > make[2]: *** [Makefile.perf:1085: /tmp/build/perf/util/bpf_skel/sample_filter.skel.h] Error 254 > make[2]: *** Deleting file '/tmp/build/perf/util/bpf_skel/sample_filter.skel.h' > make[2]: *** Waiting for unfinished jobs.... > make[1]: *** [Makefile.perf:236: sub-make] Error 2 > make: *** [Makefile:70: all] Error 2 > make: Leaving directory '/git/perf-6.3.0-rc1/tools/perf' > + exit 1 > [perfbuilder@five 10]$ > > Works with debian:experimental: > > > [perfbuilder@five experimental]$ export BUILD_TARBALL=http://192.168.86.10/perf/perf-6.3.0-rc1.tar.xz > [perfbuilder@five experimental]$ time dm . > 1 147.54 debian:experimental : Ok gcc (Debian 12.2.0-14) 12.2.0 , Debian clang version 14.0.6 > BUILD_TARBALL_HEAD=d34a77f6cd75d2a75c64e78f3d949a12903a7cf0 > > Both with: > > Debian clang version 14.0.6 > Target: x86_64-pc-linux-gnu > Thread model: posix > InstalledDir: /usr/bin > Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/12 > Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/12 > Candidate multilib: .;@m64 > Selected multilib: .;@m64 > + rm -rf /tmp/build/perf > + mkdir /tmp/build/perf > + make ARCH= CROSS_COMPILE= EXTRA_CFLAGS= -C tools/perf O=/tmp/build/perf CC=clang > > and: > > COLLECT_GCC=gcc > COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper > OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa > OFFLOAD_TARGET_DEFAULT=1 > Target: x86_64-linux-gnu > Configured with: ../src/configure -v --with-pkgversion='Debian 12.2.0-14' --with-bugurl=file:///usr/share/doc/gcc-12/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-12 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-12-bTRWOB/gcc-12-12.2.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-12-bTRWOB/gcc-12-12.2.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu > Thread model: posix > Supported LTO compression algorithms: zlib zstd > gcc version 12.2.0 (Debian 12.2.0-14) > + make ARCH= CROSS_COMPILE= EXTRA_CFLAGS= -C tools/perf O=/tmp/build/perf > make: Entering directory '/git/perf-6.3.0-rc1/tools/perf' > > > > > > > --- > > > tools/perf/Makefile.perf | 2 +- > > > tools/perf/util/bpf-filter.c | 64 ++++++++++ > > > tools/perf/util/bpf-filter.h | 26 ++-- > > > tools/perf/util/bpf_skel/sample-filter.h | 24 ++++ > > > tools/perf/util/bpf_skel/sample_filter.bpf.c | 126 +++++++++++++++++++ > > > tools/perf/util/evsel.h | 7 +- > > > 6 files changed, 236 insertions(+), 13 deletions(-) > > > create mode 100644 tools/perf/util/bpf_skel/sample-filter.h > > > create mode 100644 tools/perf/util/bpf_skel/sample_filter.bpf.c > > > > > > diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf > > > index dc9dda09b076..ed6b6a070f79 100644 > > > --- a/tools/perf/Makefile.perf > > > +++ b/tools/perf/Makefile.perf > > > @@ -1050,7 +1050,7 @@ SKELETONS := $(SKEL_OUT)/bpf_prog_profiler.skel.h > > > SKELETONS += $(SKEL_OUT)/bperf_leader.skel.h $(SKEL_OUT)/bperf_follower.skel.h > > > SKELETONS += $(SKEL_OUT)/bperf_cgroup.skel.h $(SKEL_OUT)/func_latency.skel.h > > > SKELETONS += $(SKEL_OUT)/off_cpu.skel.h $(SKEL_OUT)/lock_contention.skel.h > > > -SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h > > > +SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h $(SKEL_OUT)/sample_filter.skel.h > > > > > > $(SKEL_TMP_OUT) $(LIBAPI_OUTPUT) $(LIBBPF_OUTPUT) $(LIBPERF_OUTPUT) $(LIBSUBCMD_OUTPUT) $(LIBSYMBOL_OUTPUT): > > > $(Q)$(MKDIR) -p $@ > > > diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c > > > index c72e35d51240..f20e1bc03778 100644 > > > --- a/tools/perf/util/bpf-filter.c > > > +++ b/tools/perf/util/bpf-filter.c > > > @@ -1,10 +1,74 @@ > > > /* SPDX-License-Identifier: GPL-2.0 */ > > > #include <stdlib.h> > > > > > > +#include <bpf/bpf.h> > > > +#include <linux/err.h> > > > +#include <internal/xyarray.h> > > > + > > > +#include "util/debug.h" > > > +#include "util/evsel.h" > > > + > > > #include "util/bpf-filter.h" > > > #include "util/bpf-filter-flex.h" > > > #include "util/bpf-filter-bison.h" > > > > > > +#include "bpf_skel/sample-filter.h" > > > +#include "bpf_skel/sample_filter.skel.h" > > > + > > > +#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) > > > + > > > +int perf_bpf_filter__prepare(struct evsel *evsel) > > > +{ > > > + int i, x, y, fd; > > > + struct sample_filter_bpf *skel; > > > + struct bpf_program *prog; > > > + struct bpf_link *link; > > > + struct perf_bpf_filter_expr *expr; > > > + > > > + skel = sample_filter_bpf__open_and_load(); > > > + if (!skel) { > > > + pr_err("Failed to load perf sample-filter BPF skeleton\n"); > > > + return -1; > > > + } > > > + > > > + i = 0; > > > + fd = bpf_map__fd(skel->maps.filters); > > > + list_for_each_entry(expr, &evsel->bpf_filters, list) { > > > + struct perf_bpf_filter_entry entry = { > > > + .op = expr->op, > > > + .flags = expr->sample_flags, > > > + .value = expr->val, > > > + }; > > > + bpf_map_update_elem(fd, &i, &entry, BPF_ANY); > > > + i++; > > > + } > > > + > > > + prog = skel->progs.perf_sample_filter; > > > + for (x = 0; x < xyarray__max_x(evsel->core.fd); x++) { > > > + for (y = 0; y < xyarray__max_y(evsel->core.fd); y++) { > > > + link = bpf_program__attach_perf_event(prog, FD(evsel, x, y)); > > > + if (IS_ERR(link)) { > > > + pr_err("Failed to attach perf sample-filter program\n"); > > > + return PTR_ERR(link); > > > + } > > > + } > > > + } > > > + evsel->bpf_skel = skel; > > > + return 0; > > > +} > > > + > > > +int perf_bpf_filter__destroy(struct evsel *evsel) > > > +{ > > > + struct perf_bpf_filter_expr *expr, *tmp; > > > + > > > + list_for_each_entry_safe(expr, tmp, &evsel->bpf_filters, list) { > > > + list_del(&expr->list); > > > + free(expr); > > > + } > > > + sample_filter_bpf__destroy(evsel->bpf_skel); > > > + return 0; > > > +} > > > + > > > struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, > > > enum perf_bpf_filter_op op, > > > unsigned long val) > > > diff --git a/tools/perf/util/bpf-filter.h b/tools/perf/util/bpf-filter.h > > > index 93a0d3de038c..eb8e1ac43cdf 100644 > > > --- a/tools/perf/util/bpf-filter.h > > > +++ b/tools/perf/util/bpf-filter.h > > > @@ -4,15 +4,7 @@ > > > > > > #include <linux/list.h> > > > > > > -enum perf_bpf_filter_op { > > > - PBF_OP_EQ, > > > - PBF_OP_NEQ, > > > - PBF_OP_GT, > > > - PBF_OP_GE, > > > - PBF_OP_LT, > > > - PBF_OP_LE, > > > - PBF_OP_AND, > > > -}; > > > +#include "bpf_skel/sample-filter.h" > > > > > > struct perf_bpf_filter_expr { > > > struct list_head list; > > > @@ -21,16 +13,30 @@ struct perf_bpf_filter_expr { > > > unsigned long val; > > > }; > > > > > > +struct evsel; > > > + > > > #ifdef HAVE_BPF_SKEL > > > struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, > > > enum perf_bpf_filter_op op, > > > unsigned long val); > > > int perf_bpf_filter__parse(struct list_head *expr_head, const char *str); > > > +int perf_bpf_filter__prepare(struct evsel *evsel); > > > +int perf_bpf_filter__destroy(struct evsel *evsel); > > > + > > > #else /* !HAVE_BPF_SKEL */ > > > + > > > static inline int perf_bpf_filter__parse(struct list_head *expr_head __maybe_unused, > > > const char *str __maybe_unused) > > > { > > > - return -ENOSYS; > > > + return -EOPNOTSUPP; > > > +} > > > +static inline int perf_bpf_filter__prepare(struct evsel *evsel __maybe_unused) > > > +{ > > > + return -EOPNOTSUPP; > > > +} > > > +static inline int perf_bpf_filter__destroy(struct evsel *evsel __maybe_unused) > > > +{ > > > + return -EOPNOTSUPP; > > > } > > > #endif /* HAVE_BPF_SKEL*/ > > > #endif /* PERF_UTIL_BPF_FILTER_H */ > > > diff --git a/tools/perf/util/bpf_skel/sample-filter.h b/tools/perf/util/bpf_skel/sample-filter.h > > > new file mode 100644 > > > index 000000000000..862060bfda14 > > > --- /dev/null > > > +++ b/tools/perf/util/bpf_skel/sample-filter.h > > > @@ -0,0 +1,24 @@ > > > +#ifndef PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H > > > +#define PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H > > > + > > > +#define MAX_FILTERS 32 > > > + > > > +/* supported filter operations */ > > > +enum perf_bpf_filter_op { > > > + PBF_OP_EQ, > > > + PBF_OP_NEQ, > > > + PBF_OP_GT, > > > + PBF_OP_GE, > > > + PBF_OP_LT, > > > + PBF_OP_LE, > > > + PBF_OP_AND > > > +}; > > > + > > > +/* BPF map entry for filtering */ > > > +struct perf_bpf_filter_entry { > > > + enum perf_bpf_filter_op op; > > > + __u64 flags; > > > + __u64 value; > > > +}; > > > + > > > +#endif /* PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H */ > > > \ No newline at end of file > > > diff --git a/tools/perf/util/bpf_skel/sample_filter.bpf.c b/tools/perf/util/bpf_skel/sample_filter.bpf.c > > > new file mode 100644 > > > index 000000000000..c07256279c3e > > > --- /dev/null > > > +++ b/tools/perf/util/bpf_skel/sample_filter.bpf.c > > > @@ -0,0 +1,126 @@ > > > +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > > > +// Copyright (c) 2023 Google > > > +#include "vmlinux.h" > > > +#include <bpf/bpf_helpers.h> > > > +#include <bpf/bpf_tracing.h> > > > +#include <bpf/bpf_core_read.h> > > > + > > > +#include "sample-filter.h" > > > + > > > +/* BPF map that will be filled by user space */ > > > +struct filters { > > > + __uint(type, BPF_MAP_TYPE_ARRAY); > > > + __type(key, int); > > > + __type(value, struct perf_bpf_filter_entry); > > > + __uint(max_entries, MAX_FILTERS); > > > +} filters SEC(".maps"); > > > + > > > +int dropped; > > > + > > > +void *bpf_cast_to_kern_ctx(void *) __ksym; > > > + > > > +/* new kernel perf_sample_data definition */ > > > +struct perf_sample_data___new { > > > + __u64 sample_flags; > > > +} __attribute__((preserve_access_index)); > > > + > > > +/* helper function to return the given perf sample data */ > > > +static inline __u64 perf_get_sample(struct bpf_perf_event_data_kern *kctx, > > > + struct perf_bpf_filter_entry *entry) > > > +{ > > > + struct perf_sample_data___new *data = (void *)kctx->data; > > > + > > > + if (!bpf_core_field_exists(data->sample_flags) || > > > + (data->sample_flags & entry->flags) == 0) > > > + return 0; > > > + > > > + switch (entry->flags) { > > > + case PERF_SAMPLE_IP: > > > + return kctx->data->ip; > > > + case PERF_SAMPLE_ID: > > > + return kctx->data->id; > > > + case PERF_SAMPLE_TID: > > > + return kctx->data->tid_entry.tid; > > > + case PERF_SAMPLE_CPU: > > > + return kctx->data->cpu_entry.cpu; > > > + case PERF_SAMPLE_TIME: > > > + return kctx->data->time; > > > + case PERF_SAMPLE_ADDR: > > > + return kctx->data->addr; > > > + case PERF_SAMPLE_PERIOD: > > > + return kctx->data->period; > > > + case PERF_SAMPLE_TRANSACTION: > > > + return kctx->data->txn; > > > + case PERF_SAMPLE_WEIGHT: > > > + return kctx->data->weight.full; > > > + case PERF_SAMPLE_PHYS_ADDR: > > > + return kctx->data->phys_addr; > > > + case PERF_SAMPLE_CODE_PAGE_SIZE: > > > + return kctx->data->code_page_size; > > > + case PERF_SAMPLE_DATA_PAGE_SIZE: > > > + return kctx->data->data_page_size; > > > + default: > > > + break; > > > + } > > > + return 0; > > > +} > > > + > > > +/* BPF program to be called from perf event overflow handler */ > > > +SEC("perf_event") > > > +int perf_sample_filter(void *ctx) > > > +{ > > > + struct bpf_perf_event_data_kern *kctx; > > > + struct perf_bpf_filter_entry *entry; > > > + __u64 sample_data; > > > + int i; > > > + > > > + kctx = bpf_cast_to_kern_ctx(ctx); > > > + > > > + for (i = 0; i < MAX_FILTERS; i++) { > > > + int key = i; /* needed for verifier :( */ > > > + > > > + entry = bpf_map_lookup_elem(&filters, &key); > > > + if (entry == NULL) > > > + break; > > > + sample_data = perf_get_sample(kctx, entry); > > > + > > > + switch (entry->op) { > > > + case PBF_OP_EQ: > > > + if (!(sample_data == entry->value)) > > > + goto drop; > > > + break; > > > + case PBF_OP_NEQ: > > > + if (!(sample_data != entry->value)) > > > + goto drop; > > > + break; > > > + case PBF_OP_GT: > > > + if (!(sample_data > entry->value)) > > > + goto drop; > > > + break; > > > + case PBF_OP_GE: > > > + if (!(sample_data >= entry->value)) > > > + goto drop; > > > + break; > > > + case PBF_OP_LT: > > > + if (!(sample_data < entry->value)) > > > + goto drop; > > > + break; > > > + case PBF_OP_LE: > > > + if (!(sample_data <= entry->value)) > > > + goto drop; > > > + break; > > > + case PBF_OP_AND: > > > + if (!(sample_data & entry->value)) > > > + goto drop; > > > + break; > > > + } > > > + } > > > + /* generate sample data */ > > > + return 1; > > > + > > > +drop: > > > + __sync_fetch_and_add(&dropped, 1); > > > + return 0; > > > +} > > > + > > > +char LICENSE[] SEC("license") = "Dual BSD/GPL"; > > > diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h > > > index c272c06565c0..68072ec655ce 100644 > > > --- a/tools/perf/util/evsel.h > > > +++ b/tools/perf/util/evsel.h > > > @@ -150,8 +150,10 @@ struct evsel { > > > */ > > > struct bpf_counter_ops *bpf_counter_ops; > > > > > > - /* for perf-stat -b */ > > > - struct list_head bpf_counter_list; > > > + union { > > > + struct list_head bpf_counter_list; /* for perf-stat -b */ > > > + struct list_head bpf_filters; /* for perf-record --filter */ > > > + }; > > > > > > /* for perf-stat --use-bpf */ > > > int bperf_leader_prog_fd; > > > @@ -159,6 +161,7 @@ struct evsel { > > > union { > > > struct bperf_leader_bpf *leader_skel; > > > struct bperf_follower_bpf *follower_skel; > > > + void *bpf_skel; > > > }; > > > unsigned long open_flags; > > > int precise_ip_original; > > > -- > > > 2.40.0.rc1.284.g88254d51c5-goog > > > > > > > -- > > > > - Arnaldo > > -- > > - Arnaldo
Em Wed, Mar 15, 2023 at 09:51:03AM -0700, Namhyung Kim escreveu: > On Wed, Mar 15, 2023 at 9:39 AM Arnaldo Carvalho de Melo > <acme@kernel.org> wrote: > > > > Em Wed, Mar 15, 2023 at 01:24:37PM -0300, Arnaldo Carvalho de Melo escreveu: > > > Em Tue, Mar 14, 2023 at 04:42:29PM -0700, Namhyung Kim escreveu: > > > > The BPF program will be attached to a perf_event and be triggered when > > > > it overflows. It'd iterate the filters map and compare the sample > > > > value according to the expression. If any of them fails, the sample > > > > would be dropped. > > > > > > > > Also it needs to have the corresponding sample data for the expression > > > > so it compares data->sample_flags with the given value. To access the > > > > sample data, it uses the bpf_cast_to_kern_ctx() kfunc which was added > > > > in v6.2 kernel. > > > > > > > > Acked-by: Jiri Olsa <jolsa@kernel.org> > > > > Signed-off-by: Namhyung Kim <namhyung@kernel.org> > > > > > > > > > I'm noticing this while building on a debian:11 container: > > > > > > GENSKEL /tmp/build/perf/util/bpf_skel/bperf_leader.skel.h > > > GENSKEL /tmp/build/perf/util/bpf_skel/bperf_follower.skel.h > > > GENSKEL /tmp/build/perf/util/bpf_skel/func_latency.skel.h > > > GENSKEL /tmp/build/perf/util/bpf_skel/bpf_prog_profiler.skel.h > > > GENSKEL /tmp/build/perf/util/bpf_skel/kwork_trace.skel.h > > > GENSKEL /tmp/build/perf/util/bpf_skel/sample_filter.skel.h > > > libbpf: failed to find BTF for extern 'bpf_cast_to_kern_ctx' [21] section: -2 > > > Error: failed to open BPF object file: No such file or directory > > > make[2]: *** [Makefile.perf:1085: /tmp/build/perf/util/bpf_skel/sample_filter.skel.h] Error 254 > > > make[2]: *** Deleting file '/tmp/build/perf/util/bpf_skel/sample_filter.skel.h' > > > make[2]: *** Waiting for unfinished jobs.... > > > make[1]: *** [Makefile.perf:236: sub-make] Error 2 > > > make: *** [Makefile:70: all] Error 2 > > > make: Leaving directory '/git/perf-6.3.0-rc1/tools/perf' > > > + exit 1 > > > [perfbuilder@five 11]$ > > > > Same thing on debian:10 > > Hmm.. I thought extern symbols with__ksym are runtime > dependencies and it should build on old kernels too. > > BPF folks, any suggestions? Fedora 33 also fails, see below, but these work: [perfbuilder@five ~]$ grep Ok dm.log/summary 1 131.48 almalinux:8 : Ok gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-16) , clang version 14.0.6 (Red Hat 14.0.6-1.module_el8.7.0+3277+b822483f) 2 132.99 almalinux:9 : Ok gcc (GCC) 11.3.1 20220421 (Red Hat 11.3.1-2) , clang version 14.0.6 (Red Hat 14.0.6-4.el9_1) 3 162.36 alpine:3.15 : Ok gcc (Alpine 10.3.1_git20211027) 10.3.1 20211027 , Alpine clang version 12.0.1 4 155.25 alpine:3.16 : Ok gcc (Alpine 11.2.1_git20220219) 11.2.1 20220219 , Alpine clang version 13.0.1 5 136.69 alpine:3.17 : Ok gcc (Alpine 12.2.1_git20220924-r4) 12.2.1 20220924 , Alpine clang version 15.0.7 6 158.08 alpine:edge : Ok gcc (Alpine 12.2.1_git20220924-r9) 12.2.1 20220924 , Alpine clang version 15.0.7 12 137.19 archlinux:base : Ok gcc (GCC) 12.2.0 , clang version 14.0.6 13 117.85 centos:stream : Ok gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-18) , clang version 15.0.7 (Red Hat 15.0.7-1.module_el8.8.0+1258+af79b238) 17 122.65 debian:experimental : Ok gcc (Debian 12.2.0-14) 12.2.0 , Debian clang version 14.0.6 30 165.29 fedora:34 : Ok gcc (GCC) 11.3.1 20220421 (Red Hat 11.3.1-2) , clang version 12.0.1 (Fedora 12.0.1-1.fc34) 33 153.26 fedora:35 : Ok gcc (GCC) 11.3.1 20220421 (Red Hat 11.3.1-3) , clang version 13.0.1 (Fedora 13.0.1-1.fc35) 34 152.66 fedora:36 : Ok gcc (GCC) 12.2.1 20221121 (Red Hat 12.2.1-4) , clang version 14.0.5 (Fedora 14.0.5-2.fc36) 35 154.36 fedora:37 : Ok gcc (GCC) 12.2.1 20221121 (Red Hat 12.2.1-4) , clang version 15.0.7 (Fedora 15.0.7-1.fc37) 36 145.45 fedora:38 : Ok gcc (GCC) 13.0.1 20230208 (Red Hat 13.0.1-0) , clang version 15.0.7 (Fedora 15.0.7-2.fc38) 37 166.89 fedora:rawhide : Ok gcc (GCC) 13.0.1 20230127 (Red Hat 13.0.1-0) , clang version 15.0.7 (Fedora 15.0.7-2.fc38) 44 146.10 opensuse:15.4 : Ok gcc (SUSE Linux) 7.5.0 , clang version 13.0.1 45 165.87 opensuse:15.5 : Ok gcc (SUSE Linux) 7.5.0 , clang version 15.0.2 46 167.90 opensuse:tumbleweed : Ok gcc (SUSE Linux) 12.2.1 20221020 [revision 0aaef83351473e8f4eb774f8f999bbe87a4866d7] , clang version 15.0.6 47 130.58 oraclelinux:8 : Ok gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-16.0.2) , clang version 14.0.6 (Red Hat 14.0.6-1.0.1.module+el8.7.0+20823+214a699d) 49 132.09 rockylinux:8 : Ok gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-16) , clang version 14.0.6 (Red Hat 14.0.6-1.module+el8.7.0+1080+d88dc670) 64 161.49 ubuntu:22.04 : Ok gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0 , Ubuntu clang version 14.0.0-1ubuntu1 [perfbuilder@five ~]$ [perfbuilder@five ~]$ for a in `grep Ok dm.log/summary | cut -c15- | cut -d: -f1,2`; do grep -q GENSKEL.*sample_filter dm.log/$a && echo $a ; done almalinux:8 almalinux:9 alpine:3.15 alpine:3.16 alpine:3.17 alpine:edge archlinux:base centos:stream debian:experimental fedora:34 fedora:35 fedora:36 fedora:37 fedora:38 fedora:rawhide opensuse:15.4 opensuse:15.5 opensuse:tumbleweed oraclelinux:8 rockylinux:8 ubuntu:22.04 [perfbuilder@five ~]$ Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/10/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-redhat-linux Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,objc,obj-c++,ada,go,d,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --enable-offload-targets=nvptx-none --without-cuda-driver --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 10.3.1 20210422 (Red Hat 10.3.1-1) (GCC) + make PYTHON=python3 ARCH= CROSS_COMPILE= EXTRA_CFLAGS= -C tools/perf O=/tmp/build/perf make: Entering directory '/git/perf-6.3.0-rc1/tools/perf' BUILD: Doing 'make -j32' parallel build HOSTCC /tmp/build/perf/fixdep.o HOSTLD /tmp/build/perf/fixdep-in.o LINK /tmp/build/perf/fixdep Makefile.config:1046: No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-dev[el]/libbabeltrace-ctf-dev Makefile.config:1137: libpfm4 not found, disables libpfm4 support. Please install libpfm4-dev Auto-detecting system features: ... dwarf: [ on ] ... dwarf_getlocations: [ on ] ... glibc: [ on ] ... libbfd: [ on ] ... libbfd-buildid: [ on ] ... libcap: [ on ] ... libelf: [ on ] ... libnuma: [ on ] ... numa_num_possible_cpus: [ on ] ... libperl: [ on ] ... libpython: [ on ] ... libcrypto: [ on ] ... libunwind: [ on ] ... libdw-dwarf-unwind: [ on ] ... zlib: [ on ] ... lzma: [ on ] ... get_cpuid: [ on ] ... bpf: [ on ] ... libaio: [ on ] ... libzstd: [ on ] GEN /tmp/build/perf/common-cmds.h PERF_VERSION = 6.3.rc1.gd34a77f6cd75 GEN perf-archive GEN perf-iostat CC /tmp/build/perf/dlfilters/dlfilter-test-api-v0.o CC /tmp/build/perf/dlfilters/dlfilter-show-cycles.o MKDIR /tmp/build/perf/jvmti/ MKDIR /tmp/build/perf/jvmti/ MKDIR /tmp/build/perf/jvmti/ MKDIR /tmp/build/perf/jvmti/ CC /tmp/build/perf/jvmti/libjvmti.o CC /tmp/build/perf/jvmti/jvmti_agent.o CC /tmp/build/perf/jvmti/libstring.o CC /tmp/build/perf/jvmti/libctype.o INSTALL /tmp/build/perf/libsubcmd/include/subcmd/exec-cmd.h INSTALL /tmp/build/perf/libsubcmd/include/subcmd/help.h INSTALL /tmp/build/perf/libsubcmd/include/subcmd/pager.h INSTALL /tmp/build/perf/libsubcmd/include/subcmd/parse-options.h INSTALL /tmp/build/perf/libsubcmd/include/subcmd/run-command.h CC /tmp/build/perf/libsubcmd/exec-cmd.o CC /tmp/build/perf/libsubcmd/help.o CC /tmp/build/perf/libsubcmd/pager.o CC /tmp/build/perf/libsubcmd/parse-options.o CC /tmp/build/perf/libsubcmd/run-command.o CC /tmp/build/perf/libsubcmd/sigchain.o CC /tmp/build/perf/libsubcmd/subcmd-config.o LINK /tmp/build/perf/dlfilters/dlfilter-show-cycles.so INSTALL libsubcmd_headers LINK /tmp/build/perf/dlfilters/dlfilter-test-api-v0.so INSTALL /tmp/build/perf/libperf/include/perf/bpf_perf.h INSTALL /tmp/build/perf/libperf/include/perf/core.h INSTALL /tmp/build/perf/libperf/include/perf/cpumap.h INSTALL /tmp/build/perf/libperf/include/perf/threadmap.h INSTALL /tmp/build/perf/libsymbol/include/symbol/kallsyms.h INSTALL /tmp/build/perf/libapi/include/api/cpu.h INSTALL /tmp/build/perf/libperf/include/perf/evlist.h INSTALL /tmp/build/perf/libapi/include/api/debug.h INSTALL /tmp/build/perf/libperf/include/perf/evsel.h CC /tmp/build/perf/libperf/core.o CC /tmp/build/perf/libsymbol/kallsyms.o CC /tmp/build/perf/libperf/cpumap.o INSTALL /tmp/build/perf/libapi/include/api/io.h INSTALL /tmp/build/perf/libperf/include/perf/event.h INSTALL /tmp/build/perf/libapi/include/api/fd/array.h MKDIR /tmp/build/perf/libapi/fd/ CC /tmp/build/perf/libperf/threadmap.o INSTALL libsymbol_headers INSTALL /tmp/build/perf/libperf/include/perf/mmap.h INSTALL /tmp/build/perf/libapi/include/api/fs/fs.h CC /tmp/build/perf/libperf/evsel.o GEN /tmp/build/perf/libbpf/bpf_helper_defs.h CC /tmp/build/perf/libperf/evlist.o MKDIR /tmp/build/perf/libapi/fs/ INSTALL /tmp/build/perf/libapi/include/api/fs/tracing_path.h MKDIR /tmp/build/perf/libapi/fs/ CC /tmp/build/perf/libapi/fd/array.o CC /tmp/build/perf/libperf/mmap.o MKDIR /tmp/build/perf/libapi/fs/ CC /tmp/build/perf/libperf/zalloc.o CC /tmp/build/perf/libapi/fs/fs.o CC /tmp/build/perf/libperf/xyarray.o CC /tmp/build/perf/libperf/lib.o CC /tmp/build/perf/libapi/fs/tracing_path.o CC /tmp/build/perf/libapi/fs/cgroup.o INSTALL /tmp/build/perf/libperf/include/internal/cpumap.h INSTALL /tmp/build/perf/libperf/include/internal/evlist.h CC /tmp/build/perf/libapi/cpu.o CC /tmp/build/perf/libapi/debug.o CC /tmp/build/perf/libapi/str_error_r.o INSTALL /tmp/build/perf/libperf/include/internal/evsel.h INSTALL /tmp/build/perf/libbpf/include/bpf/bpf.h INSTALL /tmp/build/perf/libbpf/include/bpf/libbpf.h INSTALL /tmp/build/perf/libperf/include/internal/lib.h INSTALL libapi_headers INSTALL /tmp/build/perf/libperf/include/internal/mmap.h INSTALL /tmp/build/perf/libperf/include/internal/threadmap.h INSTALL /tmp/build/perf/libperf/include/internal/xyarray.h INSTALL /tmp/build/perf/libbpf/include/bpf/btf.h INSTALL /tmp/build/perf/libbpf/include/bpf/libbpf_common.h INSTALL /tmp/build/perf/libbpf/include/bpf/libbpf_legacy.h INSTALL /tmp/build/perf/libbpf/include/bpf/bpf_helpers.h INSTALL /tmp/build/perf/libbpf/include/bpf/bpf_tracing.h INSTALL /tmp/build/perf/libbpf/include/bpf/bpf_endian.h INSTALL /tmp/build/perf/libbpf/include/bpf/bpf_core_read.h INSTALL libperf_headers INSTALL /tmp/build/perf/libbpf/include/bpf/skel_internal.h INSTALL /tmp/build/perf/libbpf/include/bpf/libbpf_version.h INSTALL /tmp/build/perf/libbpf/include/bpf/usdt.bpf.h INSTALL /tmp/build/perf/libbpf/include/bpf/bpf_helper_defs.h MKDIR /tmp/build/perf/libbpf/staticobjs/ MKDIR /tmp/build/perf/libbpf/staticobjs/ INSTALL libbpf_headers MKDIR /tmp/build/perf/libbpf/staticobjs/ MKDIR /tmp/build/perf/libbpf/staticobjs/ MKDIR /tmp/build/perf/libbpf/staticobjs/ LD /tmp/build/perf/libsymbol/libsymbol-in.o MKDIR /tmp/build/perf/libbpf/staticobjs/ LD /tmp/build/perf/libapi/fd/libapi-in.o MKDIR /tmp/build/perf/libbpf/staticobjs/ CC /tmp/build/perf/libbpf/staticobjs/bpf_prog_linfo.o CC /tmp/build/perf/libbpf/staticobjs/libbpf.o CC /tmp/build/perf/libbpf/staticobjs/bpf.o CC /tmp/build/perf/libbpf/staticobjs/nlattr.o CC /tmp/build/perf/libbpf/staticobjs/btf.o CC /tmp/build/perf/libbpf/staticobjs/libbpf_errno.o CC /tmp/build/perf/libbpf/staticobjs/str_error.o CC /tmp/build/perf/libbpf/staticobjs/netlink.o CC /tmp/build/perf/libbpf/staticobjs/libbpf_probes.o CC /tmp/build/perf/libbpf/staticobjs/hashmap.o CC /tmp/build/perf/libbpf/staticobjs/btf_dump.o AR /tmp/build/perf/libsymbol/libsymbol.a CC /tmp/build/perf/libbpf/staticobjs/ringbuf.o LD /tmp/build/perf/jvmti/jvmti-in.o CC /tmp/build/perf/libbpf/staticobjs/strset.o CC /tmp/build/perf/libbpf/staticobjs/linker.o CC /tmp/build/perf/libbpf/staticobjs/gen_loader.o CC /tmp/build/perf/libbpf/staticobjs/relo_core.o CC /tmp/build/perf/libbpf/staticobjs/usdt.o LD /tmp/build/perf/libapi/fs/libapi-in.o LINK /tmp/build/perf/libperf-jvmti.so LD /tmp/build/perf/libapi/libapi-in.o LD /tmp/build/perf/libperf/libperf-in.o AR /tmp/build/perf/libapi/libapi.a AR /tmp/build/perf/libperf/libperf.a LD /tmp/build/perf/libsubcmd/libsubcmd-in.o AR /tmp/build/perf/libsubcmd/libsubcmd.a GEN /tmp/build/perf/python/perf.cpython-39-x86_64-linux-gnu.so Auto-detecting system features: ... clang-bpf-co-re: [ on ] ... llvm: [ on ] ... libcap: [ on ] ... libbfd: [ on ] MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/ MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/ INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/hashmap.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/relo_core.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_internal.h GEN /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/bpf_helper_defs.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/btf.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_common.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_legacy.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_helpers.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_tracing.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_endian.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_core_read.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/skel_internal.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_version.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/usdt.bpf.h INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_helper_defs.h MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/ MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/ MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/ MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/ MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/ INSTALL libbpf_headers MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/ MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/ MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/ CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf_probes.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/bpf.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/nlattr.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf_errno.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/hashmap.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/str_error.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/netlink.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/bpf_prog_linfo.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf_dump.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/ringbuf.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/strset.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/linker.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/gen_loader.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/relo_core.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/usdt.o LD /tmp/build/perf/libbpf/staticobjs/libbpf-in.o LINK /tmp/build/perf/libbpf/libbpf.a LD /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf-in.o LINK /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/libbpf.a CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/main.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/common.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/json_writer.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/gen.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/btf.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/xlated_dumper.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/btf_dumper.o CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/disasm.o LINK /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/bpftool GEN /tmp/build/perf/util/bpf_skel/vmlinux.h CLANG /tmp/build/perf/util/bpf_skel/.tmp/bpf_prog_profiler.bpf.o CLANG /tmp/build/perf/util/bpf_skel/.tmp/bperf_leader.bpf.o CLANG /tmp/build/perf/util/bpf_skel/.tmp/bperf_follower.bpf.o CLANG /tmp/build/perf/util/bpf_skel/.tmp/bperf_cgroup.bpf.o CLANG /tmp/build/perf/util/bpf_skel/.tmp/func_latency.bpf.o CLANG /tmp/build/perf/util/bpf_skel/.tmp/off_cpu.bpf.o CLANG /tmp/build/perf/util/bpf_skel/.tmp/lock_contention.bpf.o CLANG /tmp/build/perf/util/bpf_skel/.tmp/kwork_trace.bpf.o CLANG /tmp/build/perf/util/bpf_skel/.tmp/sample_filter.bpf.o GENSKEL /tmp/build/perf/util/bpf_skel/bpf_prog_profiler.skel.h GENSKEL /tmp/build/perf/util/bpf_skel/bperf_leader.skel.h GENSKEL /tmp/build/perf/util/bpf_skel/bperf_follower.skel.h GENSKEL /tmp/build/perf/util/bpf_skel/func_latency.skel.h libbpf: elf: skipping unrecognized data section(7) .eh_frame libbpf: elf: skipping unrecognized data section(8) .eh_frame libbpf: elf: skipping unrecognized data section(8) .eh_frame libbpf: elf: skipping unrecognized data section(9) .eh_frame libbpf: elf: skipping relo section(12) .rel.eh_frame for section(7) .eh_frame libbpf: elf: skipping relo section(13) .rel.eh_frame for section(8) .eh_frame libbpf: elf: skipping relo section(14) .rel.eh_frame for section(8) .eh_frame libbpf: elf: skipping relo section(15) .rel.eh_frame for section(9) .eh_frame GENSKEL /tmp/build/perf/util/bpf_skel/kwork_trace.skel.h libbpf: elf: skipping unrecognized data section(17) .eh_frame libbpf: elf: skipping relo section(29) .rel.eh_frame for section(17) .eh_frame GENSKEL /tmp/build/perf/util/bpf_skel/sample_filter.skel.h libbpf: elf: skipping unrecognized data section(8) .eh_frame libbpf: elf: skipping relo section(13) .rel.eh_frame for section(8) .eh_frame libbpf: failed to find BTF for extern 'bpf_cast_to_kern_ctx' [21] section: -2 Error: failed to open BPF object file: No such file or directory make[2]: *** [Makefile.perf:1085: /tmp/build/perf/util/bpf_skel/sample_filter.skel.h] Error 254 make[2]: *** Deleting file '/tmp/build/perf/util/bpf_skel/sample_filter.skel.h' make[2]: *** Waiting for unfinished jobs.... make[1]: *** [Makefile.perf:236: sub-make] Error 2 make: *** [Makefile:70: all] Error 2 make: Leaving directory '/git/perf-6.3.0-rc1/tools/perf' + exit 1 [perfbuilder@five 33]$ fg > Thanks, > Namhyung > > > > > > libbpf: failed to find BTF for extern 'bpf_cast_to_kern_ctx' [21] section: -2 > > Error: failed to open BPF object file: No such file or directory > > make[2]: *** [Makefile.perf:1085: /tmp/build/perf/util/bpf_skel/sample_filter.skel.h] Error 254 > > make[2]: *** Deleting file '/tmp/build/perf/util/bpf_skel/sample_filter.skel.h' > > make[2]: *** Waiting for unfinished jobs.... > > make[1]: *** [Makefile.perf:236: sub-make] Error 2 > > make: *** [Makefile:70: all] Error 2 > > make: Leaving directory '/git/perf-6.3.0-rc1/tools/perf' > > + exit 1 > > [perfbuilder@five 10]$ > > > > Works with debian:experimental: > > > > > > [perfbuilder@five experimental]$ export BUILD_TARBALL=http://192.168.86.10/perf/perf-6.3.0-rc1.tar.xz > > [perfbuilder@five experimental]$ time dm . > > 1 147.54 debian:experimental : Ok gcc (Debian 12.2.0-14) 12.2.0 , Debian clang version 14.0.6 > > BUILD_TARBALL_HEAD=d34a77f6cd75d2a75c64e78f3d949a12903a7cf0 > > > > Both with: > > > > Debian clang version 14.0.6 > > Target: x86_64-pc-linux-gnu > > Thread model: posix > > InstalledDir: /usr/bin > > Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/12 > > Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/12 > > Candidate multilib: .;@m64 > > Selected multilib: .;@m64 > > + rm -rf /tmp/build/perf > > + mkdir /tmp/build/perf > > + make ARCH= CROSS_COMPILE= EXTRA_CFLAGS= -C tools/perf O=/tmp/build/perf CC=clang > > > > and: > > > > COLLECT_GCC=gcc > > COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/12/lto-wrapper > > OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa > > OFFLOAD_TARGET_DEFAULT=1 > > Target: x86_64-linux-gnu > > Configured with: ../src/configure -v --with-pkgversion='Debian 12.2.0-14' --with-bugurl=file:///usr/share/doc/gcc-12/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-12 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-12-bTRWOB/gcc-12-12.2.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-12-bTRWOB/gcc-12-12.2.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu > > Thread model: posix > > Supported LTO compression algorithms: zlib zstd > > gcc version 12.2.0 (Debian 12.2.0-14) > > + make ARCH= CROSS_COMPILE= EXTRA_CFLAGS= -C tools/perf O=/tmp/build/perf > > make: Entering directory '/git/perf-6.3.0-rc1/tools/perf' > > > > > > > > > > > --- > > > > tools/perf/Makefile.perf | 2 +- > > > > tools/perf/util/bpf-filter.c | 64 ++++++++++ > > > > tools/perf/util/bpf-filter.h | 26 ++-- > > > > tools/perf/util/bpf_skel/sample-filter.h | 24 ++++ > > > > tools/perf/util/bpf_skel/sample_filter.bpf.c | 126 +++++++++++++++++++ > > > > tools/perf/util/evsel.h | 7 +- > > > > 6 files changed, 236 insertions(+), 13 deletions(-) > > > > create mode 100644 tools/perf/util/bpf_skel/sample-filter.h > > > > create mode 100644 tools/perf/util/bpf_skel/sample_filter.bpf.c > > > > > > > > diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf > > > > index dc9dda09b076..ed6b6a070f79 100644 > > > > --- a/tools/perf/Makefile.perf > > > > +++ b/tools/perf/Makefile.perf > > > > @@ -1050,7 +1050,7 @@ SKELETONS := $(SKEL_OUT)/bpf_prog_profiler.skel.h > > > > SKELETONS += $(SKEL_OUT)/bperf_leader.skel.h $(SKEL_OUT)/bperf_follower.skel.h > > > > SKELETONS += $(SKEL_OUT)/bperf_cgroup.skel.h $(SKEL_OUT)/func_latency.skel.h > > > > SKELETONS += $(SKEL_OUT)/off_cpu.skel.h $(SKEL_OUT)/lock_contention.skel.h > > > > -SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h > > > > +SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h $(SKEL_OUT)/sample_filter.skel.h > > > > > > > > $(SKEL_TMP_OUT) $(LIBAPI_OUTPUT) $(LIBBPF_OUTPUT) $(LIBPERF_OUTPUT) $(LIBSUBCMD_OUTPUT) $(LIBSYMBOL_OUTPUT): > > > > $(Q)$(MKDIR) -p $@ > > > > diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c > > > > index c72e35d51240..f20e1bc03778 100644 > > > > --- a/tools/perf/util/bpf-filter.c > > > > +++ b/tools/perf/util/bpf-filter.c > > > > @@ -1,10 +1,74 @@ > > > > /* SPDX-License-Identifier: GPL-2.0 */ > > > > #include <stdlib.h> > > > > > > > > +#include <bpf/bpf.h> > > > > +#include <linux/err.h> > > > > +#include <internal/xyarray.h> > > > > + > > > > +#include "util/debug.h" > > > > +#include "util/evsel.h" > > > > + > > > > #include "util/bpf-filter.h" > > > > #include "util/bpf-filter-flex.h" > > > > #include "util/bpf-filter-bison.h" > > > > > > > > +#include "bpf_skel/sample-filter.h" > > > > +#include "bpf_skel/sample_filter.skel.h" > > > > + > > > > +#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) > > > > + > > > > +int perf_bpf_filter__prepare(struct evsel *evsel) > > > > +{ > > > > + int i, x, y, fd; > > > > + struct sample_filter_bpf *skel; > > > > + struct bpf_program *prog; > > > > + struct bpf_link *link; > > > > + struct perf_bpf_filter_expr *expr; > > > > + > > > > + skel = sample_filter_bpf__open_and_load(); > > > > + if (!skel) { > > > > + pr_err("Failed to load perf sample-filter BPF skeleton\n"); > > > > + return -1; > > > > + } > > > > + > > > > + i = 0; > > > > + fd = bpf_map__fd(skel->maps.filters); > > > > + list_for_each_entry(expr, &evsel->bpf_filters, list) { > > > > + struct perf_bpf_filter_entry entry = { > > > > + .op = expr->op, > > > > + .flags = expr->sample_flags, > > > > + .value = expr->val, > > > > + }; > > > > + bpf_map_update_elem(fd, &i, &entry, BPF_ANY); > > > > + i++; > > > > + } > > > > + > > > > + prog = skel->progs.perf_sample_filter; > > > > + for (x = 0; x < xyarray__max_x(evsel->core.fd); x++) { > > > > + for (y = 0; y < xyarray__max_y(evsel->core.fd); y++) { > > > > + link = bpf_program__attach_perf_event(prog, FD(evsel, x, y)); > > > > + if (IS_ERR(link)) { > > > > + pr_err("Failed to attach perf sample-filter program\n"); > > > > + return PTR_ERR(link); > > > > + } > > > > + } > > > > + } > > > > + evsel->bpf_skel = skel; > > > > + return 0; > > > > +} > > > > + > > > > +int perf_bpf_filter__destroy(struct evsel *evsel) > > > > +{ > > > > + struct perf_bpf_filter_expr *expr, *tmp; > > > > + > > > > + list_for_each_entry_safe(expr, tmp, &evsel->bpf_filters, list) { > > > > + list_del(&expr->list); > > > > + free(expr); > > > > + } > > > > + sample_filter_bpf__destroy(evsel->bpf_skel); > > > > + return 0; > > > > +} > > > > + > > > > struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, > > > > enum perf_bpf_filter_op op, > > > > unsigned long val) > > > > diff --git a/tools/perf/util/bpf-filter.h b/tools/perf/util/bpf-filter.h > > > > index 93a0d3de038c..eb8e1ac43cdf 100644 > > > > --- a/tools/perf/util/bpf-filter.h > > > > +++ b/tools/perf/util/bpf-filter.h > > > > @@ -4,15 +4,7 @@ > > > > > > > > #include <linux/list.h> > > > > > > > > -enum perf_bpf_filter_op { > > > > - PBF_OP_EQ, > > > > - PBF_OP_NEQ, > > > > - PBF_OP_GT, > > > > - PBF_OP_GE, > > > > - PBF_OP_LT, > > > > - PBF_OP_LE, > > > > - PBF_OP_AND, > > > > -}; > > > > +#include "bpf_skel/sample-filter.h" > > > > > > > > struct perf_bpf_filter_expr { > > > > struct list_head list; > > > > @@ -21,16 +13,30 @@ struct perf_bpf_filter_expr { > > > > unsigned long val; > > > > }; > > > > > > > > +struct evsel; > > > > + > > > > #ifdef HAVE_BPF_SKEL > > > > struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, > > > > enum perf_bpf_filter_op op, > > > > unsigned long val); > > > > int perf_bpf_filter__parse(struct list_head *expr_head, const char *str); > > > > +int perf_bpf_filter__prepare(struct evsel *evsel); > > > > +int perf_bpf_filter__destroy(struct evsel *evsel); > > > > + > > > > #else /* !HAVE_BPF_SKEL */ > > > > + > > > > static inline int perf_bpf_filter__parse(struct list_head *expr_head __maybe_unused, > > > > const char *str __maybe_unused) > > > > { > > > > - return -ENOSYS; > > > > + return -EOPNOTSUPP; > > > > +} > > > > +static inline int perf_bpf_filter__prepare(struct evsel *evsel __maybe_unused) > > > > +{ > > > > + return -EOPNOTSUPP; > > > > +} > > > > +static inline int perf_bpf_filter__destroy(struct evsel *evsel __maybe_unused) > > > > +{ > > > > + return -EOPNOTSUPP; > > > > } > > > > #endif /* HAVE_BPF_SKEL*/ > > > > #endif /* PERF_UTIL_BPF_FILTER_H */ > > > > diff --git a/tools/perf/util/bpf_skel/sample-filter.h b/tools/perf/util/bpf_skel/sample-filter.h > > > > new file mode 100644 > > > > index 000000000000..862060bfda14 > > > > --- /dev/null > > > > +++ b/tools/perf/util/bpf_skel/sample-filter.h > > > > @@ -0,0 +1,24 @@ > > > > +#ifndef PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H > > > > +#define PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H > > > > + > > > > +#define MAX_FILTERS 32 > > > > + > > > > +/* supported filter operations */ > > > > +enum perf_bpf_filter_op { > > > > + PBF_OP_EQ, > > > > + PBF_OP_NEQ, > > > > + PBF_OP_GT, > > > > + PBF_OP_GE, > > > > + PBF_OP_LT, > > > > + PBF_OP_LE, > > > > + PBF_OP_AND > > > > +}; > > > > + > > > > +/* BPF map entry for filtering */ > > > > +struct perf_bpf_filter_entry { > > > > + enum perf_bpf_filter_op op; > > > > + __u64 flags; > > > > + __u64 value; > > > > +}; > > > > + > > > > +#endif /* PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H */ > > > > \ No newline at end of file > > > > diff --git a/tools/perf/util/bpf_skel/sample_filter.bpf.c b/tools/perf/util/bpf_skel/sample_filter.bpf.c > > > > new file mode 100644 > > > > index 000000000000..c07256279c3e > > > > --- /dev/null > > > > +++ b/tools/perf/util/bpf_skel/sample_filter.bpf.c > > > > @@ -0,0 +1,126 @@ > > > > +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > > > > +// Copyright (c) 2023 Google > > > > +#include "vmlinux.h" > > > > +#include <bpf/bpf_helpers.h> > > > > +#include <bpf/bpf_tracing.h> > > > > +#include <bpf/bpf_core_read.h> > > > > + > > > > +#include "sample-filter.h" > > > > + > > > > +/* BPF map that will be filled by user space */ > > > > +struct filters { > > > > + __uint(type, BPF_MAP_TYPE_ARRAY); > > > > + __type(key, int); > > > > + __type(value, struct perf_bpf_filter_entry); > > > > + __uint(max_entries, MAX_FILTERS); > > > > +} filters SEC(".maps"); > > > > + > > > > +int dropped; > > > > + > > > > +void *bpf_cast_to_kern_ctx(void *) __ksym; > > > > + > > > > +/* new kernel perf_sample_data definition */ > > > > +struct perf_sample_data___new { > > > > + __u64 sample_flags; > > > > +} __attribute__((preserve_access_index)); > > > > + > > > > +/* helper function to return the given perf sample data */ > > > > +static inline __u64 perf_get_sample(struct bpf_perf_event_data_kern *kctx, > > > > + struct perf_bpf_filter_entry *entry) > > > > +{ > > > > + struct perf_sample_data___new *data = (void *)kctx->data; > > > > + > > > > + if (!bpf_core_field_exists(data->sample_flags) || > > > > + (data->sample_flags & entry->flags) == 0) > > > > + return 0; > > > > + > > > > + switch (entry->flags) { > > > > + case PERF_SAMPLE_IP: > > > > + return kctx->data->ip; > > > > + case PERF_SAMPLE_ID: > > > > + return kctx->data->id; > > > > + case PERF_SAMPLE_TID: > > > > + return kctx->data->tid_entry.tid; > > > > + case PERF_SAMPLE_CPU: > > > > + return kctx->data->cpu_entry.cpu; > > > > + case PERF_SAMPLE_TIME: > > > > + return kctx->data->time; > > > > + case PERF_SAMPLE_ADDR: > > > > + return kctx->data->addr; > > > > + case PERF_SAMPLE_PERIOD: > > > > + return kctx->data->period; > > > > + case PERF_SAMPLE_TRANSACTION: > > > > + return kctx->data->txn; > > > > + case PERF_SAMPLE_WEIGHT: > > > > + return kctx->data->weight.full; > > > > + case PERF_SAMPLE_PHYS_ADDR: > > > > + return kctx->data->phys_addr; > > > > + case PERF_SAMPLE_CODE_PAGE_SIZE: > > > > + return kctx->data->code_page_size; > > > > + case PERF_SAMPLE_DATA_PAGE_SIZE: > > > > + return kctx->data->data_page_size; > > > > + default: > > > > + break; > > > > + } > > > > + return 0; > > > > +} > > > > + > > > > +/* BPF program to be called from perf event overflow handler */ > > > > +SEC("perf_event") > > > > +int perf_sample_filter(void *ctx) > > > > +{ > > > > + struct bpf_perf_event_data_kern *kctx; > > > > + struct perf_bpf_filter_entry *entry; > > > > + __u64 sample_data; > > > > + int i; > > > > + > > > > + kctx = bpf_cast_to_kern_ctx(ctx); > > > > + > > > > + for (i = 0; i < MAX_FILTERS; i++) { > > > > + int key = i; /* needed for verifier :( */ > > > > + > > > > + entry = bpf_map_lookup_elem(&filters, &key); > > > > + if (entry == NULL) > > > > + break; > > > > + sample_data = perf_get_sample(kctx, entry); > > > > + > > > > + switch (entry->op) { > > > > + case PBF_OP_EQ: > > > > + if (!(sample_data == entry->value)) > > > > + goto drop; > > > > + break; > > > > + case PBF_OP_NEQ: > > > > + if (!(sample_data != entry->value)) > > > > + goto drop; > > > > + break; > > > > + case PBF_OP_GT: > > > > + if (!(sample_data > entry->value)) > > > > + goto drop; > > > > + break; > > > > + case PBF_OP_GE: > > > > + if (!(sample_data >= entry->value)) > > > > + goto drop; > > > > + break; > > > > + case PBF_OP_LT: > > > > + if (!(sample_data < entry->value)) > > > > + goto drop; > > > > + break; > > > > + case PBF_OP_LE: > > > > + if (!(sample_data <= entry->value)) > > > > + goto drop; > > > > + break; > > > > + case PBF_OP_AND: > > > > + if (!(sample_data & entry->value)) > > > > + goto drop; > > > > + break; > > > > + } > > > > + } > > > > + /* generate sample data */ > > > > + return 1; > > > > + > > > > +drop: > > > > + __sync_fetch_and_add(&dropped, 1); > > > > + return 0; > > > > +} > > > > + > > > > +char LICENSE[] SEC("license") = "Dual BSD/GPL"; > > > > diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h > > > > index c272c06565c0..68072ec655ce 100644 > > > > --- a/tools/perf/util/evsel.h > > > > +++ b/tools/perf/util/evsel.h > > > > @@ -150,8 +150,10 @@ struct evsel { > > > > */ > > > > struct bpf_counter_ops *bpf_counter_ops; > > > > > > > > - /* for perf-stat -b */ > > > > - struct list_head bpf_counter_list; > > > > + union { > > > > + struct list_head bpf_counter_list; /* for perf-stat -b */ > > > > + struct list_head bpf_filters; /* for perf-record --filter */ > > > > + }; > > > > > > > > /* for perf-stat --use-bpf */ > > > > int bperf_leader_prog_fd; > > > > @@ -159,6 +161,7 @@ struct evsel { > > > > union { > > > > struct bperf_leader_bpf *leader_skel; > > > > struct bperf_follower_bpf *follower_skel; > > > > + void *bpf_skel; > > > > }; > > > > unsigned long open_flags; > > > > int precise_ip_original; > > > > -- > > > > 2.40.0.rc1.284.g88254d51c5-goog > > > > > > > > > > -- > > > > > > - Arnaldo > > > > -- > > > > - Arnaldo
On Wed, Mar 15, 2023 at 05:12:44PM -0300, Arnaldo Carvalho de Melo wrote: > Em Wed, Mar 15, 2023 at 09:51:03AM -0700, Namhyung Kim escreveu: > > On Wed, Mar 15, 2023 at 9:39 AM Arnaldo Carvalho de Melo > > <acme@kernel.org> wrote: > > > > > > Em Wed, Mar 15, 2023 at 01:24:37PM -0300, Arnaldo Carvalho de Melo escreveu: > > > > Em Tue, Mar 14, 2023 at 04:42:29PM -0700, Namhyung Kim escreveu: > > > > > The BPF program will be attached to a perf_event and be triggered when > > > > > it overflows. It'd iterate the filters map and compare the sample > > > > > value according to the expression. If any of them fails, the sample > > > > > would be dropped. > > > > > > > > > > Also it needs to have the corresponding sample data for the expression > > > > > so it compares data->sample_flags with the given value. To access the > > > > > sample data, it uses the bpf_cast_to_kern_ctx() kfunc which was added > > > > > in v6.2 kernel. > > > > > > > > > > Acked-by: Jiri Olsa <jolsa@kernel.org> > > > > > Signed-off-by: Namhyung Kim <namhyung@kernel.org> > > > > > > > > > > > > I'm noticing this while building on a debian:11 container: > > > > > > > > GENSKEL /tmp/build/perf/util/bpf_skel/bperf_leader.skel.h > > > > GENSKEL /tmp/build/perf/util/bpf_skel/bperf_follower.skel.h > > > > GENSKEL /tmp/build/perf/util/bpf_skel/func_latency.skel.h > > > > GENSKEL /tmp/build/perf/util/bpf_skel/bpf_prog_profiler.skel.h > > > > GENSKEL /tmp/build/perf/util/bpf_skel/kwork_trace.skel.h > > > > GENSKEL /tmp/build/perf/util/bpf_skel/sample_filter.skel.h > > > > libbpf: failed to find BTF for extern 'bpf_cast_to_kern_ctx' [21] section: -2 > > > > Error: failed to open BPF object file: No such file or directory > > > > make[2]: *** [Makefile.perf:1085: /tmp/build/perf/util/bpf_skel/sample_filter.skel.h] Error 254 > > > > make[2]: *** Deleting file '/tmp/build/perf/util/bpf_skel/sample_filter.skel.h' > > > > make[2]: *** Waiting for unfinished jobs.... > > > > make[1]: *** [Makefile.perf:236: sub-make] Error 2 > > > > make: *** [Makefile:70: all] Error 2 > > > > make: Leaving directory '/git/perf-6.3.0-rc1/tools/perf' > > > > + exit 1 > > > > [perfbuilder@five 11]$ > > > > > > Same thing on debian:10 > > > > Hmm.. I thought extern symbols with__ksym are runtime > > dependencies and it should build on old kernels too. > > > > BPF folks, any suggestions? > > Fedora 33 also fails, see below, but these work: Maybe I can declare it as a weak symbol. How about this? Thanks, Namhyung ---8<--- diff --git a/tools/perf/util/bpf_skel/sample_filter.bpf.c b/tools/perf/util/bpf_skel/sample_filter.bpf.c index 57e3c67d6d37..52cbdd1765cd 100644 --- a/tools/perf/util/bpf_skel/sample_filter.bpf.c +++ b/tools/perf/util/bpf_skel/sample_filter.bpf.c @@ -17,7 +17,7 @@ struct filters { int dropped; -void *bpf_cast_to_kern_ctx(void *) __ksym; +void *bpf_cast_to_kern_ctx(void *) __ksym __weak; /* new kernel perf_sample_data definition */ struct perf_sample_data___new { @@ -118,6 +118,10 @@ int perf_sample_filter(void *ctx) int group_result = 0; int i; + /* no kernel context support, no filtering */ + if (!bpf_cast_to_kern_ctx) + return 1; + kctx = bpf_cast_to_kern_ctx(ctx); for (i = 0; i < MAX_FILTERS; i++) {
Em Wed, Mar 15, 2023 at 10:18:25PM -0700, Namhyung Kim escreveu: > On Wed, Mar 15, 2023 at 05:12:44PM -0300, Arnaldo Carvalho de Melo wrote: > > Em Wed, Mar 15, 2023 at 09:51:03AM -0700, Namhyung Kim escreveu: > > > On Wed, Mar 15, 2023 at 9:39 AM Arnaldo Carvalho de Melo > > > <acme@kernel.org> wrote: > > > > > > > > Em Wed, Mar 15, 2023 at 01:24:37PM -0300, Arnaldo Carvalho de Melo escreveu: > > > > > Em Tue, Mar 14, 2023 at 04:42:29PM -0700, Namhyung Kim escreveu: > > > > > > The BPF program will be attached to a perf_event and be triggered when > > > > > > it overflows. It'd iterate the filters map and compare the sample > > > > > > value according to the expression. If any of them fails, the sample > > > > > > would be dropped. > > > > > > > > > > > > Also it needs to have the corresponding sample data for the expression > > > > > > so it compares data->sample_flags with the given value. To access the > > > > > > sample data, it uses the bpf_cast_to_kern_ctx() kfunc which was added > > > > > > in v6.2 kernel. > > > > > > > > > > > > Acked-by: Jiri Olsa <jolsa@kernel.org> > > > > > > Signed-off-by: Namhyung Kim <namhyung@kernel.org> > > > > > > > > > > > > > > > I'm noticing this while building on a debian:11 container: > > > > > > > > > > GENSKEL /tmp/build/perf/util/bpf_skel/bperf_leader.skel.h > > > > > GENSKEL /tmp/build/perf/util/bpf_skel/bperf_follower.skel.h > > > > > GENSKEL /tmp/build/perf/util/bpf_skel/func_latency.skel.h > > > > > GENSKEL /tmp/build/perf/util/bpf_skel/bpf_prog_profiler.skel.h > > > > > GENSKEL /tmp/build/perf/util/bpf_skel/kwork_trace.skel.h > > > > > GENSKEL /tmp/build/perf/util/bpf_skel/sample_filter.skel.h > > > > > libbpf: failed to find BTF for extern 'bpf_cast_to_kern_ctx' [21] section: -2 > > > > > Error: failed to open BPF object file: No such file or directory > > > > > make[2]: *** [Makefile.perf:1085: /tmp/build/perf/util/bpf_skel/sample_filter.skel.h] Error 254 > > > > > make[2]: *** Deleting file '/tmp/build/perf/util/bpf_skel/sample_filter.skel.h' > > > > > make[2]: *** Waiting for unfinished jobs.... > > > > > make[1]: *** [Makefile.perf:236: sub-make] Error 2 > > > > > make: *** [Makefile:70: all] Error 2 > > > > > make: Leaving directory '/git/perf-6.3.0-rc1/tools/perf' > > > > > + exit 1 > > > > > [perfbuilder@five 11]$ > > > > > > > > Same thing on debian:10 > > > > > > Hmm.. I thought extern symbols with__ksym are runtime > > > dependencies and it should build on old kernels too. > > > > > > BPF folks, any suggestions? > > > > Fedora 33 also fails, see below, but these work: > > Maybe I can declare it as a weak symbol. How about this? Unsure this is the right fix, for now I'm using NO_BPF_SKEL=1 in those older distros, will check again early next week when I'm back from a short trip. - Arnaldo > Thanks, > Namhyung > > ---8<--- > > diff --git a/tools/perf/util/bpf_skel/sample_filter.bpf.c b/tools/perf/util/bpf_skel/sample_filter.bpf.c > index 57e3c67d6d37..52cbdd1765cd 100644 > --- a/tools/perf/util/bpf_skel/sample_filter.bpf.c > +++ b/tools/perf/util/bpf_skel/sample_filter.bpf.c > @@ -17,7 +17,7 @@ struct filters { > > int dropped; > > -void *bpf_cast_to_kern_ctx(void *) __ksym; > +void *bpf_cast_to_kern_ctx(void *) __ksym __weak; > > /* new kernel perf_sample_data definition */ > struct perf_sample_data___new { > @@ -118,6 +118,10 @@ int perf_sample_filter(void *ctx) > int group_result = 0; > int i; > > + /* no kernel context support, no filtering */ > + if (!bpf_cast_to_kern_ctx) > + return 1; > + > kctx = bpf_cast_to_kern_ctx(ctx); > > for (i = 0; i < MAX_FILTERS; i++) { >
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index dc9dda09b076..ed6b6a070f79 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -1050,7 +1050,7 @@ SKELETONS := $(SKEL_OUT)/bpf_prog_profiler.skel.h SKELETONS += $(SKEL_OUT)/bperf_leader.skel.h $(SKEL_OUT)/bperf_follower.skel.h SKELETONS += $(SKEL_OUT)/bperf_cgroup.skel.h $(SKEL_OUT)/func_latency.skel.h SKELETONS += $(SKEL_OUT)/off_cpu.skel.h $(SKEL_OUT)/lock_contention.skel.h -SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h +SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h $(SKEL_OUT)/sample_filter.skel.h $(SKEL_TMP_OUT) $(LIBAPI_OUTPUT) $(LIBBPF_OUTPUT) $(LIBPERF_OUTPUT) $(LIBSUBCMD_OUTPUT) $(LIBSYMBOL_OUTPUT): $(Q)$(MKDIR) -p $@ diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c index c72e35d51240..f20e1bc03778 100644 --- a/tools/perf/util/bpf-filter.c +++ b/tools/perf/util/bpf-filter.c @@ -1,10 +1,74 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include <stdlib.h> +#include <bpf/bpf.h> +#include <linux/err.h> +#include <internal/xyarray.h> + +#include "util/debug.h" +#include "util/evsel.h" + #include "util/bpf-filter.h" #include "util/bpf-filter-flex.h" #include "util/bpf-filter-bison.h" +#include "bpf_skel/sample-filter.h" +#include "bpf_skel/sample_filter.skel.h" + +#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) + +int perf_bpf_filter__prepare(struct evsel *evsel) +{ + int i, x, y, fd; + struct sample_filter_bpf *skel; + struct bpf_program *prog; + struct bpf_link *link; + struct perf_bpf_filter_expr *expr; + + skel = sample_filter_bpf__open_and_load(); + if (!skel) { + pr_err("Failed to load perf sample-filter BPF skeleton\n"); + return -1; + } + + i = 0; + fd = bpf_map__fd(skel->maps.filters); + list_for_each_entry(expr, &evsel->bpf_filters, list) { + struct perf_bpf_filter_entry entry = { + .op = expr->op, + .flags = expr->sample_flags, + .value = expr->val, + }; + bpf_map_update_elem(fd, &i, &entry, BPF_ANY); + i++; + } + + prog = skel->progs.perf_sample_filter; + for (x = 0; x < xyarray__max_x(evsel->core.fd); x++) { + for (y = 0; y < xyarray__max_y(evsel->core.fd); y++) { + link = bpf_program__attach_perf_event(prog, FD(evsel, x, y)); + if (IS_ERR(link)) { + pr_err("Failed to attach perf sample-filter program\n"); + return PTR_ERR(link); + } + } + } + evsel->bpf_skel = skel; + return 0; +} + +int perf_bpf_filter__destroy(struct evsel *evsel) +{ + struct perf_bpf_filter_expr *expr, *tmp; + + list_for_each_entry_safe(expr, tmp, &evsel->bpf_filters, list) { + list_del(&expr->list); + free(expr); + } + sample_filter_bpf__destroy(evsel->bpf_skel); + return 0; +} + struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, enum perf_bpf_filter_op op, unsigned long val) diff --git a/tools/perf/util/bpf-filter.h b/tools/perf/util/bpf-filter.h index 93a0d3de038c..eb8e1ac43cdf 100644 --- a/tools/perf/util/bpf-filter.h +++ b/tools/perf/util/bpf-filter.h @@ -4,15 +4,7 @@ #include <linux/list.h> -enum perf_bpf_filter_op { - PBF_OP_EQ, - PBF_OP_NEQ, - PBF_OP_GT, - PBF_OP_GE, - PBF_OP_LT, - PBF_OP_LE, - PBF_OP_AND, -}; +#include "bpf_skel/sample-filter.h" struct perf_bpf_filter_expr { struct list_head list; @@ -21,16 +13,30 @@ struct perf_bpf_filter_expr { unsigned long val; }; +struct evsel; + #ifdef HAVE_BPF_SKEL struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, enum perf_bpf_filter_op op, unsigned long val); int perf_bpf_filter__parse(struct list_head *expr_head, const char *str); +int perf_bpf_filter__prepare(struct evsel *evsel); +int perf_bpf_filter__destroy(struct evsel *evsel); + #else /* !HAVE_BPF_SKEL */ + static inline int perf_bpf_filter__parse(struct list_head *expr_head __maybe_unused, const char *str __maybe_unused) { - return -ENOSYS; + return -EOPNOTSUPP; +} +static inline int perf_bpf_filter__prepare(struct evsel *evsel __maybe_unused) +{ + return -EOPNOTSUPP; +} +static inline int perf_bpf_filter__destroy(struct evsel *evsel __maybe_unused) +{ + return -EOPNOTSUPP; } #endif /* HAVE_BPF_SKEL*/ #endif /* PERF_UTIL_BPF_FILTER_H */ diff --git a/tools/perf/util/bpf_skel/sample-filter.h b/tools/perf/util/bpf_skel/sample-filter.h new file mode 100644 index 000000000000..862060bfda14 --- /dev/null +++ b/tools/perf/util/bpf_skel/sample-filter.h @@ -0,0 +1,24 @@ +#ifndef PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H +#define PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H + +#define MAX_FILTERS 32 + +/* supported filter operations */ +enum perf_bpf_filter_op { + PBF_OP_EQ, + PBF_OP_NEQ, + PBF_OP_GT, + PBF_OP_GE, + PBF_OP_LT, + PBF_OP_LE, + PBF_OP_AND +}; + +/* BPF map entry for filtering */ +struct perf_bpf_filter_entry { + enum perf_bpf_filter_op op; + __u64 flags; + __u64 value; +}; + +#endif /* PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H */ \ No newline at end of file diff --git a/tools/perf/util/bpf_skel/sample_filter.bpf.c b/tools/perf/util/bpf_skel/sample_filter.bpf.c new file mode 100644 index 000000000000..c07256279c3e --- /dev/null +++ b/tools/perf/util/bpf_skel/sample_filter.bpf.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +// Copyright (c) 2023 Google +#include "vmlinux.h" +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> +#include <bpf/bpf_core_read.h> + +#include "sample-filter.h" + +/* BPF map that will be filled by user space */ +struct filters { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, int); + __type(value, struct perf_bpf_filter_entry); + __uint(max_entries, MAX_FILTERS); +} filters SEC(".maps"); + +int dropped; + +void *bpf_cast_to_kern_ctx(void *) __ksym; + +/* new kernel perf_sample_data definition */ +struct perf_sample_data___new { + __u64 sample_flags; +} __attribute__((preserve_access_index)); + +/* helper function to return the given perf sample data */ +static inline __u64 perf_get_sample(struct bpf_perf_event_data_kern *kctx, + struct perf_bpf_filter_entry *entry) +{ + struct perf_sample_data___new *data = (void *)kctx->data; + + if (!bpf_core_field_exists(data->sample_flags) || + (data->sample_flags & entry->flags) == 0) + return 0; + + switch (entry->flags) { + case PERF_SAMPLE_IP: + return kctx->data->ip; + case PERF_SAMPLE_ID: + return kctx->data->id; + case PERF_SAMPLE_TID: + return kctx->data->tid_entry.tid; + case PERF_SAMPLE_CPU: + return kctx->data->cpu_entry.cpu; + case PERF_SAMPLE_TIME: + return kctx->data->time; + case PERF_SAMPLE_ADDR: + return kctx->data->addr; + case PERF_SAMPLE_PERIOD: + return kctx->data->period; + case PERF_SAMPLE_TRANSACTION: + return kctx->data->txn; + case PERF_SAMPLE_WEIGHT: + return kctx->data->weight.full; + case PERF_SAMPLE_PHYS_ADDR: + return kctx->data->phys_addr; + case PERF_SAMPLE_CODE_PAGE_SIZE: + return kctx->data->code_page_size; + case PERF_SAMPLE_DATA_PAGE_SIZE: + return kctx->data->data_page_size; + default: + break; + } + return 0; +} + +/* BPF program to be called from perf event overflow handler */ +SEC("perf_event") +int perf_sample_filter(void *ctx) +{ + struct bpf_perf_event_data_kern *kctx; + struct perf_bpf_filter_entry *entry; + __u64 sample_data; + int i; + + kctx = bpf_cast_to_kern_ctx(ctx); + + for (i = 0; i < MAX_FILTERS; i++) { + int key = i; /* needed for verifier :( */ + + entry = bpf_map_lookup_elem(&filters, &key); + if (entry == NULL) + break; + sample_data = perf_get_sample(kctx, entry); + + switch (entry->op) { + case PBF_OP_EQ: + if (!(sample_data == entry->value)) + goto drop; + break; + case PBF_OP_NEQ: + if (!(sample_data != entry->value)) + goto drop; + break; + case PBF_OP_GT: + if (!(sample_data > entry->value)) + goto drop; + break; + case PBF_OP_GE: + if (!(sample_data >= entry->value)) + goto drop; + break; + case PBF_OP_LT: + if (!(sample_data < entry->value)) + goto drop; + break; + case PBF_OP_LE: + if (!(sample_data <= entry->value)) + goto drop; + break; + case PBF_OP_AND: + if (!(sample_data & entry->value)) + goto drop; + break; + } + } + /* generate sample data */ + return 1; + +drop: + __sync_fetch_and_add(&dropped, 1); + return 0; +} + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index c272c06565c0..68072ec655ce 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -150,8 +150,10 @@ struct evsel { */ struct bpf_counter_ops *bpf_counter_ops; - /* for perf-stat -b */ - struct list_head bpf_counter_list; + union { + struct list_head bpf_counter_list; /* for perf-stat -b */ + struct list_head bpf_filters; /* for perf-record --filter */ + }; /* for perf-stat --use-bpf */ int bperf_leader_prog_fd; @@ -159,6 +161,7 @@ struct evsel { union { struct bperf_leader_bpf *leader_skel; struct bperf_follower_bpf *follower_skel; + void *bpf_skel; }; unsigned long open_flags; int precise_ip_original;