acl: avoid vector spills in the RVV search loops
cover acl: avoid vector spills in the RVV search loops
At -O2 the ACL match checks are not inlined into the RVV search loops, so a vector value live across those calls is spilled and the remaining locals are addressed through vlenb. -O3 inlines them already and is unchanged.
Add __rte_flatten, and apply it to the two search functions.
Sun Yuechi (2):
eal: add flatten function attribute
acl: inline the match checks into the RVV search loops
lib/acl/acl_run_rvv.h | 8 +++++--- lib/eal/include/rte_common.h | 13 +++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-)
Signature · 1 line
2.56.0
PATCH 1/2 eal: add flatten function attribute
Add __rte_flatten, which inlines every call a function makes into it, where the callee's body is available.
__rte_always_inline marks the callee and inlines it at every call site. Here the requirement is local to one caller, and the callees are shared with paths that do not want inlining. Flatten applies at the boundary that needs it.
A spill slot has a fixed offset on a fixed-width vector ISA. With RVV its size depends on VLEN and is known only at run time, and once the frame holds such a slot the rest of it is addressed through vlenb. Inlining such calls is then worth the code growth.
--- lib/eal/include/rte_common.h | 13 +++++++++++++ 1 file changed, 13 insertions(+)
lib/eal/include/rte_common.h +13 -0
@@ -547,6 +547,19 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)#define __rte_noinline __attribute__((noinline))#endif +/** +* Inline every call made by a function into it, where the callee's body +* is available, whatever the callee's own inline annotation. +* +* Useful where a call inside a hot loop is costly in itself, +* for example where values are held in registers that no call preserves. +*/ +#ifdef RTE_TOOLCHAIN_MSVC +#define __rte_flatten +#else +#define __rte_flatten __attribute__((flatten)) +#endif +/** * Hint function in the hot path *
Signature · 1 line
2.56.0
Re: [PATCH 1/2] eal: add flatten function attribute
dpdk already does too much inling. need multiple performance benchmark before accepting
Quoted 47 lines · On Sun, Nov 1, 2026, 09:04 Sun Yuechi <[email protected]> wrote:
Add
__rte_flatten, which inlines every call a function makes into it, where the callee's body is available.
__rte_always_inlinemarks the callee and inlines it at every call site. Here the requirement is local to one caller, and the callees are shared with paths that do not want inlining. Flatten applies at the boundary that needs it.A spill slot has a fixed offset on a fixed-width vector ISA. With RVV its size depends on VLEN and is known only at run time, and once the frame holds such a slot the rest of it is addressed through vlenb. Inlining such calls is then worth the code growth.
Signed-off-by Sun Yuechi <[email protected]>--- lib/eal/include/rte_common.h | 13 +++++++++++++ 1 file changed, 13 insertions(+)lib/eal/include/rte_common.h +13
-0@@ -547,6 +547,19 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)#define __rte_noinline __attribute__((noinline))#endif +/** +* Inline every call made by a function into it, where the callee's body +* is available, whatever the callee's own inline annotation. +* +* Useful where a call inside a hot loop is costly in itself, +* for example where values are held in registers that no call preserves. +*/ +#ifdef RTE_TOOLCHAIN_MSVC +#define __rte_flatten +#else +#define __rte_flatten __attribute__((flatten)) +#endif +/** * Hint function in the hot path *
--
2.56.0
PATCH 2/2 acl: inline the match checks into the RVV search loops
In reply to Sun YuechiThe match checks are called inside the search loops, between the transitions; -O3 inlines them and is unchanged, at -O2 they are not. Flatten the search functions so the loops hold no call.
--- lib/acl/acl_run_rvv.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
lib/acl/acl_run_rvv.h +5 -3
@@ -182,9 +182,11 @@ transition_vec(vuint32m1_t v_next_input, const uint64_t *trans, }/* -* Execute trie traversal with 8 traversals in parallel +* Execute trie traversal with 8 traversals in parallel. +* Flattened: a vector value live across a call is spilled, and the +* frame is then addressed through vlenb. */ -static inline int +static inline __rte_flatten intsearch_rvv_8 (const struct rte_acl_ctx *ctx,const uint8_t **data,uint32_t *results,uint32_t total_packets,uint32_t categories) {
@@ -270,7 +272,7 @@ search_rvv_8(const struct rte_acl_ctx *ctx, const uint8_t **data,/* * Execute trie traversal with 4 traversals in parallel */ -static inline int +static inline __rte_flatten intsearch_rvv_4 (const struct rte_acl_ctx *ctx,const uint8_t **data,uint32_t *results,uint32_t total_packets,uint32_t categories) {
Signature · 1 line
2.56.0
The compiler is doing what we asked. Why workaround it.
Quoted 18 lines · Sun Yuechi
At -O2 the ACL match checks are not inlined into the RVV search loops, so a vector value live across those calls is spilled and the remaining locals are addressed through vlenb. -O3 inlines them already and is unchanged.
Add
__rte_flatten, and apply it to the two search functions.Sun Yuechi (2):
eal: add flatten function attribute
acl: inline the match checks into the RVV search loopslib/acl/acl_run_rvv.h | 8 +++++--- lib/eal/include/rte_common.h | 13 +++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-)--
2.56.0
01.11.2026 20:57, Stephen Hemminger пишет:
Quoted 1 line
The compiler is doing what we asked. Why workaround it.
Same thought: why simply not to use -O3 then?
Quoted 23 lines · Sun Yuechi
At -O2 the ACL match checks are not inlined into the RVV search loops, so
a vector value live across those calls is spilled and the remaining locals
are addressed through vlenb. -O3 inlines them already and is unchanged.Add
__rte_flatten, and apply it to the two search functions.Sun Yuechi (2):
eal: add flatten function attribute
acl: inline the match checks into the RVV search loopslib/acl/acl_run_rvv.h | 8 +++++---
lib/eal/include/rte_common.h| 13 +++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-)--
2.56.0
The default DPDK build is unaffected.
Some distros package DPDK with buildtype=plain and -O2. Where ACL is used on RISC-V in such a build, the gap between -O2 and -O3 is very large. A gap is expected, but not one this large. The optimization level is the integrator's choice, and a library with hand-written vector paths should not lose this much because of it, so I would rather fix it upstream.
Quoted 8 lines · On Wed, 4 Nov 2026 01:34:01 -0800 Sun Yuechi <[email protected]> wrote:
The default DPDK build is unaffected.
Some distros package DPDK with buildtype=plain and -O2. Where ACL is used on RISC-V in such a build, the gap between -O2 and -O3 is very large. A gap is expected, but not one this large. The optimization level is the integrator's choice, and a library with hand-written vector paths should not lose this much because of it, so I would rather fix it upstream.
NAK
Then fix the distro's choice. I don't think DPDK should be overriding compiler or packaging choice.