逻辑 collective 之下还有物理路径
集合通信定义 All-Reduce/All-Gather/All-to-All 的结果 shape 与所有权;拓扑决定 bytes 经过哪些 links、是否共享 root complex/NIC、能否并行和何处拥塞。
rank → process → GPU → PCIe switch/root complex → CPU NUMA node → NIC → fabric → remote host
↘ NVLink/NVSwitch peer domain ↗
- PCIe:通用主机/设备互联;GPU peer traffic 是否直达取决于拓扑、P2P/IOMMU/ACS 等配置。
- NVLink:GPU 间高速 links;具体代际、link 数与 peer matrix 不同。
- NVSwitch:交换 fabric,让一组 GPUs 形成更均匀的 NVLink 域;不是所有机器都有。
- InfiniBand/RoCE/RDMA:跨节点网络与 remote DMA 能力;带宽/latency 还取决于 NIC、switch、routing、congestion 与 GPUDirect RDMA。
- NUMA:CPU memory/NIC/GPU 分属 sockets;CPU staging 或 control thread 绑错 socket 会增加 host path 成本。
α-β 模型加上路径与争用
一条消息的简化成本:
是每轮固定延迟, 是经过 link 的 bytes, 是该 link 可用带宽。不同 links 可流水/并行,所以上式是核对框架,不保证机械相加。Collective library 会按 topology/message size 选择 ring/tree/hierarchical/CollNet 等;API 名不固定算法。
Byte-hop:把每条消息 bytes 乘经过的 links 数后求和,可用于比较 placement 的物理流量放大,但不等于时间。一个慢共享 link 的拥塞通常比多个独立 link 的总 byte-hop 更关键。
Toy topology:同一 logical exchange,不同跨域负载
四个 GPUs 构成线性 toy fabric:
GPU0 — GPU1 === GPU2 — GPU3
^
cross-domain link
每组两 rank 双向交换 64 MiB:
- topology-aware groups
(0,1),(2,3):只用域内 links;总 byte-hop 256 MiB,跨域 0。 - bad groups
(0,2),(1,3):两组都跨(1,2);总 byte-hop 512 MiB,跨域 link 负载 256 MiB。
逻辑 payload/每组成员数相同,但坏 placement 让路径变长并共享 bottleneck。这不预测真实 NVLink/PCIe 时间,只说明为什么 TP/EP/CP groups 应优先放在高速域,并把较低通信强度的 PP/data parallel 放到较慢边界(仍需按 workload 验证)。
可运行的 byte-hop 计算
import platform
from collections import defaultdict,deque
GRAPH={0:[1],1:[0,2],2:[1,3],3:[2]}
CROSS_DOMAIN=frozenset((1,2))
def shortest_path(source,destination):
queue=deque([(source,[source])]); visited={source}
while queue:
node,path=queue.popleft()
if node==destination: return path
for neighbor in GRAPH[node]:
if neighbor not in visited:
visited.add(neighbor); queue.append((neighbor,path+[neighbor]))
raise ValueError("disconnected topology")
def route_bidirectional_pairs(groups,payload_mib):
edge_load=defaultdict(float); routes=[]
for source,destination in groups:
path=shortest_path(source,destination); routes.append((source,destination,path))
for left,right in zip(path,path[1:]):
edge_load[frozenset((left,right))]+=2*payload_mib
return routes,edge_load
def main():
good=[(0,1),(2,3)]; bad=[(0,2),(1,3)]
good_routes,good_load=route_bidirectional_pairs(good,64)
bad_routes,bad_load=route_bidirectional_pairs(bad,64)
assert good_load[CROSS_DOMAIN]==0 and bad_load[CROSS_DOMAIN]==256
assert sum(good_load.values())==256 and sum(bad_load.values())==512
edges=sorted({tuple(sorted((node,n))) for node,neighbors in GRAPH.items() for n in neighbors})
print(f"python={platform.python_version()} topology_edges={edges}")
print("logical_exchange_per_pair=64MiB_each_direction")
print(f"good_groups={good} routes={good_routes} edge_load_MiB={dict(good_load)}")
print(f"bad_groups={bad} routes={bad_routes} edge_load_MiB={dict(bad_load)}")
print(f"cross_domain_good_MiB={good_load[CROSS_DOMAIN]:.0f} cross_domain_bad_MiB={bad_load[CROSS_DOMAIN]:.0f}")
print(f"byte_hop_good_MiB={sum(good_load.values()):.0f} byte_hop_bad_MiB={sum(bad_load.values()):.0f}")
if __name__=="__main__": main()
完整文件位于 examples/topology_cost.py,只用标准库。输出验证好/坏 placement 的跨域流量为 0/256 MiB、总 byte-hop 为 256/512 MiB。
不同并行模式为何偏好不同拓扑
- TP:每层频繁 collective,latency/bandwidth 敏感,通常应在最紧密高速域内。
- CP:长上下文 K/V/partials 通信较大,也偏好高速域;ring path 要与 causal/load balance 配合。
- EP/MoE:All-to-All 流量随路由动态,跨域拥塞/straggler 明显;expert placement 可结合流量统计。
- PP:主要在 stage boundary 传 activation,频率/bytes 与 microbatch 相关,可跨较慢域但会增加 bubble。
- Model loading/CPU staging:磁盘/NIC→CPU→GPU path 受 NUMA affinity 和 pinned memory 影响。
- KV Offload/P-D:GPU↔CPU/NIC/GPU 的 64 MiB 级状态 transfer 会与 collectives 争用 PCIe/NIC;独立页面给出 payload 下界与本机 pinned copy 实测。
并行模式总览定义逻辑切分,本页定义 rank coordinates 如何映射到设备图。Topology-aware placement 不能修复算法本身通信量过大,也不能保证 overlap;需要 profiler 确认 collective 是否在关键路径。
诊断清单与失败场景
至少收集:
nvidia-smi topo -m/vendor topology、GPU↔NIC/CPU affinity;- peer access、link generation/count、PCIe negotiated width;
- NCCL debug/topology graph、实际 algorithm/protocol/channel;
- per-message size、collective group、stream 与 wait position;
- link/NIC counters、retransmit/congestion、NUMA CPU/memory binding;
- 单 rank compute skew 与 MoE route imbalance,避免把等待误判成链路慢。
常见错误:
- global ranks 连续就假定物理邻近;容器/launcher mapping 可能不同;
- TP group 跨节点,而低通信 PP stages 留在同一 NVLink island;
- CPU tokenizer/loading threads 在远端 NUMA node;
- benchmark 单 pair P2P 带宽,推断多 collective 并发性能;
- 只看峰值 link spec,不看消息大小下的 α、protocol 与 contention;
- collective API 名称当作 ring/tree 实际算法证据。