6

我刚刚读了一篇解释零拷贝机制的文章。

它讨论了有和没有 Scatter/Gather 支持的零拷贝之间的区别。

网卡不支持SG,数据副本如下

在此处输入图像描述

支持SG的网卡,数据副本如下

在此处输入图像描述

总之,支持 SG 的零拷贝可以消除一个 CPU 拷贝。

我的问题是为什么内核缓冲区中的数据会分散

4

3 回答 3

17

因为默认情况下,Linux 内核的映射/内存分配设施将创建虚拟连续但可能物理上不相交的内存区域。
这意味着从内部执行的文件系统读取进入内核虚拟内存sendfile()中的缓冲区,DMA 代码必须将其“变形”(因为没有更好的词)到网卡的 DMA 引擎可以理解的东西。

由于 DMA(通常但不总是)使用物理地址,这意味着您要么复制数据缓冲区(到专门分配的物理连续内存区域,即上面的套接字缓冲区),要么将其传输到一个物理页面一次

另一方面,如果您的 DMA 引擎能够将多个物理上不相交的内存区域聚合到单个数据传输中(称为“分散-收集”),那么您可以简单地传递物理地址列表,而不是复制缓冲区(指向内核缓冲区的物理连续子段,即上面的聚合描述符)并且您不再需要为每个物理页面启动单独的 DMA 传输。这通常更快,但是否可以完成取决于 DMA 引擎的能力。

于 2012-03-19T13:50:48.510 回答
4

Re:我的问题是为什么内核缓冲区中的数据会分散?

因为已经散了。TCP 套接字前面的数据队列不分为将发送到网络接口的数据报。Scatter 允许您将数据保留在原处,而不必复制它来创建硬件可以接受的平面缓冲区。

通过收集功能,您可以给网卡一个数据报,该数据报在内存中的不同地址被分解成片段,可以引用原始套接字缓冲区。该卡将从这些位置读取它并将其作为一个单元发送。

如果没有收集(硬件需要简单的线性缓冲区),则必须将数据报准备为连续分配的字节字符串,并且必须将属于它的所有数据memcpy从排队等待在套接字上传输的缓冲区中 -d 放置到位。

于 2012-03-19T17:06:25.363 回答
2

Because when you write to a socket, the headers of the packet are assembled in a different place from your user-data, so to be coalesced into a network packet, the device needs "gather" capability, at least to get the headers and data.

Also to avoid the CPU having to read the data (and thus, fill its cache up with useless stuff it's never going to need again), the network card also needs to generate its own IP and TCP checksums (I'm assuming TCP here, because 99% of your bulk data transfers are going to be TCP). This is OK, because nowadays they all can.

What I'm not sure is, how this all interacts with TCP_CORK.

Most protocols tend to have their own headers, so a hypothetical protocol looks like:

Client: Send request Server: Send some metadata; send the file data

So we tend to have a server application assembling some headers in memory, issuing a write(), followed by a sendfile()-like operation. I suppose the headers still get copied into a kernel buffer in this case.

于 2012-03-19T20:30:20.363 回答