# 调优 & 排查参数
## 一、调试与日志(排查问题必备)
| 变量 | 取值 | 含义 |
|-|-|-|
| `NCCL_DEBUG` | `VERSION` / `WARN` / `INFO` / `TRACE` | 日志等级。`INFO` 最常用,打印拓扑、算法选择、连接建立;`TRACE` 每次 op 都打,极吵 |
| `NCCL_DEBUG_SUBSYS` | `INIT` / `GRAPH` / `NET` / `COLL` / `P2P` / `TUNING` / `ENV` / `ALLOC` / `ALL` | 按子系统过滤日志。网络问题看 `NET`,算法选择看 `GRAPH,TUNING` |
| `NCCL_DEBUG_FILE` | 文件路径模板(支持 `%h` 主机名、`%p` pid) | 把日志写到文件而非 stderr,多机调试必用,如 `/tmp/nccl.%h.%p.log` |
| `NCCL_TOPO_DUMP_FILE` | 文件路径 | dump 探测到的硬件拓扑 XML,确认 GPU/NIC/PCIe 关系识别是否正确 |
| `NCCL_GRAPH_DUMP_FILE` | 文件路径 | dump Ring/Tree 搜索结果,确认实际走的路径 |
| `NCCL_NET_WARN_TIME` | 默认:1000(1 秒),可以配置 100 | 网络操作(主要是 IB 的 send/recv/write)超过该阈值(单位毫秒)仍未完成时,打印一条 WARN,提示“这条链路慢” |
| `NCCL_DEBUG_TIMESTAMP_LEVELS` | `WARN,INFO` | 给哪些等级的日志加时间戳前缀(NCCL 2.20+ 特性) |
> 💡 排查性能问题的起手式:`NCCL_DEBUG=INFO NCCL_DEBUG_SUBSYS=INIT,GRAPH,NET,TUNING`
---
## 二、算法与协议(性能调优核心)
| 变量 | 默认 | 含义 |
|-|-|-|
| `NCCL_ALGO` | 自动 | 强制算法:`Ring` / `Tree` / `CollnetDirect` / `CollnetChain` / `NVLS` / `NVLSTree`。一般别碰,除非 tuning 表对你的 size 选错了 |
| `NCCL_PROTO` | 自动 | 强制协议:`Simple` / `LL` / `LL128`。小消息强制 `LL128` 可能降延迟;带宽打不满时试 `Simple` |
| `NCCL_MIN_NCHANNELS` | 自动 | 最少 channel 数。提高可增加并行度(吃 SM),典型 `4~8` |
| `NCCL_MAX_NCHANNELS` | 自动 | 最多 channel 数。太多会抢 SM,影响计算 kernel |
| `NCCL_NCHANNELS_PER_PEER` | 自动 | 每对 peer 之间的 channel 数,跨机带宽瓶颈时可调 |
| `NCCL_NCHANNELS_PER_NET_PEER` | 自动 | 控制两个跨节点 rank 之间,在 NIC 上并发建立多少条 channel。它是 NCCL 在 channel 数维度上针对跨机 NIC 通信的细粒度调参 |
| `NCCL_TUNER_PLUGIN` | — | 加载自定义 tuner 动态库,覆盖内置 tuning 表 |
| `NCCL_SOCKET_NTHREADS` | `1` | 每个 rank-to-rank 连接使用多少个网络线程 |
| `NCCL_NSOCKS_PERTHREAD` | `1` | 每个线程负责多少条并发 TCP socket |
| `NCCL_CROSS_NIC` | `0` | 决定一个 ring/tree 内的不同 channel 是否允许使用不同的网卡。`0`:禁止跨 NIC;`1`:允许跨 NIC;`2`:强制跨 NIC |
| `NCCL_TUNER_CONFIG_PATH` | `$PATH` | NCCL Tuner Plugin 的配置文件路径,用来告诉 NCCL 按什么策略选择 collective 算法、协议和 channel 数 |
---
## 三、网络选择
| 变量 | 示例值 | 含义 |
|-|-|-|
| `NCCL_IB_HCA` | `mlx5_0,mlx5_1` / `=mlx5` / `^mlx5_2` | 指定 IB/RoCE 设备。`=` 精确匹配,`^` 排除。最好带端口号 `mlx5_0:1` |
| `NCCL_IB_DISABLE` | `0` / `1` | 关闭 IB,退化到 TCP。调试用 |
| `NCCL_SOCKET_IFNAME` | `eth0` / `=bond0` / `^docker,lo` | bootstrap 及 TCP fallback 走的网卡。容器环境常要设 |
| `NCCL_SOCKET_FAMILY` | `AF_INET` / `AF_INET6` | IPv4 / IPv6 |
| `NCCL_NET` | `IB` / `Socket` / 插件名 | 指定 net plugin |
| `NCCL_NET_PLUGIN` | 路径 | 加载自定义 net plugin(如 AWS OFI、SHARP) |
---
## 四、RDMA 参数
| 变量 | 默认 | 含义 |
|-|-|-|
| `NCCL_IB_GID_INDEX` | `0` 或 `3` | RoCE 选 GID 索引,RoCEv2 通常为 `3`。用 `show_gids` 查 |
| `NCCL_IB_TC` | `0` | Traffic Class,配合交换机 QoS / PFC / ECN,典型值为 `106` 或 `160` |
| `NCCL_IB_SL` | `0` | Service Level,InfiniBand QoS |
| `NCCL_IB_TIMEOUT` | `18` | QP 超时,值为 `4.096us × 2^timeout`。大规模下丢包多时调到 `22~23` |
| `NCCL_IB_RETRY_CNT` | `7` | RC 重传次数 |
| `NCCL_IB_QPS_PER_CONNECTION` | `1` | 每连接 QP 数。多 QP 能提单链路带宽,但费资源,常设 `2~4` |
| `NCCL_IB_SPLIT_DATA_ON_QPS` | `1` | 数据是否在多 QP 间分摊 |
| `NCCL_IB_AR_THRESHOLD` | `8192` | 自适应路由触发阈值(字节) |
| `NCCL_IB_ADAPTIVE_ROUTING` | `0` | 启用 IB 自适应路由(需交换机支持) |
| `NCCL_IB_PCI_RELAXED_ORDERING` | `2` | PCIe Relaxed Ordering,某些平台开了能涨带宽 |
---
## 五、GPUDirect RDMA & P2P
| 变量 | 默认 | 含义 |
|-|-|-|
| `NCCL_NET_GDR_LEVEL` | 自动 | GDR 启用门槛:`LOC` / `PIX` / `PXB` / `PHB` / `SYS`。数字越大越激进(`SYS` 表示跨 NUMA 也用)。PCIe 拓扑差时降级更稳 |
| `NCCL_NET_GDR_READ` | 自动 | 是否允许 GDR Read(发送侧直接从 GPU 显存 DMA 读)。NIC 离 GPU 远时关掉更好 |
| `NCCL_GDRCOPY_ENABLE` | `0` | 启用 gdrcopy 小消息拷贝,降延迟 |
| `NCCL_GDRCOPY_SYNC_ENABLE` | `1` | gdrcopy 同步原语 |
| `NCCL_P2P_LEVEL` | 自动 | 机内 P2P 启用门槛,同上分级 |
| `NCCL_P2P_DISABLE` | `0` | 强制关闭 P2P(NVLink + CUDA IPC),调试用 |
| `NCCL_SHM_DISABLE` | `0` | 强制关闭共享内存传输 |
---
## 六、进程与错误处理
| 变量 | 含义 |
|-|-|
| `NCCL_COMM_ID` | 手动指定 bootstrap 端点 `<ip>:<port>`,替代 `ncclUniqueId` 分发 |
| `NCCL_COMM_BLOCKING` | `1` 阻塞(默认)/ `0` 非阻塞。PyTorch 2.x 异步错误处理常用 |
| `NCCL_ASYNC_ERROR_HANDLING` | `1` 启用异步错误捕获,集群丢卡时不直接 segfault |
| `NCCL_LAUNCH_MODE` | `PARALLEL` / `GROUP`,kernel 启动模式,调度冲突时试 `GROUP` |
---
## 七、内存与缓冲区
| 变量 | 默认 | 含义 |
|-|-|-|
| `NCCL_BUFFSIZE` | `4194304`(4MB) | 每 channel 中转 buffer。大消息吞吐敏感场景可调 `8M~16M`,但吃显存 |
| `NCCL_NVLS_ENABLE` | 自动 | H100+ 启用 NVLS。某些机型或驱动不全会 init 失败,需手动设 `0` |
| `NCCL_CUMEM_ENABLE` | 自动 | 用 CUDA VMM API 管理内存(NCCL 2.18+) |
---
## 八、SHARP / CollNet(in-network reduction)
| 变量 | 含义 |
|-|-|
| `NCCL_COLLNET_ENABLE` | `1` 启用 CollNet(需 Sharp plugin) |
| `NCCL_SHARP_DISABLE` | `1` 关闭 SHARP,兼容性问题时用 |
| `SHARP_COLL_*` | SHARP 库自己的参数,不走 NCCL 前缀 |
---
# NCCL 问题排查
## NCCL 建联失败(Bootstrap / Connect Fail)
### 1.1 典型现象
- `ncclSystemError` / `ncclInvalidUsage` / `ncclRemoteError`
- 日志关键字:`bootstrap`、`connect failed`、`unhandled cuda error`、`Call to ibv_...`
- 作业在 `ncclCommInitRank` / `ncclCommInitRankConfig` 阶段退出,训练 step 0 未开始
- 部分 rank 卡在 `waiting for all peers to connect`
### 1.2 快速定位 checklist
| 顺序 | 检查项 | 命令 / 方法 |
|---|---|---|
| 1 | NIC 状态 | `ibstatus` / `ibv_devinfo` / `ethtool` / `mlxlink` |
| 2 | GID / 路由可达 | `show_gids` + `ib_send_lat` 端到端 |
| 3 | RDMA CM 端口 | `ss -ltnp \| grep 4791` (RoCEv2 默认)、防火墙 |
| 4 | GPU 拓扑 | `nvidia-smi topo -m`、确认 `PXB/PIX/NODE/SYS` |
| 5 | NCCL 环境 | `NCCL_DEBUG=INFO`、`NCCL_IB_HCA`、`NCCL_SOCKET_IFNAME`、`NCCL_NET_GDR_LEVEL` |
| 6 | PCIe ACS | `lspci -vvv \| grep ACSCtl` — SrcValid/TransBlk 应为 `-` |
### 1.3 根因层级
1. **硬件层**:NIC link down、光模块劣化(误码率高)、PCIe 训练速率跌档(`lspci -vv` LnkSta)
2. **拓扑层**:GPU 与 NIC 不同 NUMA / 不同 Root Complex、ACS 未关闭导致 GDR 不通
3. **协议层**:QP 状态机卡在 `INIT/RTR`、PSN 不匹配、MTU 不一致(4200 vs 4096 vs 1500)
4. **网络层**:ToR / Spine 路由黑洞、ECMP hash 冲突打到慢路径、BGP 失联
5. **软件层**:NCCL / driver / OFED / CUDA 版本组合未验证;`libnccl-net.so` 插件路径错误
6. **调度层**:Pod 绑核错误,NIC 亲和性未下发
### 1.4 处置动作
- 立即:剔除异常节点 → drain → 让 K8s / 调度器重新拉起
- 5 分钟内:在保留现场前打包 `dmesg / ibdump / nccl-test` 日志
- 30 分钟:通过 `nccl-tests` (`all_reduce_perf -b 8 -e 128M -g 8`) 二分定位坏节点对
---
## AllReduce / AllToAll 慢(Perf Degradation)
### 2.1 典型现象
- 单 step 训练时间突增 2~10×,但作业未挂
- `nccl-tests` 带宽未达理论值(200G 网口应达 ~24GB/s 单向)
- 慢主要出现在跨机 ring/tree 段;单机内 NVLink 正常
- Prometheus: `rdma_tx_bytes` 抖动、`ecn_marked_packets` 上升
### 2.2 快速定位 checklist
| 维度 | 工具 | 关注指标 |
|---|---|---|
| GPU 侧 | `nvidia-smi dmon`、Nsight Systems | SM 利用率、stall 原因 |
| PCIe | `nvidia-smi nvlink/--query-gpu=pcie.link.gen.current` | 跌档到 Gen3 = 性能减半 |
| NIC | `mlnx_perf`、`ethtool -S` | `rx_pause`、`tx_pause`、`rx_discards` |
| 网络 | 交换机 PFC/ECN 计数、buffer occupancy | WRED drop、PFC storm |
| 算法 | NCCL_ALGO / NCCL_PROTO / NCCL_TREE_THRESHOLD | Ring vs Tree 选择是否合理 |
| 拓扑 | `NCCL_TOPO_DUMP_FILE` | Chunk size、channel 数是否退化 |
### 2.3 根因层级(按频率排序)
1. **PFC 反压 / 死锁**:某上联口拥塞 → pause 帧扩散 → 全网慢
2. **ECMP hash 不均**:大流 elephant flow 集中在单链路,其它空闲
3. **DCQCN 参数失配**:Kmin/Kmax/Pmax 设置过激 → 频繁限速
4. **NCCL 算法退化**:消息 size 在 tree/ring 切换阈值附近抖动
5. **GDR 未生效**:`NCCL_NET_GDR_LEVEL` 降级到 CPU 中转,带宽腰斩
6. **PCIe 跨 Socket**:数据走 UPI (~20GB/s) 而非 PCIe Gen4 x16 (~32GB/s)
7. **机柜内 NIC-GPU 不同 Root Complex**:仅能走 CPU memcpy
### 2.4 处置动作
- 短期:把慢节点所在 rail 从训练拓扑中隔离(`NCCL_IB_HCA` 黑名单)
- 中期:让网络侧抓取 PFC 风暴源头,必要时回滚 DCQCN 参数
- 长期:补 `nccl-tests` 常态巡检 + 慢节点自动进隔离池
---
## NCCL Hang(卡死 / wait deadlock)
### 3.1 典型现象
- 所有 rank 全部处于 `cudaStreamSynchronize` 或 `ncclGroupEnd`,无 CPU,GPU 利用率跌到 0
- `py-spy dump` 显示栈停在 `all_reduce` / `broadcast`
- 超时后被 `NCCL_ASYNC_ERROR_HANDLING` / `watchdog` 拉起,或直接 silent hang
- 持续 30 分钟以上无任何日志推进
### 3.2 定位三板斧
1. **抓栈**:所有节点 `py-spy dump --pid $PID` + `gdb -p` / `cuda-gdb`
2. **抓网**:交换机端口镜像 + `ibdump` 10 秒,看 QP 是否还在收发
3. **抓状态**:`NCCL_DEBUG=TRACE` + `NCCL_DEBUG_SUBSYS=ALL`;启用 NCCL 2.20+ 的 `flight recorder`
### 3.3 根因层级
1. **集合通信语义不一致**:rank 间 group call 顺序 / 参数不一致(size、dtype、count 错位)
2. **单张卡 ECC / Xid**:一张 GPU 悄悄退出队列,其它 rank 无限等待
3. **PFC 死锁**:buffer 互相等待,整条路径静默
4. **交换机闪断**:BFD 超时前的 RTO 重传耗尽
5. **应用层 bug**:DataLoader/Checkpoint 阻塞在主线程,通信 stream 被饿死
6. **框架层**:DeepSpeed / Megatron pipeline bubble 未对齐
### 3.4 处置动作
- 立刻:保留现场(禁止先重启!)→ 触发 `nvidia-smi --query-remapped-rows`、`dmesg | grep -i xid`
- 30 秒内:全机 `py-spy dump` → 对比找出"最先停住的那个 rank"
- 2 分钟:按该 rank 的栈反推是等网络、等 GPU 还是等 CPU
---
## 通用排查矩阵
| 层级 | 关键信号 | 首选工具 | 负责角色 |
|---|---|---|---|
| 硬件 | Xid、ECC、LnkSta 跌档 | `nvidia-smi`、`dmesg`、`mlxlink` | SRE |
| 拓扑 | `topo -m`、NUMA、ACS | `nvidia-smi topo`、`lstopo` | 平台 |
| 协议 | QP 状态、MTU、PSN | `ibv_*`、`show_gids` | AI Infra |
| 网络 | PFC / ECN / discards | 交换机计数、`mlnx_perf` | 网络 |
| 软件 | NCCL / driver / OFED 版本 | `nccl-tests`、版本清单 | AI Infra |
| 调度 | 绑核、亲和、资源隔离 | K8s topology manager | 平台 |
| 框架 | group call、pipeline、ckpt | `py-spy`、`torch.profiler` | 算法 |
---
# NCCL 集合通信算子总结
NCCL(NVIDIA Collective Communications Library)主要提供面向多 GPU / 多机场景的**集合通信(collective communication)**能力,常用
于深度学习训练中的梯度同步、参数分发和结果聚合。
## 1. 核心集合通信算子
| 算子 | 含义 |典型作用 | 数据流特征 |
|---|---|---|---|
| **Broadcast** | 广播 | 将一个 root GPU 上的数据复制到所有 GPU | 一发多收 |
| **Reduce** |归约 | 将所有 GPU 上的数据按某种规约操作汇总到 root GPU | 多发一收 |
| **AllReduce** | 全归约 |先做 Reduce,再将结果分发给所有 GPU | 多发多收 |
| **AllGather** | 全收集 | 每个 GPU 提供一份数据,最终所有 GPU 拿到全部数据拼接结果 | 多发多收,拼接 |
| **ReduceScatter** |归约后分发 |先对所有 GPU 数据做规约,再把结果切分后分给各 GPU | 多发多收,规约+切分 |
| **Scatter** | 分发 | root GPU 将一整块数据切分后分给各 GPU | 一发多收,切分 |
| **Gather** | 汇聚 | 所有 GPU 的数据收集到 root GPU 并拼接 | 多发一收,拼接 |
| **AllToAll** | 全交换 | 每个 GPU 给其他所有 GPU发送不同分片,并接收来自所有 GPU 的分片 | 全互发 |
## 2. 各算子说明
### 2.1 Broadcast
> 把 root rank 上的一份数据复制到通信域中的所有 rank。
- 输入:只有 root 的源数据有效
- 输出:所有 rank 拥有相同数据
- 常见用途:
- 初始化模型参数
- 同步配置、随机种子相关状态
### 2.2 Reduce
> 把所有 rank 上的数据做规约运算,结果只保留在 root rank。
- 支持的规约操作通常包括:
- `sum`
- `prod`
- `max`
- `min`
- `avg`(某些框架层封装提供)
- 常见用途:
-统计全局 loss
- 汇总指标到主卡
### 2.3 AllReduce
> 所有 rank 的数据先规约,再把规约结果返回给每个 rank。
- 最常见的 NCCL 算子之一
- 在数据并行训练中用于:
- 梯度同步
- 参数统计同步
- 等价理解:
- `Reduce + Broadcast`
### 2.4 AllGather
> 每个 rank 提供自己的一段数据,最终所有 rank 收到所有 rank 的数据拼接结果。
- 输入:每个 rank 一份局部数据
- 输出:每个 rank 拿到完整拼接后的全量数据
- 常见用途:
- 收集分片 embedding
- 张量并行中的激活/特征拼接
### 2.5 ReduceScatter
>先对所有 rank 的对应数据做规约,再把结果切片分发给各 rank。
- 等价理解:
- `AllReduce + Scatter`
- 相比直接 AllReduce:
- 通常能减少后续冗余拷贝
- 更适合分片优化场景
- 常见用途:
- ZeRO / 分片优化器
- 张量并行、序列并行中的梯度或激活切分
### 2.6 Scatter
> root rank 将一整块数据分片后发送给所有 rank。
- 输入:root 上完整数据
- 输出:每个 rank 得到自己的那一片
- 常见用途:
- 数据分块下发
- 某些参数分片初始化
### 2.7 Gather
> 各 rank 将本地数据发送到 root rank,由 root 拼接成完整结果。
- 输入:每个 rank 一份局部数据
- 输出:root 上完整拼接数据
- 常见用途:
- 收集局部结果
- 推理或评测时汇总输出
### 2.8 AllToAll
> 每个 rank 都向其他所有 rank 发送不同的数据块,同时从其他所有 rank 接收数据块。
- 通信模式最复杂
- 常见用途:
- Mixture of Experts(MoE)中的 token dispatch
- 张量重排 / 数据重分布
## 3. 常见规约操作(Reduction Ops)
NCCL 的 `Reduce` / `AllReduce` / `ReduceScatter` 等算子通常配合以下规约类型:
|规约类型 | 含义 |例子 |
|---|---|---|
| **sum** | 求和 | 梯度累加 |
| **prod** | 求积 | 较少使用 |
| **max** |取最大值 |统计最大值 |
| **min** |取最小值 |统计最小值 |
| **avg** | 求平均 | 常作为 `sum` 后再除 `world size` 的语义封装 |
## 4.训练场景里的典型对应关系
|训练场景 | 常用 NCCL 算子 |
|---|---|
| 数据并行梯度同步 | **AllReduce** |
| 模型初始化参数同步 | **Broadcast** |
| 分布式指标汇总 | **Reduce / AllReduce** |
| 张量并行结果拼接 | **AllGather** |
| 分片梯度规约 | **ReduceScatter** |
| MoE token 路由 | **AllToAll** |
## 5. 算子之间的关系
| 算子 | 可近似拆解为 |
|---|---|
| **AllReduce** | `Reduce + Broadcast` |
| **ReduceScatter** | `Reduce + Scatter` |
| **AllGather** | `Gather + 广义上的全员可见` |
| **AllToAll** | 更一般化的多对多交换 |
## 6. 一句话理解
- **Broadcast**:一份数据发给所有人
- **Reduce**:所有人的数据汇总到一个人
- **AllReduce**:所有人的数据汇总后,每个人都拿到结果
- **AllGather**:每个人的分片拼成完整数据,所有人都拿到
- **ReduceScatter**:先汇总,再把结果分片给每个人
- **AllToAll**:每个人都和其他所有人交换不同的数据
NCCL 集合通信总结