使用 O_SYNC 时 mmap 非常慢

mmap very slow when using O_SYNC

我们项目的简要描述:我们在我们的项目中使用CycloneV,FPGA将使用AXI总线将数据写入DDR,我们的应用程序需要使用以太网将数据发送出去。我们使用 iperf 对以太网吞吐量进行基准测试,它可以达到大约 700Mbps 的速度。当我们测试我们的应用程序吞吐量时,我们得到的结果仅为 400Mbps。我们在不使用 /dev/mem 的情况下编写一个简单的服务器代码,然后使用 dd 命令用随机数据填充内存,应用程序读取文件发送出去。我们注意到吞吐量实际上接近 iperf 基准。我们发现在打开/dev/mem的时候去掉O_SYNC,吞吐量可以达到接近iperf的吞吐量。但现在的问题是,如果我们不使用 O_SYNC.

,我们会得到间歇性的错误数据

我们使用dma_alloc_coherent分配连续内存:

p_ximageConfig->fpgamem_virt = dma_alloc_coherent(NULL, Dma_Size, &(p_ximageConfig->fpgamem_phys), GFP_KERNEL);

然后我们使用 IOCTL 将 phys 内存传递给用户空间以进行 mmap:

uint32 DMAPHYSADDR = getDmaPhysAddr();
pImagePool = ((volatile unsigned char*)mmap( 0,MAPPED_SIZE_BUFFER, PROT_READ|PROT_WRITE, MAP_SHARED, _fdFpga, DMAPHYSADDR));

我们尝试了以下方法:

  1. 在我们的驱动程序中编写我们自己的mmap:如果我们不同步,我们仍然会间歇性地获取错误数据。我们试过的同步方式是pgprot_noncachedpgprot_dmacoherent,但是只能达到300Mbps

  2. 我们尝试使用dma_mmap_coherent:得到的结果是500Mbps左右。

有没有什么方法可以帮助我们达到接近iperf性能的性能?

我不知道为什么 iperf 这么快,但是 mmap 设备内存是如何工作的。

让我们看看 mmap_mem() function, which is called by user's mmap call. According to this line,如果指定 O_SYNC,此函数将内存映射为非缓存,否则为(可能)writeback。所以这样做 vma->vm_page_prot = __pgprot_modify(vma->vm_page_prot, L_PTE_MT_MASK, L_PTE_MT_WRITEBACK); 可能会更快。

所以这里我们启用了一个内存区域的缓存。那么如何与FPGA同步内容呢?

一种方法是通过软件同步。相应地有dmac_map_area() and dmac_unmap_area() calls which correspond to v7_dma_map_area() and v7_dma_unmap_area()。这些函数采用三个参数:用户地址 addr、大小 size 和 DMA 方向 dir.

当我们调用dmac_map_area(addr, size, DMA_TO_DEVICE)时,CPU缓存的内容被写入内存。因此,当 CPU 完成写入内存并且设备将从该位置读取时执行此操作。

当我们调用dmac_unmap_area(addr, size, DMA_FROM_DEVICE)时,CPU缓存的内容被标记为"invalid",当我们从该位置读取时,设备的新内容被读取到[=45] =]缓存。因此,当设备完成写入内存并且 CPU 将从该位置读取时执行此操作。

另一种方法是使用专用硬件。根据 this pdf,Cyclone V 具有加速器一致性端口 (ACP),使 FPGA 能够读取 ARM 的缓存内容。我认为这可能比软件更快,但因为我不知道如何使用 ACP,请尝试谷歌搜索。