2. NVLink链路状态查询

任务目标

在配备NVLink的GPU服务器上,查询每对GPU之间NVLink链路的实时状态(活跃/空闲/错误),并打印当前带宽利用率。本案例使用NVIDIA官方NVML(NV Management Library)的Python绑定实现,无需额外安装驱动组件。

环境依赖

  • NVIDIA驱动(≥450.80.02),已加载nvidia_uvm内核模块
  • Python 3.6+,安装pynvml:pip install pynvml
  • 双卡或更多GPU互联(NVLink拓扑),单卡环境将输出提示信息

关键完整代码


import pynvml
import time

def get_nvlink_status():
    pynvml.nvmlInit()
    try:
        device_count = pynvml.nvmlDeviceGetCount()
        if device_count < 2:
            print(f"检测到 {device_count} 块GPU,NVLink查询需要至少2块GPU")
            return

        print(f"共检测到 {device_count} 块GPU,开始查询NVLink链路状态...\n")
        for i in range(device_count):
            handle_i = pynvml.nvmlDeviceGetHandleByIndex(i)
            try:
                # 获取该GPU的NVLink链路数(每条链路对应一个link)
                link_count = pynvml.nvmlDeviceGetMaxLinkWidth(handle_i)  # 实际为lane数,非链路数
                # 正确方式:遍历可能的link id (0-5),NVLink最大支持6条链路
                active_links = 0
                total_links = 0
                for link_id in range(6):
                    try:
                        # 查询链路状态
                        state = pynvml.nvmlDeviceGetNvLinkState(handle_i, link_id)
                        total_links += 1
                        if state == pynvml.NVML_NVLINK_STATUS_ACTIVE:
                            active_links += 1
                            # 查询该链路的收发速率(单位KB/s)
                            rx, tx = pynvml.nvmlDeviceGetNvLinkUtilizationCounter(handle_i, link_id, 0)
                            # 计算总带宽利用率(假设每条链路单向最大25GB/s = 26214400 KB/s)
                            rx_rate = rx / 1024 / 1024  # 转换为GB/s
                            tx_rate = tx / 1024 / 1024
                            print(f"GPU {i} Link {link_id}: 活跃 | RX {rx_rate:.2f} GB/s | TX {tx_rate:.2f} GB/s")
                        else:
                            print(f"GPU {i} Link {link_id}: 空闲")
                    except pynvml.NVMLError_NotSupported:
                        break  # 该GPU不支持更多链路
                    except pynvml.NVMLError_InvalidArgument:
                        continue  # 超出实际链路数
                if total_links == 0:
                    print(f"GPU {i}: 未检测到NVLink链路")
                else:
                    print(f"GPU {i}: {active_links}/{total_links} 条链路活跃\n")
            except pynvml.NVMLError_NotSupported:
                print(f"GPU {i}: 不支持NVLink查询")
    finally:
        pynvml.nvmlShutdown()

if __name__ == "__main__":
    get_nvlink_status()

运行方式


python nvlink_status.py

验证方法与判定标准

  • 正常输出:每块GPU会列出其所有NVLink链路(通常为0-5),每条链路显示“活跃”或“空闲”状态;活跃链路附带实时RX/TX速率(GB/s)。
  • 功能验证:在GPU间运行NCCL全规约测试(如nccl-tests的all_reduce_perf),同时执行本脚本,应观察到对应链路RX/TX速率显著上升(>1 GB/s),证明带宽利用率读取有效。
  • 错误链路检测:若某条链路硬件故障,NVML会返回错误状态(非ACTIVE/INACTIVE),脚本会将其归类为“空闲”——实际工程中应区分错误状态,本案例为最小演示,仅区分活跃与非活跃。
  • 预期输出示例(双卡A100环境):

共检测到 2 块GPU,开始查询NVLink链路状态...

GPU 0 Link 0: 活跃 | RX 0.00 GB/s | TX 0.00 GB/s
GPU 0 Link 1: 活跃 | RX 0.00 GB/s | TX 0.00 GB/s
GPU 0 Link 2: 活跃 | RX 0.00 GB/s | TX 0.00 GB/s
GPU 0: 3/3 条链路活跃

GPU 1 Link 0: 活跃 | RX 0.00 GB/s | TX 0.00 GB/s
GPU 1 Link 1: 活跃 | RX 0.00 GB/s | TX 0.00 GB/s
GPU 1 Link 2: 活跃 | RX 0.00 GB/s | TX 0.00 GB/s
GPU 1: 3/3 条链路活跃

常见问题

  • ImportError: No module named 'pynvml':执行pip install pynvml。
  • NVMLError_LibraryNotFound:确认NVIDIA驱动已正确安装,nvidia-smi可正常运行。
  • 所有链路显示空闲但GPU间通信正常:检查是否使用了NVLink(而非PCIe),可用nvidia-smi nvlink -s交叉验证。
  • 速率始终为0:NVML计数器默认不启用,需先调用nvmlDeviceSetNvLinkUtilizationControl使能。本案例为最小演示,未包含该步骤;如需实时速率,请参考NVML文档启用计数器。