我使用的是基于 Xilinx Zynq 7000 ARM 的 SoC。我正在努力处理 DMA 缓冲区(需要帮助映射 Xilinx/ARM SoC (Zynq 7000) 上的预留 **可缓存** DMA 缓冲区 https://stackoverflow.com/questions/34884313/need-help-mapping-pre-reserved-cacheable-dma-buffer-on-xilinx-arm-soc-zynq),所以我追求的一件事是更快的 memcpy。
我一直在考虑使用 Neon 指令和内联汇编为 ARM 编写更快的 memcpy。无论 glibc 有什么,它都很糟糕,尤其是当我们从 ucached DMA 缓冲区复制时。
我从各种来源整合了自己的复制功能,包括:
- 快速 ARM NEON memcpy https://stackoverflow.com/questions/11161237/fast-arm-neon-memcpy
- gcc 中的 arm 内联汇编 https://stackoverflow.com/questions/9302575/arm-inline-assembly-in-gcc
- http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka13544.html http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka13544.html
对我来说主要的区别是我试图从uncached缓冲区,因为它是 DMA 缓冲区,并且 ARM 对缓存 DMA 缓冲区的支持不存在。
这就是我写的:
void my_copy(volatile unsigned char *dst, volatile unsigned char *src, int sz)
{
if (sz & 63) {
sz = (sz & -64) + 64;
}
asm volatile (
"NEONCopyPLD: \n"
" VLDM %[src]!,{d0-d7} \n"
" VSTM %[dst]!,{d0-d7} \n"
" SUBS %[sz],%[sz],#0x40 \n"
" BGT NEONCopyPLD \n"
: [dst]"+r"(dst), [src]"+r"(src), [sz]"+r"(sz) : : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "cc", "memory");
}
我做的主要事情是省略预取指令,因为我认为它在未缓存的内存上毫无价值。
与 glibc memcpy 相比,这样做的速度提高了 4.7 倍。速度从大约 70MB/秒增加到大约 330MB/秒。
不幸的是,这远不如缓存内存中的 memcpy 快,系统 memcpy 的运行速度约为 720MB/秒,Neon 版本的运行速度约为 620MB/秒(可能会慢一些,因为我的 memcpy 可能不进行预取)。
谁能帮我弄清楚我可以做些什么来弥补这种性能差距?
我尝试过很多方法,例如一次复制更多、两次加载然后两次存储。我可以尝试预取只是为了证明它没有用。还有其他想法吗?