Skip to content

第 3 周:RDMA verbs、QP、CQ 和 RNIC

对应原计划:plans/muxi-fabric-network-learning-plan.md 第 3 周。
本章定位:理解通信库最终如何把工作交给 RNIC 执行。重点不是把 verbs API 背下来,而是知道 MR、QP、WQE、CQE、GID、MTU、QP 数这些对象如何影响性能和可观测性。


0. 这一周到底学什么

第 1 周你已经知道 collective 会被通信库拆成 channel/chunk,然后交给底层通信路径。第 3 周要回答:

通信库真正把数据交给网卡时,发生了什么?

RDMA/RoCE 和普通 socket 最大的不同是:应用不是每次 send() 都走内核复制数据,而是预先建立一组对象,然后把 work request 放进队列,让 RNIC 异步执行。

学完你要能回答:

  • MR 为什么要注册和 pin memory?
  • lkeyrkey 解决什么问题?
  • QP 是什么?为什么一个 QP 不只是“一条连接”?
  • WQE/CQE 分别表达什么?
  • RDMA write/read/send/recv 有什么区别?
  • 为什么 RDMA fast path 可以少 syscall,但不是完全不需要 CPU/内核/驱动?
  • 为什么 QP 数变化可能同时影响 RNIC 并发和 ECMP hash?
  • 为什么 ib_write_bw 快,不等于 MCCL AllReduce 快?

本周核心心智模型:

text
应用/通信库 post work request;
RNIC 根据 QP/MR 执行 DMA 和网络传输;
完成事件通过 CQE 返回;
软件继续 poll 和推进状态机。

1. RDMA 和普通 socket 的直觉差异

1.1 普通 socket 粗略模型

普通 TCP/UDP 发送可以粗略理解为:

text
应用 buffer
  ↓ send syscall
内核协议栈
  ↓ copy / skb / qdisc / driver
网卡

网络

这里内核参与很多:协议栈、缓冲、调度、copy、系统调用。

1.2 RDMA 粗略模型

RDMA 的目标是让数据搬运更接近:

text
应用预先注册内存

应用把 work request 放进设备队列

RNIC 直接 DMA 读写内存

网络传输

RNIC 写入远端内存或完成接收

这不代表没有内核,而是把 fast path 做得更靠近用户态和设备。

1.3 “绕过内核”这句话的边界

常见说法:

text
RDMA bypass kernel

更准确地说:

text
数据传输 fast path 尽量不为每个 packet 走 syscall 和内核协议栈;
但资源创建、权限隔离、内存注册、设备管理、错误处理仍需要内核和驱动。

所以如果看到 CPU/proxy/polling 异常,不能说“RDMA 不用 CPU,所以无关”。


2. verbs 对象总图

一个简化 RDMA 程序通常涉及这些对象:

text
Device / Context

Protection Domain (PD)

Memory Region (MR)

Completion Queue (CQ)

Queue Pair (QP)

Work Queue Entry (WQE)

Completion Queue Entry (CQE)

可以画成:

text
应用 / 通信库

  │ register memory

MR: addr + length + lkey/rkey

  │ create QP, CQ

QP: Send Queue + Receive Queue

  │ post WQE

RNIC 执行 DMA / packet / retry / completion

  │ write CQE

CQ: 软件 poll 完成事件

你不需要一开始记住所有 API 参数,但要知道这些对象的位置。


3. MR:为什么内存要注册

3.1 MR 是什么

MR = Memory Region,表示一段允许 RNIC 访问的内存区域。

注册 MR 大致做几件事:

text
1. 告诉内核和驱动这段内存要给 RNIC 用;
2. pin 住页面,避免传输中被换出或移动;
3. 建立 RNIC 可以使用的地址映射;
4. 生成访问 key:lkey / rkey。

3.2 为什么不能直接给 RNIC 一个指针

普通指针是进程虚拟地址:

text
0x7f....

但 RNIC 做 DMA 需要稳定、可访问的物理/I/O 地址映射。如果操作系统在传输中把页面换出、迁移或回收,RNIC 就会写错地方。

所以必须注册和 pin。

3.3 lkey 和 rkey

粗略理解:

text
lkey:本地 RNIC 访问本地 MR 时使用的权限 key
rkey:远端 RNIC 访问这段 MR 时需要的权限 key

如果你要做 RDMA write 到远端内存,远端需要把地址和 rkey 告诉你。

3.4 GPU memory 的特殊性

如果 buffer 在 GPU 上,GDRDMA 还需要:

text
GPU memory 可被 RNIC DMA;
GPU driver / RNIC driver / IOMMU 支持;
GPU 和 HCA 拓扑可达;
内存注册和 cache/coherency 语义正确。

这就是为什么 GPU↔HCA 亲和也可能影响性能。

3.5 小 case:MR 问题会表现成什么

MR/GDRDMA 路径问题可能表现为:

text
建连成功但传输失败;
小消息正常大消息异常;
某些 GPU/HCA 组合慢;
回退到 host staging 后性能下降;
注册开销导致短消息性能差;
错误日志里出现 access error / protection error。

所以不要只看“网络连通”。


4. QP:通信上下文和并发单元

4.1 QP 是什么

QP = Queue Pair,一对队列:

text
Send Queue (SQ)
Receive Queue (RQ)

应用把 work request post 到 SQ/RQ,RNIC 执行后把完成写到 CQ。

4.2 QP 状态机

可靠连接 RC QP 通常要经历:

text
RESET → INIT → RTR → RTS

建连需要双方交换:

text
QP number
PSN
GID / LID
MTU
其他路径属性

所以 QP 不只是“开个端口”,它包含 RDMA transport 的状态。

4.3 QP 类型

常见类型:

text
RC:Reliable Connected,可靠连接
UC:Unreliable Connected
UD:Unreliable Datagram

大多数你关心的可靠 RDMA 数据传输会先从 RC 心智模型理解。

4.4 QP 数为什么会影响性能

QP 数可能同时影响多个层:

text
RNIC 内部并发;
WQE 排队;
CQ polling 压力;
retry / flow control 状态;
RoCEv2 UDP source port / flow entropy;
ECMP hash 分布;
通信库 channel 到 QP 的映射;
CPU/proxy thread 工作量。

这就是为什么“多 QP 后变快”不能直接等于“ECMP 碰撞被解决”。它也可能是 RNIC 并发或通信库调度变了。

4.5 小 case:1 QP vs 8 QP

实验:

text
固定 src/dst host
固定 rail
固定 message size
固定并发 pair 数
只改变 QP 数:1 → 8

结果:

text
1 QP: 12GB/s
8 QP: 23GB/s

可能解释:

  1. 8 QP 增加 ECMP entropy,分散到更多 path;
  2. 8 QP 提高 RNIC 内部并发;
  3. 1 QP 被某个队列/credit/retry 限制;
  4. 通信库 channel 映射随 QP 变化;
  5. 接收端 CQ polling 更有效或更差;
  6. 测量噪声/背景流量变化。

要区分,需要:

text
实际 UDP source port;
交换机 per-uplink bytes;
RNIC QP counter;
CQE/retry/CNP counter;
多次随机 seed 复测;
负对照 pair。

5. WQE/CQE:异步执行模型

5.1 WQE 是什么

WQE = Work Queue Entry。它告诉 RNIC 要做什么:

text
从哪个 MR 读;
写到哪里;
长度多少;
使用哪个 lkey/rkey;
操作类型是 send/write/read/atomic;
是否需要 completion。

5.2 CQE 是什么

CQE = Completion Queue Entry。RNIC 执行完或失败后,在 CQ 里写完成事件。

text
success
error
byte length
work request id
status

5.3 post 时间不等于完成时间

软件 post WQE 很快:

text
应用把任务放进队列

但真正完成要等:

text
RNIC 取 WQE;
DMA 读本地数据;
网络传输;
远端处理;
ACK/完成;
CQE 写回;
软件 poll 到 CQE。

所以 benchmark timing 必须明确测的是 post 时间、poll 完成时间,还是全局同步时间。

5.4 小 case:为什么 timing 修正很重要

如果一个脚本只测:

text
post isend 的时间

可能得到很小时间。

但真实数据还在 RNIC/网络里飞,直到:

text
wait / synchronize / poll completion

才算完成。

Muxi 主计划里 W0.1 timing 修正就是为了避免这种误判。


6. RDMA 操作语义:send/recv、write、read、atomic

6.1 send/recv

send/recv 像消息传递:

text
发送端 post send
接收端必须提前 post recv

如果接收端没有准备好,可能出现 RNR 等问题。

6.2 RDMA write

发送端直接把数据写入远端已授权的 MR:

text
local MR → network → remote MR

远端 CPU 不一定参与 data path,但远端需要提前交换地址和 rkey。

6.3 RDMA read

发送端主动从远端 MR 读取数据:

text
remote MR → network → local MR

read 对延迟、credit、远端响应路径敏感。

6.4 atomic

远端原子操作,例如 compare-and-swap、fetch-and-add。常用于同步,不是大流量数据搬运主力。

6.5 通信库封装后的边界

当你用 torch.distributed.isend/irecv 或 MCCL collective 时,你不一定能直接知道底层用的是 RDMA write/read/send/recv 的哪种组合。

所以正确说法是:

text
应用层 API 是 isend/irecv 或 AllReduce;
底层 RDMA verb 语义需要通过通信库文档、debug 日志、抓包或厂商支持确认。

7. perftest 和通信库 benchmark:测的不是同一层

7.1 ib_write_bw 测什么

ib_write_bw 通常测两个 RDMA 端点之间的 write bandwidth。它负载简单、变量少:

text
一个或多个 QP;
固定消息大小;
固定 RDMA operation;
固定端点。

它适合回答:

text
这条 RDMA path 在简单负载下能不能跑起来?
单 rail / 单 QP / 多 QP 的基线是多少?
MTU、GID、QP 数变化有什么影响?

7.2 MCCL AllReduce 测什么

AllReduce 测的是:

text
多 rank;
多阶段;
多 channel;
GPU kernel;
rank mapping;
同步尾部;
网络路径;
通信库算法。

所以 perftest 快,只能说明底层简单 RDMA 路径健康,不代表 collective 一定快。

7.3 小 case:perftest 24GB/s,AllReduce 5GB/s

可能解释:

text
简单 RDMA 单流路径没问题;
AllReduce 的多 rank 多阶段触发了 ECMP/queue/rail/channel/tail 问题;
通信库算法或 rank mapping 不理想;
每节点注入模式不同;
背景流量只在大规模同步时显现。

这不是矛盾,而是不同层级基准提供不同证据。


8. 和 Muxi 现象的关系

Muxi 的 W2/W4 中多次涉及 QP/channel/rail/GPU 映射。第 3 周给你一个判断框架:

text
channel 改变 → 可能改变 QP/flow/RNIC 并发/rail 映射
rail 掩码改变 → 可能改变 HCA、GID、ECMP group、物理路径
GPU 集合改变 → 可能改变 GPU-HCA 亲和、NUMA、通信库 rank mapping

因此,任何一个 A/B 结果都要问:

text
这次只改变了一个因素吗?
它在 verbs/RNIC 层改变了什么?
它在网络 ECMP 层改变了什么?
它在通信库 channel 层改变了什么?

最终报告说 MCCL/本地软件映射是参与因素,但不是已证实单一根因。这个判断是合理的,因为 QP/channel/rail 这些变量跨层耦合太强。


9. 推荐阅读提炼

9.1 Linux userspace verbs

一句话

userspace verbs 解释用户态程序如何通过 verbs 接口和 RDMA 设备交互。

抓哪个问题

text
RDMA 为什么可以减少 per-packet syscall?
为什么 fast path 快,但资源管理仍需要内核?

和 Muxi 的关系

当你看到 CPU/proxy/polling 相关问题时,不要说“RDMA 绕过内核所以 CPU 无关”。RDMA 只是让数据 fast path 更靠近设备,通信库仍需要软件推进。

9.2 RDMA Aware Networks Programming Manual

一句话

这是学习 PD、MR、CQ、QP、WR、SGE 等对象的基础手册。

抓哪个问题

text
一个 RDMA 程序创建和使用对象的顺序是什么?

最小顺序:

text
open device
alloc PD
register MR
create CQ
create QP
exchange QP info
modify QP to RTS
post WQE
poll CQE

和 Muxi 的关系

MCCL 把这些细节封装了,但 debug 时你仍然需要问:QP 数是多少?CQ polling 在哪里?MR/GDRDMA 是否生效?

9.3 rdma-core ibv_rc_pingpong

一句话

ibv_rc_pingpong 是理解 RC QP 建连和最小收发的经典例子。

抓哪个问题

text
两端如何交换 QP number、PSN、GID?
QP 状态如何从 INIT 到 RTR 到 RTS?

小 case

如果 GID index 或 MTU 不一致,可能不是“网络带宽低”,而是 QP 根本没正确进入可通信状态,或者走了错误路径。

9.4 perftest

一句话

perftest 提供 ib_write_bwib_read_bwib_send_bw 等简单 RDMA 负载,用来建立底层基线。

抓哪个问题

text
在不引入 collective 的情况下,单 RDMA operation 的路径能跑多快?

不能照搬

perftest 是低层对照,不是训练/AllReduce 性能预测器。


10. 常见误判

  • RDMA 完全不需要 CPU、内核或驱动。
  • GDRDMA 正常就说明网络不会慢。
  • QP 数影响带宽,就一定是 ECMP。
  • ib_write_bw 快,就代表 AllReduce 应该快。
  • CQE 成功就说明没有队列、重传、拥塞或尾部问题。
  • post WQE 的时间就是传输完成时间。
  • 通信库 API 名字能直接告诉你底层 verb 操作。

11. 本周任务设计

11.1 任务 A:画 verbs 对象依赖图

画出:

text
context → PD → MR/CQ/QP → WQE → CQE

并说明每个对象解决什么问题。

11.2 任务 B:解释 MR/lkey/rkey

用人话解释:

text
为什么 RNIC 不能随便读写进程指针?
lkey 和 rkey 的权限边界是什么?
GPU memory 注册有什么额外复杂性?

11.3 任务 C:QP 数 A/B 辨析

假设:

text
1 QP: 12GB/s
8 QP: 23GB/s

列出至少 6 个可能原因,并标注哪些属于 RNIC,哪些属于 ECMP,哪些属于通信库。

11.4 任务 D:perftest vs AllReduce

写一段解释:

text
为什么 ib_write_bw 快,不能反证 MCCL AllReduce 慢?

12. 和 agent 讨论的问题模板

12.1 QP/RNIC 拆解

text
请把这个带宽变化拆成 RNIC/QP/CQ、ECMP、通信库 channel、GPU-HCA 亲和四类候选。
每类说明需要什么日志或实验才能区分。

12.2 verbs 语义确认

text
请根据现有脚本判断它测的是 RDMA write/read/send/recv 中哪类语义,还是被通信库封装后无法直接判断。
列出需要补充的低层证据。

12.3 perftest 对照

text
我想用 perftest 给 Muxi 建立底层 RDMA 基线。
请设计单 rail、单 QP、多 QP、不同 message size、不同 MTU/GID 的只读/低风险实验矩阵,并说明它不能证明什么。

13. 本周最小掌握清单

  1. MR 是授权和固定内存:RNIC 不能随便读写进程指针。
  2. QP 是通信上下文:它有状态、队列和传输语义。
  3. WQE/CQE 是异步模型:post 不等于完成。
  4. QP 数跨层耦合:可能同时影响 RNIC 并发、ECMP hash、通信库 channel。
  5. perftest 是低层基线:不能直接预测 collective。
  6. RDMA fast path 不等于没有 CPU:软件仍要 post、poll、管理资源。

14. 本周结束时你应该能解释的一段话

如果有人问:

“多 QP 后带宽变好,是不是就证明 ECMP hash 用了 UDP 源端口?”

你应该能回答:

text
不能直接证明。多 QP 可能改变 RoCEv2 flow entropy,从而影响 ECMP 分布;但它也可能提高 RNIC 内部并发、改变 WQE/CQ 排队、改变通信库 channel 到 QP/HCA 的映射,或者改变接收端处理压力。
要证明 ECMP 机制,需要观察实际 UDP 源端口、交换机 ECMP group、逐上行端口 bytes,以及多 seed 复测。没有这些,只能说结果支持“QP/flow entropy 相关”的行为假设。

15. 进阶总图:一次 RDMA write 具体经历什么

用一个最小 RDMA write 来把本周概念串起来。

15.1 准备阶段

两端先准备资源:

text
发送端:
open device
alloc PD
register local MR
create CQ
create QP

接收端:
open device
alloc PD
register remote MR
create CQ
create QP

然后交换连接信息:

text
QP number
GID / LID
PSN
MTU
remote addr
rkey

接着 QP 状态切换:

text
RESET → INIT → RTR → RTS

只有到 RTS,QP 才真正 ready to send。

15.2 执行阶段

发送端 post 一个 RDMA write WQE:

text
operation = RDMA_WRITE
local addr = local MR address
local lkey = xxx
remote addr = remote MR address
remote rkey = yyy
length = N bytes

RNIC 执行:

text
读取本地 MR

生成 RoCE packet

通过 Ethernet/IP/UDP 网络发送

远端 RNIC 校验 rkey 和地址

写入远端 MR

返回完成/ACK

本地 CQ 出现 CQE

15.3 这条路径上可能慢在哪里

text
MR 注册开销;
GPU memory 到 RNIC DMA 路径;
QP send queue 堵;
RNIC 调度;
PCIe/NUMA;
RoCE packet 在 ECMP 上撞路径;
交换机 queue;
PFC/ECN/CNP;
远端写入路径;
CQ polling 不及时;

所以 RDMA write 看起来是“网卡直接写远端内存”,但性能仍然跨越 GPU、CPU、RNIC、网络和远端内存路径。


16. 进阶辨析:QP、connection、flow、channel 不是一回事

这几个词很容易混。

16.1 QP

QP 是 RDMA transport 上的队列对和状态机。

它包含:

text
SQ/RQ;
QP number;
状态;
PSN;
访问属性;
路径属性;

16.2 connection

connection 是更高层的通信关系。一个 peer pair 之间可能有一个或多个 QP。

text
rank A ↔ rank B
  ├─ QP0
  ├─ QP1
  └─ QP2

16.3 flow

网络里的 flow 通常由 header 字段定义:

text
src IP, dst IP, protocol, src port, dst port, ...

一个 QP 可能对应一个或多个网络 flow,具体取决于 RoCE UDP source port、实现和封装。

16.4 channel

channel 是通信库内部并行车道。一个 channel 可能映射到一个或多个 QP,也可能多个 channel 共享某些 QP/HCA。

16.5 为什么这个辨析重要

如果你看到:

text
channel 数增加后带宽变好

不能直接说:

text
ECMP flow 变多了。

中间可能是:

text
channel 增加 → QP 增加 → UDP source port 增加 → ECMP entropy 增加

也可能是:

text
channel 增加 → RNIC 并发提高

或者:

text
channel 增加 → GPU kernel pipeline 改变

如果没有实际 QP 和 packet header 证据,就不能跳过中间环节。


17. 进阶 case:RNR、retry、CQ error 怎么进入性能分析

RDMA 不是只有成功/失败,也有很多中间状态会表现为慢。

17.1 RNR:Receiver Not Ready

send/recv 语义下,接收端要提前 post recv。如果没有 recv buffer,发送端可能遇到 RNR。

表现可能是:

text
传输没有立即失败;
但等待重试;
延迟和尾部变高;

17.2 retry

可靠传输遇到丢包、NACK 或超时,可能重传。

表现:

text
带宽下降;
尾部增加;
RNIC retry counter 增加;

17.3 CQ error

CQE 里可能返回错误状态,例如 protection error、remote access error、timeout 等。

如果只看应用层 benchmark 输出,可能看不到完整原因。

17.4 和 Muxi 的关系

如果怀疑链路错误、QoS 或拥塞控制,应该尽量拿:

text
RNIC retry counter;
timeout / error CQE;
CNP counter;
packet drop;
CRC/FEC;

只看 bandwidth 不足以区分。


18. 进阶 case:GDRDMA 路径为什么也可能有亲和问题

18.1 GPU、CPU、PCIe、RNIC 不是均匀全互联

一台机器里可能有:

text
GPU0 更靠近 HCA0;
GPU7 更靠近 HCA3;
某些 GPU 到某些 HCA 要跨 PCIe switch 或 NUMA;

如果通信库把 GPU0 的数据主要走 HCA3,可能不如走 HCA0。

18.2 这会怎么表现

text
同一 host 上不同 GPU 集合性能不同;
同一 rail 对不同 GPU 表现不同;
单机/跨机差异;
GPU 顺序 A/B 有影响;

18.3 不能直接下的结论

看到 GPU 集合影响性能,不能直接说:

text
某张 GPU 坏了。

它可能是:

text
GPU-HCA 亲和;
PCIe/NUMA;
通信库 rank mapping;
rail 选择;

需要 GPU↔HCA topo、实际 HCA bytes 和复测。


19. perftest 该怎么设计才有信息量

19.1 不要只跑一个数字

只跑:

text
ib_write_bw A B

得到 24GB/s,信息量有限。

更有用的是矩阵:

text
operation: write / read / send
message size: 4KiB / 64KiB / 1MiB / 16MiB / 256MiB
QP: 1 / 2 / 4 / 8
rail: xscale_0 / xscale_1 / xscale_2 / xscale_3
direction: A→B / B→A
repeat: 多次

19.2 每个维度回答什么

text
operation:区分 write/read/send 语义差异;
message size:区分 latency 和 throughput;
QP 数:区分并发/entropy;
rail:区分 HCA/路径;
direction:区分方向性慢;
repeat:区分稳定问题和间歇问题;

19.3 和 collective 的关系

perftest 是底层基线:

text
如果 perftest 都慢,collective 慢不意外;
如果 perftest 快,collective 仍可能慢;

第二种情况说明问题可能出现在:

text
通信库调度;
rank mapping;
多流并发;
collective 同步;
网络聚合;

19.4 安全边界

在真实集群里,perftest 也可能制造大流量。要控制:

text
节点数;
并发数;
消息大小;
持续时间;
结果目录;
停止条件;

Muxi 规则里实验类要先 verify/probe,不盲目起大作业。


20. 推荐阅读进一步拆解:怎么读 verbs 材料

20.1 读 userspace verbs 时,重点看“fast path 和 control path”

不要只记住 “bypass kernel”。要画出:

text
control path:创建 PD/MR/CQ/QP,注册内存,权限管理
fast path:post WQE,RNIC 执行,poll CQE

然后问:

text
当前问题发生在 control path 还是 fast path?

例如:

text
第一次 iteration 慢 → 可能 control path/lazy init/MR
稳态每轮慢 → 可能 fast path/network/queue

20.2 读 RDMA Aware Programming Manual 时,重点看对象依赖

可以做这张表:

text
对象      解决什么问题               出问题可能表现
PD        资源隔离                   权限/访问错误
MR        授权内存给 RNIC             注册失败/访问错误/性能回退
CQ        完成事件                   poll 不及时/完成延迟
QP        通信上下文                 建连失败/重试/性能差
WQE       发给 RNIC 的任务            post 快但完成慢
CQE       完成/错误状态               成功/错误/超时

20.3 读 ibv_rc_pingpong 时,重点看连接建立

你要关注:

text
双方交换了哪些字段?
GID/MTU/PSN/QPN 在哪里出现?
QP 状态如何切换?

这会帮助你理解为什么 GID index 或 MTU 错误可能导致奇怪行为。

20.4 读 perftest 时,重点看实验变量

不要只把 perftest 当成测速命令。要看它能控制:

text
message size;
QP 数;
operation type;
inline;
MTU;
GID index;
report units;

这些变量可以帮你构造低层对照。


21. 本周自测题:带答案方向

21.1 为什么 MR 需要 pin memory?

答案方向:

text
RNIC 做 DMA 需要稳定可访问的地址映射。普通虚拟内存可能被换出或移动,所以要注册和 pin,并生成 lkey/rkey 做权限控制。

21.2 QP 数增加后带宽变好,为什么不能直接证明 ECMP?

答案方向:

text
QP 数增加可能改变 ECMP entropy,也可能改变 RNIC 并发、WQE/CQ 排队、通信库 channel 映射和 CPU/proxy 压力。需要 UDP port、交换机 bytes、QP counter 等证据。

21.3 ib_write_bw 快,为什么 AllReduce 仍可能慢?

答案方向:

text
ib_write_bw 是简单 RDMA operation 基线;AllReduce 是多 rank、多阶段、多 channel、同步 collective,会触发并发、mapping、ECMP、queue 和 tail 问题。

21.4 post WQE 快,为什么传输不一定快?

答案方向:

text
post 只是把任务放进队列;真正完成还需要 RNIC 执行、网络传输、远端处理、ACK/完成和 CQ polling。

21.5 GPU 集合影响性能,为什么不能直接说 GPU 坏?

答案方向:

text
可能是 GPU-HCA 亲和、PCIe/NUMA、rank mapping、rail 选择或通信库调度造成,需要 topology 和 per-HCA bytes 支持。