使用O_SYNC时,mmap非常慢

时间:2018-01-10 01:35:26

标签: c linux-device-driver embedded-linux mmap ethernet

我们项目的简要描述:我们在项目中使用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_noncached pgprot_dmacoherent ,但它只能达到300Mbps。

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

  3. 是否有任何方法可以帮助我们实现接近iperf性能的性能?

1 个答案:

答案 0 :(得分:1)

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

让我们看看mmap_mem() function,它由用户的mmap电话调用。根据{{​​3}},如果指定O_SYNC,则此函数将内存映射为非缓存,并且(可能)写回其他。因此,vma->vm_page_prot = __pgprot_modify(vma->vm_page_prot, L_PTE_MT_MASK, L_PTE_MT_WRITEBACK);可以使其更快。

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

一种方法是通过软件进行同步。 this linedmac_map_area()次呼叫相应地对应dmac_unmap_area()v7_dma_map_area()。这些函数有三个参数:用户地址addr,大小size和DMA方向dir

当我们调用dmac_map_area(addr, size, DMA_TO_DEVICE)时,CPU缓存的内容将写入内存。当CPU完成写入内存并且设备将从该位置读取时,这样做。

当我们调用dmac_unmap_area(addr, size, DMA_FROM_DEVICE)时,CPU缓存的内容被标记为“无效”,当我们从该位置读取时,设备中的新内容被读取到CPU缓存。因此,当设备完成写入内存并且CPU将从该位置读取时,请执行此操作。

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