ARM/NEON优化的memcpy适用于*非缓存*内存吗?

4
我正在使用基于ARM的Xilinx Zynq 7000 SoC。我在处理DMA缓冲区(需要帮助在Xilinx / ARM SoC(Zynq 7000)上映射预留的**可缓存** DMA缓冲区)方面遇到了困难,因此我追求更快的memcpy。
我一直在研究使用Neon指令和内联汇编编写更快的ARM memcpy。无论glibc有什么,它都很糟糕,特别是如果我们从未缓存的DMA缓冲区复制。
我从各种来源组合了自己的复制函数,包括:

对我来说,主要的区别在于我试图从一个未缓存的缓冲区中进行复制,因为它是一个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没有进行预取,也许)。
有谁可以帮助我想出什么办法来弥补这个性能差距吗?
我尝试了很多事情,例如一次复制更多,两次负载后跟两次存储。我可以尝试使用预取来证明它是无用的。还有其他的想法吗?

您的源代码是否是“一级缓存线大小的倍数”? - David Wohlferd
我已确保数据缓冲区在64字节边界上对齐,并且以64字节为单位进行划分。(技术上,最后一个64字节单元的末尾可能会被忽略。) - Timothy Miller
你的未缓存缓冲区是否位于DRAM中?如果是,那么很可能无法弥补差距。高速缓存在隐藏这种工作负载中的内存延迟方面表现出色。如果您的缓冲区大小足够小且带宽是一个真正的问题,请考虑使用芯片上的内存。 - Tony K
根据我的经验,最好的方法是进行实验。也许不要使用vldm,而是使用单个load/store变量,进一步展开,更早地进行subs操作。此外,我会做一个非NEON版本,看看是否能得到更好的结果。有时NEON有自己的内存端口,有时没有。 - auselen
@TonyK 到目前为止,我们可能想要传输的最大数据块大小只有不到32MB。我们正在使用的芯片是Xilinx Zynq 7000,FPGA中的SRAM容量不足。大容量内存主要是主DRAM。 - Timothy Miller
显示剩余6条评论
2个回答

1
如果你想进行大规模、快速的传输,缓存内存通常会优于非缓存内存,但正如你指出的那样,对于缓存DMA缓冲区内存的支持必须在某个地方进行管理,在ARMv7及以下版本中,这个地方是内核/内核驱动程序。
我假设你的设计有两点:
- 用户空间正在读取一个内存映射的硬件缓冲区 - FPGA向CortexA9 VIC/GIC发出某种信号/事件/中断,告诉CortexA9何时可以读取新的缓冲区
将DMA缓冲区与高速缓存行边界对齐,并且不要在DMA缓冲区的结尾和下一个高速缓存行之间放置任何内容。每当FPGA向CPU发出缓冲区准备好的信号时,都要使缓存失效。
我认为A9没有一种机制可以控制所有核心和层的高速缓存线,因此您可能希望将执行此操作的程序固定到一个核心上,以便可以跳过在其他核心上维护高速缓存。

0

您可以尝试使用缓存内存而不是非缓存内存。


有一个ACP(加速一致性端口),我们可以通过ARM L2缓存*写入DRAM。不幸的是,这方面存在一些问题,但已经过了很长时间,我不记得具体的麻烦是什么了。 - Timothy Miller
使用缓冲内存的目的是启用写缓冲区,而不仅仅是L2缓存。你解决了这个问题吗? - Horace Hsieh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接