On Tue, Aug 4, 2026 at 8:48 AM Leon Hwang <[email protected]> wrote:
>
> In CI, the tracing_multi_bench_attach test could cost >10s, which should
> be avoided in daily CI running.
>
>  ./test_progs -t tracing_multi_bench_attach -v
>  WATCHDOG: test case tracing_multi_bench_attach executes for 10 seconds...
>  serial_test_tracing_multi_bench_attach: found 40163 functions
>  serial_test_tracing_multi_bench_attach: attached in   9.367s
>  serial_test_tracing_multi_bench_attach: detached in   1.798s
>  #546     tracing_multi_bench_attach:OK
>
> Since it is for benchmark attachment of tracing_multi link, move it to
> the generic bench framework.
>
>  ./bench tracing-multi-attach
>  Setting up benchmark 'tracing-multi-attach'...
>  tracing-multi-attach: found 40166 functions
>  tracing-multi-attach: attached in   9.278s
>  tracing-multi-attach: detached in   1.836s
>
> Assisted-by: Codex:gpt-5.6-sol
> Signed-off-by: Leon Hwang <[email protected]>
> ---
>  tools/testing/selftests/bpf/Makefile          |   2 +
>  tools/testing/selftests/bpf/bench.c           |   2 +
>  .../bpf/benchs/bench_tracing_multi_attach.c   | 177 ++++++++++++++++++
>  .../selftests/bpf/prog_tests/tracing_multi.c  | 125 -------------
>  4 files changed, 181 insertions(+), 125 deletions(-)
>  create mode 100644 
> tools/testing/selftests/bpf/benchs/bench_tracing_multi_attach.c
>

Jiri, are you ok with not exercising this logic regularly?

but also hm, is 10 seconds expected?


> diff --git a/tools/testing/selftests/bpf/Makefile 
> b/tools/testing/selftests/bpf/Makefile
> index 55d394438705..e4d8cbd51d71 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
> @@ -966,6 +966,7 @@ $(OUTPUT)/bench_ringbufs.o: 
> $(OUTPUT)/ringbuf_bench.skel.h \
>  $(OUTPUT)/bench_bloom_filter_map.o: $(OUTPUT)/bloom_filter_bench.skel.h
>  $(OUTPUT)/bench_bpf_loop.o: $(OUTPUT)/bpf_loop_bench.skel.h
>  $(OUTPUT)/bench_strncmp.o: $(OUTPUT)/strncmp_bench.skel.h
> +$(OUTPUT)/bench_tracing_multi_attach.o: $(OUTPUT)/tracing_multi_bench.skel.h
>  $(OUTPUT)/bench_bpf_hashmap_full_update.o: 
> $(OUTPUT)/bpf_hashmap_full_update_bench.skel.h
>  $(OUTPUT)/bench_local_storage.o: $(OUTPUT)/local_storage_bench.skel.h
>  $(OUTPUT)/bench_local_storage_rcu_tasks_trace.o: 
> $(OUTPUT)/local_storage_rcu_tasks_trace_bench.skel.h
> @@ -991,6 +992,7 @@ $(OUTPUT)/bench: $(OUTPUT)/bench.o \
>                  $(OUTPUT)/bench_bloom_filter_map.o \
>                  $(OUTPUT)/bench_bpf_loop.o \
>                  $(OUTPUT)/bench_strncmp.o \
> +                $(OUTPUT)/bench_tracing_multi_attach.o \
>                  $(OUTPUT)/bench_bpf_hashmap_full_update.o \
>                  $(OUTPUT)/bench_local_storage.o \
>                  $(OUTPUT)/bench_local_storage_rcu_tasks_trace.o \
> diff --git a/tools/testing/selftests/bpf/bench.c 
> b/tools/testing/selftests/bpf/bench.c
> index 3d9d2cd7764b..5ce31459835c 100644
> --- a/tools/testing/selftests/bpf/bench.c
> +++ b/tools/testing/selftests/bpf/bench.c
> @@ -545,6 +545,7 @@ extern const struct bench bench_trig_uprobe_multi_nop5;
>  extern const struct bench bench_trig_uretprobe_multi_nop5;
>  extern const struct bench bench_trig_usdt_nop;
>  extern const struct bench bench_trig_usdt_nop5;
> +extern const struct bench bench_tracing_multi_attach;
>  #endif
>
>  extern const struct bench bench_rb_libbpf;
> @@ -628,6 +629,7 @@ static const struct bench *benchs[] = {
>         &bench_trig_uretprobe_multi_nop5,
>         &bench_trig_usdt_nop,
>         &bench_trig_usdt_nop5,
> +       &bench_tracing_multi_attach,
>  #endif
>         /* ringbuf/perfbuf benchmarks */
>         &bench_rb_libbpf,
> diff --git a/tools/testing/selftests/bpf/benchs/bench_tracing_multi_attach.c 
> b/tools/testing/selftests/bpf/benchs/bench_tracing_multi_attach.c
> new file mode 100644
> index 000000000000..7389d1742ddc
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/benchs/bench_tracing_multi_attach.c
> @@ -0,0 +1,177 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#define _GNU_SOURCE
> +#include <search.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <bpf/btf.h>
> +#include "bench.h"
> +#include "testing_helpers.h"
> +#include "trace_helpers.h"
> +#include "tracing_multi_bench.skel.h"
> +#include "bpf/libbpf_internal.h"
> +
> +static int compare(const void *ppa, const void *ppb)
> +{
> +       const char *pa = *(const char **)ppa;
> +       const char *pb = *(const char **)ppb;
> +
> +       return strcmp(pa, pb);
> +}
> +
> +static void tdestroy_free_nop(void *ptr)
> +{
> +}
> +
> +static void tracing_multi_attach_setup(void)
> +{
> +       LIBBPF_OPTS(bpf_tracing_multi_opts, opts);
> +       struct tracing_multi_bench *skel = NULL;
> +       long attach_start_ns, attach_end_ns;
> +       long detach_start_ns, detach_end_ns;
> +       double attach_delta, detach_delta;
> +       struct bpf_link *link = NULL;
> +       size_t i, cap = 0, cnt = 0;
> +       struct ksyms *ksyms = NULL;
> +       void *root = NULL;
> +       void *dups = NULL;
> +       __u32 *ids = NULL;
> +       __u32 nr, type_id;
> +       struct btf *btf;
> +       int err;
> +
> +       setup_libbpf();
> +
> +       btf = btf__load_vmlinux_btf();
> +       err = libbpf_get_error(btf);
> +       if (err) {
> +               btf = NULL;
> +               fprintf(stderr, "failed to load vmlinux BTF: %s\n", 
> strerror(-err));
> +               goto cleanup;
> +       }
> +
> +       skel = tracing_multi_bench__open_and_load();
> +       err = libbpf_get_error(skel);
> +       if (!skel) {
> +               fprintf(stderr, "failed to open and load skeleton: %s\n", 
> strerror(-err));
> +               goto cleanup;
> +       }
> +
> +       err = bpf_get_ksyms(&ksyms, true);
> +       if (err) {
> +               fprintf(stderr, "failed to get kernel symbols: %s\n", 
> strerror(-err));
> +               goto cleanup;
> +       }
> +
> +       /* Get all ftrace 'safe' symbols.. */
> +       for (i = 0; i < ksyms->filtered_cnt; i++) {
> +               if (!tsearch(&ksyms->filtered_syms[i], &root, compare)) {
> +                       err = -ENOMEM;
> +                       fprintf(stderr, "failed to index ftrace symbols\n");
> +                       goto cleanup;
> +               }
> +       }
> +
> +       /*
> +        * Collect names that are not unique in kallsyms. The kernel resolves 
> a
> +        * tracing-multi BTF id to an address with kallsyms_lookup_name(), 
> which
> +        * returns the first symbol of that name. For a duplicate name that 
> may
> +        * be a different (non-ftrace-able) instance than the ftrace-able one 
> in
> +        * available_filter_functions, so attaching to it by BTF id fails with
> +        * -ENOENT (e.g. t_start/t_next/t_stop). ksyms->syms is sorted by 
> name,
> +        * so equal names are adjacent.
> +        */
> +       for (i = 1; i < ksyms->sym_cnt; i++) {
> +               if (strcmp(ksyms->syms[i].name, ksyms->syms[i - 1].name))
> +                       continue;
> +               if (!tsearch(&ksyms->syms[i].name, &dups, compare)) {
> +                       err = -ENOMEM;
> +                       fprintf(stderr, "failed to index duplicate kernel 
> symbols\n");
> +                       goto cleanup;
> +               }
> +       }
> +
> +       /* ..and filter them through BTF and btf_type_is_traceable_func. */
> +       nr = btf__type_cnt(btf);
> +       for (type_id = 1; type_id < nr; type_id++) {
> +               const struct btf_type *type;
> +               const char *str;
> +
> +               type = btf__type_by_id(btf, type_id);
> +               if (!type)
> +                       break;
> +
> +               if (BTF_INFO_KIND(type->info) != BTF_KIND_FUNC)
> +                       continue;
> +
> +               str = btf__name_by_offset(btf, type->name_off);
> +               if (!str)
> +                       break;
> +
> +               if (!tfind(&str, &root, compare))
> +                       continue;
> +
> +               /* Skip names that are not unique in kallsyms, see above. */
> +               if (tfind(&str, &dups, compare))
> +                       continue;
> +
> +               if (!btf_type_is_traceable_func(btf, type))
> +                       continue;
> +
> +               err = libbpf_ensure_mem((void **)&ids, &cap, sizeof(*ids), 
> cnt + 1);
> +               if (err) {
> +                       fprintf(stderr, "failed to allocate BTF ID array: 
> %s\n",
> +                               strerror(-err));
> +                       goto cleanup;
> +               }
> +
> +               ids[cnt++] = type_id;
> +       }
> +
> +       opts.ids = ids;
> +       opts.cnt = cnt;
> +
> +       attach_start_ns = get_time_ns();
> +       link = bpf_program__attach_tracing_multi(skel->progs.bench, NULL, 
> &opts);
> +       attach_end_ns = get_time_ns();
> +
> +       err = libbpf_get_error(link);
> +       if (err) {
> +               link = NULL;
> +               fprintf(stderr, "failed to attach tracing multi link: %s\n",
> +                       strerror(-err));
> +               goto cleanup;
> +       }
> +
> +       detach_start_ns = get_time_ns();
> +       err = bpf_link__destroy(link);
> +       detach_end_ns = get_time_ns();
> +       link = NULL;
> +       if (err) {
> +               fprintf(stderr, "failed to detach tracing multi link: %s\n",
> +                       strerror(-err));
> +               goto cleanup;
> +       }
> +
> +       attach_delta = (attach_end_ns - attach_start_ns) / 1000000000.0;
> +       detach_delta = (detach_end_ns - detach_start_ns) / 1000000000.0;
> +
> +       printf("%s: found %zu functions\n", bench->name, cnt);
> +       printf("%s: attached in %7.3lfs\n", bench->name, attach_delta);
> +       printf("%s: detached in %7.3lfs\n", bench->name, detach_delta);
> +
> +cleanup:
> +       bpf_link__destroy(link);
> +       tracing_multi_bench__destroy(skel);
> +       tdestroy(root, tdestroy_free_nop);
> +       tdestroy(dups, tdestroy_free_nop);
> +       free_kallsyms_local(ksyms);
> +       free(ids);
> +       btf__free(btf);
> +
> +       exit(err ? 1 : 0);
> +}
> +
> +const struct bench bench_tracing_multi_attach = {
> +       .name = "tracing-multi-attach",
> +       .setup = tracing_multi_attach_setup,
> +};
> diff --git a/tools/testing/selftests/bpf/prog_tests/tracing_multi.c 
> b/tools/testing/selftests/bpf/prog_tests/tracing_multi.c
> index 0aa9532a05cf..fd4f256d2e0a 100644
> --- a/tools/testing/selftests/bpf/prog_tests/tracing_multi.c
> +++ b/tools/testing/selftests/bpf/prog_tests/tracing_multi.c
> @@ -3,14 +3,12 @@
>  #include <test_progs.h>
>  #include <bpf/btf.h>
>  #include <search.h>
> -#include "bpf/libbpf_internal.h"
>  #include "tracing_multi.skel.h"
>  #include "tracing_multi_module.skel.h"
>  #include "tracing_multi_intersect.skel.h"
>  #include "tracing_multi_session.skel.h"
>  #include "tracing_multi_fail.skel.h"
>  #include "tracing_multi_verifier.skel.h"
> -#include "tracing_multi_bench.skel.h"
>  #include "tracing_multi_rollback.skel.h"
>  #include "trace_helpers.h"
>
> @@ -662,129 +660,6 @@ static void test_attach_api_fails(void)
>         free(ids2);
>  }
>
> -void serial_test_tracing_multi_bench_attach(void)
> -{
> -       LIBBPF_OPTS(bpf_tracing_multi_opts, opts);
> -       struct tracing_multi_bench *skel = NULL;
> -       long attach_start_ns, attach_end_ns;
> -       long detach_start_ns, detach_end_ns;
> -       double attach_delta, detach_delta;
> -       struct bpf_link *link = NULL;
> -       size_t i, cap = 0, cnt = 0;
> -       struct ksyms *ksyms = NULL;
> -       void *root = NULL;
> -       void *dups = NULL;
> -       __u32 *ids = NULL;
> -       __u32 nr, type_id;
> -       struct btf *btf;
> -       int err;
> -
> -#ifndef __x86_64__
> -       test__skip();
> -       return;
> -#endif
> -
> -       btf = btf__load_vmlinux_btf();
> -       if (!ASSERT_OK_PTR(btf, "btf__load_vmlinux_btf"))
> -               return;
> -
> -       skel = tracing_multi_bench__open_and_load();
> -       if (!ASSERT_OK_PTR(skel, "tracing_multi_bench__open_and_load"))
> -               goto cleanup;
> -
> -       if (!ASSERT_OK(bpf_get_ksyms(&ksyms, true), "get_syms"))
> -               goto cleanup;
> -
> -       /* Get all ftrace 'safe' symbols.. */
> -       for (i = 0; i < ksyms->filtered_cnt; i++) {
> -               if (!tsearch(&ksyms->filtered_syms[i], &root, compare)) {
> -                       ASSERT_FAIL("tsearch failed");
> -                       goto cleanup;
> -               }
> -       }
> -
> -       /*
> -        * Collect names that are not unique in kallsyms. The kernel resolves 
> a
> -        * tracing-multi BTF id to an address with kallsyms_lookup_name(), 
> which
> -        * returns the first symbol of that name. For a duplicate name that 
> may
> -        * be a different (non-ftrace-able) instance than the ftrace-able one 
> in
> -        * available_filter_functions, so attaching to it by BTF id fails with
> -        * -ENOENT (e.g. t_start/t_next/t_stop). ksyms->syms is sorted by 
> name,
> -        * so equal names are adjacent.
> -        */
> -       for (i = 1; i < ksyms->sym_cnt; i++) {
> -               if (strcmp(ksyms->syms[i].name, ksyms->syms[i - 1].name))
> -                       continue;
> -               if (!tsearch(&ksyms->syms[i].name, &dups, compare)) {
> -                       ASSERT_FAIL("tsearch failed");
> -                       goto cleanup;
> -               }
> -       }
> -
> -       /* ..and filter them through BTF and btf_type_is_traceable_func. */
> -       nr = btf__type_cnt(btf);
> -       for (type_id = 1; type_id < nr; type_id++) {
> -               const struct btf_type *type;
> -               const char *str;
> -
> -               type = btf__type_by_id(btf, type_id);
> -               if (!type)
> -                       break;
> -
> -               if (BTF_INFO_KIND(type->info) != BTF_KIND_FUNC)
> -                       continue;
> -
> -               str = btf__name_by_offset(btf, type->name_off);
> -               if (!str)
> -                       break;
> -
> -               if (!tfind(&str, &root, compare))
> -                       continue;
> -
> -               /* Skip names that are not unique in kallsyms, see above. */
> -               if (tfind(&str, &dups, compare))
> -                       continue;
> -
> -               if (!btf_type_is_traceable_func(btf, type))
> -                       continue;
> -
> -               err = libbpf_ensure_mem((void **) &ids, &cap, sizeof(*ids), 
> cnt + 1);
> -               if (err)
> -                       goto cleanup;
> -
> -               ids[cnt++] = type_id;
> -       }
> -
> -       opts.ids = ids;
> -       opts.cnt = cnt;
> -
> -       attach_start_ns = get_time_ns();
> -       link = bpf_program__attach_tracing_multi(skel->progs.bench, NULL, 
> &opts);
> -       attach_end_ns = get_time_ns();
> -
> -       if (!ASSERT_OK_PTR(link, "bpf_program__attach_tracing_multi"))
> -               goto cleanup;
> -
> -       detach_start_ns = get_time_ns();
> -       bpf_link__destroy(link);
> -       detach_end_ns = get_time_ns();
> -
> -       attach_delta = (attach_end_ns - attach_start_ns) / 1000000000.0;
> -       detach_delta = (detach_end_ns - detach_start_ns) / 1000000000.0;
> -
> -       printf("%s: found %lu functions\n", __func__, cnt);
> -       printf("%s: attached in %7.3lfs\n", __func__, attach_delta);
> -       printf("%s: detached in %7.3lfs\n", __func__, detach_delta);
> -
> -cleanup:
> -       tracing_multi_bench__destroy(skel);
> -       tdestroy(root, tdestroy_free_nop);
> -       tdestroy(dups, tdestroy_free_nop);
> -       free_kallsyms_local(ksyms);
> -       free(ids);
> -       btf__free(btf);
> -}
> -
>  static void tracing_multi_rollback_run(struct tracing_multi_rollback *skel)
>  {
>         LIBBPF_OPTS(bpf_test_run_opts, topts);
> --
> 2.55.0
>

Reply via email to