summaryrefslogtreecommitdiff
path: root/tools/perf/tests/bpf.c
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2023-08-11 15:26:11 -0300
committerArnaldo Carvalho de Melo <acme@redhat.com>2023-08-15 16:41:48 -0300
commit3d6dfae889174340af94c7357c8bae018966c524 (patch)
treece07577a6991185abc416eda6f62b46ae34310c8 /tools/perf/tests/bpf.c
parent56b11a2126bf2f422831ecf6112b87a4485b221b (diff)
downloadlwn-3d6dfae889174340af94c7357c8bae018966c524.tar.gz
lwn-3d6dfae889174340af94c7357c8bae018966c524.zip
perf parse-events: Remove BPF event support
New features like the BPF --filter support in perf record have made the BPF event functionality somewhat redundant. As shown by commit fcb027c1a4f6 ("perf tools: Revert enable indices setting syntax for BPF map") and commit 14e4b9f4289a ("perf trace: Raw augmented syscalls fix libbpf 1.0+ compatibility") the BPF event support hasn't been well maintained and it adds considerable complexity in areas like event parsing, not least as '/' is a separator for event modifiers as well as in paths. This patch removes support in the event parser for BPF events and then the associated functions are removed. This leads to the removal of whole source files like bpf-loader.c. Removing support means that augmented syscalls in perf trace is broken, this will be fixed in a later commit adding support using BPF skeletons. The removal of BPF events causes an unused label warning from flex generated code, so update build to ignore it: ``` util/parse-events-flex.c:2704:1: error: label ‘find_rule’ defined but not used [-Werror=unused-label] 2704 | find_rule: /* we branch to this label when backing up */ ``` Committer notes: Extracted from a larger patch that was also removing the support for linking with libllvm and libclang, that were an alternative to using an external clang execution to compile the .c event source code into BPF bytecode. Testing it: # perf trace -e /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c event syntax error: '/home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c' \___ Bad event or PMU Unabled to find PMU or event on a PMU of 'home' Initial error: event syntax error: '/home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c' \___ Cannot find PMU `home'. Missing kernel support? Run 'perf list' for a list of valid events Usage: perf trace [<options>] [<command>] or: perf trace [<options>] -- <command> [<options>] or: perf trace record [<options>] [<command>] or: perf trace record [<options>] -- <command> [<options>] -e, --event <event> event/syscall selector. use 'perf list' to list available events # Signed-off-by: Ian Rogers <irogers@google.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Andrii Nakryiko <andrii@kernel.org> Cc: Anshuman Khandual <anshuman.khandual@arm.com> Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com> Cc: Brendan Gregg <brendan.d.gregg@gmail.com> Cc: Carsten Haitzler <carsten.haitzler@arm.com> Cc: Eduard Zingerman <eddyz87@gmail.com> Cc: Fangrui Song <maskray@google.com> Cc: He Kuang <hekuang@huawei.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@arm.com> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Leo Yan <leo.yan@linaro.org> Cc: Madhavan Srinivasan <maddy@linux.ibm.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Nathan Chancellor <nathan@kernel.org> Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> Cc: Nick Desaulniers <ndesaulniers@google.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ravi Bangoria <ravi.bangoria@amd.com> Cc: Rob Herring <robh@kernel.org> Cc: Tiezhu Yang <yangtiezhu@loongson.cn> Cc: Tom Rix <trix@redhat.com> Cc: Wang Nan <wangnan0@huawei.com> Cc: Wang ShaoBo <bobo.shaobowang@huawei.com> Cc: Yang Jihong <yangjihong1@huawei.com> Cc: Yonghong Song <yhs@fb.com> Cc: YueHaibing <yuehaibing@huawei.com> Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230810184853.2860737-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/tests/bpf.c')
-rw-r--r--tools/perf/tests/bpf.c390
1 files changed, 0 insertions, 390 deletions
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c
deleted file mode 100644
index 9ccecd873ecd..000000000000
--- a/tools/perf/tests/bpf.c
+++ /dev/null
@@ -1,390 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/epoll.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <util/record.h>
-#include <util/util.h>
-#include <util/bpf-loader.h>
-#include <util/evlist.h>
-#include <linux/filter.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <api/fs/fs.h>
-#include <perf/mmap.h>
-#include "tests.h"
-#include "llvm.h"
-#include "debug.h"
-#include "parse-events.h"
-#include "util/mmap.h"
-#define NR_ITERS 111
-#define PERF_TEST_BPF_PATH "/sys/fs/bpf/perf_test"
-
-#if defined(HAVE_LIBBPF_SUPPORT) && defined(HAVE_LIBTRACEEVENT)
-#include <linux/bpf.h>
-#include <bpf/bpf.h>
-
-static int epoll_pwait_loop(void)
-{
- struct epoll_event events;
- int i;
-
- /* Should fail NR_ITERS times */
- for (i = 0; i < NR_ITERS; i++)
- epoll_pwait(-(i + 1), &events, 0, 0, NULL);
- return 0;
-}
-
-#ifdef HAVE_BPF_PROLOGUE
-
-static int llseek_loop(void)
-{
- int fds[2], i;
-
- fds[0] = open("/dev/null", O_RDONLY);
- fds[1] = open("/dev/null", O_RDWR);
-
- if (fds[0] < 0 || fds[1] < 0)
- return -1;
-
- for (i = 0; i < NR_ITERS; i++) {
- lseek(fds[i % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
- lseek(fds[(i + 1) % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
- }
- close(fds[0]);
- close(fds[1]);
- return 0;
-}
-
-#endif
-
-static struct {
- enum test_llvm__testcase prog_id;
- const char *name;
- const char *msg_compile_fail;
- const char *msg_load_fail;
- int (*target_func)(void);
- int expect_result;
- bool pin;
-} bpf_testcase_table[] = {
- {
- .prog_id = LLVM_TESTCASE_BASE,
- .name = "[basic_bpf_test]",
- .msg_compile_fail = "fix 'perf test LLVM' first",
- .msg_load_fail = "load bpf object failed",
- .target_func = &epoll_pwait_loop,
- .expect_result = (NR_ITERS + 1) / 2,
- },
- {
- .prog_id = LLVM_TESTCASE_BASE,
- .name = "[bpf_pinning]",
- .msg_compile_fail = "fix kbuild first",
- .msg_load_fail = "check your vmlinux setting?",
- .target_func = &epoll_pwait_loop,
- .expect_result = (NR_ITERS + 1) / 2,
- .pin = true,
- },
-#ifdef HAVE_BPF_PROLOGUE
- {
- .prog_id = LLVM_TESTCASE_BPF_PROLOGUE,
- .name = "[bpf_prologue_test]",
- .msg_compile_fail = "fix kbuild first",
- .msg_load_fail = "check your vmlinux setting?",
- .target_func = &llseek_loop,
- .expect_result = (NR_ITERS + 1) / 4,
- },
-#endif
-};
-
-static int do_test(struct bpf_object *obj, int (*func)(void),
- int expect)
-{
- struct record_opts opts = {
- .target = {
- .uid = UINT_MAX,
- .uses_mmap = true,
- },
- .freq = 0,
- .mmap_pages = 256,
- .default_interval = 1,
- };
-
- char pid[16];
- char sbuf[STRERR_BUFSIZE];
- struct evlist *evlist;
- int i, ret = TEST_FAIL, err = 0, count = 0;
-
- struct parse_events_state parse_state;
- struct parse_events_error parse_error;
-
- parse_events_error__init(&parse_error);
- bzero(&parse_state, sizeof(parse_state));
- parse_state.error = &parse_error;
- INIT_LIST_HEAD(&parse_state.list);
-
- err = parse_events_load_bpf_obj(&parse_state, &parse_state.list, obj, NULL, NULL);
- parse_events_error__exit(&parse_error);
- if (err == -ENODATA) {
- pr_debug("Failed to add events selected by BPF, debuginfo package not installed\n");
- return TEST_SKIP;
- }
- if (err || list_empty(&parse_state.list)) {
- pr_debug("Failed to add events selected by BPF\n");
- return TEST_FAIL;
- }
-
- snprintf(pid, sizeof(pid), "%d", getpid());
- pid[sizeof(pid) - 1] = '\0';
- opts.target.tid = opts.target.pid = pid;
-
- /* Instead of evlist__new_default, don't add default events */
- evlist = evlist__new();
- if (!evlist) {
- pr_debug("Not enough memory to create evlist\n");
- return TEST_FAIL;
- }
-
- err = evlist__create_maps(evlist, &opts.target);
- if (err < 0) {
- pr_debug("Not enough memory to create thread/cpu maps\n");
- goto out_delete_evlist;
- }
-
- evlist__splice_list_tail(evlist, &parse_state.list);
-
- evlist__config(evlist, &opts, NULL);
-
- err = evlist__open(evlist);
- if (err < 0) {
- pr_debug("perf_evlist__open: %s\n",
- str_error_r(errno, sbuf, sizeof(sbuf)));
- goto out_delete_evlist;
- }
-
- err = evlist__mmap(evlist, opts.mmap_pages);
- if (err < 0) {
- pr_debug("evlist__mmap: %s\n",
- str_error_r(errno, sbuf, sizeof(sbuf)));
- goto out_delete_evlist;
- }
-
- evlist__enable(evlist);
- (*func)();
- evlist__disable(evlist);
-
- for (i = 0; i < evlist->core.nr_mmaps; i++) {
- union perf_event *event;
- struct mmap *md;
-
- md = &evlist->mmap[i];
- if (perf_mmap__read_init(&md->core) < 0)
- continue;
-
- while ((event = perf_mmap__read_event(&md->core)) != NULL) {
- const u32 type = event->header.type;
-
- if (type == PERF_RECORD_SAMPLE)
- count ++;
- }
- perf_mmap__read_done(&md->core);
- }
-
- if (count != expect * evlist->core.nr_entries) {
- pr_debug("BPF filter result incorrect, expected %d, got %d samples\n", expect * evlist->core.nr_entries, count);
- goto out_delete_evlist;
- }
-
- ret = TEST_OK;
-
-out_delete_evlist:
- evlist__delete(evlist);
- return ret;
-}
-
-static struct bpf_object *
-prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name)
-{
- struct bpf_object *obj;
-
- obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, name);
- if (IS_ERR(obj)) {
- pr_debug("Compile BPF program failed.\n");
- return NULL;
- }
- return obj;
-}
-
-static int __test__bpf(int idx)
-{
- int ret;
- void *obj_buf;
- size_t obj_buf_sz;
- struct bpf_object *obj;
-
- ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
- bpf_testcase_table[idx].prog_id,
- false, NULL);
- if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
- pr_debug("Unable to get BPF object, %s\n",
- bpf_testcase_table[idx].msg_compile_fail);
- if ((idx == 0) || (ret == TEST_SKIP))
- return TEST_SKIP;
- else
- return TEST_FAIL;
- }
-
- obj = prepare_bpf(obj_buf, obj_buf_sz,
- bpf_testcase_table[idx].name);
- if ((!!bpf_testcase_table[idx].target_func) != (!!obj)) {
- if (!obj)
- pr_debug("Fail to load BPF object: %s\n",
- bpf_testcase_table[idx].msg_load_fail);
- else
- pr_debug("Success unexpectedly: %s\n",
- bpf_testcase_table[idx].msg_load_fail);
- ret = TEST_FAIL;
- goto out;
- }
-
- if (obj) {
- ret = do_test(obj,
- bpf_testcase_table[idx].target_func,
- bpf_testcase_table[idx].expect_result);
- if (ret != TEST_OK)
- goto out;
- if (bpf_testcase_table[idx].pin) {
- int err;
-
- if (!bpf_fs__mount()) {
- pr_debug("BPF filesystem not mounted\n");
- ret = TEST_FAIL;
- goto out;
- }
- err = mkdir(PERF_TEST_BPF_PATH, 0777);
- if (err && errno != EEXIST) {
- pr_debug("Failed to make perf_test dir: %s\n",
- strerror(errno));
- ret = TEST_FAIL;
- goto out;
- }
- if (bpf_object__pin(obj, PERF_TEST_BPF_PATH))
- ret = TEST_FAIL;
- if (rm_rf(PERF_TEST_BPF_PATH))
- ret = TEST_FAIL;
- }
- }
-
-out:
- free(obj_buf);
- bpf__clear();
- return ret;
-}
-
-static int check_env(void)
-{
- LIBBPF_OPTS(bpf_prog_load_opts, opts);
- int err;
- char license[] = "GPL";
-
- struct bpf_insn insns[] = {
- BPF_MOV64_IMM(BPF_REG_0, 1),
- BPF_EXIT_INSN(),
- };
-
- err = fetch_kernel_version(&opts.kern_version, NULL, 0);
- if (err) {
- pr_debug("Unable to get kernel version\n");
- return err;
- }
- err = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, license, insns,
- ARRAY_SIZE(insns), &opts);
- if (err < 0) {
- pr_err("Missing basic BPF support, skip this test: %s\n",
- strerror(errno));
- return err;
- }
- close(err);
-
- return 0;
-}
-
-static int test__bpf(int i)
-{
- int err;
-
- if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
- return TEST_FAIL;
-
- if (geteuid() != 0) {
- pr_debug("Only root can run BPF test\n");
- return TEST_SKIP;
- }
-
- if (check_env())
- return TEST_SKIP;
-
- err = __test__bpf(i);
- return err;
-}
-#endif
-
-static int test__basic_bpf_test(struct test_suite *test __maybe_unused,
- int subtest __maybe_unused)
-{
-#if defined(HAVE_LIBBPF_SUPPORT) && defined(HAVE_LIBTRACEEVENT)
- return test__bpf(0);
-#else
- pr_debug("Skip BPF test because BPF or libtraceevent support is not compiled\n");
- return TEST_SKIP;
-#endif
-}
-
-static int test__bpf_pinning(struct test_suite *test __maybe_unused,
- int subtest __maybe_unused)
-{
-#if defined(HAVE_LIBBPF_SUPPORT) && defined(HAVE_LIBTRACEEVENT)
- return test__bpf(1);
-#else
- pr_debug("Skip BPF test because BPF or libtraceevent support is not compiled\n");
- return TEST_SKIP;
-#endif
-}
-
-static int test__bpf_prologue_test(struct test_suite *test __maybe_unused,
- int subtest __maybe_unused)
-{
-#if defined(HAVE_LIBBPF_SUPPORT) && defined(HAVE_BPF_PROLOGUE) && defined(HAVE_LIBTRACEEVENT)
- return test__bpf(2);
-#else
- pr_debug("Skip BPF test because BPF or libtraceevent support is not compiled\n");
- return TEST_SKIP;
-#endif
-}
-
-
-static struct test_case bpf_tests[] = {
-#if defined(HAVE_LIBBPF_SUPPORT) && defined(HAVE_LIBTRACEEVENT)
- TEST_CASE("Basic BPF filtering", basic_bpf_test),
- TEST_CASE_REASON("BPF pinning", bpf_pinning,
- "clang isn't installed or environment missing BPF support"),
-#ifdef HAVE_BPF_PROLOGUE
- TEST_CASE_REASON("BPF prologue generation", bpf_prologue_test,
- "clang/debuginfo isn't installed or environment missing BPF support"),
-#else
- TEST_CASE_REASON("BPF prologue generation", bpf_prologue_test, "not compiled in"),
-#endif
-#else
- TEST_CASE_REASON("Basic BPF filtering", basic_bpf_test, "not compiled in or missing libtraceevent support"),
- TEST_CASE_REASON("BPF pinning", bpf_pinning, "not compiled in or missing libtraceevent support"),
- TEST_CASE_REASON("BPF prologue generation", bpf_prologue_test, "not compiled in or missing libtraceevent support"),
-#endif
- { .name = NULL, }
-};
-
-struct test_suite suite__bpf = {
- .desc = "BPF filter",
- .test_cases = bpf_tests,
-};