我刚读了article来解释零拷贝机制。
它讨论了有和没有Scatter / Gather支持的零拷贝之间的区别。
没有SG支持的网卡,数据副本如下
支持SG的网卡,数据副本如下
总之,使用SG支持的零拷贝可以消除一个CPU拷贝。
我的问题是为什么内核缓冲区中的数据可能会分散?
答案 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()操作。我想在这种情况下标题仍会被复制到内核缓冲区中。