原力注入

NCCL InfiniBand 测试验证工具说明文档

NCCL InfiniBand 测试验证工具说明文档

原文:https://github.com/ForceInjection/AI-fundermentals/blob/main/ops/IB/nccl_ib_test_usage.md
相关脚本:https://github.com/ForceInjection/AI-fundermentals/blob/main/ops/IB/nccl_ib_test.sh

相关文章

InfiniBand 网络理论与实践

InfiniBand 网络检查脚本使用说明

InfiniBand 网络带宽监控脚本使用说明

IB 系列到此搞一段路。

1. 概述

nccl_ib_test.sh 是一个专业的 NCCL (NVIDIA Collective Communications Library) InfiniBand 网络测试验证工具,用于验证和测试 NCCL 在 InfiniBand 网络环境下的性能和配置。


2. 主要功能

2.1 系统检查

  • • 依赖检查: 验证 Python3、PyTorch、CUDA、NCCL、NVIDIA GPU 等必要组件
  • • InfiniBand 状态检查: 检测 IB 设备状态、Link Layer 类型、网络拓扑

2.2 环境配置

  • • 自动网络类型检测: 智能识别原生 IB 或 RoCE 环境
  • • NCCL 环境变量配置: 自动设置最优的 NCCL 参数
  • • GPUDirect RDMA 支持: 启用高性能 GPU 直接内存访问

2.3 性能测试

  • • 分布式 AllReduce 测试: 使用多 GPU 进行 NCCL 通信测试
  • • 延迟和吞吐量分析: 详细的性能指标测量
  • • 理论传输量计算: Ring AllReduce 算法效率分析

2.4 报告生成

  • • 详细测试报告: 包含系统信息、配置参数、测试结果
  • • 性能数据分析: 延迟、数据吞吐量、理论传输量统计
  • • 问题诊断: 错误和警告的统计与分析

3. 使用方法

3.1 基本语法

./nccl_ib_test.sh [选项]

3.2 可用选项

功能模块
描述
env
设置 NCCL 环境变量
test
运行 NCCL 分布式测试
report
生成详细测试报告
all
执行完整测试流程 (默认)

3.3 使用示例

3.3.1 完整测试流程

# 执行所有检查、配置、测试和报告生成
./nccl_ib_test.sh
# 或
./nccl_ib_test.sh all

3.3.2 仅检查系统状态

# 检查依赖和 InfiniBand 状态
./nccl_ib_test.sh check

3.3.3 仅运行 NCCL 测试

# 运行分布式通信测试
./nccl_ib_test.sh test

3.3.4 生成测试报告

# 生成详细的测试报告
./nccl_ib_test.sh report

4. 系统要求

4.1 硬件要求

  • • GPU: 一个或多个 NVIDIA GPU (支持 CUDA)
  • • 网络: InfiniBand 网卡 (原生 IB 或 RoCE)
  • • 内存: 建议 8GB 以上系统内存

4.2 软件要求

  • • 操作系统: Linux (Ubuntu/CentOS/RHEL)
  • • Python: Python 3.6+
  • • PyTorch: 支持 CUDA 的 PyTorch
  • • NCCL: NVIDIA NCCL 库
  • • CUDA: NVIDIA CUDA Toolkit
  • • InfiniBand 工具: ibstat, ibv_devinfo, perfquery

4.3 依赖安装

4.3.1 Ubuntu/Debian

# 安装 InfiniBand 工具
sudo apt-get install infiniband-diags ibverbs-utils

# 安装 Python 和 PyTorch (示例)
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

4.3.2 CentOS/RHEL

# 安装 InfiniBand 工具
sudo yum install infiniband-diags libibverbs-utils

# 或使用 dnf (较新版本)
sudo dnf install infiniband-diags libibverbs-utils

5. 关键技术说明

5.1 NCCL AllReduce 算法原理

5.1.1 Ring AllReduce 算法

NCCL 默认使用 Ring AllReduce 算法,该算法具有以下特点:

# Ring AllReduce 算法伪代码
defring_allreduce(data, rank, world_size):
"""
    Ring AllReduce 算法实现

    参数:
        data: 本地数据张量
        rank: 当前进程的排名 (0 到 world_size-1)
        world_size: 总进程数

    算法步骤:
        1. Reduce-Scatter 阶段: 将数据分块,每个节点负责一个块的归约
        2. AllGather 阶段: 将归约结果广播到所有节点
    """


# 第一阶段: Reduce-Scatter
# 每个节点将其数据块发送给下一个节点,接收上一个节点的数据块
for step inrange(world_size - 1):
        send_rank = (rank + 1) % world_size
        recv_rank = (rank - 1 + world_size) % world_size

# 发送数据块到下一个节点,从上一个节点接收数据块
# 并进行归约操作 (求和)

# 第二阶段: AllGather  
# 将归约后的数据块广播到所有节点
for step inrange(world_size - 1):
        send_rank = (rank + 1) % world_size
        recv_rank = (rank - 1 + world_size) % world_size

# 发送完整的数据块到下一个节点

算法复杂度分析:

  • • 通信复杂度: O(N) 其中 N 是数据大小
  • • 时间复杂度: 2 × (N-1)/N × (数据传输时间)
  • • 带宽利用率: 接近 100% (理论最优)

5.1.2 理论传输量计算

defcalculate_theoretical_transfer(data_size_mb, world_size):
"""
    计算 Ring AllReduce 的理论传输量

    公式: 2 × (N-1)/N × data_size

    解释:
        - 第一个 (N-1)/N: Reduce-Scatter 阶段的传输比例
        - 第二个 (N-1)/N: AllGather 阶段的传输比例  
        - 系数 2: 两个阶段的总和
    """

    transfer_ratio = 2 * (world_size - 1) / world_size
    theoretical_transfer_mb = transfer_ratio * data_size_mb

return theoretical_transfer_mb

# 示例计算
# 4个GPU,100MB数据: 2 × (4-1)/4 × 100 = 150MB 理论传输量

5.2 GPUDirect RDMA 技术原理

5.2.1 传统数据路径 vs GPUDirect RDMA

# 传统数据路径 (无 GPUDirect RDMA)
GPU1 Memory → CPU Memory → Network → CPU Memory → GPU2 Memory
#           ↑ PCIe      ↑ System Bus  ↑ System Bus ↑ PCIe
#           4次内存拷贝,高延迟

# GPUDirect RDMA 数据路径  
GPU1 Memory → Network → GPU2 Memory
#           ↑ 直接连接,零拷贝,低延迟

5.2.2 NCCL 环境变量技术细节

# 关键环境变量及其技术含义

# 1. 启用 InfiniBand 支持
export NCCL_IB_DISABLE=0
# 技术说明: 
#   - 0: 启用 IB 传输
#   - 1: 禁用 IB,回退到 Socket/Ethernet
#   - 影响: 直接决定是否使用高性能 IB 网络

# 2. GPUDirect RDMA 级别控制
export NCCL_NET_GDR_LEVEL=2  
# 技术说明:
#   - 0: 禁用 GPUDirect RDMA
#   - 1: 启用 GPUDirect RDMA (读取)
#   - 2: 启用 GPUDirect RDMA (读取+写入) - 最高性能
#   - 影响: 控制 GPU 内存与网络的直接访问程度

# 3. HCA 设备选择
export NCCL_IB_HCA=mlx5_0
# 技术说明:
#   - 指定使用的 InfiniBand 网卡设备
#   - 多网卡环境下的负载均衡和性能优化
#   - 格式: 设备名称 (通过 ibstat -l 获取)

# 4. GID 索引配置 (关键性能参数)
export NCCL_IB_GID_INDEX=0    # 原生 IB
export NCCL_IB_GID_INDEX=3    # RoCE v2
# 技术说明:
#   - GID (Global Identifier): IB 网络中的全局标识符
#   - 不同 GID 索引对应不同的网络协议栈
#   - 错误配置会导致连接失败或性能下降

# 5. 流控制参数
export NCCL_IB_TC=136         # Traffic Class
export NCCL_IB_SL=0           # Service Level  
# 技术说明:
#   - TC: 流量分类,用于 QoS 控制
#   - SL: 服务级别,影响数据包优先级
#   - 136: 常用的高优先级 TC 值

# 6. 超时和重试机制
export NCCL_IB_TIMEOUT=22     # 超时时间 (对数刻度)
export NCCL_IB_RETRY_CNT=7    # 重试次数
# 技术说明:
#   - TIMEOUT: 2^22 微秒 ≈ 4.2 秒
#   - 网络不稳定时的容错机制
#   - 过小值可能导致误报,过大值影响故障检测

5.3 网络类型自动检测机制

5.3.1 检测算法实现

# 脚本中的网络类型检测逻辑
detect_network_type() {
local is_roce=false
local network_type="未知"

# 使用 ibv_devinfo 检测链路层类型
ifcommand -v ibv_devinfo >/dev/null 2>&1; then
# 获取第一个设备的链路层信息
local link_layer=$(ibv_devinfo | grep "link_layer:" | head -1 | awk '{print $2}')

case"$link_layer"in
"Ethernet")
                is_roce=true
                network_type="RoCE (Ethernet over IB)"
# RoCE 特定配置
                configure_roce_parameters
                ;;
"InfiniBand") 
                network_type="原生 InfiniBand"
# 原生 IB 特定配置
                configure_native_ib_parameters
                ;;
            *)
                network_type="未知类型: $link_layer"
# 使用保守的默认配置
                configure_default_parameters
                ;;
esac
fi

echo"检测到网络类型: $network_type"
}

5.3.2 配置差异对比

参数
原生 InfiniBand
RoCE v2
技术说明
NCCL_IB_GID_INDEX
0
3
GID 索引选择不同的协议栈
NCCL_SOCKET_IFNAME
未设置
""
RoCE 需禁用 Socket 接口避免冲突
网络层
IB Verbs
Ethernet + IB Verbs
底层传输协议不同
性能特征
超低延迟
较低延迟,更好兼容性
硬件和协议栈差异

5.4 性能测试核心代码解析

5.4.1 动态张量大小计算

# 脚本生成的 Python 测试代码关键部分
defcalculate_tensor_size(test_size_str):
"""
    根据用户输入计算张量元素数量

    技术细节:
        - float32 张量: 每个元素 4 字节
        - 内存对齐: GPU 内存分配需要考虑对齐要求
        - 大小限制: 受 GPU 内存容量限制
    """

    size_mapping = {
"1M":  262144,      # 1MB / 4 bytes = 262,144 elements
"10M": 2621440,     # 10MB / 4 bytes = 2,621,440 elements  
"100M": 26214400,   # 100MB / 4 bytes = 26,214,400 elements
"1G": 268435456# 1GB / 4 bytes = 268,435,456 elements
    }

return size_mapping.get(test_size_str, 262144)

# GPU 内存安全检查
defcheck_gpu_memory_safety(tensor_size, device):
"""
    检查 GPU 内存是否足够容纳测试数据

    安全策略:
        - 预留 20% 内存用于 CUDA 上下文和其他开销
        - 考虑 NCCL 内部缓冲区需求
        - 多 GPU 环境下的内存碎片问题
    """

    gpu_memory_bytes = torch.cuda.get_device_properties(device).total_memory
    required_memory_bytes = tensor_size * 4# float32

# 安全阈值: 80% GPU 内存
    safety_threshold = gpu_memory_bytes * 0.8

if required_memory_bytes > safety_threshold:
print(f"警告: 所需内存 {required_memory_bytes/1024**3:.2f}GB "
f"超过安全阈值 {safety_threshold/1024**3:.2f}GB")
returnFalse

returnTrue

5.4.2 性能指标计算详解

defcalculate_performance_metrics(tensor, duration_ms, world_size):
"""
    计算详细的性能指标

    返回指标说明:
        - 延迟: AllReduce 操作的端到端时间
        - 数据吞吐量: 应用层数据处理速率 (非网络带宽)
        - 理论传输量: Ring AllReduce 算法的理论网络传输量
        - 算法效率: 实际性能与理论最优的比值
    """


# 1. 基础数据计算
    data_size_bytes = tensor.numel() * tensor.element_size()
    data_size_mb = data_size_bytes / (1024 * 1024)

# 2. 延迟计算 (毫秒)
    latency_ms = duration_ms

# 3. 数据吞吐量计算 (Gbps)
# 注意: 这是应用层吞吐量,包含了算法开销
    throughput_gbps = (data_size_mb * 8) / (duration_ms / 1000) / 1000

# 4. 理论传输量计算 (Ring AllReduce)
if world_size > 1:
# Ring AllReduce 公式: 2 * (N-1) / N * data_size
        transfer_efficiency = 2 * (world_size - 1) / world_size
        theoretical_transfer_mb = transfer_efficiency * data_size_mb
else:
        theoretical_transfer_mb = 0# 单 GPU 无网络传输

# 5. 算法效率分析
# 理论最优: 每个字节只传输一次
# Ring AllReduce: 每个字节传输 2*(N-1)/N 次
    algorithm_overhead = transfer_efficiency if world_size > 1else1.0

return {
'latency_ms': latency_ms,
'throughput_gbps': throughput_gbps, 
'data_size_mb': data_size_mb,
'theoretical_transfer_mb': theoretical_transfer_mb,
'algorithm_overhead': algorithm_overhead
    }

5.5 调试和诊断技术

5.5.1 NCCL 调试级别详解

# NCCL 调试级别配置
export NCCL_DEBUG=TRACE    # 最详细的调试信息
export NCCL_DEBUG=INFO     # 标准调试信息 (推荐)
export NCCL_DEBUG=WARN     # 仅警告和错误 (生产环境)

# 调试子系统选择
export NCCL_DEBUG_SUBSYS=ALL        # 所有子系统
export NCCL_DEBUG_SUBSYS=INIT,NET   # 初始化和网络子系统
export NCCL_DEBUG_SUBSYS=GRAPH      # 通信图构建
export NCCL_DEBUG_SUBSYS=TUNING     # 性能调优信息

# 调试输出示例解析
# [nccl] INFO NCCL_IB_HCA set by environment to mlx5_0
#        ↑     ↑    ↑
#     组件  级别  消息内容

5.5.2 性能瓶颈诊断流程

# 1. 网络连通性检查
ping_test() {
# IB 网络 ping 测试
    ibping -S    # 服务端
    ibping -c 1000 -f <server_lid>  # 客户端
}

# 2. 带宽基准测试  
bandwidth_test() {
# 使用 ib_write_bw 测试原始 IB 带宽
    ib_write_bw -d mlx5_0 -i 1 -s 1048576

# 对比 NCCL 测试结果与原始带宽
# 如果差距过大,可能存在配置问题
}

# 3. 延迟基准测试
latency_test() {
# 使用 ib_write_lat 测试原始 IB 延迟
    ib_write_lat -d mlx5_0 -i 1000

# NCCL 延迟通常比原始 IB 延迟高 2-5 倍
# 这是正常的算法和协议开销
}

# 4. GPU 内存带宽测试
gpu_memory_test() {
# 使用 bandwidthTest (CUDA Samples)
    ./bandwidthTest --memory=pinned --mode=quick

# GPU 内存带宽应远高于网络带宽
# 确保不是 GPU 内存成为瓶颈
}

6. 配置说明

6.1 NCCL 环境变量

脚本会自动配置以下关键的 NCCL 环境变量:

6.1.1 基础配置

  • • NCCL_IB_DISABLE=0: 启用 InfiniBand 支持
  • • NCCL_NET_GDR_LEVEL=2: 启用 GPUDirect RDMA
  • • NCCL_IB_HCA: 自动检测并设置 HCA 设备名

6.1.2 网络类型特定配置

原生 InfiniBand:

  • • NCCL_IB_GID_INDEX=0: 使用默认 GID
  • • NCCL_IB_TC=136: 流控制参数
  • • NCCL_IB_SL=0: 服务级别

RoCE (Ethernet over IB):

  • • NCCL_IB_GID_INDEX=3: RoCE v2 GID
  • • NCCL_IB_TC=136: 流控制参数
  • • NCCL_IB_SL=0: 服务级别
  • • NCCL_SOCKET_IFNAME="": 禁用 Socket 接口

6.2 调试和性能优化

  • • NCCL_DEBUG=INFO: 启用详细日志
  • • NCCL_DEBUG_SUBSYS=INIT,NET: 网络初始化调试
  • • NCCL_IB_TIMEOUT=22: IB 超时设置
  • • NCCL_IB_RETRY_CNT=7: 重试次数

7. 输出文件

7.1 日志文件

  • • 位置: /tmp/nccl_ib_test_YYYYMMDD_HHMMSS.log
  • • 内容: 详细的执行日志,包括所有检查、配置和测试过程

7.2 测试输出

  • • 位置: /tmp/nccl_test_output.log
  • • 内容: NCCL 测试的原始输出,包含性能数据和调试信息

7.3 测试报告

  • • 位置: /tmp/nccl_ib_test_report_YYYYMMDD_HHMMSS.txt
  • • 内容: 格式化的测试报告,包含系统信息、配置参数、测试结果

7.4 临时文件

  • • /tmp/nccl_ib_test.py: 动态生成的 NCCL 测试脚本

8. 性能指标说明

8.1 延迟 (Latency)

  • • 单位: 毫秒 (ms)
  • • 含义: AllReduce 操作的端到端延迟
  • • 典型值: 0.1-2.0 ms (取决于数据大小和网络配置)

8.2 数据吞吐量 (Data Throughput)

  • • 单位: Gbps
  • • 含义: NCCL 操作的数据处理速率
  • • 注意: 这不等同于网络带宽,包含了算法开销

8.3 理论传输量 (Theoretical Transfer)

  • • 单位: MB
  • • 计算公式: Ring AllReduce: 2 * (N-1) / N * data_size
  • • 含义: 理论上需要传输的数据量

9. 故障排除

9.1 常见问题

9.1.1 依赖检查失败

[ERROR] Python3 未安装
[ERROR] PyTorch 未安装或不可用

解决方案: 安装缺失的依赖包

9.1.2 InfiniBand 设备不可用

[ERROR] InfiniBand 设备不可用或未配置

解决方案:

  • • 检查 IB 驱动是否正确安装
  • • 确认 IB 网卡硬件连接正常
  • • 运行 ibstat 检查设备状态

9.1.3 NCCL 测试失败

[ERROR] NCCL 测试执行失败

解决方案:

  • • 检查 GPU 内存是否充足
  • • 确认 NCCL 环境变量配置正确
  • • 查看详细日志文件排查具体错误

9.1.4 网络性能不佳

[WARNING] 数据吞吐量低于预期

解决方案:

  • • 检查 IB 网络拓扑和连接
  • • 验证 GPUDirect RDMA 是否启用
  • • 调整 NCCL 参数优化性能

9.2 调试技巧

9.2.1 启用详细日志

export NCCL_DEBUG=TRACE
export NCCL_DEBUG_SUBSYS=ALL
./nccl_ib_test.sh test

9.2.2 检查 IB 状态

# 查看 IB 设备状态
ibstat

# 查看设备详细信息
ibv_devinfo

# 检查性能计数器
perfquery -a

9.2.3 监控网络流量

# 在测试前后比较计数器
perfquery -a > before.txt
# 运行测试
perfquery -a > after.txt
diff before.txt after.txt

10. 最佳实践

10.1 测试前准备

  • • 建议先运行 ib_health_check.sh 确保 InfiniBand 网络正常
  • • 使用 ib_bandwidth_monitor.sh 监控测试期间的网络性能
  • • 确保所有节点的时间同步
  • • 确保所有 GPU 可用且内存充足
  • • 验证 InfiniBand 网络连接正常
  • • 关闭不必要的后台进程

10.2 性能监控

  • • 在测试期间,可以使用专门的 ib_bandwidth_monitor.sh 脚本监控 InfiniBand 网络性能
  • • 建议在另一个终端窗口运行监控脚本:
    # 在测试期间监控网络性能
    ./ib_bandwidth_monitor.sh -d mlx5_0 -p 1 -t 300

10.3 性能优化

  • • 使用多 GPU 环境进行测试
  • • 确保 GPUDirect RDMA 正确配置
  • • 根据网络类型调整 NCCL 参数

10.4 定期监控

  • • 定期运行脚本检查系统健康状态
  • • 监控 IB 性能计数器变化
  • • 保存测试报告用于性能趋势分析

注意: 本工具专为 NCCL InfiniBand 环境设计,建议在生产环境部署前进行充分测试。