
先问个问题你上一次盯着nvidia-smi输出发呆是什么时候是不是发现显存占用很高、GPU-Util 却来回跳训练速度上不去却根本不知道瓶颈在哪儿这就是 GPU 性能实时监控存在的意义——它不只是看那些百分比数字而是帮你在训练、推理、压测和运维过程中把GPU 到底在干什么这件事彻底看清楚。这篇东西适合谁刚配好深度学习环境的初学者、跑大模型训练的研究人员、管着几台甚至几十台 GPU 服务器的运维人员还有做 GPU 驱动开发或性能调优的工程师。我会从最常用的命令工具讲到多机集群监控方案给出完整可复现的命令和参数也会穿插一些只有踩过坑才懂的经验比如为什么有时候 GPU 利用率看着不错但训练就是慢再比如trt-warn: unable to determine GPU memory usage这类警告到底意味着什么。1. 显存爆了还是算力没吃满GPU实时监控到底在看什么很多人把 GPU 监控理解成盯着显存和利用率看这没错但太粗糙了。GPU 是一个包含计算单元、显存控制器、缓存、视频编解码器等多个子系统的复杂处理器。你在终端敲nvidia-smi看到的几个数字只是它抛给你的冰山一角。1.1 监控的核心维度不止是显存和利用率实时监控 GPU 性能本质上是监控这几类指标SM 利用率GPU-Util显示流处理器SM的忙碌程度但要注意它统计的是某采样间隔内 SM 上至少有一个 warp 在执行指令的时间占比不是算力被用了百分之多少。这意味着 50% 的利用率可能代表计算时断时续也可能代表任务本身只用了部分 SM。显存占用与带宽显存占用反映容量压力显存带宽反映数据搬运压力。训练大模型时经常出现显存容量快满了但带宽利用率并不高的状况这时候单纯加显存不一定能提速。温度与散热GPU 核心温度超过 85℃ 甚至 90℃ 会产生热节流thermal throttling自动降低核心频率来保护硬件。这是最常见的性能神秘下降原因。功耗与频率通过nvidia-smi -q -d POWER可以看到当前功耗、功耗上限以及当前核心/显存频率。如果功耗撞墙power cap或频率上不去说明供电或散热受限。PCIe 传输速率数据从 CPU 内存搬到 GPU 显存要走 PCIe 总线如果传输速率持续跑满说明数据供给跟不上 GPU 计算速度训练/推理会出现周期性空闲。光知道这些还不够关键是建立数据流的思维。一次深度学习训练的最小循环是CPU 读取数据 → 预处理 → 拷贝到 GPU 显存 → GPU 计算 → 结果拷回。这个环节里任何一段瓶颈都会反映在 GPU 监控数据上。比如 GPU-Util 反复跳动通常不是 GPU 的问题而是 CPU 数据供给的瓶颈。1.2 什么样的监控频率才算实时实时是个弹性概念。人眼观察习惯用watch -n 1 nvidia-smi每秒刷新一次性能剖析需要毫秒级采样如nvprof、Nsight Systems而集群资源管理只需秒级或分钟级采集如 Prometheus 默认 15 秒抓取一次。我的建议是分场景临时排查问题用 0.5~1 秒刷新率持续观察训练过程用 2~5 秒做长期监控和告警用 15~60 秒。如果刷新频率太高采集程序本身也会消耗一定 CPU 和 PCIe 带宽反过来影响性能数据的准确性。2. 工具也要分场景选从单卡调试到集群运维的监控工具分层GPU 监控工具五花八门但不是越高级越好。选型的关键是匹配你当下的场景。我把常用工具按使用场景分成了四层每一层解决不同的问题。场景推荐工具特点上手难度单机快速查状态nvidia-smi系统自带信息全适合临时瞄一眼低单机交互式监控nvtop类htop界面多卡一目了然低脚本/自动化采集gpustat、nvidia-smi --query-gpu输出结构化方便解析中压测与稳定性验证gpu-burn满负荷压测验证算力/散热中多机集群持久监控DCGM Prometheus Grafana指标全、可告警、可追溯高有些朋友一上来就搭 Grafana结果发现日常训练中利用率波动根本不需要这么重的方案。反过来管着几十台 GPU 服务器的人还在挨个机器敲nvidia-smi那也是拿大炮打蚊子却打错了方向。我的一贯原则是先用手边最快的工具定位问题再决定要不要上重型监控系统。下面几节我会按日常使用频率从高到低的顺序逐个讲这些工具的实际用法和需要注意的细节。3. nvidia-smi 的完整打开方式一个老命令被你用成了皮毛大多数人用nvidia-smi只是敲一下回车看个大概其实这个命令包含了很多实用子命令。掌握好了单机场景下它能覆盖 80% 的监控需求。3.1 从静态输出开始读懂每一行字段裸敲nvidia-smi的输出分为几部分----------------------------------------------------------------------------- | NVIDIA-SMI 525.85.12 Driver Version: 525.85.12 CUDA Version: 12.0 | --------------------------------------------------------------------------- | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | | 0 NVIDIA GeForce RTX 4090 | On | 00000000:01:00.0 On | N/A | | 0% 43C P8 18W / 450W | 1024MiB / 24564MiB | 0% Default | | | | N/A | ---------------------------------------------------------------------------几个容易被忽视的点Persistence-M 状态如果显示Off建议用nvidia-smi -pm 1开启持久模式可以降低程序反复启动时 GPU 的初始化延迟。Perf 状态P0 是最高性能状态P8 是空闲状态。如果 GPU 有负载但 Perf 始终不是 P0说明驱动或供电状态有问题。Pwr:Usage/Cap当前功耗/最大功耗。RTX 4090 的 450W 是上限训练时如果长期在 300W 以下波动说明计算负载不均匀。GPU-Util注意它包含图形与计算任务但不会区分是图形渲染还是 CUDA 计算。做深度学习时建议用nvidia-smi -c查看计算模式或用nvidia-smi dmon看详细分类。3.2 定时刷新watch 与 dmon 的实战选择要让信息动起来最直接的办法是watch -n 1 nvidia-smi但watch的缺点是每次执行都是完整重绘CPU 占用稍高在内存紧张的机器上不太友好。更专业的做法是使用nvidia-smi dmon设备监控模式nvidia-smi dmon -s pucvmet -d 1参数说明-s pucvmet指定显示哪些指标p功耗、u利用率、c显存使用率、v显存已用、m显存总量、eECC、t温度。-d 1每 1 秒输出一次。dmon的输出是流式文本非常适合重定向到文件做性能日志nvidia-smi dmon -s pucvmet -d 5 gpu_monitor.log 之后用tail -f gpu_monitor.log边训练边观察。比起watch在终端界面里闪烁这种方式更适合放在后台长期运行。3.3 参数化查询脚本自动化的基础如果要写脚本定时采集 GPU 指标nvidia-smi --query-gpu比解析nvidia-smi的表格输出可靠得多nvidia-smi --query-gpuindex,name,utilization.gpu,memory.used,memory.total,temperature.gpu,power.draw --formatcsv,noheader,nounits输出示例0, NVIDIA GeForce RTX 4090, 67, 1024, 24564, 43, 18用,分隔再配合 awk、python 或 pandas就能轻松构建自己的监控脚本。我还习惯加上-l 1让它周期性输出配合 tee 存入 CSV 文件nvidia-smi --query-gpuindex,utilization.gpu,memory.used,power.draw,temperature.gpu --formatcsv,noheader -l 1 | tee gpu_history.csv提示在容器内运行这条命令时需要以--gpus all方式启动容器否则可能看不到 GPU 或报Unable to determine GPU memory usage之类的警告。docker run --gpus all是访问 GPU 设备节点的前提不是可选项。3.4 查进程定位谁在占 GPU多用户共用服务器时经常需要找出谁占了我的卡。用nvidia-smi --query-compute-appspid,used_memory,process_name --formatcsv,noheader或者直接nvidia-smi看下半部分的进程列表。结合ps -fp pid就能确认是哪个用户在跑什么程序。遇到僵尸进程占显存的情况kill -9 pid是常用手段但操作前建议先和进程所有者沟通一下避免误杀别人的训练任务。4. nvtop 和 gpustat适合个人训练的轻量交互式监控单机训练时我不太建议频繁切到终端敲watch nvidia-smi交互式的nvtop和一行一刷的gpustat体验会好很多。这两个工具都很轻安装也不复杂。4.1 nvtopGPU 界的 htopnvtop的界面长得很像 Linux 里的htop但展示的是 GPU 数据。安装方式# Ubuntu/Debian sudo apt install nvtop # 其他发行版或想装新版 git clone https://github.com/Syllo/nvtop.git mkdir -p nvtop/build cd nvtop/build cmake .. make sudo make install启动后直接nvtop。主界面按 GPU 分块展示占用率、显存、功耗、温度、频率、风扇转速底部还有进程列表和系统负载。支持鼠标点击排序也可以按p切换进程视图。我在实际使用中觉得它最实用的两个场景多卡对比同时观察 8 张卡时一眼能找出哪张卡温度异常高或利用率异常低。快捷键过滤按g可以选择只看部分 GPU按c切换色彩模式长时间盯屏幕时护眼效果好。需要留意的是nvtop在很老的驱动版本或某些虚拟化环境下可能采集不到频率/功耗数据显示 N/A。这时优先确认驱动版本是不是太旧别急着怪工具。4.2 gpustat适合写进脚本和 SSH 登录提示gpustat是 Python 写的小工具核心 API 会调用nvidia-smi但输出做了人性化处理pip install gpustat gpustat -cp输出示例k80vm01.local Thu May 18 10:23:45 2024 [0] NVIDIA RTX 4090 | 67% | 1024/24564 MB | python train.py(1024M)参数说明-c显示命令名称。-p显示进程 PID。-i间隔几秒刷新比如gpustat -i 2。--json输出 JSON 格式适合脚本解析。我习惯把它写进.bashrc的登录提示里让用户一登录服务器就能看到当前 GPU 占用和自己在跑的任务# ~/.bashrc 末尾加一行 gpustat --no-colorgpustat还支持把结果发到 Slack、微信等 Webhook适合个人用小规模告警比如某张卡利用率跌到 0 超过十分钟这种情况。它最大的优势就是轻——没有守护进程、没有数据库、没有额外依赖装完就能跑。5. gpu-burn 压力测试验证算力与散热的极限状态监控工具只能看到当前状态但如果你想确认一台 GPU 服务器在全负载下到底稳不稳就得主动制造压力。gpu-burn是这一场景里最常用的工具。5.1 gpu-burn 能解决什么问题简单说gpu-burn让 GPU 进入持续满负荷计算状态用来验证算力是否正常在相同 GPU 型号下跑同一份压测代码结果分数可以横向对比。分数明显偏低说明 GPU 核心可能有故障或降频。散热是否达标持续满载会让温度爬升如果很快就冲到 90℃ 甚至触发保护性关机说明散热系统需要处理。供电是否稳定功耗持续维持在 TDP 上限如果出现功率波动或掉驱动大概率是电源或供电模块问题。多卡之间是否有隐性故障多卡同时压测时某张卡崩掉或报 ECC 错误这张卡基本可以标记为待检修。5.2 编译与运行实操步骤代码在 GitHub 的wilicc/gpu-burn仓库编译依赖 NVCCCUDA Toolkit 自带git clone https://github.com/wilicc/gpu-burn.git cd gpu-burn make运行默认压测所有 GPU持续 10 秒./gpu_burn 60命令最后一位数字是持续秒数我一般建议压测 30~60 分钟来看散热表现。也可以指定只压测某几张卡CUDA_VISIBLE_DEVICES0,2 ./gpu_burn 300压测过程中的典型输出GPU 0 (Tesla T4): 145.6 GFLOPS GPU 1 (Tesla T4): 144.3 GFLOPS Test completed.同时另开一个终端跑nvtop或nvidia-smi dmon观察温度和功耗曲线。如果温度曲线持续上升后平稳在 70~80℃功耗稳定在上限说明整卡散热和供电都没问题。注意gpu-burn会把 GPU 占用打到接近 100%如果机器上有别人正在跑训练任务压测前一定要先沟通最好申请一个空闲的维护窗口再做。5.3 压测结果的解读压测不只是看有没有报错还要关注两点一是分数稳定性。多次运行gpu_burn 60结果波动在 ±2% 以内算正常。如果第一次 145 GFLOPS第二次 120 GFLOPS大概率是温度导致降频了需要检查硅脂、风扇、灰尘甚至机箱风道。二是卡间一致性。相同型号的卡跑出来分数接近如果某张卡差距明显可以单独用nvidia-smi -q -d CLOCK看它的当前核心频率是否被锁定在较低档位。曾经有朋友遇到过一张 3090 因为坏了的风扇导致核心频率锁在 300MHz 左右压测分数比其他卡低了 4 倍靠的就是卡间对比才发现的问题。6. DCGM Prometheus Grafana多机多卡场景的持久化监控方案当你手上管的 GPU 从个位数变成两位数以上或者要监控 GPU 集群一段时间的性能变化趋势单机的nvidia-smi和nvtop就不够了。这时候需要一套指标采集 → 存储 → 可视化的闭环方案NVIDIA 官方的 DCGMData Center GPU Manager是我推荐的首选数据源。6.1 DCGM 是什么和 nvidia-smi 有什么区别nvidia-smi适合单机单次查询DCGM 是为数据中心大规模管理设计的。它本身不是可视化工具而是一个后台服务加一套指标模型你要通过dcgmi命令行查询或者用它的 Prometheus 导出器把指标暴露给监控系统。DCGM 能提供的指标比nvidia-smi丰富得多比如SM 占用、内存控制器占用、FP32/FP16 单元利用率细分显卡功耗、核心温度、显存温度、NVLink 带宽PCIe 收发速率、ECC 错误计数、Xid 错误计算的充分性指标比如是否存在GPU 空闲但显存占用高的状态安装方式Ubuntusudo apt-get install -y datacenter-gpu-manager sudo systemctl enable --now nvidia-dcgm6.2 dcgmi 常用命令快速验证DCGM 自带dcgmi命令可以做基本的健康检查和指标查询# 查看所有 GPU 的健康状态 dcgmi diag -r 1 # 查看 GPU 实时指标类似 nvidia-smi dmon dcgmi dmon -e 100,101,102,103,104,105,110,111,112,113,114,115这里-e后面跟的是指标 ID100 表示 GPU 利用率101 表示 SM 利用率102 表示显存占用110 表示核心温度111 表示功耗等。完整指标列表可以用dcgmi dmon --listmetrics -v查看。我实际用下来DCGM 相比裸敲nvidia-smi的最大价值是能够准确判断性能是否被正确利用。举个例子DCGM 有一个指标叫DCGM_FI_DEV_GPU_UTIL利用率还有一个叫DCGM_FI_PROF_SM_OCCUPANCYSM 占用率。前者可能显示 100%但后者可能只有 20%说明任务虽然一直占用 GPU但每个 SM 内部的执行单元并没有塞满。这种细粒度信息对分析算子性能瓶颈特别关键。6.3 接入 Prometheus 和 GrafanaNVIDIA 官方提供了dcgm-exporter把 DCGM 指标暴露为 Prometheus 格式git clone https://github.com/NVIDIA/dcgm-exporter.git cd dcgm-exporter make ./dcgm-exporter --address:9400 然后在 Prometheus 配置里加一个 jobscrape_configs: - job_name: dcgm static_configs: - targets: [gpu-node-01:9400, gpu-node-02:9400]Grafana 里导入 NVIDIA 官方提供的 DCGM DashboardID 号 12239就能看到每张卡的利用率、温度、功耗、显存、NVLink 等一整套图表。这套方案我用了很久最大的体会是出问题不用猜了——某个时间段训练变慢直接在 Grafana 上叠加查看当时段的 GPU 频率、功耗、温度曲线基本能找到原因。6.4 集群场景的告警配置思路长期监控必须配告警否则监控数据只是事后诸葛。我常用的几条告警规则某张卡温度持续超过 85℃ 超过 10 分钟 → 告警散热问题某张卡出现 ECC 错误或 Xid 错误 → 告警硬件故障GPU 利用率持续高于 95%但任务不是压测 → 提示可能过度使用需要排队或扩容显存占用持续超过 90% 且发生 OOM 事件 → 告警任务调度不合理Prometheus 的alertmanager可以对接钉钉、飞书、邮件具体配置各家有差异核心思路是告警要能推动人去处理而不是躺在日志里没人看。7. 一次真实的GPU利用率低排查过程从监控数据倒推瓶颈前面讲了不少工具这里用一个非常典型的案例串起来某天同事反馈训练速度比之前慢了很多但看 nvidia-smiGPU-Util 有 70% 左右显存占用也正常CPU 和内存占用都不高。这种哪里都不高但就是卡的现象在深度学习环境里太常见了。下面是我完整的排查过程。7.1 第一轮用 nvidia-smi dmon 抓细粒度数据我先让同事把训练任务跑起来然后我用nvidia-smi dmon -s pucvmet -d 0.5观察 2 分钟。输出显示 GPU-Util 在 60%~80% 之间反复跳动每 2~3 秒出现一次跌到 10% 以下的谷底。同时观察显存使用发现mem列没有明显变化说明不是显存不足而是计算过程周期性空转。这种锯齿形利用率曲线通常不是 GPU 本身的问题。GPU 一旦开始执行 kernel利用率就会打满除非 kernel 很小或中间有等待。7.2 第二轮确认数据加载是不是瓶颈我用perf和top检查 CPU 上的数据加载线程top -H -p $(pgrep -f train.py | head -1)发现 CPU 总占用率才 40%但有几个 Python worker 线程满负荷在跑且si软中断数值偏高。进一步分析训练脚本用了 DataLoader但num_workers0所有数据预处理都在主进程里同步执行。GPU 算完当前 batch 后CPU 还没准备好下一批数据GPU 只能空转等待。这个问题的本质是CPU 数据供给跟不上 GPU 消耗速度。把num_workers调到 8并把pin_memoryTrue打开重新跑一遍GPU-Util 稳定在 95% 以上。7.3 第三轮检查 PCIe 传输是否有瓶颈提升 DataLoader 之后还有轻微波动。继续观察发现 GPU-Util 每隔 5 秒会掉一次。我用nvidia-smi -q -d PCIE查看 PCIe 速率nvidia-smi -q -d PCIE | grep -A 8 PCIe看到TX和RX的吞吐接近 1.5GB/s而这个服务器的主板 PCIe 插槽只跑在 PCIe 3.0 x8 上理论带宽约 8GB/s实际有效带宽打对折。如果数据尺寸大且频繁传输PCIe 很容易成为瓶颈。解决思路有三种换到 PCIe 4.0 x16 插槽或者换支持更多通道的 CPU 平台。使用torch.cuda的固定内存pinned memory减少拷贝次数。尽量一次性把数据放 GPU 显存减少小批次高频传输。同事最终把数据预处理后的张量提前放到 GPU 显存缓存起来解决了周期性掉速问题。7.4 排查链路总结这次排查的完整路径是整体观察 → 细粒度采样 → 定位周期性波动 → 检查 CPU 数据供给 → 检查 PCIe 传输 → 针对性调优。每一步都依赖监控工具给出准确数据而不是靠猜。我把常用排查思路整理成了一张表现象优先怀疑方向用哪个工具确认利用率高但速度慢算子效率低、线程占用低、SM 占用率不高nvidia-smi dmon、Nsight Compute利用率锯齿波动数据加载/预处理瓶颈top -H、nvidia-smi dmon看时间相关性温度高且频率低散热/供电问题nvidia-smi -q -d CLOCK、gpu-burn压测显存 OOM模型/输入太大、内存碎片nvidia-smi --query-gpumemory.used多卡训练时某卡利用率低负载不均、通信瓶颈DCGM 的 NVLink/PCIe 指标8. 监控数据里的几个坑踩过才敢说最后这部分是我自己的血泪经验。工具给的数据不是绝对真理解读不当会让你在错误方向上浪费大量时间。8.1 GPU-Util 不一定是你任务的利用率多进程共享 GPU 时nvidia-smi显示的 GPU-Util 是整卡上所有进程的总利用率。你看到 90% 的占用可能有一半是别人的任务在用。排查自己任务的真实占用率需要用nvidia-smi --query-compute-appspid,used_gpu_memory,utilization按 PID 过滤或者用 Nsight 做进程级 profile。8.2 显存占用高不等于计算饱和这个坑出现频率极高。一张卡显存占用 20GB / 24GB但 GPU-Util 只有 5%这很可能是在做推理服务显存用来装载模型权重但计算稀疏。也可能是代码里把大量缓存全塞进了显存或者训练过程中等待外部响应。遇到这种状态我通常先看进程是训练还是推理再去翻代码里有没有显式分配缓存或torch.cuda.empty_cache用的时机是否合理。盲目加显存容量往往解决不了问题。8.3 频率和功耗才是真实状态GPU 核心频率比利用率更能反映真实工作强度。同型号两张卡一张在 1.8GHz 稳定运行另一张在 1.2GHz 到 1.8GHz 之间反复跳变——即使利用率都显示 80%后者的实际算力输出也明显偏低。查调频原因要看nvidia-smi -q -d CLOCK | grep -A 6 Clocks Event Reasons输出里的HW Slowdown、Thermal、Power Cap等字段会直接说明降频原因。8.4 容器内监控注意设备映射和权限问题在 Docker 容器里如果没加--gpus all或者加了但容器里的驱动版本和宿主机不兼容经常出现nvidia-smi报错或输出为空。有一次我在容器里用gpustat死活看不到显存数据最后发现是容器缺少nvidia-smi二进制需要把宿主机的命令挂载进去或者装完整 NVIDIA 驱动工具包。还有一个坑是 TensorRT 推理时日志提示trt-warn: unable to determine GPU memory usage这通常发生在用 TensorRT 读取显存信息失败时。原因可能是容器权限不足或驱动与 CUDA 版本不匹配。排查思路先确认宿主机的nvidia-smi正常再检查容器内的 CUDA 和 TensorRT 版本是否与驱动兼容别盯着日志本身纠结太久。8.5 监控工具本身也会拖累性能长时间高频采样会引入额外开销。nvidia-smi -l 0.1这种 10Hz 的采样会频繁唤醒 GPU 管理接口在一些驱动版本下反而干扰任务的显存分配性能。做性能测试时监控采样频率尽量低或者只在关键时段开启免得数据污染了你的实验结论。根据我个人的使用经验日常训练建议用nvtop做人工观察用nvidia-smi dmon做后台日志真正排查算子级性能问题再上 Nsight 系列服务器数量多的时候DCGM Grafana 是值得投入的方向。没有什么工具是万能的关键是搞清楚你当前最需要解决什么问题再选对工具。希望这篇内容能让你在 GPU 性能监控这件事上少走点弯路。