如果你管过一台装满GPU的服务器,一定见过这种诡异现象:跑分软件全绿,短时间的GPU稳定性测试也全绿,可一上真实训练任务,过两三个小时就崩一次。我最早接触gpu_burn,就是因为被这种间歇性崩溃搞到怀疑人生。后来才明白,普通测试根本压不出问题,真正需要的是像gpu_burn这样能把GPU长时间按在满载区间的工具,并且要结合温度监控一起看,才能把故障钉死在具体某张卡、某个温度拐点上。
这篇文章我就把gpu_burn从编译安装到实战排查的完整链路写清楚,重点讲两个东西:一是这个工具到底怎么用、参数怎么选,二是怎么把温度监控和压测日志配合起来,做到“测完就能下结论”。不管你是搞深度学习训练、GPU服务器运维,还是自己装了台多卡机器跑渲染,这篇都适用。GPU稳定性测试这件事,本质上不是“跑一遍看过不过”,而是“跑多久、以什么方式跑、跑的时候发生了什么”。
1. 间歇性崩溃的元凶:为什么GPU需要真正的压力测试
1.1 所有“跑一会儿才崩”的故障,几乎都和热相关
先说我踩过的一个典型场景:一台8卡服务器,用户反馈训练任务每跑两小时必崩一次,系统不重启,但CUDA context直接丢失,日志里能看到NVRM驱动报错。最初我怀疑是驱动版本问题,重装驱动、升级CUDA都没用。后来把任务缩小到单卡复现,发现只有机箱中间位置那张卡会崩,其余七张卡完全正常。
当时我用的测试方法是跑标准benchmark,几十秒就结束,GPU温度还没起来,当然测不出问题。后来我把gpu_burn单跑那张卡,时间拉到30分钟,问题就暴露了:温度超过78°C之后,开始随机报错,而且是计算错误,不是驱动崩溃。再拆开检查,发现那张卡的风扇转速异常,散热器积灰严重,热点温度比旁边卡高了将近15°C。
这种“跑一会儿才崩”的故障,九成以上和热有关。GPU内部有非常多的电压和频率控制逻辑,温度升高时,为了保证不烧毁,会触发降频甚至功耗限制,但如果某个供电模块、显存颗粒或者核心本身已经劣化,高温状态下时序就会出错,表现出来就是CUDA error、D3D device removed或者驱动重置。短时间的跑分根本来不及把温度推上去,所以测不出来。
1.2 单卡瞬间跑分说明不了任何稳定性问题
很多人习惯用“跑一遍3DMark/鲁大师/某个AI推理脚本不报错”来证明GPU稳定,这个逻辑在轻度负载下成立,在稳定性测试这个场景下完全不成立。原因很简单:GPU Boost机制会根据温度、功耗余量动态调整频率,轻负载下Boost频率能冲到很高,反而掩盖了问题。真正容易出问题的,是长时间持续满载、温度稳定在高温区间、功耗贴着TDP上限的时候。
gpu_burn的核心思路就是把GPU的计算单元持续压到接近100%占用率,让它连续执行密集的矩阵乘法,并且每一轮结果都会和预期值做比对。一旦某个计算单元在高温下产生错误结果,程序立刻捕获并报错。这种设计思路非常适合复现“跑一会儿才出现”的软故障,因为它不仅制造负载,还在不断校验计算正确性。
1.3 gpu_burn适合谁用、不适合谁用
说句实话,这个工具不是给所有人准备的。它适合三类人:
- 服务器运维,需要在多卡机器上快速定位哪张卡有隐患
- 深度学习训练玩家,换卡、换驱动、改散热之后想做一轮可靠性验证
- 显卡维修、二手显卡检测人群,需要一种能长时间施压的测试手段
不适合的场景:如果你只是想知道“这块卡跑游戏会不会卡”,gpu_burn给不了你答案,它不做图形渲染测试。它也不适合做显存故障检测,虽然显存出问题也可能导致测试失败,但它的设计重点是计算单元,而不是显存颗粒的读写校验。显存问题需要配合专门的显存测试工具去做。
2. 源码编译与安装:三十分钟把gpu_burn跑起来
2.1 先确认CUDA Toolkit和驱动的版本关系
gpu_burn的安装方式和大多数需要编译的Linux工具一样,从源码编译。它依赖CUDA Toolkit,需要用到nvcc编译器,运行时依赖NVIDIA驱动提供的libcuda.so。所以在装gpu_burn之前,我建议你先确认两件事:
nvidia-smi能正常输出GPU信息,说明驱动装好了nvcc --version能输出CUDA版本,说明Toolkit装好了
驱动和CUDA Toolkit的版本关系比较容易踩坑。NVIDIA的驱动向下兼容,新驱动一般能跑旧CUDA,但CUDA Toolkit版本太老或者太新,可能会导致编译报错。我自己现在的环境是CUDA 12.4,编译gpu_burn没有问题。如果你的环境还是CUDA 11.x,建议先用nvcc --version确认,再去仓库README里看一下当前版本推荐的最低CUDA版本。
提示:如果你只是装在本地跑一下,不需要把CUDA Toolkit装到系统全局路径,只要能保证
nvcc在PATH里能找到就行。很多服务器为了兼容不同框架,会同时装多个CUDA版本,这时候编译gpu_burn之前最好先export PATH=/usr/local/cuda/bin:$PATH,避免连到错的nvcc。
2.2 编译三部曲与三个高频报错
安装步骤非常简单,三条命令:
git clone https://github.com/wilicc/gpu-burn.git cd gpu-burn make编译完成后,目录下会出现gpu_burn这个可执行文件。不需要install到系统目录,直接在当前目录运行即可。
我编译过很多次,最常见的三个报错给你列一下:
- nvcc: command not found:说明PATH里没有nvcc,或者CUDA Toolkit没装。先确认
/usr/local/cuda/bin目录是否存在,存在就export到PATH。 - error: #error -- unsupported GNU version!:编译器太新,和当前CUDA版本不匹配。这种情况最容易出现在用很新版本的GCC编译老CUDA环境的时候。建议装一个匹配的GCC版本,或者升级CUDA Toolkit版本。
- error while loading shared libraries: libcuda.so.1:运行时找不到驱动库。一般是驱动没装好,或者
ldconfig没配置。检查/usr/lib/x86_64-linux-gnu/libcuda.so.1是否存在,如果存在就执行sudo ldconfig。
2.3 装完先别急着长测:自检三步走
刚编译完不要直接跑一小时,先做三步快速自检:
# 第一步,确认能列出GPU nvidia-smi -L # 第二步,跑一个20秒短测试 ./gpu_burn -t 20 # 第三步,确认测试期间GPU真的打满了 nvidia-smi --query-gpu=utilization.gpu,temperature.gpu,power.draw --format=csv -l 1这三步看起来冗余,但有实际用处。第一步确认gpu_burn能看到哪几张卡,第二步确认程序能正常初始化CUDA context并跑满一个短循环,第三步确认压测期间GPU利用率确实接近100%。如果第二步走完直接看到Test FAILED,就别浪费时间跑长测了,先解决当前的问题再说。第三步特别重要,很多人跑完短测试没看监控,其实GPU根本没吃满,等于白测。
3. 参数与多卡玩法:默认70秒之外你必须知道的操作
3.1 默认70秒的来历与长短权衡
gpu_burn不带参数直接运行,默认就是70秒。这个数字不算玄学,延续了早期NVIDIA压力测试脚本的习惯,设计意图是让GPU从冷启动开始爬温,在几十秒内进入接近满载的状态,同时覆盖一个温度爬坡区间。
但我必须泼个冷水:70秒远远不足以判断一张卡是否稳定。对一张健康的卡来说,70秒当然不会坏;对一张有隐患的卡来说,70秒可能刚好卡在问题爆发之前。我自己做稳定性验证,最短也是-t 600,也就是10分钟,真正下结论至少跑30分钟以上。温度爬到峰值、功耗稳定、Boost频率不再跳水,都需要时间,一般来说10分钟是个分水岭,30分钟才是判断“稳定”的最低门槛。
3.2 -d指定设备和-t时间:多卡服务器操作
多卡服务器上最常用的参数是-d和-t:
# 全部GPU同时压测,跑10分钟 ./gpu_burn -t 600 # 只测0号卡,跑30分钟 ./gpu_burn -d 0 -t 1800 # 指定0号、2号两张卡同时压测 ./gpu_burn -d 0,2 -t 1800需要注意,-t后面的单位是秒,别把-t 1800当成30分钟就写错成-t 30。-d后面跟的是GPU序号,以nvidia-smi里显示的编号为准,也就是从0开始。还有一种情况是服务器上开了CUDA_VISIBLE_DEVICES环境变量,此时gpu_burn看到的设备编号会受这个环境变量影响。为了避免搞混,我建议压测前先nvidia-smi -L看一眼实际编号,再配合CUDA_VISIBLE_DEVICES控制可见范围。
在老版本的gpu_burn里,多卡测试用的是单独的gpu_burn_multi二进制,新版本基本统一到了gpu_burn加-d参数。如果你在仓库里看到gpu_burn_multi,用法思路是一样的,不用纠结,跑单卡用gpu_burn,多卡用-d或者gpu_burn_multi都行。
3.3 怎么确认GPU真的被“打满”了
跑压测不是把命令敲下去就完事了,一定要同步验证GPU是否满载。我用的是这个命令:
nvidia-smi --query-gpu=index,utilization.gpu,power.draw,temperature.gpu,clocks.sm --format=csv -l 1正常的压测状态应该是:utilization.gpu稳定在98%~100%,power.draw接近该卡TDP(比如RTX 4090满载功耗在400W~450W),temperature.gpu缓慢爬升并最终稳定,clocks.sm维持在一个较高频率。如果你看到利用率在50%上下跳动、功耗上不去,八成是压测进程没跑对,先停下来检查-d参数或者CUDA环境。
还有一个很容易忽略的知识点:看到clocks.sm没有跑在最高Boost频率,不一定是坏事。当GPU温度触达设定阈值,核心会自动降频,这是正常的热保护机制,不代表卡坏了。做稳定性测试时,我们应该关注的是“在某个稳定温度区间内是否能长时间保持正确计算”,而不是“能不能一直跑在最高频率”。
4. 温度监控三板斧:从实时观测到日志留痕
4.1 实时版:nvidia-smi dmon与watch
温度监控这件事,很多人只会开个watch -n 1 nvidia-smi,一边盯着屏幕一边跑压测。人肉盯屏不是不行,但不适合长时间测试,因为你总会有走神的时候,而且眼睛看屏幕根本抓不住温度曲线变化的规律。
我更推荐nvidia-smi dmon,它的实时输出比nvidia-smi的默认视图更适合监控连续变化:
# 每秒输出一次功耗、利用率、时钟、内存、温度等信息 nvidia-smi dmon -s pucvmet -d 1 -c 1000注意这里的-d是“采集间隔秒数”,不是设备编号,别和gpu_burn的-d搞混了。-s pucvmet后面的每个字母代表一组指标:p是功耗,u是利用率,c是时钟,v是功耗违规事件,m是显存,e是ECC,t是温度。-c是采集多少次后退出,比如每秒一次、采集1000次,就是跑1000秒。
dmon输出是空格分隔的表格,第一行是表头。实际看的时候,重点看温度列和功耗违规列。如果压测期间出现功耗违规(对应NVIDIA的violation机制,比如功耗超了被强制限制),说明卡可能已经在降频保护边缘了,配合温度数据一起看,基本能判断出是散热不足还是供电问题。
4.2 留痕版:query-gpu导出CSV
实时监控适合人盯着看,但如果要跑一晚上、第二天拿数据说话,我建议用nvidia-smi --query-gpu导出CSV日志:
mkdir -p ~/gpu_burn_logs nvidia-smi --query-gpu=timestamp,index,temperature.gpu,utilization.gpu,power.draw,clocks.sm --format=csv -l 1 > ~/gpu_burn_logs/gpu_burn_metrics.csv 2>&1 &这条命令会把每秒一条的GPU状态追加到CSV文件里。设置好之后,你就可以放心去睡觉了,第二天用脚本分析。有一点经验要告诉你:文件重定向用>>追加比>覆盖更安全,尤其是你想多次压测、保留多份日志的时候,建议把时间戳加到文件名里:
LOG_FILE=~/gpu_burn_logs/$(date +%Y%m%d_%H%M%S)_gpu_burn.csv nvidia-smi --query-gpu=timestamp,index,temperature.gpu,utilization.gpu,power.draw --format=csv -l 1 > "$LOG_FILE" 2>&1 &4.3 分析版:用Python脚本找温度拐点
日志文件采集了一堆CSV,人眼很难看出门道。我的习惯是用Python简单处理一下,直接算出最高温度、平均功耗、达标率这几个关键指标:
import pandas as pd df = pd.read_csv("gpu_burn_metrics.csv") df.columns = [c.strip() for c in df.columns] # 清洗温度列,取最大值和最终稳定值 max_temp = df["temperature.gpu"].astype(float).max() last_temp = df["temperature.gpu"].astype(float).iloc[-1] # 功耗列会带单位,先去掉 power = df["power.draw"].astype(str).str.replace(" W", "").astype(float) avg_power = power.mean() # 利用率打满比例(>95%算打满) util = df["utilization.gpu"].astype(str).str.replace(" %", "").astype(float) satisfied_ratio = (util > 95).mean() print(f"最高温度: {max_temp:.1f}°C") print(f"测试结束温度: {last_temp:.1f}°C") print(f"平均功耗: {avg_power:.1f}W") print(f"利用率超过95%的时间占比: {satisfied_ratio*100:.1f}%")这个脚本看起来简单,但能回答几个关键问题:温度有没有持续爬升没有稳定下来?功耗是否打到预期TDP?压测期间有没有掉负载?如果温度一直往上走、到测试结束都没稳定,说明散热余量已经不足了;如果功耗和利用率长时间低于预期,说明压测可能没真正打满。
我的判断标准供参考:压测30分钟,温度曲线应该在前5~10分钟快速上升,之后进入平台期,波动不超过2°C~3°C。如果温度一直缓慢爬升、始终不收敛,比一上来就冲到85°C更危险,说明散热路径上存在瓶颈,长时间运行大概率会出问题。
4.4 测稳定性和测散热的区别:功耗墙与温度墙
这里要区分两个容易混淆的概念:功耗墙和温度墙。功耗墙是GPU硬件设置的功耗上限,超过这个值,核心频率会被主动压低;温度墙是温度上限,触达后也会降频甚至触发保护性关机。gpu_burn这类压力测试工具能让GPU很快撞到功耗墙,但不一定能撞到温度墙。
我见过不少人在夏天给显卡压测,一跑就85°C甚至90°C,然后吓坏了。其实对于某些高功耗卡,满载85°C左右是正常水平,关键是看它有没有出现功耗违规、频率骤降、计算错误。真正需要重视的是:同一张卡,之前压测稳定在75°C,过段时间变成85°C,说明散热系统劣化了,哪怕测试结果显示PASS,也要留个心眼。
如果你希望在固定频率下做压测,排除Boost频率随机性的干扰,可以用nvidia-smi -lgc锁频:
# 锁定SM频率到1500MHz(数字按你显卡实际范围调) sudo nvidia-smi -lgc 1500,1500 # 压测完记得恢复自动频率 sudo nvidia-smi -rgc锁频做压测时,如果GPU依然报错,那问题范围就缩小到“固定频率下也错”,和Boost机制无关,基本可以锁定是硬件层面的缺陷了。
5. 实战复盘:用12小时压测定位一张问题卡
5.1 现象:训练两小时必崩一次
说一个完整的排查案例,帮你把前面的工具串起来。之前遇到过一台4卡机器,跑深度学习训练,用户反馈每次跑到两小时前后,进程就会报CUDA error,有时是an illegal memory access was encountered,有时是out of memory但检查显存明明够用。最迷惑的是重启之后能正常跑,但下一次还是会在两小时左右崩。
第一反应自然是查驱动日志。dmesg里能看到NVRM报错,但没有明确的Xid错误代码指向具体哪张卡。这种情况在多卡机里特别难办,因为CUDA默认使用的设备可能和用户程序实际指定的设备不一致,日志里不会直接写“就是物理槽位第3张卡坏了”。
5.2 排查链路:从dmesg到逐卡压测
我的排查顺序是这样的:
- 先用
nvidia-smi -q | grep -i "Serial\|UUID"记录每张卡的UUID,建立物理槽位到系统设备号的映射 - 停掉业务,逐卡跑gpu_burn做排除法
- 每张卡单独压测30分钟,同步记录温度日志
具体命令是:
# 逐卡压测,每张卡先跑30分钟 ./gpu_burn -d 0 -t 1800 ./gpu_burn -d 1 -t 1800 ./gpu_burn -d 2 -t 1800 ./gpu_burn -d 3 -t 1800注意这里没有同时压4张卡,而是逐卡压。原因很简单:同时压4张卡会让机箱整体温度升高,噪声信号会淹没掉真正的问题卡。逐卡压测时,其他卡空闲,机箱环境温度相对干净,有利于隔离问题。
结果很清晰:0号、1号、3号卡各跑30分钟全部PASS,2号卡在跑了大约17分钟后输出Test FAILED。查看同时记录的CSV日志,发现2号卡在失败前温度曲线一直正常,没有突然飙升或者降频,也就是说不是散热瞬间恶化,而是计算单元在持续高温下产生了错误。这个信号指向芯片本身的时序劣化,不是散热问题。
5.3 结论:不是芯片坏,是散热劣化
拆机检查后,真相和纯计算错误有点不一样:2号卡的散热器积灰严重,风扇转速明显比其他卡低了几百转,但温度为什么看起来正常?因为那张卡的风扇策略有问题,温度传感器读到的核心温度还可以,但热点温度和显存温度已经悄悄超了,等到计算单元开始报错时,表面温度还停留在“看起来正常”的范围。
后来把散热器拆开清灰、重新涂硅脂、校准风扇策略之后,再跑同一张卡gpu_burn 12小时,全PASS,温度比之前还低了8°C。这场排查最大的教训是:压测报告PASS不代表万事大吉,你得把温度日志和压测结果放在一起看。如果一张卡虽然PASS,但温度曲线异常,或者和同型号其他卡温差超过10°C,那它大概率是下一块出问题的卡,趁早处理比等它坏了再换要省心得多。
6. 边界与组合拳:gpu_burn测不出哪些故障
6.1 显存故障与ECC错误是另一条线
gpu_burn的核心是计算单元压力,不是专门的显存测试。虽然显存颗粒故障严重时也会导致计算结果错误,从而让压测失败,但早期的、轻微的显存故障不一定能被gpu_burn捕捉到。GPU显存出问题的表现往往是驱动重置、ECC错误累计、特定显存地址访问失败,这些需要专门的显存压力测试工具来验证,比如cuda-memtest这类工具。
如果你是做二手卡验收,或者怀疑显存有问题,我建议不要只依赖gpu_burn。先用显存测试工具跑几轮,再做一次gpu_burn长测,两轮都过了,才能比较放心地说这张卡能用。
6.2 通信、编解码、虚拟化切分都不归它管
多卡服务器通信问题,gpu_burn完全测不出来。NVLink带宽、PCIe P2P通信、RDMA、GPU Direct Storage这类问题,需要用到nccl-tests或者dcgmproftester之类的工具。我遇到过不止一次:单卡压测全PASS,一旦多卡跑分布式训练就通信超时,最后查出是NVLink线缆接触不良,这种问题gpu_burn帮不上忙。
视频编解码能力也不是gpu_burn的测试范围。做转码、直播、渲染相关业务的,需要额外使用对应的编解码压力测试方法。虚拟化环境同样如此,如果你在K8s里通过设备插件调用GPU,压测通过只能说明物理卡没问题,但MIG切片、CUDA_VISIBLE_DEVICES分配、设备插件调度这些环节都可能出现新问题,需要结合容器内的测试和调度系统日志一起排查。
6.3 组合工具矩阵:gpu_burn + nvidia-smi + DCGM
以我现在的做法,给GPU做一次比较完整的健康检查,会跑一套组合拳:
| 检查维度 | 工具 | 时间建议 | 关键指标 |
|---|---|---|---|
| 计算稳定性 | gpu_burn | 30分钟以上 | 是否PASS、功耗、频率 |
| 温度曲线 | nvidia-smi --query-gpu | 全程记录 | 最高温、稳定温、是否收敛 |
| 显存读写 | cuda-memtest | 多轮循环 | ECC错误、读写是否一致 |
| 多卡通信 | nccl-tests | 按业务规模 | allreduce带宽、超时率 |
| 长期健康巡检 | DCGM | 持续运行 | 电压、功耗、温度基线 |
这套组合拳看起来重,但真正做一次也就半天时间。对服务器这种7x24小时运行、一次故障可能拖累整个训练任务的设备来说,这个时间成本非常值得。
最后说一个我自己的体会:gpu_burn这个工具从编译到上手,真正花不了多少时间,难点从来不在工具本身,而在于你怎么读懂它给出的结果。压测PASS只是一个启动条件,不是最终结论。我的习惯是每次压测都留日志,同一张卡的历史温度曲线放在一起对比,一旦发现某个指标慢慢偏移了,就提前干预,别等它真正崩溃了才去救火。