DCGM 指标与 GPU 健康检查:从 diag 四级到 Prometheus 遥测
一句话:把 GPU 交付上线,不能靠"跑个训练没报错"就算过——DCGM 提供的是三件不同的事:一个能在 2.5 秒内回答"这台机器现在能不能接活"的主动诊断、一套不打扰作业的被动健康监控、以及一个把 GPU 指标变成 Prometheus 时间序列的 exporter。三者分工不清,最容易出现"监控图很好看、故障照样炸"的局面。
一、DCGM 是什么,以及它明确不做什么
DCGM(Data Center GPU Manager)是一个轻量的用户态库与 agent,定位是给 GPU 主机提供统一的管理平面:监控 GPU 行为、配置管理、策略监督、健康与诊断、记账与进程统计,以及 NVSwitch 的配置与监控。它有两种运行形态:
- Standalone:由
nv-hostengine守护进程常驻,dcgmi命令作为客户端连上去; - Embedded:被第三方 agent 嵌进自己的进程里(dcgm-exporter 的容器模式就是这种)。
这个 host engine 不是"命令分发器",它持有实体命名空间、field watch、保留的采样、可复用的 group、模块状态与作业记录。所以它是长期驻留的:多个客户端可以共享同一份采集流。
一个版本相关的硬事实:v2.x 起 DCGM 不再内置 Fabric Manager。NVSwitch 系统必须另外安装 FM,DCGM 只观测 fabric,不负责配置它,也不管 FM 的生命周期。
官方同时明确划了边界——DCGM 诊断不做这四件事:
- 不提供全面硬件诊断;
- 不主动修复问题;
- 不替代厂商现场诊断工具(field diagnostics);
- 不参与 RMA 流程。
这四条决定了它在运维流程里的位置:它是筛子,不是判官。它说"这台机器有问题",下一步是隔离并送修;它说"通过",不等于这张卡永远没问题。
二、实体与 field:先把 ID 从运行时读出来
DCGM 的世界由 entity(实体)和 field(字段)组成。实体不只是 GPU,还可能是 MIG 实例、NVSwitch、NVLink 端口、NVIDIA CPU 及其核心、ConnectX 网卡。
# 盘点本机 host engine 当前管理的实体
$ dcgmi discovery --list
# 用 GPU UUID / PCI bus ID 与资产、调度系统对齐
$ dcgmi discovery --info a --gpuid 0
# MIG 机器上读父子层级
$ dcgmi discovery --compute-hierarchy必须记住的一条:实体 ID 是当前这个 host engine 的本地编号,不是可以跨机器复制的稳定标识。写进工单、写进 CMDB 的应该是 GPU UUID 或 PCI bus ID。
field 是 DCGM 对硬件的观测项,分库存值、gauge、counter、事件四类。watch 告诉 host engine"哪些实体的哪些 field、以多长间隔采集、保留多少历史":
$ dcgmi dmon --list # 列出当前 DCGM 版本支持的 field 目录
$ dcgmi dmon --field-id 150,155 --count 5 # 温度(150) 与功耗(155),采 5 次dmon 建的是临时 watch,默认对所有 GPU 打印已保留的采样。读一个采样通常不会重新查询硬件,时间戳是 DCGM 采集它的时刻——这点在做跨指标关联时很重要。
另外:field 在目录里存在,不代表每张卡都支持。输出里的 N/A 可能是"不支持"、"当前不可用"、"没权限"或"还没采到",不要一律当硬件故障。
三、diag 四个级别:时间预算是选级的唯一依据
dcgmi diag 的四个运行级别是留给不同场景的,官方把耗时写得很清楚(Hopper 平台实测):
| 级别 | 名称 | 时间预算 |
|---|---|---|
-r 1 | Quick / System Validation | < 2.5 秒 |
-r 2 | Medium / Extended System Validation | 4 卡 < 2.5 分钟;8 卡 < 10.5 分钟 |
-r 3 | Long / System HW Diagnostics | 4 卡 < 10 分钟;8 卡 < 35 分钟 |
-r 4 | Extended | 4 卡 < 45 分钟;8 卡 < 2.25 小时 |
高层级包含低层级的全部测试。插件与级别的对应关系(同一张官方表):
| 插件 | r1 | r2 | r3 | r4 |
|---|---|---|---|---|
software | ✓ | ✓ | ✓ | ✓ |
pcie(含 NVLink) | ✓ | ✓ | ✓ | |
memory | ✓ | ✓ | ✓ | |
memory_bandwidth | ✓ | ✓ | ✓ | |
diagnostic | ✓ | ✓ | ||
targeted_stress | ✓ | ✓ | ||
targeted_power | ✓ | ✓ | ||
nvbandwidth | ✓ | ✓ | ||
nccl_tests | ✓ | ✓ | ||
memtest | ✓ | |||
pulse(Input EDPp) | ✓ |
这张表直接决定选级策略:
- r1 是门禁。2.5 秒跑完,适合放在作业启动的 prologue 里——每次分配前跑一遍,成本可以忽略;
- r2 是失败作业的收尾检查。作业莫名挂了、卡已空闲,用它把内存与 PCIe/NVLink 扫一遍;
- r3 是管理员定位。真正做加压力测试(诊断、定向压力、定向功耗、NVLink 带宽、NCCL),要停机或至少把卡从调度里摘出来;
- r4 是归修前的长跑。memtest 与 pulse 只在 r4 出现,45 分钟到 2 小时以上的代价意味着它属于维护窗口,不属于日常。
四、参数与判定阈值:默认值是"能跑",不是"该用"
# 指定实体跑某级
$ dcgmi diag -r 2 --entity-id gpu:0 --json
# 只跑指定插件(逗号分隔)
$ dcgmi diag -r "pcie,diagnostic"
# 覆盖单个插件参数
$ dcgmi diag -r 3 -p diagnostic.test_duration=300.0几个高频参数与它们的默认值:
| 参数 | 默认 | 说明 |
|---|---|---|
diagnostic.test_duration | 180.0 | 秒;加压力测试的持续时长 |
diagnostic.matrix_dim | 2048.0(Blackwell 起 8192.0) | GEMM 起始维度 |
diagnostic.gflops_tolerance_pcnt | 0.0 | 低于全体均值多少比例判失败;0 表示关闭比较 |
pcie.max_pcie_replays | 80.0 | 单卡在整个插件时长内允许的 PCIe 重放上限 |
pcie.max_latency | 100000 | 微秒;超时判失败 |
pcie.min_pci_width | 1.0 | 16x 要写成 16.0 |
memory.minimum_allocation_percentage | 75.0 | 显存测试分配比例 |
三条实操结论:
gflops_tolerance_pcnt是横向比较,不是绝对性能承诺。它比较的是"这台机器上各卡之间的均值",所以一台 8 卡机器里有一张卡明显蔫了才抓得到;单卡机器上这个参数没有输入意义;min_pci_width不设等于不检查。默认 1.0 意味着 x16 的卡降速到 x1 也能通过。要抓"插错槽位/降速"这类问题,必须显式写16.0;temperature_max的行为已变。老版本用它卡测试期间的温度上限;较新版本(DCGM 4.6)改用 GPU 自报的最高工作温度做公共错误监控,这个参数只为兼容保留——不要再用它设站点自己的低温阈值,该在外部监控里做。
另外,--fail-early 值得单独提:开启后 targeted_power、targeted_stress、diagnostic 会在测试运行期间每 5 秒检查一次失败条件(--check-interval 可调 1–300 秒),而不是等测试跑完才判定。跑 r3 这种 10 分钟起的测试,早失败能省下大量墙钟时间。
五、退出码与日志:自动化必须读对这两样
dcgmi 的退出码是 dcgmReturn_t 的无符号 8 位补码表示(负值转成正数),信号则是 128 + 信号值。常用的几个:
| 值 | 符号 | 含义 |
|---|---|---|
0 | DCGM_ST_OK | 成功 |
255 | DCGM_ST_BADPARAM | 参数错误(注意:-1 也映射成 255) |
226 | DCGM_ST_NVVS_ERROR | 诊断成功执行,但报告了错误(这是最需要区分的一档) |
217 | DCGM_ST_DIAG_ALREADY_RUNNING | 已有一个诊断在跑 |
237 | DCGM_ST_RESET_REQUIRED | GPU 需要复位 |
227 | DCGM_ST_REQUIRES_ROOT | host engine 非 root 运行,做不了这个操作 |
226 是最容易被误判的:它不代表"命令没执行",而代表"执行完了,结果里判了失败"。只看退出码会漏掉具体是哪张卡哪个插件挂了,所以自动化脚本应该同时读 -j 的 JSON 输出,把 test 名、entity 结果、错误码一起落库。
日志默认在 /var/log/nvidia-dcgm/nvvs.log。要在事后复盘,这个文件和 JSON 结果比一次退出码有价值得多——官方也要求升级问题时保留完整命令、目标选择、完整输出、debug 日志与插件统计数据。
六、多节点诊断:门槛比单机高得多
dcgmi mndiag 用 MPI 在所有节点上同时跑一个叫 mnubergemm 的 GEMM 压力应用,验证跨机互联、内存与算力。它能抓的东西单机诊断抓不到(跨节点带宽不达标、NCCL 初始化失败)。
# 在一台节点上发起,hostList 里包含它自己
$ dcgmi mndiag --hostList "node1;node2;node3"
# 自定义时长(默认 3600 秒)
$ dcgmi mndiag --hostList "node1;node2" -p "mnubergemm.time_to_run=600"
# JSON 输出
$ dcgmi mndiag --hostList "node1;node2" -j但它有一串硬前提,缺一个就跑不起来:
- DCGM 4.3.0 起才支持,且当前只支持 GB200 NVL / GB300 NVL;
- 所有节点装 OpenMPI,全部节点同一驱动版本;
- 节点间 passwordless SSH,且私钥必须以不加密形式落盘——ssh-agent 不管用,因为 SSH 会话是由
nv-hostengine进程拉起的,继承不到你的 shell 环境; - 每个节点都要有
nv-hostengine在跑; - 多节点 NVLink 系统必须先把 IMEX channel 配好,否则 NCCL 初始化直接失败,报
unhandled system error; - 运行超时限制是默认 1 小时 + 60 秒。
最后两条最值得记:mndiag 失败很多时候不是硬件问题,而是 IMEX 没配或 SSH 密钥加密了。
七、被动健康监控:不打扰作业的那一层
主动诊断要占卡,日常不可能一直跑。日常靠的是 health watch——它只评估普通运行期间采集的遥测,不施加任何负载:
$ dcgmi group --create fabric-adapters --add cx:0
$ dcgmi health --set x --group <group-id>
$ dcgmi health --check --group <group-id>几点语义要注意:
dcgmi health --set a --group s里的s是内置的"全部 NVSwitch"组,a是包含 NVSwitch 检查在内的全量 watch 选择器;- watch 需要时间积累采样,刚开启就 check 往往还没数据;
- 诊断与健康监控是两套证据,不能互替:一台机器可能被动监控零告警,主动诊断却失败;也可能健康里留着历史告警,而后续主动测试全过。两者一起看,才是这台机器当前状态的完整叙述。
八、dcgm-exporter:把指标接进 Prometheus
dcgm-exporter 是 Go 写的指标导出器,把 GPU 指标以 /metrics 暴露给 Prometheus 类系统:
$ docker run -d --rm --gpus all --net host --cap-add SYS_ADMIN \
nvcr.io/nvidia/k8s/dcgm-exporter:<tag>-ubuntu20.04 \
-f /etc/dcgm-exporter/dcp-metrics-included.csv
$ curl localhost:9400/metrics默认行为与常见改动:
| 项 | 默认 | 说明 |
|---|---|---|
| 监听地址 | :9400 | -a 可改 |
| 采集间隔 | 30000 ms | -c 可改;30 秒对排障偏粗 |
| 采集项清单 | /etc/dcgm-exporter/default-counters.csv | -f 指定自定义 CSV |
| 连接已有 host engine | 未启用 | -r localhost:5555(DGX 这类已自带 DCGM 的机器必须用) |
| 设备选择 | f(MIG 关=全部 GPU,MIG 开=全部实例) | -d g:0,1 / -d i:0,2-4 |
版本兼容性有一条硬约束:exporter 镜像里带的是自己的 libdcgm.so,它要和宿主 nv-hostengine 用私有协议通信,所以exporter 基于的 DCGM 版本必须 ≥ 宿主 DCGM 版本。用 nv-hostengine --version 对照镜像 tag 即可。
关键指标及其运维含义:
| 指标 | 含义 | 什么时候看 |
|---|---|---|
DCGM_FI_DEV_GPU_TEMP / DCGM_FI_DEV_MEMORY_TEMP | 核心温度 / 显存温度 | 散热异常、降频排查 |
DCGM_FI_DEV_POWER_USAGE | 板卡功耗 | 与 TDP 对照,判断是否被功耗墙限制 |
DCGM_FI_DEV_SM_CLOCK | SM 时钟 | 与标称对照,抓降频 |
DCGM_FI_DEV_PCIE_REPLAY_COUNTER | PCIe 重放计数 | 链路质量问题的最早信号之一 |
DCGM_FI_DEV_XID_ERRORS | 最近一次 Xid 值 | 与内核日志关联,是 GPU 级故障的入口 |
DCGM_FI_DEV_FB_FREE / FB_USED | 显存空闲/已用 | 泄漏、碎片、调度是否真的隔离 |
DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL | NVLink 带宽总量 | P2P 路径是否在工作 |
DCGM_FI_PROF_PIPE_TENSOR_ACTIVE | Tensor 管线活跃度(0~1) | 判断算力是否真被喂饱 |
DCGM_FI_PROF_DRAM_ACTIVE | 显存带宽活跃度 | 判断瓶颈在算力还是访存 |
DCGM_FI_PROF_PCIE_TX_BYTES / RX_BYTES | PCIe 收发字节 | 数据加载路径是否成为瓶颈 |
两张 0~1 的 PROF 指标(Tensor 活跃、DRAM 活跃)是判断"GPU 利用率虚高"的关键:利用率 95% 但 Tensor 活跃度只有 0.3,说明显式算力没跑满、瓶颈在数据或同步上。
MIG 场景下,指标会同时带 GPU_I_PROFILE / GPU_I_ID 标签,粒度落到 GPU 实例级;此时不能按 GPU 聚合,否则会把多个实例的使用叠在一张图上。
还有一条安全边界:host engine 的 TCP 协议不带认证、授权与加密,所以 5555 端口只能放在受信管理网内,别暴露到业务网。
九、三层栈怎么配合:一张决策表
| 场景 | 用哪一层 | 具体动作 |
|---|---|---|
| 作业分配前,2 秒内判断能否接活 | 主动诊断 r1 | dcgmi diag -r 1 --entity-id gpu:N |
| 作业挂了,卡已空闲 | 主动诊断 r2 | -r 2 --json,把失败实体与错误码落库 |
| 怀疑某子系统(PCIe / 内存 / 通信) | 指定插件 | -r "pcie,diagnostic",配合 --iterations |
| 日常运行期 | 被动 health watch | health --set + 定时 --check |
| 集群级基准与验收 | 多节点诊断 | mndiag --hostList,先确认 IMEX 与 SSH |
| 长期趋势、容量、告警 | exporter + Prometheus | 30 秒以下间隔,重点抓 PCIe replay、Xid、降频 |
| 送修前取证 | r3/r4 + JSON + 日志 | 保留命令、输出、nvvs.log、插件统计 |
上线验收清单
dcgmi discovery --list的实体数量与物理卡数一致,MIG 机器上父子层级正确;dcgmi diag -r 1全卡通过且耗时在 3 秒内,已接入 prologue 或交付流水线;dcgmi diag -r 2 -j在至少一台样机上跑通,JSON 能被脚本解析出 test/entity/错误码;- 关键插件参数按站点策略显式设定(尤其
pcie.min_pci_width=16.0),不是全用默认; dcgmi health --set a已开启,--check的输出有告警分级;- dcgm-exporter 版本 ≥ 宿主 DCGM 版本,
-r指向宿主 5555,:9400/metrics可抓; - Prometheus 侧对
DCGM_FI_DEV_PCIE_REPLAY_COUNTER、DCGM_FI_DEV_XID_ERRORS、DCGM_FI_PROF_PIPE_TENSOR_ACTIVE建了告警/看板; nvvs.log有轮转策略,别在需要取证时发现日志被覆盖。
收口三句
- 三层职责不能混:diag 是主动取证(要停机或摘卡)、health 是被动观察(不影响作业)、exporter 是长期时间序列——用其中一个去替代另一个,必然留下盲区;
- 默认值是"能跑",不是"该用":
min_pci_width=1.0、gflops_tolerance_pcnt=0.0这类默认等于把检查关掉,站点必须显式定策略; - 退出码 226 与 JSON 必须一起读:诊断跑完但判失败,是最容易被流水线当成"执行成功"放过的一档。