使用和不使用Scatter / Gather操作进行零拷贝

时间:2012-03-19 12:23:33

标签: c linux network-programming linux-kernel zero-copy

我刚读了article来解释零拷贝机制。

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

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

enter image description here

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

enter image description here

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

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

3 个答案:

答案 0 :(得分:14)

因为默认情况下Linux内核的映射/内存分配工具会创建几乎连续但可能是物理上不相交的内存区域。
这意味着文件系统的读取sendfile()在内部进入内核虚拟内存中的缓冲区,DMA代码必须将“transmogrify”(缺少更好的词)转换为某种东西网卡的DMA引擎可以解决。

由于DMA(通常但并非总是)使用物理地址,这意味着你要么复制数据缓冲区(进入一个特殊分配的物理上连续的内存区域,你的套接字缓冲区< / em>上面),或者一次传输一个物理页面

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

答案 1 :(得分:4)

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

因为已经分散了。 TCP套接字前面的数据队列不会分成将出现在网络接口上的数据报。 Scatter允许您将数据保存在原处,而不必将其复制以构成硬件可接受的平缓冲突。

使用 gather 功能,您可以为网卡提供一个数据报,该数据报在内存中的不同地址分成几部分,可以引用原始套接字缓冲区。该卡将从这些位置读取并将其作为一个单元发送。

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

答案 2 :(得分:2)

因为当您写入套接字时,数据包的标头汇集在与用户数据不同的位置,因此要合并到网络数据包中,设备需要“收集”功能,至少要获得标题和数据。

另外为了避免CPU必须读取数据(因此,用无用的东西填充其缓存,它永远不再需要),网卡也需要生成自己的IP和TCP校验和(我假设TCP在这里,因为99%的批量数据传输将是TCP)。这没关系,因为现在他们都可以。

我不确定的是,这一切是如何与TCP_CORK进行交互的。

大多数协议都有自己的标头,因此假设的协议如下:

客户:发送请求 服务器:发送一些元数据;发送文件数据

因此,我们倾向于让服务器应用程序在内存中组装一些头文件,发出write(),然后执行sendfile()操作。我想在这种情况下标题仍会被复制到内核缓冲区中。