小编rem*_*rem的帖子

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()进行探测时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;
}
Run Code Online (Sandbox Code Playgroud)

但是,这导致send: Bad address

谷歌搜索了一段时间之后,我的第二种方法是使用管道,splice()然后执行以下操作vmsplice()

ssize_t sent_bytes;
int pipes[2];
struct iovec iov = {
    .iov_base = buf,
    .iov_len = len
};

pipe(pipes);

sent_bytes = vmsplice(pipes[1], &iov, 1, 0);
if (sent_bytes < 0) {
    perror("vmsplice"); …
Run Code Online (Sandbox Code Playgroud)

linux linux-kernel splice embedded-linux zero-copy

14
推荐指数
1
解决办法
150
查看次数

标签 统计

embedded-linux ×1

linux ×1

linux-kernel ×1

splice ×1

zero-copy ×1