1. NVLink拓扑发现与可视化
任务目标
本案例要求枚举当前主机中GPU与DPU(BlueField)的NVLink连接关系,输出连接矩阵,并生成可视化拓扑图。通过NVML(NVIDIA Management Library)编程接口实现,不依赖外部图数据库或可视化库,使用Python标准库完成数据采集与SVG拓扑生成。
环境依赖
- NVIDIA驱动(含NVML)已安装,执行
nvidia-smi可正常输出 - DPU(BlueField)已通过NVLink连接至GPU,且DPU的NVML可见(需安装Mellanox NVML扩展)
- Python 3.6+,需安装
pynvml库:pip install pynvml
核心实现
以下代码通过NVML枚举所有设备(GPU与DPU),查询每个设备的NVLink链路对端信息,构建连接矩阵并生成SVG拓扑图。代码可直接运行,输出JSON格式连接矩阵与拓扑SVG文件。
import pynvml
import json
import os
def get_device_type(handle):
"""判断设备类型:GPU或DPU(BlueField)"""
try:
name = pynvml.nvmlDeviceGetName(handle).decode()
if 'BlueField' in name or 'DPU' in name:
return 'DPU'
return 'GPU'
except:
return 'GPU'
def enumerate_nvlink_topology():
pynvml.nvmlInit()
device_count = pynvml.nvmlDeviceGetCount()
devices = []
handle_map = {} # index -> (type, name, uuid)
for i in range(device_count):
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
name = pynvml.nvmlDeviceGetName(handle).decode()
uuid = pynvml.nvmlDeviceGetUUID(handle).decode()
dtype = get_device_type(handle)
devices.append({'index': i, 'type': dtype, 'name': name, 'uuid': uuid})
handle_map[i] = handle
# 构建连接矩阵
n = len(devices)
matrix = [[0]*n for _ in range(n)]
links = []
for i in range(n):
handle = handle_map[i]
try:
# 获取NVLink数量
link_count = pynvml.nvmlDeviceGetMaxLinkInfo(handle) if hasattr(pynvml, 'nvmlDeviceGetMaxLinkInfo') else 0
# 遍历可能的NVLink链路
for link_idx in range(link_count):
try:
# 查询链路对端设备
remote = pynvml.nvmlDeviceGetNvLinkRemoteDeviceInfo(handle, link_idx)
remote_handle = remote.deviceHandle
# 找到对端设备索引
for j in range(n):
if handle_map[j] == remote_handle:
matrix[i][j] = 1
links.append((i, j, link_idx))
break
except pynvml.NVMLError:
continue
except pynvml.NVMLError:
continue
pynvml.nvmlShutdown()
return devices, matrix, links
def generate_svg(devices, links, filename='nvlink_topology.svg'):
"""生成SVG拓扑图"""
n = len(devices)
# 计算布局:圆形排列
import math
cx, cy, radius = 200, 150, 100
positions = {}
for i, dev in enumerate(devices):
angle = 2 * math.pi * i / n - math.pi/2
x = cx + radius * math.cos(angle)
y = cy + radius * math.sin(angle)
positions[i] = (x, y)
# 颜色映射
colors = {'GPU': '#76b900', 'DPU': '#00a1e0'}
svg_parts = []
svg_parts.append(f'<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300">')
# 绘制连接线
for src, dst, _ in links:
x1, y1 = positions[src]
x2, y2 = positions[dst]
svg_parts.append(f'<line x1="{x1:.1f}" y1="{y1:.1f}" x2="{x2:.1f}" y2="{y2:.1f}" stroke="#ff6600" stroke-width="2"/>')
# 绘制设备节点
for i, dev in enumerate(devices):
x, y = positions[i]
color = colors.get(dev['type'], '#999999')
svg_parts.append(f'<circle cx="{x:.1f}" cy="{y:.1f}" r="20" fill="{color}" stroke="#333" stroke-width="1.5"/>')
# 设备标签
label = f"{dev['type']}{dev['index']}"
svg_parts.append(f'<text x="{x:.1f}" y="{y+5:.1f}" text-anchor="middle" font-size="10" fill="white" font-family="Arial">{label}</text>')
svg_parts.append('</svg>')
with open(filename, 'w') as f:
f.write('\n'.join(svg_parts))
return filename
if __name__ == '__main__':
devices, matrix, links = enumerate_nvlink_topology()
# 输出连接矩阵
print("=== NVLink连接矩阵 ===")
header = " " + " ".join([f"{d['type'][0]}{d['index']:2d}" for d in devices])
print(header)
for i, row in enumerate(matrix):
line = f"{devices[i]['type'][0]}{devices[i]['index']:2d} "
line += " ".join(["1" if v else "." for v in row])
print(line)
# 输出JSON格式
result = {
'devices': devices,
'matrix': matrix,
'links': [{'src': s, 'dst': d, 'link': l} for s, d, l in links]
}
with open('nvlink_topology.json', 'w') as f:
json.dump(result, f, indent=2)
# 生成SVG
svg_file = generate_svg(devices, links)
print(f"\n拓扑图已保存: {svg_file}")
print(f"连接数据已保存: nvlink_topology.json")
运行与验证
- 保存代码为
nvlink_topology.py,执行python nvlink_topology.py - 程序输出连接矩阵,每行每列对应一个设备(G=GPU,D=DPU),"1"表示存在NVLink连接,"."表示无连接
- 验证通过条件:
- 矩阵为对称矩阵(NVLink为双向连接)
- 对角线为0(设备自身无连接)
- 矩阵中"1"的数量与
nvidia-smi nvlink -s命令显示的链路数一致 - 生成的
nvlink_topology.svg可在浏览器中打开,GPU节点为绿色,DPU节点为蓝色,橙色连线表示NVLink连接
常见问题
- NVML不支持DPU枚举:需安装Mellanox的NVML扩展(
libnvidia-ml.so需包含BlueField支持),或使用nvidia-smi nvlink -s命令交叉验证 - 无NVLink连接:确认GPU与DPU已通过NVLink线缆物理连接,且驱动版本支持NVLink互联
- 权限不足:NVML调用需要root权限,使用
sudo python nvlink_topology.py执行