Appearance
Inline WQE 总结
Inline WQE 是指 WQE 中直接存放用户要传输的数据,而不是填写 Sges。相比于 Normal WQE 有如下区别:
| Normal WQE | Inline WQE | |
|---|---|---|
| 数据格式 | 填写 Sges。硬件拿到 Sges 后再 DMA 数据到网卡。 | 直接填写用户数据。 |
| 长度限制 | 极高的上限。因为 WR 有 sge list 描述结构,每个 sge 最大可以描述 4GB - 1 大小的数据,因此一个 WR 甚至可以描述 TB 级的数据量。 | 存在限制。因为 WQE 大小有限制,因此 Inline 的数据长度也有限制。不同厂商有不同的规格限制,有的限制 100B,有的限制 400B。 |
在 IB Architecture Specification 中没有明确定义 “Inline WQE”,只定义了 WR,至于 Inline WQE 则是设备厂商的实现细节了。
但是在 OFED 中,rdma-core 设置了 IBV_SEND_INLINE flag,用于告知底层驱动:本次 WR 的数据不要走 DMA scatter-gather,而是由驱动(CPU)直接把数据拷贝到 WQE 中。
注意,用户在 WR 的 send_flags 中设置了
IBV_SEND_INLINE,驱动也不是一定按照 Inline 来构造 WQE 的。当 WR 的数据长度超过了 Inline 的最大上限,仍然会退回到使用 sge 描述的普通 WQE。
使用 Inline 会带来两个优点:
- 无需注册 MR。因为数据由 CPU 直接拷贝到 WQE 中,网卡不需要根据 L_Key 去解析本地内存地址。在 Inline 中,用户省去 “MR 的注册/销毁” 又进一步降低了系统开销,进而降低时延。
- 调用返回即可重用 Buffer。不像普通 WR 那样,需要等 CQE 才能重用 Buffer,Inline 数据在
ibv_post_send返回后,Buffer 就可以立即复用。
Q&A
虽然 Inline WQE 在硬件层面少了一次 DMA 的过程,但是在驱动(CPU)构造 Inline WQE 时,也多了一次内存拷贝,这种好处和坏处的平衡该如何理解呢?
先说结论:在小数据场景下,内存拷贝的性能代价一定小于一次 DMA 的代价。
首先需要确定一个前提:这是小数据的情况。其次需要理解 “一次 DMA 操作的代价是固定的” 和 “CPU 内存拷贝的边际成本随着数据量的线性增长” 这两个概念。在这个小数据场景下,DMA 固定开销 > CPU 拷贝边际成本。可以对比一下两边的成本:
成本项 普通 DMA 模式 Inline 模式 数据搬运 网卡 DMA 从用户 buffer 读数据 CPU memcpy把数据拷进 WQE ring地址翻译 需要解析 MR/L_Key,做虚拟地址→物理地址转换 不需要,数据已经在 WQE 的 DMA 内存里 Doorbell/通知 需要告诉网卡 “去内存里取数据” 同样需要 doorbell,但网卡直接从 WQE 取数据 Buffer 生命周期 用户 buffer 必须保持有效直到 CQE 回来 ibv_post_send返回即可重用 buffer队列空间 WQE 只存描述符,紧凑 WQE 里塞了数据,同样 ring 大小下队列深度变浅 举个例子,假设你要发 64 Byte 的控制消息:
- DMA 的固定开销:准备 DMA descriptor、写 doorbell、网卡读取 descriptor、启动 DMA 引擎。这一套流程在现代硬件上所需的时间在 微秒级,而且与数据量大小基本无关。
- CPU 拷贝 64 Byte:现代 CPU 一次内存拷贝所需时间在 纳秒级,且数据大概率在 L1/L2 cache 中。
可见两者的时间开销都不在一个数量级上,因此在 64 Byte 这种小数据的情况下,内存拷贝的延迟更低。这就是 Inline 降低小消息延迟的原理。
但是如果在大数据的情况下,两者的情况完全相反。
假设你要发 1MB 的数据:
- CPU 拷贝 1MB:需要占用 CPU 核心跑几百微秒,消耗内存带宽,且会污染 cache(把业务数据挤出 L1/L2)。
- DMA 1MB:网卡直接从内存取数据,CPU 几乎零参与。虽然 DMA 启动仍有固定开销,但摊到 1MB 数据上,边际成本极低。
此时 CPU 拷贝的边际成本远远超过了 DMA 的固定开销,Inline 就成了负优化。这也是为什么硬件要限制
max_inline_data(通常几百 Byte 到几 KB)。Inline 超过这个阈值后,驱动将 Inline WQE 自动转换成 Normal WQE。一个容易被忽略的隐性收益:省 MR 注册
问题中提到"多了一次内存拷贝",但在 DMA 模式下还有一个前置成本:
- 用户 buffer 如果要走 DMA,通常需要提前注册 Memory Region(
ibv_reg_mr),或者从已注册的内存池分配。
但是在 Inline 模式下,数据直接拷进驱动预分配的 WQE ring(这块内存已经注册好了),用户完全不需要注册 MR。这对于频繁发送小消息且 buffer 不固定的场景(比如每次从堆上分配不同对象),省掉 MR 注册/注销的开销,有时候比省那一次 DMA 更有价值。
另一个隐性收益:Buffer 立即重用
普通 WR 在
ibv_post_send返回后,用户 buffer 还不能碰,因为网卡可能还没 DMA 完;必须等到 CQE。Inline 模式下,数据已经被 CPU 拷进了 WQE,用户 buffer 在
ibv_post_send返回后立刻可以释放或重用。这简化了应用层的 buffer 管理逻辑,对某些零拷贝架构来说,这个编程便利性本身就是收益。Inline WQE 的数据规格限制受到哪些方面的影响?为什么 CX 友商能做到 800B?
根据上面的分析,并不是说 Inline 的数据越大越好,而是因为数据大到一定程度后,性能反而比 DMA 更慢(驱动拷贝数据的代价随着数据量而增大)。除此之外,芯片内部模块间的带宽也需要考虑,假设某款芯片整体能支持 900 多 Byte 的 Inline,但是因为芯片内部模块带宽受限,导致当 Inline 大于 300 多 Byte 时,性能就不如 normal WQE 了,此时大 Inline 也没什么意义了。对于 CX 友商的网卡,可能是因为在设计 Inline 时,芯片各个模块间的带宽设计的比较大,最终能支持到 800 多 Byte 的 Inline。