Add testcase for the performance of the trace bpf progs. In this testcase, bpf_fentry_test1() will be called 10000000 times in bpf_testmod_bench_run, and the time consumed will be returned. Following cases is considered: - nop: nothing is attached to bpf_fentry_test1() - fentry: a empty FENTRY bpf program is attached to bpf_fentry_test1() - fentry_multi_single: a empty FENTRY_MULTI bpf program is attached to bpf_fentry_test1() - fentry_multi_all: a empty FENTRY_MULTI bpf program is attached to all the kernel functions - kprobe_multi_single: a empty KPROBE_MULTI bpf program is attached to bpf_fentry_test1() - kprobe_multi_all: a empty KPROBE_MULTI bpf program is attached to all the kernel functions And we can get the result by running: ./test_progs -t tracing_multi_bench -v | grep time Signed-off-by: Menglong Dong <dongml2@xxxxxxxxxxxxxxx> --- .../selftests/bpf/prog_tests/trace_bench.c | 149 ++++++++++++++++++ .../selftests/bpf/progs/fentry_empty.c | 13 ++ .../testing/selftests/bpf/progs/trace_bench.c | 21 +++ .../selftests/bpf/test_kmods/bpf_testmod.c | 16 ++ 4 files changed, 199 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/trace_bench.c create mode 100644 tools/testing/selftests/bpf/progs/fentry_empty.c create mode 100644 tools/testing/selftests/bpf/progs/trace_bench.c diff --git a/tools/testing/selftests/bpf/prog_tests/trace_bench.c b/tools/testing/selftests/bpf/prog_tests/trace_bench.c new file mode 100644 index 000000000000..673c9acf358c --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/trace_bench.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2025 ChinaTelecom */ + +#include <test_progs.h> +#include "bpf/libbpf_internal.h" + +#include "fentry_multi_empty.skel.h" +#include "fentry_empty.skel.h" +#include "kprobe_multi_empty.skel.h" +#include "trace_bench.skel.h" + +static void test_bench_run(const char *name) +{ + struct trace_bench *skel; + __u64 bench_result; + int err; + + skel = trace_bench__open_and_load(); + if (!ASSERT_OK_PTR(skel, "trace_bench__open_and_load")) + return; + + err = trace_bench__attach(skel); + if (!ASSERT_OK(err, "trace_bench__attach")) + goto cleanup; + + ASSERT_OK(trigger_module_test_read(1), "trigger_read"); + + bench_result = skel->bss->bench_result / 1000; + printf("bench time for %s: %lld.%03lldms\n", name, bench_result / 1000, + bench_result % 1000); +cleanup: + trace_bench__destroy(skel); +} + +static void test_fentry_multi(bool load_all, char *name) +{ + LIBBPF_OPTS(bpf_trace_multi_opts, opts); + struct fentry_multi_empty *skel; + char **syms = NULL; + struct bpf_link *link; + size_t cnt = 0; + int err; + + skel = fentry_multi_empty__open_and_load(); + if (!ASSERT_OK_PTR(skel, "fentry_multi_empty__open_and_load")) + goto cleanup; + + if (!load_all) { + err = fentry_multi_empty__attach(skel); + if (!ASSERT_OK(err, "fentry_multi_empty__attach")) + goto cleanup; + goto do_test; + } + + if (!ASSERT_OK(bpf_get_ksyms(&syms, &cnt, true), "get_syms")) + return; + opts.syms = (const char **) syms; + opts.cnt = cnt; + opts.skip_invalid = true; + link = bpf_program__attach_trace_multi_opts(skel->progs.fentry_multi_empty, + &opts); + if (!ASSERT_OK_PTR(link, "bpf_program__attach_trace_multi_opts")) + goto cleanup; + skel->links.fentry_multi_empty = link; + printf("attach %d functions before testings\n", (int)opts.cnt); + +do_test: + test_bench_run(name); +cleanup: + fentry_multi_empty__destroy(skel); + if (syms) + free(syms); +} + +static void test_fentry_single(void) +{ + struct fentry_empty *skel; + int err; + + skel = fentry_empty__open_and_load(); + if (!ASSERT_OK_PTR(skel, "fentry_empty__open_and_load")) + return; + + err = fentry_empty__attach(skel); + if (!ASSERT_OK(err, "fentry_empty__attach")) + goto cleanup; + + test_bench_run("fentry_single"); +cleanup: + fentry_empty__destroy(skel); +} + +static void test_kprobe_multi(bool load_all, char *name) +{ + LIBBPF_OPTS(bpf_kprobe_multi_opts, opts); + char *test_func = "bpf_fentry_test1"; + struct kprobe_multi_empty *skel; + struct bpf_link *link; + char **syms = NULL; + size_t cnt = 0; + + if (!ASSERT_OK(bpf_get_ksyms(&syms, &cnt, true), "get_syms")) + return; + + skel = kprobe_multi_empty__open_and_load(); + if (!ASSERT_OK_PTR(skel, "kprobe_multi_empty__open_and_load")) + goto cleanup; + + if (load_all) { + opts.syms = (const char **) syms; + opts.cnt = cnt; + } else { + opts.syms = (const char **) &test_func; + opts.cnt = 1; + } + link = bpf_program__attach_kprobe_multi_opts(skel->progs.test_kprobe_empty, + NULL, &opts); + if (!ASSERT_OK_PTR(link, "bpf_program__attach_kprobe_multi_opts")) + goto cleanup; + skel->links.test_kprobe_empty = link; + + if (load_all) + printf("attach %d functions before testings\n", (int)opts.cnt); + test_bench_run(name); + +cleanup: + kprobe_multi_empty__destroy(skel); + if (syms) + free(syms); +} + +void test_trace_bench(void) +{ + if (test__start_subtest("nop")) + test_bench_run("nop"); + + if (test__start_subtest("fentry_single")) + test_fentry_single(); + + if (test__start_subtest("fentry_multi_single")) + test_fentry_multi(false, "fentry_multi_single"); + if (test__start_subtest("fentry_multi_all")) + test_fentry_multi(true, "fentry_multi_all"); + + if (test__start_subtest("kprobe_multi_single")) + test_kprobe_multi(false, "kprobe_multi_single"); + if (test__start_subtest("kprobe_multi_all")) + test_kprobe_multi(true, "kprobe_multi_all"); +} diff --git a/tools/testing/selftests/bpf/progs/fentry_empty.c b/tools/testing/selftests/bpf/progs/fentry_empty.c new file mode 100644 index 000000000000..f2bfaf04d56a --- /dev/null +++ b/tools/testing/selftests/bpf/progs/fentry_empty.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2025 ChinaTelecom */ +#include <linux/bpf.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> + +char _license[] SEC("license") = "GPL"; + +SEC("fentry/bpf_fentry_test1") +int BPF_PROG(fentry_empty) +{ + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/trace_bench.c b/tools/testing/selftests/bpf/progs/trace_bench.c new file mode 100644 index 000000000000..98373871414a --- /dev/null +++ b/tools/testing/selftests/bpf/progs/trace_bench.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2025 ChinaTelecom */ + +#include <linux/bpf.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> + +char _license[] SEC("license") = "GPL"; + +__u64 bench_result; + +SEC("fexit.multi/bpf_testmod_bench_run") +int BPF_PROG(fexit_bench_done) +{ + __u64 ret = 0; + + bpf_get_func_ret(ctx, &ret); + bench_result = ret; + + return 0; +} diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c index ebc4d5204136..d21775eba211 100644 --- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c +++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c @@ -405,6 +405,20 @@ noinline int bpf_testmod_fentry_test11(u64 a, void *b, short c, int d, return a + (long)b + c + d + (long)e + f + g + h + i + j + k; } +extern int bpf_fentry_test1(int a); +noinline u64 bpf_testmod_bench_run(void) +{ + u64 start = ktime_get_boottime_ns(); + u64 time; + + for (int i = 0; i < 10000000; i++) + bpf_fentry_test1(i); + + time = ktime_get_boottime_ns() - start; + + return time; +} + int bpf_testmod_fentry_ok; noinline ssize_t @@ -443,6 +457,8 @@ bpf_testmod_test_read(struct file *file, struct kobject *kobj, (void)trace_bpf_testmod_test_raw_tp_null(NULL); + (void)bpf_testmod_bench_run(); + bpf_testmod_test_struct_ops3(); struct_arg3 = kmalloc((sizeof(struct bpf_testmod_struct_arg_3) + -- 2.39.5