[PATCH] aarch64:Modify the copy_long function in the SVE memcpy implementation for 32-byte aligned access

longwei (I) longwei27@huawei.com
Fri Sep 5 00:47:02 GMT 2025


aarch64: Optimize memcpy_sve by using 32-byte alignment

The current memcpy_sve implementation shifts the destination pointer
forward to achieve only 16-byte alignment. This can lead to two
performance issues:
1.  Cross-cache-line accesses: With 16-byte alignment, a 32-byte store
     operation can still straddle two cache lines. This forces the CPU
     to perform two separate cache line accesses, effectively doubling
     the time for the store.
2.  Cache bank conflicts: On some ARM microarchitectures, L1 cache is
     organized into banks. 16-byte alignment can cause stores to frequently
     hit the same bank, creating contention and reducing effective memory
     bandwidth.

Change the implementation of memcpy_sve from shifting forward to 16-byte
alignment to shifting forward to 32-byte alignment, which is more
cache-friendly.
-   All 32-byte SVE vector stores are fully contained within a
     single 64-byte cache line, minimizing access latency.
-   Stores are distributed across different cache banks more
     evenly, preventing conflicts and maximizing throughput.

We tested the performance of `memcpy` on Kunpeng servers using the 
libmicro test suite.
The results showed that using 32-byte alignment can reduce the latency 
of `memcpy`.
The test results are in microseconds.

16-byte alignment:
memcpy_10    memcpy_32    memcpy_64    memcpy_128    memcpy_256 memcpy_512
0.0028        0.0028        0.0028        0.0035        0.0063 0.0122
memcpy_1k    memcpy_2k    memcpy_4k    memcpy_8k    memcpy_10k memcpy_16k
0.0165        0.0315        0.0605        0.1251        0.1597 0.2458
memcpy_32k    memcpy_64k    memcpy_128k    memcpy_256k memcpy_512k memcpy_1m
0.512        1.024        2.048        4.096        7.936 16.8
memcpy_2m    memcpy_4m    memcpy_8m    memcpy_10m
33.152        66.72        132.096        165.12

32-byte alignment:
memcpy_10    memcpy_32    memcpy_64    memcpy_128    memcpy_256 memcpy_512
0.0028        0.0028        0.0028        0.0035        0.0058 0.0096
memcpy_1k    memcpy_2k    memcpy_4k    memcpy_8k    memcpy_10k memcpy_16k
0.0165        0.0315        0.0614        0.121        0.1515 0.2355
memcpy_32k    memcpy_64k    memcpy_128k    memcpy_256k memcpy_512k memcpy_1m
0.512        1.024        2.048        3.84        7.168 15.072
memcpy_2m    memcpy_4m    memcpy_8m    memcpy_10m
29.952        60.032        119.04        147.968
No functional change.

sysdeps/aarch64/multiarch/memcpy_sve.S:  Change alignment shifting from 16
bytes to 32 bytes.
---
  sysdeps/aarch64/multiarch/memcpy_sve.S | 30 +++++++++++++-------------
  1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/sysdeps/aarch64/multiarch/memcpy_sve.S 
b/sysdeps/aarch64/multiarch/memcpy_sve.S
index 0ba6358bbd..3418b082b1 100644
--- a/sysdeps/aarch64/multiarch/memcpy_sve.S
+++ b/sysdeps/aarch64/multiarch/memcpy_sve.S
@@ -103,22 +103,22 @@ L(copy_long):
         add     srcend, src, count
         add     dstend, dstin, count

-       /* Copy 16 bytes and then align src to 16-byte alignment. */
-       ldr     D_q, [src]
-       and     tmp1, src, 15
-       bic     src, src, 15
+       /* Copy 32 bytes and then align src to 32-byte alignment. */
+       ldp     G_q, H_q, [src]
+       and     tmp1, src, 31
+       bic     src, src, 31
         sub     dst, dstin, tmp1
-       add     count, count, tmp1      /* Count is now 16 too large.  */
-       ldp     A_q, B_q, [src, 16]
-       str     D_q, [dstin]
-       ldp     C_q, D_q, [src, 48]
-       subs    count, count, 128 + 16  /* Test and readjust count. */
+       add     count, count, tmp1      /* Count is now 32 too large.  */
+       ldp     A_q, B_q, [src, 32]
+       stp     G_q, H_q, [dstin]
+       ldp     C_q, D_q, [src, 64]
+       subs    count, count, 128 + 32  /* Test and readjust count. */
         b.ls    L(copy64_from_end)
  L(loop64):
-       stp     A_q, B_q, [dst, 16]
-       ldp     A_q, B_q, [src, 80]

-       stp     C_q, D_q, [dst, 48]
-       ldp     C_q, D_q, [src, 112]
+       stp     A_q, B_q, [dst, 32]
+       ldp     A_q, B_q, [src, 96]
+       stp     C_q, D_q, [dst, 64]
+       ldp     C_q, D_q, [src, 128]
         add     src, src, 64
         add     dst, dst, 64
         subs    count, count, 64
@@ -127,9 +127,9 @@ L(loop64):
         /* Write the last iteration and copy 64 bytes from the end. */
  L(copy64_from_end):
         ldp     E_q, F_q, [srcend, -64]
-       stp     A_q, B_q, [dst, 16]
+       stp     A_q, B_q, [dst, 32]
         ldp     A_q, B_q, [srcend, -32]
-       stp     C_q, D_q, [dst, 48]
+       stp     C_q, D_q, [dst, 64]
         stp     E_q, F_q, [dstend, -64]
         stp     A_q, B_q, [dstend, -32]
         ret

-- 
2.43.0



More information about the Libc-alpha mailing list