1. 场景还原:这个错误什么时候出现
1.1 典型上报路径
我最早碰到 CUDA Error Code 802 是在一次 8 卡 A100 的分布式训练上。程序用的是 PyTorch DDP,启动脚本也没问题,nvidia-smi能看到 8 张卡都在线,显存也全部空闲,但只要一执行torch.cuda.is_available()或者初始化进程组,就会在某个 rank 上报错,错误信息里明确写着CUDA_ERROR_SYSTEM_NOT_READY。除了 PyTorch,TensorFlow、PaddlePaddle,甚至自己写的 CUDA C++ 代码,只要走到cudaSetDevice、cudaGetDeviceCount、cudaMalloc这些 API,都可能把这个错误码抛出来。
让我印象更深的是,这个错误并不是每次都能复现。有时候重启机器后正常,跑一两个小时后突然出现;有时候卡 1 的进程正常,卡 2 的进程报错;还有一次是所有人都在一起用机器,新提交任务只要一启动就报 802,但已经在跑的旧进程反而没受影响。这种随机性最让人头疼,因为你不知道是代码问题、环境问题还是硬件问题。
从错误码定义来看,CUDA_ERROR_SYSTEM_NOT_READY属于系统级错误,跟普通的“显存不足”“非法参数”完全不一样。普通错误通常可以定位到某个具体的 API 调用和资源状态,但 802 更像是整个 CUDA 运行环境没有准备好,导致任何后续操作都无法继续。多卡机器上遇到这种问题,影响范围往往不是单卡,而是整机所有任务,严重的时候只能重启。
1.2 多卡机器为什么更容易踩中
单卡机器遇到 802 的概率低很多,因为驱动只需要管理一个设备的状态。多卡机器上,驱动要同时初始化和管理多块 GPU,还要处理它们之间可能的 NVLink 互联、PCIe 带宽竞争和显示器输出。任何一个设备在 reset 或掉卡时,都可能影响到整个驱动状态机。比如有一块 GPU 因为瞬时功耗过高触发了硬件保护,驱动会在内核日志里记录一个 Xid 错误,然后把这块卡从驱动管理列表中摘掉。这个过程中,其他卡上的 CUDA 上下文也可能被强制失效,新任务如果恰好在这个时候初始化,就会收到 802。
另外,多卡机器往往是多人共用的,多个进程同时调用 CUDA 的概率远高于单卡开发机。多个进程同时打开设备节点、同时创建 context,驱动层如果处理不当,就会产生竞态。尤其是某些进程异常退出后没有正确释放显存和 context,新进程再访问同一个物理设备时,驱动可能还停留在上一个进程的失效状态中,于是直接返回“系统未就绪”。所以我说,多卡环境下 802 本质上是驱动链路里的状态错位,而不是单纯的代码 bug。
2. 错误码 802 背后的机制
2.1 错误从哪里来
我们得先分清错误层次。一般的 CUDA 应用调用链大概是:代码调用 CUDA Runtime API(cudart),Runtime 再调用 Driver API(libcuda),最后通过 ioctl 进入内核态的 NVIDIA 驱动,再由驱动访问物理 GPU。Error Code 802 是 Driver API 层的错误,也就是说驱动模块是起作用的,但底层状态机认为系统没有准备好。
这跟常见的 “CUDA driver version is insufficient” 不一样,那是版本不匹配;802 更像是驱动对某个设备或整个系统返回“我现在不能给你干活”。打个比方:你去银行柜台办业务,网点开门了,柜员也在,但内部系统正在维护,所有操作都办不了。nvidia-smi能看到 GPU,说明硬件和驱动主框架通信正常;但 CUDA 初始化需要额外的能力,比如 UVM 模块、持久化线程、设备文件节点,这些底层设施任意一个没就绪,都会卡在 802 上。
从驱动代码的角度看,CUDA_ERROR_SYSTEM_NOT_READY通常由驱动内部的状态检查触发。比如驱动尝试初始化一个 GPU 的上下文时,发现该 GPU 正处于 reset、掉卡或者不可恢复状态,就返回这个错误。又比如 UVM(统一虚拟内存)模块没有加载,或者nvidia_uvm这个设备节点无法打开,CUDA Runtime 在初始化虚拟内存管理时也会报 802。
2.2 哪些底层状态会导致 802
根据我踩过的坑,触发 802 的底层因素大致可以分成几类:
第一,驱动模块没有完全加载。开机后如果nvidia_uvm没有自动加载,CUDA Runtime 初始化就会失败。这个问题在手动编译驱动或者更新内核后特别常见。
第二,某块 GPU 掉卡或正在 reset。前面提到的 Xid 79 “GPU has fallen off the bus”,就是典型。GPU 掉卡后,驱动只对这块卡标记为 error,但没有彻底重启整个驱动,其他卡上的 context 可能已经脏了,新任务一初始化就碰到 802。
第三,设备节点权限不够。CUDA 需要访问/dev/nvidia0、/dev/nvidiactl、/dev/nvidia-uvm这些设备文件。如果 udev 规则没配好,普通用户打不开这些节点,驱动虽然正常,但用户态程序拿不到句柄,最终报错也可能泛化成 802。
第四,非持久化模式下多个进程频繁退出。GPU 默认不是持久化模式,当最后一个使用 GPU 的进程退出后,驱动会清理 context。如果紧接着有新进程快速启动,驱动还没来得及完成清理,新进程就可能拿到“系统未就绪”。这种情况在多用户多机的实验室环境里特别常见。
第五,虚拟化环境下的驱动错位。比如 WSL2 里,Windows 侧显示驱动版本和 Linux 侧的 CUDA 工具链不匹配,或者容器里没有挂载正确的 NVIDIA 设备节点,也会出现 802。这类问题不是单卡物理故障,但表现和驱动链路故障几乎一样。
3. 排查进阶:一步步定位根因
3.1 第一步:给整机做个体检
遇到 802,我建议先不要急着重装驱动或者 CUDA,先花两分钟做一组快速体检。打开终端,依次执行下面三条命令:
nvidia-smi nvcc -V dmesg | grep -i nvidia | tail -n 50第一条看驱动和 GPU 状态。如果nvidia-smi能正常列出所有显卡,说明驱动主模块还活着;如果输出为空或者报 “No devices were found”,说明驱动和 GPU 之间的通道已经断了。第二条看 CUDA Toolkit 版本,用来和驱动支持的最高 CUDA 版本做对比。第三条看内核日志里的 NVIDIA 相关记录,这一步最关键,Xid 错误、模块加载失败、总线错误都会被记录在这里,而且日志里的时间戳能帮你定位事故发生的准确时间点。
还要单独检查nvidia_uvm模块有没有加载:
lsmod | grep nvidia正常情况下会看到nvidia_uvm、nvidia_drm、nvidia_modeset、nvidia这几个模块。如果nvidia_uvm不在列表里,直接加载它:
sudo modprobe nvidia_uvm加载完再跑一次 CUDA 程序,很多情况下问题就消失了。
注意:在加载或卸载 NVIDIA 内核模块之前,最好停止所有使用 GPU 的服务,比如运行中的训练任务、Jupyter、桌面窗口管理器。强制卸载模块有时会导致系统卡死,特别是还在跑图形界面的机器。
3.2 第二步:清理进程与资源锁
nvidia-smi正常但程序报 802,我第二个怀疑对象是进程残留。看哪些进程占用了 GPU:
fuser -v /dev/nvidia*如果有属于僵尸 PID 的进程,或者你看得到但不确定是干嘛的 Python 进程,先确认一下再 kill:
sudo kill -9 <pid>很多时候,崩溃的训练进程没有释放显存,驱动里还保留着一堆失效的 context,新进程初始化时撞上这些残留资源就会报 802。杀完进程后,最好等几秒再跑测试,给驱动一点清理时间。
另一个常见场景是多个进程同时启动。假设你用torch.multiprocessing启动 4 个 worker,每个 worker 都调用torch.cuda.init(),驱动可能因为并发创建 context 而返回 802。这时候一个简单的办法是给每个进程设置不同的CUDA_VISIBLE_DEVICES,让它们物理隔离到不同的卡上;或者在子进程的入口函数里先sleep1 到 2 秒,错开初始化时间。
3.3 第三步:重置驱动模块与 GPU
如果清理进程后还报 802,可以尝试开启 GPU 持久化模式并做一次软件重置。先开启持久化模式:
nvidia-smi -pm 1这样驱动会保持 context 常驻,避免频繁创建和销毁。接着尝试重置指定 GPU,比如第 0 张卡:
nvidia-smi --gpu-reset -i 0这个操作要求该卡上没有任何进程,否则会报 “Unable to reset selected GPU”。如果整机没有其他任务,也可以直接重载驱动模块:
sudo rmmod nvidia_uvm nvidia_drm nvidia_modeset nvidia sudo modprobe nvidia_uvm但要注意,重载模块会影响所有 GPU 上的进程,所以只适合空闲机器。如果重载之后问题还在,或者系统已经卡得连nvidia-smi都跑不动,那就不要犹豫,直接重启机器。重启后第一件事就是再次打开dmesg看有没有新的错误。
3.4 第四步:检查硬件与固件
软件层面都试过了还是不行,大概率是硬件层面的问题。最典型的表现是某块卡在nvidia-smi里显示ERR!,或者在dmesg里看到类似下面的日志:
NVRM: Xid (PCI:0000:3b:00.0): 79, GPU has fallen off the bus.Xid 79 说明 GPU 从 PCIe 总线上掉下来了。原因可能是供电不足、PCIe 卡槽接触不良、GPU 过热或者固件问题。遇到这种情况,先尝试用热重置命令恢复:
nvidia-smi -r -i <gpu_id>如果提示无法重置,那就只能关机断电,重新拔插显卡,换一个 PCIe 插槽,或者检查电源线的连接。对于临时恢复系统,你可以先用环境变量把有问题的卡屏蔽掉,让其他卡继续工作:
export CUDA_VISIBLE_DEVICES=0,1,2,3,4,6,7这样虽然损失了一张卡的算力,但至少机器还能用,训练任务不至于全部停摆。
4. 完整实操记录:一次 8 卡机 802 排障
4.1 故障现场
这里记录一次比较典型的排障过程。实验室有一台 8 卡 A100 的机器,驱动版本 545.23.08,CUDA 12.3。某天下午,几个同学同时在跑训练,突然新提交的任务全部报 802,老的进程也陆陆续续挂掉。我登录上去先看nvidia-smi,发现第 5 张卡的状态列显示ERR!,其他 7 张卡看起来正常,但显存使用率被之前崩溃的进程占了,PID 已经不存在了。
结合用户反馈,事故发生在一次瞬时高负载之后。当场判断大概率是某块卡触发了 Xid 错误,导致驱动状态异常。这时我没有直接重启,而是先抓现场日志。
4.2 关键命令与输出解读
我先看了dmesg:
dmesg | grep -i "Xid" | tail输出里有这样一条关键信息:
[12345.678] NVRM: Xid (PCI:0000:3b:00.0): 79, GPU has fallen off the bus.说明第 5 张卡从 PCIe 总线上掉下来了。我又确认了一下这张卡的详细状态:
nvidia-smi -q -i 5 | head -n 30其中有一行显示GPU State: Not Supported,说明驱动无法正常获取这块卡的运行状态。接着查看系统日志里有没有供电和温度相关的告警:
dmesg -T | grep -i -E "thermal|power|nvidia" | tail -n 50虽然没直接看到温度报警,但 Xid 79 出现在高负载节点之后,高度怀疑是供电瞬时不足或 PCIe 插槽脱落。于是尝试用软件重置一次:
nvidia-smi -r -i 5结果返回:
Unable to reset selected GPU.软件重置失败,只能走硬件排查。
4.3 解决与验证
和机房管理员确认后,决定临时处理。先把第 5 卡从可见列表中排除,同时清理残留进程:
export CUDA_VISIBLE_DEVICES=0,1,2,3,4,6,7 pkill -9 python然后跑一次显存测试和 CUDA 样本:
nvidia-smi -L /usr/local/cuda/samples/1_Utilities/deviceQuery/deviceQuerydeviceQuery的输出里,7 张卡都能正常初始化,PASS 通过。接着重新启动训练任务,刚开始有些担心多卡 DDP 会挂,但实际运行稳定了十几个小时没有复现 802。等机器窗口空闲后,再计划断电重插这张卡,并在 BIOS 里关闭 PCIe ASPM 以降低掉卡概率。
这次排障给我的经验是:802 不一定代表所有卡都坏了,更多时候是单卡故障连带驱动整体异常。只要快速定位到问题卡并隔离,整个系统就能恢复可用。
5. 常见问题速查与避坑清单
5.1 常见报错组合速查表
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
nvidia-smi正常,程序报 802 | 多进程并发初始化、context 残留 | 清理进程,设置CUDA_VISIBLE_DEVICES,错开初始化时间 |
nvidia-smi卡死或输出为空 | 驱动模块无响应、GPU 掉卡 | 检查dmesg,必要时重启 |
dmesg有 Xid 79 | GPU 从总线掉落 | nvidia-smi -r重置,检查供电和插槽 |
某张卡状态显示ERR! | 硬件故障或过热 | 隔离该卡,规划断电替换或重插 |
| WSL2 里报 802 | Windows 驱动和 WSL 内工具链不匹配 | 更新 Windows 侧 NVIDIA 驱动,不要手动装 Linux 驱动 |
| 容器内报 802 | 没有挂载 NVIDIA 设备节点 | 使用nvidia-container-toolkit,正确配置 runtime |
| 更新内核后报 802 | NVIDIA 内核模块与内核版本不匹配 | 重新安装或重编驱动,确认 DKMS 状态 |
这张表基本覆盖了我遇到过的绝大多数 802 场景。如果你手里的报错信息不在表里,也不用慌,按 3.1 到 3.4 的顺序排查,总能找到方向。
5.2 那些年我踩过的坑
第一个坑是下载驱动安装包不完整。某次用浏览器下载 NVIDIA 驱动.run文件,安装时提示:
gzip: stdin: invalid compressed>export PATH=/usr/local/cuda-12.3/bin:$PATH export LD_LIBRARY_PATH=/usr/local/cuda-12.3/lib64:$LD_LIBRARY_PATH有条件的话,尽量在 conda 或虚拟环境里装独立 CUDA Toolkit,这样不同项目之间不会互相污染。我在生产环境维护过多套环境,这个习惯帮我避开了一堆版本兼容问题。
6.2 多卡环境下的初始化策略
最后分享几个日常能减少 802 出现概率的小策略。第一,在训练脚本入口统一设置设备顺序:
import os os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,2,3,4,5,6,7"这样在所有进程里保证同样的 GPU 编号逻辑,避免因为系统枚举顺序不同导致多进程互相抢卡。第二,多进程启动时加入小延时或使用文件锁,避免同一瞬间涌入大量 CUDA 初始化请求。第三,对使用 NCCL 的多卡任务,设置NCCL_DEBUG=INFO,一旦通信初始化失败,日志里能直接看到是哪个 rank、哪张卡出了问题。
另外,建议给多卡机器配一个简单的监控脚本,每小时检查一次dmesg里有没有新增 Xid 错误,一旦发现就告警。Xid 错误是 GPU 故障的前兆,早发现早处理,远比等到 802 爆发再救火要省事。
处理 802 这么多次,我的感受是:不要一上来就重装 CUDA,也不要频繁重启。先学会看dmesg和nvidia-smi,大多数时候原因都写在日志里。日常做好驱动和 CUDA 版本记录,多卡机器上保留一张干净的启动盘,关键时刻能省下大量排查时间。希望这篇分享能帮你把 802 从“玄学问题”变成“可排查问题”。