2. PCIe 拓扑结构:根复合体、交换器、端点、桥接器
在动手调吞吐之前,得先把 PCIe 的“骨架”摸清楚。说白了,拓扑就是设备之间怎么连的。
我刚接触 PCIe 时,以为所有设备都直接挂在 CPU 上。直到第一次排查吞吐瓶颈,才发现问题出在 Switch 内部。
2.1 四个核心角色
PCIe 拓扑里,角色很清晰。每个设备都有明确的定义。
| 组件 | 英文 | 一句话 |
|---|---|---|
| 根复合体 | Root Complex (RC) | CPU 的门户,所有请求的起点 |
| 交换器 | Switch | 内部数据,扩展端口用 |
| 端点 | Endpoint (EP) | 实际的业务设备,比如 GPU、NVMe SSD |
| 桥接器 | Bridge | 连接其他总线(比如 PCI/PCI-X) |
我的习惯:拿到一块新板卡,先翻原理图,确认 RC 和 Switch 之间的通道数。很多时候性能不达标,就是这个链路本身不够宽。
2.2 根复合体 (Root Complex)
RC 就是 CPU 侧的总指挥。它负责将 CPU 和内存的请求,转发到 PCIe 总线上去。
我个人习惯把 RC 想象成机场的出发大厅。所有登机手续(事务层报文)都得从这里办。
- 任务:生成配置请求、内存请求、I/O 请求。
- 位置:通常集成在 CPU 或芯片组内部。
- 吞吐关键:RC 端的入站/出站地址翻译缓冲区的大小。如果这个缓冲区太小,在高吞吐时容易丢包。
注意:我曾经调试过一个 case,吞吐始终跑不满 x16 的带宽。最后发现是 RC 的 MSI-X 中断分配不合理,导致中断风暴。这不是硬件故障,是 RC 端资源管理的问题。
2.3 交换器 (Switch)
Switch 就是拓扑里的“立交桥”。它把一根 PCIe 链路,扩展成多根。记住,它不参与业务,只负责转发。
- 内部架构:一个上行端口 + 多个下行端口。
- 转发方式:基于报文头里的 BDF(总线:设备:功能)号。
- 吞吐瓶颈:内部仲裁逻辑。多端点同时向主机写数据时,如果仲裁费时太久,就会产生气泡。
为什么 Switch 会吃掉延迟?
因为每个报文都要经过内部虚拟通道(VC Buffer)排队。端口越多,竞争越激烈。所以,能用直连就别过 Switch。
2.4 端点 (Endpoint)
端点是最常见的。我们调吞吐,其实就是在调端点和 RC 之间的数据交换效率。
- 类型 A:普通 EP,比如网卡、存储控制器。
- 类型 B:根复合体集成端点,比如 CPU 内部集成的 GPU(不过这种少见)。
- 关键属性:DMA 能力、BAR 空间大小、是否支持 ARI(替代路由ID解释)。
避坑指南:我曾见过一个 NVMe SSD 在连续写入时速度断崖式下跌。检查发现该 EP 的 Max Payload Size 只设了 128 字节。改成 512 字节后,吞吐提升 40%。很多时候,性能不是架构的问题,是端点配置没对齐。
2.5 桥接器 (Bridge)
桥接器是“翻译官”。它让 PCIe 可以兼容老旧的 PCI/PCI-X 设备。
说句实在话,在纯 PCIe 环境里,桥接器出现得很少。但如果你的系统里真的有,那就得注意了。
- 作用:协议转换、地址转换。
- 吞吐影响:桥接器会引入额外的处理延迟。因为要拆包、翻译、再组包。通常吞吐会打 7-8 折。
你觉得什么样的拓扑结构对吞吐最友好?我个人认为,越扁平越好。
2.6 典型拓扑结构
下面是我总结的几种常见拓扑,以及它们对性能的影响。
| 拓扑类型 | 描述 | 吞吐特性 |
|---|---|---|
| 直连拓扑 | EP 直接连在 RC 上,不经过 Switch | 延迟最低,吞吐最高 |
| 单 Switch 树形 | RC 连一个 Switch,Switch 下挂多个 EP | 共享上行带宽,多 EP 同时写时需注意 |
| 多 Switch 级联 | Switch 下面再连 Switch | 延迟增加,吞吐受制于最窄链路 |
| 非透明桥 (NTB) | 两个系统通过桥连接 | 多用于多主机通信,吞吐取决于桥能力 |
我的建议:画拓扑图时,别只看物理连接。更要看逻辑链路。比如 EP 支持 ARI(替代路由ID解释),就能减少 Switch 内部的地址查找步骤。很多低延迟设计都在这些细节里。
2.7 拓扑对吞吐的影响
说完了结构,聊聊实实在在的影响。我总结为三点:
- 共享瓶颈:多端点通过一个 Switch 上行端口,总吞吐不会超过上行链路的速率。比如上行是 PCIe 4.0 x8(~16 GB/s),那所有端点加起来就这么多。
- 内部 Congestion:Switch 内部的交叉开关和 Virtual Channel 仲裁。如果多端点同时发送大块写请求,内部排队会导致延迟增加,从而降低有效吞吐。
- 地址转换开销:在 NTB 或桥接器场景里。地址转换成本不可忽略。我曾经测过,一次 NTB 地址翻译要额外消耗 200 ns。每秒百万次事务,累积下来就是几百毫秒的延迟。
我曾经踩过的坑:在调试一个多 GPU 服务器吞吐时,发现两个 GPU 之间的通信速率只有理论值的 60%。查拓扑发现 GPU 1 挂 Switch A,GPU 2 挂 Switch B,而 Switch A 和 Switch B 之间只有一个 x4 的级联口。数据得绕一大圈。解决方案是改拓扑,让两个 GPU 都挂在同一个 Switch 下,或使用 GPU Direct RDMA 绕过主机内存。
所以,每次做性能优化,第一步就是看拓扑图。确认从 EP 到 RC 之间,每一跳的链路宽度和协议版本。这一步看不出来,后面的优化就是盲人摸象。