From: Puranjay Mohan <puranjay@kernel.org>
To: bpf@vger.kernel.org
Cc: Puranjay Mohan <puranjay@kernel.org>,
"Alexei Starovoitov" <ast@kernel.org>,
"Daniel Borkmann" <daniel@iogearbox.net>,
"Andrii Nakryiko" <andrii@kernel.org>,
"Martin KaFai Lau" <martin.lau@linux.dev>,
"Eduard Zingerman" <eddyz87@gmail.com>,
"Kumar Kartikeya Dwivedi" <memxor@gmail.com>,
"Song Liu" <song@kernel.org>,
"Yonghong Song" <yonghong.song@linux.dev>
Subject: [PATCH bpf-next 0/4] bpf: Inline the numeric open-coded iterator kfuncs
Date: Wed, 15 Jul 2026 06:04:22 -0700 [thread overview]
Message-ID: <20260715130430.318421-1-puranjay@kernel.org> (raw)
The bpf_for(i, start, end) macro is BPF's open-coded numeric iterator. It
expands into calls to three kfuncs: bpf_iter_num_new() to set the iterator
up, bpf_iter_num_next() once per iteration, and bpf_iter_num_destroy() to
tear it down. The verifier emits these as ordinary kfunc calls, so a
bpf_for() loop pays function-call overhead on setup, teardown, and — most
importantly — on every single iteration via bpf_iter_num_next().
All three kfuncs are tiny and only touch the 8-byte on-stack iterator state
(struct bpf_iter_num_kern { int cur; int end; }). That makes them good
candidates for inlining, the same way several other special kfuncs are
already open-coded in bpf_fixup_kfunc_call(). This series replaces each of
the three calls with an equivalent inline BPF instruction sequence:
- bpf_iter_num_new(): keeps the (s64)end - (s64)start overflow check
(emitted with sign-extending moves) and returns the same
-EINVAL / -E2BIG / 0 results as the kfunc.
- bpf_iter_num_next(): the hot path. Since cur and end are int, the
kfunc's (s64)(s->cur + 1) >= s->end test reduces to a signed 32-bit
comparison of (s->cur + 1) against s->end, so the inlined code uses a
32-bit compare with no sign extension.
- bpf_iter_num_destroy(): a single 8-byte store zeroing the state.
The emitted instructions are plain BPF and remain valid for the
interpreter, so interpreter fallback stays correct and no jit_required
marking is needed.
Patch 4 adds a bench_bpf_for benchmark, modeled on the existing bpf_loop
benchmark, that runs a bpf_for() loop with an empty body so the
per-iteration iterator cost can be measured directly.
Results (./bench -p 1 --nr_loops 1000 bpf-for):
+--------+----------------------+----------------------+--------------+
| arch | inlined | kfunc calls | result |
+--------+----------------------+----------------------+--------------+
| x86-64 | 12884 M/s (0.078 ns) | 5812 M/s (0.172 ns) | ~2.2x faster |
+--------+----------------------+----------------------+--------------+
| arm64 | 546.1 M/s (1.831 ns) | 545.8 M/s (1.832 ns) | neutral |
+--------+----------------------+----------------------+--------------+
On x86-64, removing the per-iteration call to bpf_iter_num_next() roughly
doubles throughput. On arm64 the numbers are unchanged: the loop is bound
by the load/store dependency chain on the on-stack iterator state rather
than by call overhead, so inlining neither helps nor hurts there. It still
removes the calls.
Puranjay Mohan (4):
bpf: Inline bpf_iter_num_new() kfunc
bpf: Inline bpf_iter_num_next() kfunc
bpf: Inline bpf_iter_num_destroy() kfunc
selftests/bpf: Add bpf_for() benchmark
kernel/bpf/verifier.c | 79 +++++++++++++
tools/testing/selftests/bpf/Makefile | 2 +
tools/testing/selftests/bpf/bench.c | 4 +
.../selftests/bpf/benchs/bench_bpf_for.c | 105 ++++++++++++++++++
.../selftests/bpf/benchs/run_bench_bpf_for.sh | 15 +++
.../selftests/bpf/progs/bpf_for_bench.c | 32 ++++++
6 files changed, 237 insertions(+)
create mode 100644 tools/testing/selftests/bpf/benchs/bench_bpf_for.c
create mode 100755 tools/testing/selftests/bpf/benchs/run_bench_bpf_for.sh
create mode 100644 tools/testing/selftests/bpf/progs/bpf_for_bench.c
base-commit: d1f4b56417a3dc1a0600f960b14f46bd25eda89d
--
2.53.0-Meta
next reply other threads:[~2026-07-15 13:05 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-15 13:04 Puranjay Mohan [this message]
2026-07-15 13:04 ` [PATCH bpf-next 1/4] bpf: Inline bpf_iter_num_new() kfunc Puranjay Mohan
2026-07-15 13:33 ` sashiko-bot
2026-07-15 13:04 ` [PATCH bpf-next 2/4] bpf: Inline bpf_iter_num_next() kfunc Puranjay Mohan
2026-07-15 13:04 ` [PATCH bpf-next 3/4] bpf: Inline bpf_iter_num_destroy() kfunc Puranjay Mohan
2026-07-15 13:04 ` [PATCH bpf-next 4/4] selftests/bpf: Add bpf_for() benchmark Puranjay Mohan
2026-07-15 14:11 ` [PATCH bpf-next 0/4] bpf: Inline the numeric open-coded iterator kfuncs Leon Hwang
2026-07-15 14:15 ` Puranjay Mohan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260715130430.318421-1-puranjay@kernel.org \
--to=puranjay@kernel.org \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox