深度学习这行干得越久越会发现,GPU监控这事看着不起眼,但关键时刻真能救命。模型训练一半卡住不动了,到底是因为显存瓶颈还是GPU利用率太低?多机训练的时候哪张卡掉链子了?卡在跑推理服务时功耗飙到多少、温度有没有逼近降频线?这些如果全凭肉眼去登服务器敲命令,效率太低,也不容易及时发现问题。
市面上能用来做GPU性能实时监控的软件其实不少,从最基础的NVIDIA自带命令行工具,到终端里的图形化面板,再到能对接Prometheus和Grafana的数据中心级方案,覆盖的场景差别很大。这篇文章我就结合自己日常在单机调模型、多卡训练、以及集群运维这几个场景里实际用下来的经验,把这几种软件从原理到操作再到坑点,好好梳理一遍。
1. 为什么要单独盯GPU:核心场景与需求拆解
1.1 深度学习训练中GPU容易出什么问题
先说一个很多人踩过的坑:GPU利用率显示99%,你以为它在满负荷干活,可训练一个batch的时间就是降不下来。这时候光看利用率是没用的,你得看SM(流处理器簇)实际占用、显存带宽吞吐,甚至要看是不是CPU先把数据喂不过来,导致GPU在空转等待。
我实习那会儿第一次跑ResNet-50训练,发现GPU利用率波动得像过山车,一会儿99%,一会儿掉到20%以下。查了半天发现是数据加载线程数设置太低,CPU端成了瓶颈。如果没有实时监控工具把利用率曲线拉出来看,这种问题排查起来全靠猜。
另外还有几类特别典型的GPU异常场景:
- 显存泄漏:训练脚本里某些张量没释放,跑几十个epoch之后显存越占越大,最终OOM崩掉。这种情况看内存曲线最直观。
- 温度墙降频:笔记本或者涡轮散热的卡在满载下温度飙到90℃以上,核心自动降频,明明满负载在跑,算力却只有原来的六成。
- 掉卡/驱动异常:多卡训练时报错说找不到设备,或者某张卡在监控工具里直接消失,这种问题如果不靠持续监控日志,几乎没法复盘。
- 多租户抢占:特别是在公司共用的GPU服务器上,别人起个任务把你卡占满了,你的任务排队时间长了,没有监控面板根本说不清。
1.2 监控GPU到底要看哪些指标
不同场景需要关注的指标侧重点完全不同。常规的GPU监控工具都能显示如下几类核心指标,但你要理解每一项的含义:
- GPU利用率:这其实是“采样周期内SM上有活动指令执行的时间占比”,并不是说100%就说明算力跑满了,它不能直接反映性能是否达到理论峰值。
- 显存占用:容易理解,但要注意区分“已用显存”和“进程实际占用”,很多时候已用显存高是CUDA缓存机制造成的假象。
- 温度、功耗、风扇转速:这些决定降频和稳定性,尤其长时间多卡训练,一张卡温度异常就要警惕散热风道是否堵了。
- 显存带宽、SM占用率、PCIe吞吐:这类细粒度指标能够更准确判断性能瓶颈,普通工具不一定默认展示,但高级监控软件能采集到。
- ECC错误计数、GPU卡状态(如P2P链路状态):这属于硬件健康范畴,集群运维时必须盯。
搞清楚了该看哪些指标,再来看工具,就不会被各种软件五花八门的界面带跑偏了。
2. 主流实时监控软件盘点:从命令行到Web面板
2.1 nvidia-smi:最基础也最容易被低估的命令行工具
要说最普及的GPU监控工具,绝对绕不开NVIDIA驱动自带的nvidia-smi。这东西不需要额外安装,只要装好了NVIDIA驱动就能用。很多人对它印象停留在“看一眼显存占了多少”,实际上它的能力被严重低估了。
nvidia-smi除了常规的进程列表展示,还可以通过参数实现很多实用功能。我自己最常用的几个组合:
# 每1秒自动刷新并带上时间戳,适合临时挂后台采集 watch -n 1 nvidia-smi # 打印完整的信息,包括每个卡的时钟频率、PCIe带宽等 nvidia-smi -q # 只查询关键指标,并格式化为方便解析的csv格式 nvidia-smi --query-gpu=index,utilization.gpu,memory.used,temperature.gpu,power.draw --format=csv -l 1 # 查看某张卡上有哪些进程在占用显存 nvidia-smi -i 0 -f gpu0.log很有意思的是,nvidia-smi在Python里也能直接调用nvidia-ml-py这个库来读取数据,很多自研监控脚本就是在它的基础上做二次封装。用熟了之后你会发现,它不只是个“看一眼”的命令行工具,完全可以作为监控系统的数据采集底座。
不过它也有短板:历史数据不会自动保存,没有图形曲线,多卡环境下想看趋势就费劲了,而且它对日志和告警的支持为零。所以我把nvidia-smi当成“手术刀”,快速定位问题的时候用,替代不了长时监控方案。
2.2 nvtop:终端里的图形化实时监控
如果你习惯了在终端里干活,想快速看到直观的图形化界面,nvtop绝对是不二选择。这工具从名字上就能看出来是仿照Linux下的htop设计的,但它专门面向GPU监控,用起来非常舒服。
nvtop支持NVIDIA、AMD甚至Intel的显卡(通过不同的后端插件),安装方式也很简单,apt或yum都能直接装。界面里会实时显示每张GPU卡的利用率、显存、温度、功耗和进程占用,还会用简单的字符画展示利用率百分比条,一眼扫过去就能看出哪张卡在偷懒,哪张卡在过热。
多说一句,nvtop其实能显示不少细粒度指标,比如内存带宽利用率、SM利用率等,这些在nvidia-smi基础版里是看不到的。真正的亮点在于交互:可以按键排序进程,可以只查看某张GPU卡,还能显示GPU上运行的CUDA计算进程的CPU利用率。当时排查数据加载瓶颈,我就是用nvtop的实时进程视图确认了数据加载进程CPU打满,而GPU利用率在周期性归零,一下就定位到问题出在CPU侧。
需要注意的是,nvtop只是“看得见”,它本身不存数据,也没有告警能力。它适合的是人坐在电脑前面、临时诊断或持续肉眼观察的场景,不适合做成7x24小时服务体系。
2.3 gpustat:适合脚本化和批量场景的轻量工具
gpustat是一个基于Python的命令行工具,底层就是调用nvidia-smi来获取数据,但它把数据整理得更干净,输出更紧凑,而且可以直接嵌入到Python代码里使用。
gpustat最大的优点在于可编程性。它能以JSON格式输出分层结构,方便脚本消费。写深度学习训练脚本时,我会在代码的关键位置调用gpustat获取当前显存和利用率,然后配合训练日志一起输出:
import gpustat stats = gpustat.new_query() for gpu in stats.gpus: print(f"GPU {gpu['index']}: {gpu['utilization.gpu']}%, " f"Memory {gpu['memory.used']}/{gpu['memory.total']} MB")这种能力在写自动化工具链的时候特别好用,比如训练前自动检查是否有空闲卡,没有就等位;比如监控显存变化趋势,判断是否出现泄漏。它还能配合终端下的简单文字图形界面(gpustat -i)显示实时刷新视图,虽然不如nvtop炫酷,但胜在轻量。
稍微会让人踩坑的地方是,gpustat需要安装其依赖的库,建议使用pip安装:
pip install gpustat它对Python版本有要求,某些老系统上Python版本过低会装不上。此外,gpustat输出的指标完全依赖于nvidia-smi的数据,如果想看功耗曲线周期,需要自己收集并落库。
2.4 DCGM + Grafana:数据中心级的完整监控方案
前几个工具都是单机视角。一旦你开始接触GPU集群、多节点训练或者K8s环境,就必须要上NVIDIA官方出的一套数据中心GPU管理工具组合:DCGM(Data Center GPU Manager)。
DCGM不只做性能监控,它提供的能力包括健康检查、性能指标统计、GPU状态管理、以及系统性诊断。它带了一个informer组件——dcgm-exporter,可以直接把指标暴露成Prometheus格式,后续接到Grafana做可视化面板,这是目前业界比较标准的一套开源GPU监控体系。
部署方式简单说就是:
# 1. 下载并运行dcgm-exporter容器 docker run -d --gpus all \ --rm --cap-add SYS_ADMIN \ -v /proc:/proc:ro \ -p 9400:9400 \ nvidia/dcgm-exporter:3.1.8-1.0.0-ubuntu20.04 # 2. 在prometheus.yml里追加job配置 - job_name: 'dcgm-gpu' static_configs: - targets: ['your-node-ip:9400']配置完成后,Prometheus就会持续抓取DCGM暴露的指标。指标名称通常是DCGM_FI_DEV_GPU_UTIL、DCGM_FI_DEV_MEM_COPY_UTIL、DCGM_FI_DEV_GPU_TEMP、DCGM_FI_DEV_POWER_USAGE这类格式,直接能在Grafana里画大屏。
这套方案的好处是:历史数据可以追溯,可以做告警规则(比如温度超过阈值就发告警到钉钉/邮件),还能对接K8s的监控体系,实现Pod和GPU卡的一一映射。如果你在公司运维部门工作,希望把GPU资源纳入统一监控大屏,这套东西几乎是必学的。
3. 实操:不同场景下的监控方案选型与部署
3.1 单机深度学习调试:nvtop + 自定义采样脚本的搭配
在单机调模型的时候,我实际用得最多的是nvtop加上一个自己写的小脚本。nvtop负责直观呈现,脚本负责把关键指标记录成文件,便于训练结束后复盘。
我的做法是,在训练脚本外层包一个简单的采样循环:
# monitor_gpu.sh while true; do nvidia-smi --query-gpu=index,utilization.gpu,memory.used,power.draw,temperature.gpu \ --format=csv >> gpu_monitor_$(date +%d).csv sleep 2 done训练跑完之后,再在Jupyter或Excel里快速画一下曲线图,看看有没有明显异常的尖峰或者台阶。比如显存在逐渐升高但利用率长期偏低,就很可能有内存泄漏或者数据管道卡顿。
这里要特别强调,不要以为把采样间隔设到0.1秒就更精确。监控本身也有开销,采样太频繁反而可能影响训练性能,尤其在一张卡上既跑训练又跑采样脚本的时候。实测下来,单机调试场景下2秒一次的采样粒度已经足够定位绝大多数问题。
3.2 多机集群与K8s环境:Prometheus + DCGM Exporter接入流程
多机集群和K8s环境里,情况会复杂得多。你在笔记本上敲nvtop那种方式根本行不通,节点一多,靠人肉登录去看是不现实的,必须依赖集中式监控。
完整的接入流程可以拆成四步:
第一步:每个GPU节点部署dcgm-exporter,确保暴露9400端口。如果是K8s环境,用DaemonSet部署比较合适,保证每个节点只有一个exporter实例,同时把GPU指标标记到对应的Pod Label上,这样才能在Grafana里按Pod维度看。
第二步:在Prometheus中配置服务发现或静态targets。如果你是裸机集群,直接把节点IP加进去;如果你用的是K8s,更推荐用ServiceMonitor自动发现。
第三步:在Grafana里导入现成的仪表盘。NVIDIA官方其实提供了dcgm-exporter的dashboard JSON模板,我从它的GitHub仓库里拿过来改了下细节就能直接用,面板里包含核心利用率、显存占用、温度、功耗、PCIe流量这些关键视图。如果你不想自己从零画图,这个是最高效的路径。
第四步:配置告警规则。这一步很少人做,但恰恰是最能体现运维价值的地方。我常用的几条规则如下:
| 告警项 | 触发条件 | 说明 |
|---|---|---|
| GPU温度过高 | GPU温度 > 90℃ 持续5分钟 | 检查散热和风扇状态 |
| 显存占用接近上限 | 显存利用率 > 95% 持续3分钟 | 可能是内存泄漏或负载过高 |
| GPU利用率异常归零 | GPU利用率 < 5% 但进程存在 持续10分钟 | 可能卡死或等待数据 |
| 掉卡 | GPU卡数量 < 预期值 持续1分钟 | 需要立刻人工介入 |
这套体系搭起来之后,GPU运维才算真正进入“可观察”状态。之前公司有几张卡频繁出现ECC错误,当时就是靠DCGM的ECC计数器指标提前发现,赶在彻底故障前把训练任务迁移走了,避免了一次大事故。
3.3 压测与稳定性验收:gpu-burn与监控配合使用
GPU买回来或者租下来,第一件事其实不是直接跑模型,而是先做压力测试和稳定性验收。gpu-burn属于比较常用的压测工具,它会在GPU上执行高强度的CUDA计算来压榨出最高负载和最大功耗。
压测时一定不能只看gpu-burn的输出日志,还要配合监控工具看是否出现掉驱动、温度墙降频、ECC错误暴增等现象。我之前在一台新交付的服务器上跑gpu-burn,结果其中一张卡跑了几分钟就温度报警,排查之后发现是散热硅脂涂布不均。这种事情如果没监控配合,压测就白白浪费了。
一个常规的压测验收流程如下:
# 1. 压测前记录基础指标 nvidia-smi --query-gpu=index,utilization.gpu,temperature.gpu,power.draw,ecc.errors.corrected.volatile.total \ --format=csv # 2. 编译并运行gpu-burn,运行10分钟 git clone https://github.com/wilicc/gpu-burn cd gpu-burn make ./gpu_burn 600 # 3. 压测期间另开一个终端观察实时数据 watch -n 2 nvidia-smi跑完压测之后,要检查输出的最大耗时、错误信息,以及压测期间有没有出现Xid错误。如果全程温度稳定在合理区间,功耗接近TDP,没有掉卡,那这台机器就算验收通过了。
4. 常见问题与排查技巧实录
4.1 GPU利用率很高,但训练速度还是很慢
这是我被问过最多的问题之一。GPU利用率高说明SM上有指令在跑,但指令也可能是低效的。这个时候建议先用nvtop看SM利用率和内存带宽利用率,如果是卷积运算密集模型,SM利用率高但内存带宽利用率也高,说明权重加载频繁,可以考虑混合精度或者优化通道布局;如果SM占用率低但利用率高,大概率是小算子频繁启动导致的,需要减少kernel launch次数,比如把一些逐元素操作融合起来。
另一种更常见的原因就是CPU喂不动数据,尤其是机器上CPU核心数少但是数据预处理很重的时候。这种情况特征很明显:GPU利用率呈周期性锯齿状,配合监控能看到周期里有一段利用率接近0。解决方法是增大num_workers,开启pin_memory,同时把数据增强放到GPU之外预处理。
4.2 监控显示显存占用不高,但训练时一直OOM
不少人会有个疑惑:nvidia-smi看显存占用明明只有50%,为什么一跑模型就OOM?原因是GPU显存里还驻留着其他进程或者上一个训练任务留下的CUDA上下文。CUDA在进程退出后并不总是立刻释放显存,特别是用了某些分布式框架或CUDA缓存机制时。
排查思路是:
nvidia-smi # 查看哪个进程占用了显存在单卡上跑多个不同规模模型时也会遇到这个问题,你可能看到总共占用了80%,但某个进程实际占用的显存远大于模型需要的,这是CUDA的显存缓存策略。处理办法是设置环境变量限制CUDA缓存:
export PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:128对于PyTorch的显存碎片化,这个参数很有效。
如果在容器环境里,也要注意运行时可能默认保留了部分显存。可以给容器加上--gpus '"device=0"'限定使用某张卡,避免同一张卡被多个容器写写画画,互相干扰。
4.3 多卡环境下工具识别不到GPU或掉卡
监控工具显示卡数目不对,或者某张卡的状态是“不支持”/“ERR!”,首先得确认驱动和硬件链路是否正常。最常见的原因是PCIe链路松了或者转接卡接触不良,其次是电源供电不足导致高负载下某张卡掉线。
排查顺序建议是:
# 1. 查看PCIe和NVML识别情况 lspci | grep -i nvidia nvidia-smi -L # 2. 查看系统日志中的Xid错误 dmesg | grep -i xid # 3. 如果是K8s环境,查看容器是否绑定了正确的GPU资源 kubectl describe pod your-pod-name如果是持续偶发掉卡,还有一种可能是GPU到达了温度墙,持续高温触发了保护机制。这时候用DCGM的历史温度数据一看便知。所以前面提到的长期监控方案不只是“为了好看”,它能让这种偶发问题有据可查。
4.4 监控工具本身占用的资源也不能忽视
最后提醒一句,监控工具本身是有开销的。nvtop还好,它的开销极低;但如果你的Grafana+Prometheus体系采集了数千个GPU指标,并且每5秒抓一次,Prometheus的CPU和内存占用会明显上升。在资源紧张的集群里,需要对采集频率做调整,一般10~15秒抓一次就够日常监控了。
另外,很多人在采集脚本里用到nvidia-smi dmon这类实时输出流并写数据库,这个方式在高频采样时也会增加CPU占用。如果只是要记录曲线,建议把采样数据先写入本地的TSDB(比如VictoriaMetrics),再统一查询,而不是让每个节点都装一堆重型agent。
5. 工具选型不是越重越好:给几个很实用的判断维度
做了这么久GPU监控,我发现最大的误区是盲目追求功能强大的监控体系。单机调试用Grafana确实杀鸡用牛刀,反而拖慢问题排查速度。反过来,如果集群规模大了还在人肉敲nvidia-smi,那运维效率也太低了。
我的建议是,按人和场景来分:
- 如果你是算法工程师,大部分时间在本机或单机开发调试,配置好nvtop和一个小采样脚本就够了,重点是把利用率、显存、温度三条曲线记下来,方便定位训练中的性能拐点。
- 如果你是平台或Infra工程师,需要管理多台GPU服务器,那DCGM+Prometheus+Grafana这套标配组合必须搭起来,而且要尽早把告警规则加上去。
- 如果你只是临时租了一台云GPU跑个任务,那最轻量的方式是直接用云平台自带的监控面板,或者起一个gpustat定时输出到日志文件,跑完再看。
还有一个常被忽略的点:工具的告警能力。命令行的nvidia-smi和nvtop都是没有告警的,你得保持人在现场看。只要有长期运行的任务,就应该把能够产生告警的方案纳入考虑。哪怕只是写一个简单的Shell脚本,每5分钟检查一次显存占用,超过阈值就发消息通知,也比完全不设防强得多。
我自己在后来的实践中还把监控分为了两个层次:一层是基础健康监控(温度、功耗、掉卡、ECC错误),另一层是性能监控(利用率、内存带宽、SM occupancy)。基础健康监控必须有告警;性能监控则主要用于训练后复盘和调优参考。这两层别混在一起,不然告警太多,反而没人去看了。
6. 后记:一点实操经验总结
最后说一个我踩了两三次坑才学到的经验:不管用哪种监控工具,一定要给监控数据加时间戳,并且和训练日志保持一致的时间源。要不然事后排查的时候,GPU利用率的曲线和训练日志的报错时间对不上号,白白浪费好几个小时去海量日志里捞线索。
另外,所有的监控数据默认收集到最后,尽量定期清理。Prometheus的TSDB如果持久化不做数据保留策略,磁盘会被写满,到时候监控系统本身就开始报警了。给Prometheus配一个合理的retention参数(比如--storage.tsdb.retention.time=15d),是运维实操里的标配动作。
GPU性能实时监控这件事,看起来很简单,好像装个工具看数字就行,但真正做深了会发现每个指标背后都有值得深挖的东西。工具本身都不是最难的,难的是你知道自己在这个场景下到底要排除什么问题、盯住哪些参数。希望这篇文章能帮你省掉一些摸索的时间,少跳几个坑。