一、一次"理论上应该发生",实际上却没有发生的故障
某数据中心部署了一套基于DPDK开发的100GbE高性能交换机。
新加入的一位开发同事阅读PMD源码时提出了一个问题:
PMD线程一直在不停读取DD Bit。
代码几乎就是:
while (nb_rx < nb_pkts) {
rxdp = &rx_ring[rx_id];
if (!(rxdp->status & DD))
break;
...
}
按照CPU主频计算。
假设每个Worker每秒轮询2亿次。
系统16个Worker意味着:每秒读取30多亿次RX Descriptor。
开发同事立即提出疑问:
Descriptor不是放在网卡里面吗?
如果:
每次CPU读取Descriptor都要PCIe Read。
那么:
PCIe应该瞬间被读满。
然而:
现实情况却完全不同。
系统长期稳定运行100Gbps。
PCIe监控Read Traffic几乎没有明显增长。
为什么?
核心知识点一
很多人潜意识里认为:RX Descriptor属于网卡。
实际上。
真正拥有Descriptor内存的并不是NIC。
而是Host Memory。
二、Descriptor到底存放在哪里?
继续分析:DPDK初始化流程。
网卡初始化时:PMD首先申请Descriptor Ring。
例如:
rte_eth_rx_queue_setup(...)
最终:申请的是一块DMA一致性内存。
其位置实际上位于HugePage。
例如:
HugePage
↓
RX Descriptor Ring
↓
Descriptor0
Descriptor1
Descriptor2
...
随后:
驱动将Descriptor Ring物理地址写入网卡寄存器。
例如:
Intel网卡会保存RX Ring Base Address。
从这一刻开始。
CPU和NIC共同访问同一块Host Memory。
而不是:
CPU访问网卡内部RAM。
核心知识点二
Descriptor Ring不是放在NIC里面。
而是放在服务器内存。
NIC只是通过DMA访问它。

三、CPU读取Descriptor,到底读的是哪里?
继续思考:
PMD每次执行:
status = rxdp->status;
CPU是不是通过PCIe去读取Descriptor?
答案:几乎不是。
CPU首先读取L1 Cache。
如果没有继续L2。
然后L3。
最后才可能访问内存。
整个过程中。
CPU根本不会主动通过PCIe去读取Descriptor。
因为:Descriptor本来就在Host Memory。
CPU访问Descriptor与访问普通数组没有本质区别。
四、真正通过PCIe访问Descriptor的是谁?
这里很多人第一次会产生认知反转。
真正通过PCIe访问Descriptor。
并不是CPU。
而是NIC。
例如:
收到Packet真正流程如下:
Packet
│
▼
MAC
│
▼
RX Packet Buffer
│
▼
DMA 写入 mbuf Data Buffer
│
▼
DMA 更新 RX Descriptor
│
▼
Write Back DD Bit
可以看到Descriptor真正发生PCIe事务是在NIC执行DMA。
CPU只是后来读取已经更新好的内存。
核心知识点三
PCIe总线主要承担的是:NIC → Memory 和 Memory → NIC 的数据搬运。
CPU访问Descriptor走的是CPU自己的Cache体系。
不是PCIe。
五、那CPU怎么知道DD已经变化了?
问题开始变得更加有趣。
既然CPU一直读取Cache。
那么NICDMA更新Descriptor以后。
CPU为什么能够马上看到DD变成1?
难道CPUCache自己知道NIC写了内存?
如果不知道:CPU岂不是永远看到旧数据?
真正的问题开始指向:CPU Cache Coherency(缓存一致性)。
六、很多人误解了DMA与Cache的关系
不少开发者认为:
DMA直接修改内存。
CPU Cache不会同步。
因此:
CPU应该不断读到旧Descriptor。
事实上:
现代Intel服务器平台并非如此简单。
支持DMA一致性的PCIe平台中:
NIC发起DMA Write后,会通过平台的一致性机制(具体实现依赖CPU、Chipset及PCIe特性)保证CPU后续能够观察到最新的数据,而不需要软件主动去刷新Cache。
也就是说:
CPU不会一直看到旧DD。
否则:
DPDK根本无法正常工作。
这里需要特别说明:
Cache一致性的具体实现方式,与CPU架构、PCIe Root Complex以及DMA一致性能力有关,并不是所有SoC平台都完全一致。本文讨论的是主流Intel Xeon服务器平台,也是DPDK部署最常见的平台。
核心知识点四
DD Bit不是CPU主动去网卡读取。
而是NIC主动DMA写回Host Memory。
CPU随后通过Cache一致性观察到Descriptor已经发生变化。

七、真正值得思考的问题来了
如果CPU一直读取Cache。
那么为什么DPDK仍然要不断PrefetchDescriptor?
例如:
PMD源码大量出现:
rte_prefetch0(rxdp + 4);
如果:Descriptor一直都在Cache。
Prefetch岂不是毫无意义?
事实上。
真正影响RX性能的已经不是PCIe。
而是:另一件更加重要的事情……
CPU Cache Line。
(未完待续)
176

被折叠的 条评论
为什么被折叠?



