【问题标题】:ARM/neon memcpy optimized for *uncached* memory?ARM/neon memcpy 针对 *uncached* 内存进行了优化?
【发布时间】:2016-04-25 15:04:51
【问题描述】:

我正在使用基于 ARM 的 Xilinx Zynq 7000 SoC。我正在为 DMA 缓冲区 (Need help mapping pre-reserved **cacheable** DMA buffer on Xilinx/ARM SoC (Zynq 7000)) 苦苦挣扎,所以我追求的一件事是更快的 memcpy。

我一直在考虑使用 Neon 指令和内联 asm 为 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 可能不进行预取) .

谁能帮我弄清楚我可以做些什么来弥补这个性能差距?

我尝试了很多方法,例如一次复制多个,两次加载,然后是两次存储。我可以尝试预取只是为了证明它没用。还有其他想法吗?

【问题讨论】:

  • 你的源是“一级缓存行大小的倍数”吗?
  • 我已确保数据缓冲区在 64 字节边界和 64 字节单元中对齐。 (从技术上讲,最后一个 64 字节单元的结尾可能会被忽略。)
  • 您的未缓存缓冲区是否位于 DRAM 中?如果是这样,可能无法缩小差距。缓存擅长隐藏此类工作负载中的内存延迟。如果您的缓冲区足够小并且带宽是一个真正的问题,请考虑迁移到片上内存。
  • 根据我的经验,最好的方法是进行实验。可能不使用 vldm 而是使用单个加载/存储变体,进一步展开,更早地执行 subs。我也会做一个非霓虹灯版本,看看是否会变得更好。有时霓虹灯有自己的内存端口,有时没有。
  • @TonyK 到目前为止,我们可能要传输的最大数据块不到 32MB。我们正在使用的芯片是 Xilinx Zynq 7000,而 FPGA 结构中没有足够的 SRAM。大内存是主要的 DRAM。

标签: arm memcpy neon soc


【解决方案1】:

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

【讨论】:

  • 有一个 ACP(加速一致性端口),我们可以使用它通过 ARM L2 缓存写入DRAM。不幸的是,这有一些问题,但是时间太长了,我不记得到底是什么问题。
  • 使用缓冲内存的目的是为了启用写缓冲,而不仅仅是二级缓存。问题解决了吗?
【解决方案2】:

如果您尝试进行大型、快速的传输,缓存内存通常会胜过非缓存内存,但正如您所指出的,必须在某处管理对缓存 DMA 缓冲内存的支持,并且在

我假设您的设计有两点:

  • 用户空间正在读取内存映射的硬件缓冲区
  • 从 FGPA 到 CortexA9 VIC/GIC 存在某种信号/事件/中断,当有新缓冲区可供读取时,会通知 CortexA9。

将 DMA 缓冲区与缓存线边界对齐,并且不要在 DMA 缓冲区的末端和下一个缓存线之间放置任何东西。每当 FPGA 向 CPU 发出缓冲区已准备就绪的信号时,缓存就会失效。

我不认为 A9 有一种机制可以同时控制所有内核和层上的缓存线,因此您可能希望将执行此操作的程序固定到一个内核上,这样您就可以跳过维护另一个内核上的缓存。

【讨论】:

    猜你喜欢
    • 2014-09-18
    • 2012-06-25
    • 1970-01-01
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-20
    • 1970-01-01
    相关资源
    最近更新 更多