<div dir="auto">How does this compare to glibc/gcc memcpy? I would like to see rte_memcpy go away </div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Thu, Oct 9, 2025, 08:32 Sun Yuechi <<a href="mailto:sunyuechi@iscas.ac.cn">sunyuechi@iscas.ac.cn</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Improve rte_memcpy implementation on RISC-V platform for sizes under<br>
64 bytes, based on the ARM implementation.<br>
<br>
Enhanced handling for cases smaller than 64 bytes shows very significant<br>
performance benefits, while the impact is minimal after 64 bytes.<br>
<br>
This optimization is disabled by default as a conservative measure,<br>
since future glibc versions may include similar improvements that<br>
could conflict with this implementation.<br>
<br>
Use RTE_ARCH_RISCV_MEMCPY to enable this optimization.<br>
<br>
Signed-off-by: Sun Yuechi <<a href="mailto:sunyuechi@iscas.ac.cn" target="_blank" rel="noreferrer">sunyuechi@iscas.ac.cn</a>><br>
---<br>
 config/riscv/meson.build           |   5 ++<br>
 lib/eal/riscv/include/rte_memcpy.h | 122 +++++++++++++++++++++++++++++<br>
 2 files changed, 127 insertions(+)<br>
<br>
diff --git a/config/riscv/meson.build b/config/riscv/meson.build<br>
index f93ea3e145..73fd0ab4da 100644<br>
--- a/config/riscv/meson.build<br>
+++ b/config/riscv/meson.build<br>
@@ -20,6 +20,11 @@ dpdk_conf.set('RTE_FORCE_INTRINSICS', 1)<br>
<br>
 # common flags to all riscv builds, with lowest priority<br>
 flags_common = [<br>
+    # Accelerate rte_memcpy for copies smaller than 64 bytes. Be sure to run<br>
+    # the unit test (memcpy_perf_autotest) to verify performance improvements.<br>
+    # Refer to notes in source file (lib/eal/riscv/include/rte_memcpy.h) for<br>
+    # more details.<br>
+    ['RTE_ARCH_RISCV_MEMCPY', false],<br>
     ['RTE_ARCH_RISCV', true],<br>
     ['RTE_CACHE_LINE_SIZE', 64],<br>
     # Manually set wall time clock frequency for the target. If 0, then it is<br>
diff --git a/lib/eal/riscv/include/rte_memcpy.h b/lib/eal/riscv/include/rte_memcpy.h<br>
index d8a942c5d2..ae6e79e2fc 100644<br>
--- a/lib/eal/riscv/include/rte_memcpy.h<br>
+++ b/lib/eal/riscv/include/rte_memcpy.h<br>
@@ -2,6 +2,7 @@<br>
  * Copyright(c) 2022 StarFive<br>
  * Copyright(c) 2022 SiFive<br>
  * Copyright(c) 2022 Semihalf<br>
+ * Copyright(c) 2025 ISCAS<br>
  */<br>
<br>
 #ifndef RTE_MEMCPY_RISCV_H<br>
@@ -14,6 +15,125 @@<br>
<br>
 #include "generic/rte_memcpy.h"<br>
<br>
+#ifdef RTE_ARCH_RISCV_MEMCPY<br>
+<br>
+#ifdef __cplusplus<br>
+extern "C" {<br>
+#endif<br>
+<br>
+/*<br>
+ * This implementation is improved from eal/arm/include/rte_memcpy_64.h,<br>
+ * targeting only cases of < 64 bytes.<br>
+ * Currently shows significant performance improvement over various glibc versions,<br>
+ * but is disabled by default due to uncertainty about potential performance<br>
+ * degradation in future versions.<br>
+ * You can use memcpy_perf_autotest to test the performance.<br>
+ */<br>
+<br>
+static __rte_always_inline<br>
+void rte_mov16(uint8_t *dst, const uint8_t *src)<br>
+{<br>
+       __uint128_t *dst128 = (__uint128_t *)dst;<br>
+       const __uint128_t *src128 = (const __uint128_t *)src;<br>
+       *dst128 = *src128;<br>
+}<br>
+<br>
+static __rte_always_inline<br>
+void rte_mov32(uint8_t *dst, const uint8_t *src)<br>
+{<br>
+       __uint128_t *dst128 = (__uint128_t *)dst;<br>
+       const __uint128_t *src128 = (const __uint128_t *)src;<br>
+       const __uint128_t x0 = src128[0], x1 = src128[1];<br>
+       dst128[0] = x0;<br>
+       dst128[1] = x1;<br>
+}<br>
+<br>
+static __rte_always_inline<br>
+void rte_mov48(uint8_t *dst, const uint8_t *src)<br>
+{<br>
+       __uint128_t *dst128 = (__uint128_t *)dst;<br>
+       const __uint128_t *src128 = (const __uint128_t *)src;<br>
+       const __uint128_t x0 = src128[0], x1 = src128[1], x2 = src128[2];<br>
+       dst128[0] = x0;<br>
+       dst128[1] = x1;<br>
+       dst128[2] = x2;<br>
+}<br>
+<br>
+static __rte_always_inline void<br>
+rte_mov64(uint8_t *dst, const uint8_t *src)<br>
+{<br>
+       memcpy(dst, src, 64);<br>
+}<br>
+<br>
+static __rte_always_inline void<br>
+rte_mov128(uint8_t *dst, const uint8_t *src)<br>
+{<br>
+       memcpy(dst, src, 128);<br>
+}<br>
+<br>
+static __rte_always_inline void<br>
+rte_mov256(uint8_t *dst, const uint8_t *src)<br>
+{<br>
+       memcpy(dst, src, 256);<br>
+}<br>
+<br>
+static __rte_always_inline void<br>
+rte_memcpy_lt16(uint8_t *dst, const uint8_t *src, size_t n)<br>
+{<br>
+       if (n & 0x08) {<br>
+               /* copy 8 ~ 15 bytes */<br>
+               *(uint64_t *)dst = *(const uint64_t *)src;<br>
+               *(uint64_t *)(dst - 8 + n) = *(const uint64_t *)(src - 8 + n);<br>
+       } else if (n & 0x04) {<br>
+               /* copy 4 ~ 7 bytes */<br>
+               *(uint32_t *)dst = *(const uint32_t *)src;<br>
+               *(uint32_t *)(dst - 4 + n) = *(const uint32_t *)(src - 4 + n);<br>
+       } else if (n & 0x02) {<br>
+               /* copy 2 ~ 3 bytes */<br>
+               *(uint16_t *)dst = *(const uint16_t *)src;<br>
+               *(uint16_t *)(dst - 2 + n) = *(const uint16_t *)(src - 2 + n);<br>
+       } else if (n & 0x01) {<br>
+               /* copy 1 byte */<br>
+               *dst = *src;<br>
+       }<br>
+}<br>
+<br>
+static __rte_always_inline void<br>
+rte_memcpy_ge16_lt64(uint8_t *dst, const uint8_t *src, size_t n)<br>
+{<br>
+       if (n == 16) {<br>
+               rte_mov16(dst, src);<br>
+       } else if (n <= 32) {<br>
+               rte_mov16(dst, src);<br>
+               rte_mov16(dst - 16 + n, src - 16 + n);<br>
+       } else if (n <= 48) {<br>
+               rte_mov32(dst, src);<br>
+               rte_mov16(dst - 16 + n, src - 16 + n);<br>
+       } else {<br>
+               rte_mov48(dst, src);<br>
+               rte_mov16(dst - 16 + n, src - 16 + n);<br>
+       }<br>
+}<br>
+<br>
+static __rte_always_inline void *<br>
+rte_memcpy(void *dst, const void *src, size_t n)<br>
+{<br>
+       if (n >= 64)<br>
+               return memcpy(dst, src, n);<br>
+       if (n < 16) {<br>
+               rte_memcpy_lt16((uint8_t *)dst, (const uint8_t *)src, n);<br>
+               return dst;<br>
+       }<br>
+       rte_memcpy_ge16_lt64((uint8_t *)dst, (const uint8_t *)src, n);<br>
+       return dst;<br>
+}<br>
+<br>
+#ifdef __cplusplus<br>
+}<br>
+#endif<br>
+<br>
+#else /* RTE_ARCH_RISCV_MEMCPY */<br>
+<br>
 #ifdef __cplusplus<br>
 extern "C" {<br>
 #endif<br>
@@ -60,4 +180,6 @@ rte_mov256(uint8_t *dst, const uint8_t *src)<br>
 }<br>
 #endif<br>
<br>
+#endif /* RTE_ARCH_RISCV_MEMCPY */<br>
+<br>
 #endif /* RTE_MEMCPY_RISCV_H */<br>
-- <br>
2.51.0<br>
<br>
</blockquote></div>