Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: fix bpf_loop_bench for new callback verification scheme

This is a preparatory change. A follow-up patch "bpf: verify callbacks
as if they are called unknown number of times" changes logic for
callbacks handling. While previously callbacks were verified as a
single function call, new scheme takes into account that callbacks
could be executed unknown number of times.

This has dire implications for bpf_loop_bench:

SEC("fentry/" SYS_PREFIX "sys_getpgid")
int benchmark(void *ctx)
{
for (int i = 0; i < 1000; i++) {
bpf_loop(nr_loops, empty_callback, NULL, 0);
__sync_add_and_fetch(&hits, nr_loops);
}
return 0;
}

W/o callbacks change verifier sees it as a 1000 calls to
empty_callback(). However, with callbacks change things become
exponential:
- i=0: state exploring empty_callback is scheduled with i=0 (a);
- i=1: state exploring empty_callback is scheduled with i=1;
...
- i=999: state exploring empty_callback is scheduled with i=999;
- state (a) is popped from stack;
- i=1: state exploring empty_callback is scheduled with i=1;
...

Avoid this issue by rewriting outer loop as bpf_loop().
Unfortunately, this adds a function call to a loop at runtime, which
negatively affects performance:

throughput latency
before: 149.919 ± 0.168 M ops/s, 6.670 ns/op
after : 137.040 ± 0.187 M ops/s, 7.297 ns/op

Acked-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20231121020701.26440-4-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Eduard Zingerman and committed by
Alexei Starovoitov
f40bfd16 87eb0152

+8 -5
+8 -5
tools/testing/selftests/bpf/progs/bpf_loop_bench.c
··· 15 15 return 0; 16 16 } 17 17 18 + static int outer_loop(__u32 index, void *data) 19 + { 20 + bpf_loop(nr_loops, empty_callback, NULL, 0); 21 + __sync_add_and_fetch(&hits, nr_loops); 22 + return 0; 23 + } 24 + 18 25 SEC("fentry/" SYS_PREFIX "sys_getpgid") 19 26 int benchmark(void *ctx) 20 27 { 21 - for (int i = 0; i < 1000; i++) { 22 - bpf_loop(nr_loops, empty_callback, NULL, 0); 23 - 24 - __sync_add_and_fetch(&hits, nr_loops); 25 - } 28 + bpf_loop(1000, outer_loop, NULL, 0); 26 29 return 0; 27 30 }