开发者社区> 问答> 正文

dma_mmap_coherent()映射内存的零拷贝用户空间TCP发送

我正在Cyclone V SoC上运行Linux 5.1,这是一个FPGA,在一个芯片中具有两个ARMv7内核。我的目标是从外部接口收集大量数据,并通过TCP套接字流出(部分)这些数据。这里的挑战是数据速率非常高,并且可能接近饱和GbE接口。我有一个write()可行的实现,该实现只使用对套接字的调用,但其最高速度为55MB / s;大约是理论GbE限制的一半。我现在正在尝试使零拷贝TCP传输能够提高吞吐量,但是我遇到了麻烦。

为了将数据从FPGA传送到Linux用户空间,我编写了一个内核驱动程序。该驱动程序使用FPGA中的DMA块将大量数据从外部接口复制到附加到ARMv7内核的DDR3存储器中。当使用dma_alloc_coherent()with 进行探测时GFP_USER,驱动程序将该内存分配为一堆连续的1MB缓冲区,并通过mmap()在文件中实现并将这些/dev/地址返回给应用程序使用dma_mmap_coherent()预分配的缓冲区,将这些缓冲区公开给用户空间应用程序。

到目前为止,一切都很好; 用户空间应用程序正在查看有效数据,吞吐率大于360MB / s时,还有足够的余量(外部接口的速度不够快,无法真正看到上限)。

为了实现零拷贝TCP网络,我的第一种方法是SO_ZEROCOPY在套接字上使用:

sent_bytes = send(fd, buf, len, MSG_ZEROCOPY);
if (sent_bytes < 0) {
    perror("send");
    return -1;
}

展开
收起
祖安文状元 2020-01-08 15:27:02 1949 0
1 条回答
写回答
取消 提交回答
  • 正如我在问题的更新中发布的那样,潜在的问题是,零复制网络不适用于已使用映射的内存remap_pfn_range()(也dma_mmap_coherent()恰好在后台使用)。原因是这种类型的内存(VM_PFNMAP设置了标志)没有struct page*与所需的每个页面相关联的元数据。

    然后将溶液是在一种方式分配存储器struct page*小号都与所述存储器相关联。

    现在对我来说分配内存的工作流程是:

    使用struct page* page = alloc_pages(GFP_USER, page_order);要分配的连续的物理存储器,在那里将被分配的连续页的数目由下式给出的块2page_order。 通过调用,将高阶/复合页面分为0阶页面split_page(page, page_order);。现在,这意味着struct page* page已成为具有2page_order条目的数组。 现在将这样的区域提交给DMA(用于数据接收):

    dma_addr = dma_map_page(dev, page, 0, length, DMA_FROM_DEVICE); dma_desc = dmaengine_prep_slave_single(dma_chan, dma_addr, length, DMA_DEV_TO_MEM, 0); dmaengine_submit(dma_desc); 当我们从DMA接收到回调已完成传输时,我们需要取消映射该区域,以将该内存块的所有权转移回CPU,这将负责缓存以确保我们不会读取过时的数据:

    dma_unmap_page(dev, dma_addr, length, DMA_FROM_DEVICE);

    2020-01-08 15:27:13
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
内存取证与IaaS云平台恶意行 为的安全监控 立即下载
云服务器ECS内存增强型实例re6全新发布 立即下载
TCP Cluster for mqtt技术实施方案 立即下载