3 ms·
Gosh that's complex. On all RISC-V CPUs I have currently access to with the pre-ratification RVV 0.7.1, the simple 9 instruction memcpy function shown by camel
by brucehoult 3y ago
Gosh that's complex.
On all RISC-V CPUs I have currently access to with the pre-ratification RVV 0.7.1, the simple 9 instruction memcpy function shown by camel-cdr is faster than any other kind of memcpy (simple byte-by-byte loop with no decision overhead, or complex glibc function) at EVERY sensible size.
These range from the C906 core found in Linux-capable boards costing $6 or $10 (Pine64 Ox64, Sipeed M1s, Milk-V Duo), the the C920 OoO cores in the 64 core SOPHON SG2042.
Here are some numbers I ran on a 1 GHz C906 over two years ago:
https://hoult.org/d1_memcpy.txt https://hoult.org/d1_memcpy.txt
The short RVV function has absolutely constant execution time out to n=64 AND this time is 40% less than standard memcpy even at size 0 or 1 byte, and from 8 to 128 bytes it is at least 3x faster.
A 1.8x advantage is maintained for any size that fits in L1 cache, then after that both are able to saturate the memory bus.
Remember, this is a low-end in-order core (similar to Cortex-A35) designed in 2019, with only 128 bit vector registers and ALU. But the same thing applies on newer, higher-performance cores.
- camel-cdr 3y agoI found that for randomly aligned data, memcpy that aligns the destination pointer to vlenb is more stable when copying more data, on my MangoPi MQ Pro. (https://i.postimg.cc/Z4r29hnM/1.png https://i.postimg.cc/Z4r29hnM/1.png) I've got the best results from this code: memcpy_rvv_align_dest_hybrid: mv a3, a0 csrr t0, vlenb slli t1, t0, 8 # skip costly division for more values bltu a2, t1, 2f # len < vlen sub t1, zero, a0 remu t1, t1, t0 # align = (-dest) % vlen vsetvli t0, t1, e8, m8, ta, ma # align dest to vlen 1: vle8.v v0, (a1) add a1, a1, t0 sub a2, a2, t0 vse8.v v0, (a3) add a3, a3, t0 2: vsetvli t0, a2, e8, m8, ta, ma bnez a2, 1b ret
- camel-cdr 3y agoI'd actually expect the final version to also incorporate the Zihintntl extension, which would allow the load/stores to bypass the cache, since the equivalent non temporal instruction on x86 are also the fastest.
- brucehoult 3y agoOMG you've bloated a 9 instruction function to 15 instructions!!!! Well, ok, scalar optimised memcpy() gets into hundreds of instructions. Your result may well be hardware dependent. That's the kind of thing that you kind of have to wait for hardware to appear to actually know (or be in the team designing the hardware). Just how much faster is it on C906? And does the same happen on C910?