先建立一个判断模型
CUDA 环境排查最常见的错误,是把 nvidia-smi、nvcc、Python 包里的 CUDA runtime、系统动态库混成一件事。它们实际处在不同层级:
| 层级 | 典型检查命令 | 作用 |
|---|---|---|
| NVIDIA Driver | nvidia-smi、cat /proc/driver/nvidia/version | 让内核和用户态程序能够访问 GPU |
| CUDA Runtime | ldd executable、Conda/PyTorch/TensorFlow 包依赖 | 程序运行时加载的 CUDA 动态库 |
| CUDA Toolkit | nvcc --version、/usr/local/cuda-* | 编译 CUDA 源码、提供头文件和开发库 |
| Host Compiler | gcc --version、g++ --version | nvcc 编译 host 端 C/C++ 代码时调用 |
nvidia-smi 输出中的 CUDA Version 不是本机已安装的 Toolkit 版本,而是当前驱动可支持的 CUDA 能力上限。源码编译时真正要看的是 nvcc --version 和 host compiler;运行 Python 包时更要看当前环境实际加载了哪些 runtime 库。
采集一份最小环境快照
每次排查前先保存下面这些输出。不要只截一张 nvidia-smi 图。
date
hostnamectl
uname -a
nvidia-smi
cat /proc/driver/nvidia/version 2>/dev/null || true
which nvcc || true
nvcc --version || true
gcc --version | head -1
g++ --version | head -1
echo "PATH=$PATH"
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH"
ldconfig -p | grep -E 'libcuda.so|libcudart.so' | head -20
如果系统使用 module/Lmod:
module list
module avail cuda 2>&1 | sed -n '1,80p'
如果问题发生在 Conda/Python 环境:
which python
python - <<'PY'
import os, sys
print(sys.executable)
print("LD_LIBRARY_PATH=", os.environ.get("LD_LIBRARY_PATH", ""))
PY
conda list | grep -Ei 'cuda|cudnn|pytorch|tensorflow|deepmd' || true
判断分支一:nvidia-smi 不工作
如果 nvidia-smi 本身失败,先不要处理 Toolkit 或 Python 包。此时问题通常在驱动层:
- 内核模块没有加载。
- 驱动版本和当前内核不匹配。
- Secure Boot、DKMS、内核升级后未重编译模块。
- 容器内没有正确暴露 NVIDIA 设备。
优先检查:
lsmod | grep nvidia
dmesg | grep -i nvidia | tail -80
systemctl status nvidia-persistenced 2>/dev/null || true
在远程服务器上升级或重装驱动有失联风险,尤其是带桌面环境或内核刚升级的机器。生产环境应先确认带外管理、SSH 会话保持、当前内核和可回滚方案。
判断分支二:nvidia-smi 正常,但 nvcc 不存在
这不一定是错误。很多运行型软件不需要系统安装 Toolkit:
- PyTorch、TensorFlow、DeepMD-kit 的 Conda/Pip 包可能携带 runtime 组件。
- 只运行已编译好的二进制程序时,可能只需要驱动和运行时库。
- 需要从源码编译 CUDA 代码时,才必须确认 Toolkit 和
nvcc。
如果目标是编译 LAMMPS、GROMACS、GPUMD 或自定义 CUDA 程序,就需要安装或加载 Toolkit,并确认 nvcc 使用的是预期版本:
readlink -f "$(which nvcc)"
nvcc --version
判断分支三:driver/runtime mismatch
典型报错:
CUDA driver version is insufficient for CUDA runtime version
这个错误通常表示运行时 CUDA 库需要的驱动能力高于当前驱动。NVIDIA 从 CUDA 11 开始提供 minor version compatibility,但仍然有最低驱动版本要求。不要根据“CUDA 12.x 看起来都差不多”来猜,应该对照 NVIDIA CUDA Compatibility 文档。
排查时关注两件事:
nvidia-smi
ldd /path/to/executable | grep -i cuda
如果是 Python 包,重点看 Conda 环境里的 CUDA runtime,而不是只看 /usr/local/cuda:
conda list | grep -Ei 'cuda|cudnn|pytorch|tensorflow'
判断分支四:nvcc 找得到,但编译失败
这类问题经常是 host compiler 不被当前 CUDA Toolkit 支持。NVIDIA CUDA Linux Installation Guide 中有 host compiler support policy;不同 CUDA 大版本对 GCC/Clang 的支持范围不同。
先记录:
nvcc --version
gcc -dumpfullversion
g++ -dumpfullversion
如果是 CMake 项目,还要记录 CMake 实际发现的编译器:
grep -E 'CMAKE_(C|CXX|CUDA)_COMPILER(:|=)' CMakeCache.txt
grep -E 'CMAKE_CUDA_HOST_COMPILER|CUDAHOSTCXX' CMakeCache.txt
不要用 --allow-unsupported-compiler 当作常规方案。它可以绕过 nvcc 的版本检查,但不能保证模板库、C++ 标准库、ABI 和目标软件都能稳定编译。
判断分支五:多个 CUDA 路径互相污染
常见污染来自全局 .bashrc:
export PATH=/usr/local/cuda/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
如果机器同时安装多个 CUDA 版本,或者用户还使用 Conda,这种全局写法很容易让不同项目加载到错误 runtime。更推荐使用 module、项目级环境脚本或容器,把每个软件的 CUDA 路径固定下来。
检查当前加载顺序:
echo "$PATH" | tr ':' '\n' | nl
echo "$LD_LIBRARY_PATH" | tr ':' '\n' | nl
验收标准
CUDA 环境可用不能只看 nvidia-smi。至少要按目标场景验收:
- 编译型场景:
nvcc、host compiler、CMake 配置和最小 CUDA 示例通过。 - Python 场景:目标包能导入,能看到 GPU,最小 GPU 任务可运行。
- 科研软件场景:目标软件的小算例能走 GPU 后端,日志中能看到对应 backend 或 GPU device 信息。
验收记录应包含驱动版本、Toolkit/runtime 来源、编译器版本、环境加载方式、测试命令和输出日志。