AI 加速器系列 · 第 7 篇
GPU 利用率 100%!一切看起来很好。直到你发现 Tensor Core 使用率只有 15%,80% 的时间 GPU 在等 CPU 喂数据和 AllReduce 通信。"GPU 利用率"是 AI 基础设施里最大的谎言。
一、为什么 GPU 监控跟 CPU 监控完全不同
CPU 监控很简单。top 告诉你 CPU 在跑什么,vmstat 告诉你上下文切换是否频繁,iostat 告诉你磁盘是否瓶颈。这些指标的含义是清晰的------CPU 利用率 80% 意味着 CPU 真的在干活,20% 的时间在 idle。
GPU 不是这样。nvidia-smi 显示的 GPU 利用率代表的是"过去一秒内,有多少时间 GPU kernel 在执行"。注意------只要有任何 kernel 正在执行,就计入"忙碌"。这意味着:
erlang
一个向量加法 kernel 占着 SM 跑 → GPU 利用率 100%
一个矩阵乘法 kernel 只用 15% 的 Tensor Core 跑 → GPU 利用率 100%
一个 kernel 在等显存数据加载,SM 空转 → GPU 利用率 100%
同样的 100%,实际有效算力可能差 6 倍。所以 GPU 监控必须从四个维度展开:
markdown
GPU 观测四象限
计算效率 显存效率
┌─────────────────┐ ┌─────────────────────┐
│ Tensor Core 占比 │ │ 带宽利用率 │
│ SM 占用率 │ │ 碎片化程度 │
│ FP16/FP8/FP4 │ │ HBM vs SRAM 命中率 │
└─────────────────┘ └─────────────────────┘
通信效率 功耗/稳定性
┌─────────────────┐ ┌─────────────────────┐
│ NVLink 带宽 │ │ 实际功耗 vs TDP │
│ IB/RoCE 吞吐 │ │ 降频次数 │
│ NCCL 耗时占比 │ │ XID 错误 │
└─────────────────┘ └─────────────────────┘
没有哪一个维度单独能说明 GPU 的健康状态------四个维度交叉校验,才能判断训练任务是真的在高效运行还是"假忙碌"。
二、DCGM:NVIDIA 的数据中心 GPU 遥测标准
DCGM(Data Center GPU Manager)是 NVIDIA 官方出品的 GPU 遥测和诊断套件。它不是一个简单的 metrics exporter------而是一套完整的 GPU 生命周期管理系统。
架构
scss
┌─────────────────────────────────────────────┐
│ DCGM 体系 │
│ │
│ ┌───────────┐ ┌───────────┐ ┌──────────┐ │
│ │Host Engine│ │Diagnostics│ │ Policy │ │
│ │ (采集) │ │ (诊断) │ │ Actions │ │
│ │ │ │ │ │ (动作) │ │
│ │ 100+ 指标 │ │ Level 1-4 │ │ Taint/迁移 │ │
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ ▼ │
│ ┌───────────────────┐ │
│ │ NVML Library │ │
│ │ (底层驱动接口) │ │
│ └───────────────────┘ │
└─────────────────────────────────────────────┘
- Host Engine:持久守护进程,通过 NVML(NVIDIA Management Library)每 10ms-1s 采集一次 GPU 遥测数据。包括 SM 利用率、显存带宽、NVLink 吞吐、功耗、温度、PCIe 吞吐、时钟频率、ECC 错误计数等 100+ 个指标。
- Diagnostics:四级诊断体系------Level 1(快速自检,秒级)、Level 2(中等深度,分钟级)、Level 3(全量压力测试,小时级)、Level 4(长时间浸泡测试,天级)。Level 3 会跑完整的显存带宽测试、计算正确性测试、NVLink 连通性测试。
- Policy Actions:检测到异常后自动执行的修复动作------GPU 降级、节点 Taint、Pod 驱逐或迁移。
核心指标表
DCGM 暴露的指标分为 12 个 Field Group(字段组)。以下是训练和推理场景最关键的一组:
| 指标 | 含义 | 正常范围 | 告警阈值 |
|---|---|---|---|
DCGM_FI_DEV_GPU_UTIL |
GPU kernel 执行时间占比 | - | 不要单独使用------它与实际效率无关 |
DCGM_FI_PROF_PIPE_TENSOR_ACTIVE |
Tensor Core 管道活跃占比 | > 50% | < 20% 说明模型瓶颈不在计算,在数据/通信 |
DCGM_FI_PROF_PIPE_FP16_ACTIVE |
FP16 管道活跃占比 | 取决于精度 | 全 FP32 且 Tensor Core 低 → 没开混合精度训练 |
DCGM_FI_DEV_FB_USED |
显存(Framebuffer)已用量 | - | > 95% → 即将 OOM,考虑减小 batch size |
DCGM_FI_DEV_FB_FREE |
显存剩余量 | - | < 4GB → 碎片化风险高 |
DCGM_FI_PROF_DRAM_ACTIVE |
HBM 显存读写活跃占比 | 30-70% | > 90% → 显存带宽瓶颈 |
DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL |
NVLink 总吞吐 | 接近理论峰值 | < 50% 理论峰值 → NVLink 降速或拓扑异常 |
DCGM_FI_DEV_POWER_USAGE |
实时功耗 | 接近 TDP(如 A100 400W) | 远低于 TDP 且 GPU_UTIL 高 → GPU 在降频运行 |
DCGM_FI_DEV_PCIE_TX_THROUGHPUT |
PCIe 发送吞吐 | - | 持续接近 PCIe 带宽上限 → Host-to-Device 数据搬运瓶颈 |
DCGM_FI_DEV_XID_ERRORS |
XID 错误累计计数 | 严格为 0 | > 0 → 立即告警,根据 XID 编号判断严重性 |
DCGM_FI_DEV_ECC_CURRENT |
当前 ECC 错误数 | 0 | > 0 → 显存有可纠正单比特错误,累积可能升级 |
DCGM_FI_DEV_CLOCK_THROTTLE_REASONS |
时钟降频原因编码 | 0 | 非零 → GPU 因为功耗/温度/电流限制在降频 |
XID 错误快速参考
XID(eXternal ID)是 NVIDIA GPU 驱动报告错误的编码。不是所有 XID 都致命,但任何一个 XID > 0 都意味着发生了不该发生的事:
ini
XID 48 = 双比特显存错误(Uncorrectable ECC)
→ 硬件故障,GPU 必须更换,数据可能已损坏
XID 79 = GPU 从 PCIe 总线上掉落了("GPU fell off the bus")
→ 驱动崩溃/硬件故障/电源不足,应用进程被 kill
XID 45 = 显存页退役(Page retirement)
→ 部分显存扇区被标记为不可用,显存容量减少
XID 31 = GPU 内部微控制器超时
→ 可能由功耗不足、散热问题、驱动 bug 触发
XID 13 = 图形引擎挂起(Graphics Engine Hang)
→ 在计算密集型训练中较少见,但可能表明加速卡压力过大
XID 61 = ECC 单比特错误超过阈值被报告
→ 显存磨损的早期信号,先于 XID 48 出现
告警策略:XID 48 / XID 79 → 紧急,自动 Taint 节点并通知 SRE;XID 45 → 高危,标记节点为"降级",不再调度新训练任务;XID 31 → 中等,观察是否复现,连续 3 次触发 Taint。
三、DCGM Exporter → Prometheus → Grafana 完整链路
整体架构
bash
┌──────────────────────────────────────────────────────────────┐
│ GPU Node │
│ ┌──────────┐ ┌──────────────────┐ │
│ │ GPU 0 │ │ DCGM daemon │ │
│ │ GPU 1 │◄┼──────────────────┤ │
│ │ GPU 2 │ │ (Host Engine) │ │
│ │ GPU 3 │ └────────┬─────────┘ │
│ └──────────┘ │ Unix Socket / TCP │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ DCGM Exporter (sidecar) │ │
│ │ - 从 DCGM Host Engine 拉取遥测数据 │ │
│ │ - 暴露 :9400/metrics (Prometheus 格式) │ │
│ │ - 支持 GPU 级别标签注入 │ │
│ └────────────────────┬────────────────────┘ │
└───────────────────────┼──────────────────────────────────────┘
│ scrape (15s interval)
▼
┌─────────────────────────┐
│ Prometheus │
│ - 持久化时序数据 │
│ - PromQL 告警规则引擎 │
│ - 多集群联邦 │
└────────────┬────────────┘
│ data source
▼
┌─────────────────────────┐
│ Grafana │
│ - GPU 集群全局仪表盘 │
│ - 训练任务钻取视图 │
│ - NVLink/NCCL 健康面板 │
└─────────────────────────┘
DCGM Exporter 部署
通过 NVIDIA GPU Operator 统一部署,在 ClusterPolicy CR 中启用 DCGM Exporter:
yaml
apiVersion: nvidia.com/v1
kind: ClusterPolicy
metadata:
name: gpu-cluster-policy
spec:
dcgmExporter:
enabled: true
env:
- name: DCGM_EXPORTER_LISTEN
value: ":9400"
- name: DCGM_EXPORTER_KUBERNETES
value: "true" # 自动注入 K8s Pod/Node 标签
- name: DCGM_EXPORTER_COLLECTORS
value: "/etc/dcgm-exporter/default-counters.csv" # 指标白名单
serviceMonitor:
enabled: true
interval: 15s
# 自动创建 ServiceMonitor CRD,Prometheus Operator 自动发现
自定义指标采集策略。default-counters.csv 包含 60+ 指标,但部分高采样率指标会显著增加 Prometheus 的存储压力。根据场景剪裁:
csv
# 训练场景关键指标(低频采样就够,大部分指标 10s-30s 采样)
DCGM_FI_DEV_GPU_UTIL, gauge, GPU Utilization
DCGM_FI_PROF_PIPE_TENSOR_ACTIVE, gauge, Tensor Core Active
DCGM_FI_DEV_FB_USED, gauge, Framebuffer Used (MB)
DCGM_FI_DEV_FB_FREE, gauge, Framebuffer Free (MB)
DCGM_FI_PROF_DRAM_ACTIVE, gauge, DRAM Active
DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL, counter, NVLink Bandwidth Total
DCGM_FI_DEV_POWER_USAGE, gauge, Power Usage (W)
DCGM_FI_DEV_XID_ERRORS, counter, XID Errors
DCGM_FI_DEV_CLOCK_THROTTLE_REASONS, gauge, Clock Throttle Reasons
DCGM_FI_DEV_ECC_CURRENT, counter, ECC Errors
DCGM_FI_DEV_PCIE_TX_THROUGHPUT, counter, PCIe TX Throughput
Prometheus 告警规则
告警规则不是"超阈值就发通知"------需要避开常见误报并关联业务上下文:
yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: gpu-alerts
namespace: monitoring
spec:
groups:
# --- 硬件故障(立即响应)---
- name: gpu-hardware-critical
rules:
- alert: GPUXidCriticalError
expr: increase(DCGM_FI_DEV_XID_ERRORS[5m]) > 0
for: 1m
labels:
severity: critical
component: gpu
annotations:
summary: "GPU {{ $labels.gpu }} XID error detected"
description: >
Node {{ $labels.node }}, GPU {{ $labels.gpu }} reported XID error.
XID values seen: {{ $value }}.
Common causes: HW failure (XID 48), GPU fell off bus (XID 79).
# --- 显存告警(即将 OOM)---
- name: gpu-memory
rules:
- alert: GPUMemoryHighUsage
expr: |
(DCGM_FI_DEV_FB_USED / (DCGM_FI_DEV_FB_USED + DCGM_FI_DEV_FB_FREE)) > 0.95
for: 5m
labels:
severity: warning
annotations:
summary: "GPU {{ $labels.gpu }} memory usage > 95%"
# --- 计算效率告警 ---
- name: gpu-efficiency
rules:
- alert: GPULowTensorCoreUtilization
expr: |
DCGM_FI_DEV_GPU_UTIL > 80
and
DCGM_FI_PROF_PIPE_TENSOR_ACTIVE < 20
for: 10m
labels:
severity: warning
annotations:
summary: "GPU busy but Tensor Core idle"
description: >
GPU {{ $labels.gpu }}: GPU_UTIL={{ $labels.DCGM_FI_DEV_GPU_UTIL }}%,
but Tensor Core only {{ $value }}% active.
Likely bottlenecked by data loading or communication, not compute.
# --- 降频检测 ---
- name: gpu-throttling
rules:
- alert: GPUClockThrottling
expr: DCGM_FI_DEV_CLOCK_THROTTLE_REASONS > 0
for: 5m
labels:
severity: warning
annotations:
summary: "GPU {{ $labels.gpu }} clock throttling active"
description: >
Throttle reason mask: {{ $value }}.
Check: power limit, thermal limit, or current limit.
Grafana 仪表盘设计
三块仪表盘对应三个关注层级:
第一块:集群全局概览(Cluster Overview)
做"红绿灯"式健康总览------80% 的日常巡检在这一块面板上完成:
scss
┌──────────────────────────────────────────────────────────┐
│ GPU Cluster Health [Last 1h] [🔴3 ⚠5]│
├───────────────────┬──────────────────┬───────────────────┤
│ GPU Count │ 256 │ Healthy │ 248 │ Degraded │ 8 │
│ XID Errors│ 0 │ Throttle│ 3 GPU │ High Mem │ 12 GPU│
├───────────────────┴──────────────────┴───────────────────┤
│ Top 10 GPU by Tensor Core Util (line chart) │
│ Bottom 10 GPU by NVLink BW (line chart) │
│ Average Power vs TDP per Node (gauge) │
│ FB Memory Distribution Histogram (heatmap) │
└──────────────────────────────────────────────────────────┘
第二块:训练任务深钻(Training Job Deep Dive)
按 training-job 标签筛选,展示单个训练任务的 GPU 效率全貌:
- MFU 估算:
TensorCoreActive / GPUUtil * FP16_Peak_TFLOPS / GPU_Actual_TFLOPS - 各 GPU 间的 Tensor Core 利用率方差------方差大说明负载不均衡(DataLoader 问题或网络拓扑不对等)
- NCCL AllReduce 时间占比:
NVLink_BW_Actual / NVLink_BW_Peak结合 ResNet-50/NCCL 测试基线
第三块:NVLink + NCCL 健康面板
训练任务突然变慢时首先打开的面板:
bash
Panel: NVLink Bandwidth per GPU Pair (heatmap)
GPU0→GPU1: ████████ 850 GB/s (▼ 5% vs peak)
GPU2→GPU3: ████░░░░ 420 GB/s (▼ 53% vs peak) ← 异常!
GPU4→GPU5: ████████ 880 GB/s (normal)
Panel: NVLink Error Count (counter, per link)
→ 任何非零值都说明物理链路或线缆有问题
Panel: NCCL Bus Bandwidth Histogram
→ 预期:集中在 ~280 GB/s (A100 SXM)
→ 异常:双峰分布或有 15% 远离均值 → 网络拓扑有非对称链路
Grafana Dashboard JSON 关键片段
仪表盘的变量筛选器让同一块面板服务于所有训练任务:
json
{
"templating": {
"list": [
{
"name": "training_job",
"label": "Training Job",
"type": "query",
"datasource": "Prometheus",
"query": "label_values(DCGM_FI_DEV_GPU_UTIL, training_job)",
"multi": false,
"includeAll": true
},
{
"name": "node",
"label": "GPU Node",
"type": "query",
"datasource": "Prometheus",
"query": "label_values(DCGM_FI_DEV_GPU_UTIL{training_job=\"$training_job\"}, node)",
"multi": true
}
]
},
"panels": [
{
"title": "Tensor Core Utilization (per GPU)",
"targets": [
{
"expr": "DCGM_FI_PROF_PIPE_TENSOR_ACTIVE{training_job=\"$training_job\", node=~\"$node\"}",
"legendFormat": "{{gpu}}"
}
],
"thresholds": [
{ "value": 20, "color": "red", "op": "lt" },
{ "value": 50, "color": "yellow", "op": "lt" },
{ "value": 80, "color": "green", "op": "gte" }
]
},
{
"title": "NVLink Bandwidth (node-level aggregated)",
"targets": [
{
"expr": "sum by (node) (rate(DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL{node=~\"$node\"}[5m]))",
"legendFormat": "{{node}}"
}
]
}
]
}
四、SLO/A 监控:AI 服务的生死线
GPU 硬件监控解决的是"卡是不是坏了"的问题,SLO 监控解决的是"服务是不是在正常服务用户"的问题。两者缺一不可------GPU 全绿但用户体感烂的情况太常见了。
推理服务 SLO
大模型推理是一个延迟敏感且成本极高的服务。一次请求可能跨越:
scss
用户请求 → API 网关 → 推理服务 → Preprocessing(CPU)
→ Tokenizer → Model Forward(GPU) → KV Cache Lookup
→ Token Generation × N → Detokenizer → Postprocessing
→ API 响应
核心 SLO 指标:
| 指标 | 目标 | 说明 |
|---|---|---|
| Time to First Token (TTFT) | P95 < 500ms | 用户感知延迟的关键------"模型是不是卡住了" |
| Token Generation Latency | P95 < 50ms/token | 影响流式输出的流畅度 |
| End-to-End Latency | P99 < 5s (100 token) | 包含预处理+推理+后处理的总延迟 |
| QPS (Queries Per Second) | 随 TPS 线性增长 | 并发能力的直接度量 |
| Token Per Second (TPS) | 基准性能的 90%+ | 发现 GPU 性能退化 |
| OOM Rate | < 0.1% | 请求触发 CUDA OOM 的比例------直接故障 |
| Request Timeout Rate | < 0.5% | 超过 deadline 被取消的请求比例 |
注意------推理的 TTFT 跟 GPU 时钟频率不是线性关系。GPU 降频 15% 可能导致 TTFT 恶化 80%。原因:TTFT 包含了大量的 kernel launch 开销、CUDA context 切换、KV Cache 分配。GPU 降频直接拉长每个 kernel 的执行时间,这些固定开销的累积效应对首 token 延迟的影响远超对吞吐的影响。所以 GPU 降频监测量的是根因,TTFT 监测量的是用户体验------两者必须对应。
训练 SLO:MFU(Model FLOPS Utilization)
训练任务不看 QPS------看的是有效浮点运算效率:
erlang
MFU = 实际达到的 TFLOPS / GPU 理论峰值 TFLOPS
MFU 与 GPU_UTIL 的关键区别:
GPU 有 312 TFLOPS (A100 FP16)
████████████████████████████████████████████ 312 TFLOPS (理论峰值)
████████████████████████░░░░░░░░░░░░░░░░░░░ 180 TFLOPS (实际有效算力)
GPU_UTIL = 98% ← 几乎所有时间都有 kernel 在跑
MFU = 58% ← 但有效算力只有理论峰值的 58%
丢失的 42% 去哪里了?
→ 15% 等数据从 host 搬到 device (PCIe 瓶颈)
→ 12% AllReduce 梯度同步时 GPU 空转 (NCCL 通信开销)
→ 8% kernel launch 开销 (太多小 kernel,CPU dispatch 跟不上)
→ 5% Tensor Core 闲置 (算子没有用 Tensor Core 实现)
→ 2% ECC 纠错开销
典型 MFU 基线(GPT 类大模型,大规模分布式训练):
- MFU > 55%:训练效率优秀
- MFU 50-55%:正常范围
- MFU 35-50%:存在明显瓶颈(通信、数据加载或 kernel 优化空间大)
- MFU < 35%:严重问题,训练成本翻倍
业界标杆:Meta 在 Llama 3 训练中达到 MFU ~38-43%(24k H100 集群),DeepSeek 在 V3 训练中报告 MFU ~38-42%。MFU 随集群规模增大呈递减趋势------这不是优化不到位,而是通信拓扑的物理极限。
OpenTelemetry 在 AI 链路中的角色
GPU metrics 给你"现在 GPU 在干什么",Prometheus + Grafana 给你"过去一段时间的趋势和异常",但排查一次具体的慢请求------"为什么用户 A 在第 15:03 分的请求用了 12 秒"------你需要 OpenTelemetry 的 trace:
yaml
Span: InferenceRequest (12.3s)
│
├─ Span: Preprocessing (1.2s)
│ ├─ Tokenizer.encode() 0.8s
│ ├─ Image resize (ViT) 0.3s
│ └─ Tensor to GPU 0.1s
│
├─ Span: Model Forward (10.1s) ← 瓶颈在这里
│ ├─ KV Cache Query 1.2s
│ ├─ Attention × 32 layers 7.8s ← Trace 能定位到第几层慢
│ │ ├─ Layer 0-7: 0.4s
│ │ ├─ Layer 8-15: 0.6s
│ │ ├─ Layer 16-23: 2.1s ← 这一组突然变慢 → 显存换页 or 降频
│ │ └─ Layer 24-31: 4.7s
│ └─ FFN × 32 layers 1.1s
│
└─ Span: Postprocessing (1.0s)
├─ Detokenizer.decode() 0.7s
└─ Response serialization 0.3s
OTLP Exporter 配置示例:
yaml
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: inference-otel
spec:
config: |
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
processors:
batch:
timeout: 5s
send_batch_size: 512
exporters:
prometheus:
endpoint: 0.0.0.0:8889
# 将 OTel trace 派生出的 RED metrics 推给 Prometheus
jaeger:
endpoint: jaeger-collector:14250
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [jaeger]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [prometheus]
一句话总结
GPU 利用率是基础设施里最大的谎言------用 Tensor Core 活跃度 + NVLink 带宽 + MFU + TTFT 四维交叉校验,才能区分 GPU 是在高效计算还是在假装忙碌。DCGM 给数据,Prometheus 存数据,Grafana 看数据,OpenTelemetry 追数据,四个组件不是可选的------是 GPU 集群从"能跑"到"可靠"的分界线。
下一篇:NVIDIA NIM------从检查点到生产级推理 API 的最后一公里。怎么把 HuggingFace 上的模型权重变成生产环境里带鉴权、限流、监控、自适应批处理的推理端点,以及 NIM 在 K8s 上的部署全流程。