Skip to contentSkip to conversation

acl: avoid vector spills in the RVV search loops

PATCH NAK Sun Yuechi 3 participants 8 messages Nov 1 – Nov 4

lore
Share & tools
lore

Sun Yuechi

author
#0 lore raw

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
author
#1 lore raw

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
index fed373f412..e32b6b13d6 100644
@@ -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
#2 lore raw

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_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
index fed373f412..e32b6b13d6 100644
@@ -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

author
#3 lore raw

PATCH 2/2 acl: inline the match checks into the RVV search loops

In reply to Sun Yuechi

The 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
index 1d6fdff045..c4daf10224 100644
@@ -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 int
 search_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 int
 search_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
#4 lore raw
In reply to Sun Yuechi

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 loops

 lib/acl/acl_run_rvv.h        |  8 +++++---
 lib/eal/include/rte_common.h | 13 +++++++++++++
 2 files changed, 18 insertions(+), 3 deletions(-)

--
2.56.0

#5 lore raw

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 loops

 lib/acl/acl_run_rvv.h        |  8 +++++--- lib/eal/include/rte_common.h | 13 +++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-)

--
2.56.0

author
#6 lore raw

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.

#7 lore raw
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.