1. GPU科学计算环境自检与驱动兼容性排查
先建立“版本三角”再谈核函数报错
核函数启动失败(如 CUDA error: no kernel image is available for execution on the device 或 invalid device function)在科学计算环境里经常不是代码问题,而是驱动、CUDA 运行时、编译器三者版本关系断裂。排查顺序应是:先确认 GPU 与驱动支持的最高 CUDA 版本,再确认运行时与编译器实际版本,最后核对编译产物中的目标架构(SM 版本)是否被当前驱动/设备接受。
第一步:采集三处真实版本信息
不要凭记忆判断版本,逐条执行并记录输出。以下命令在 Linux 目标机上运行,示例输出仅作格式说明,实际值以你的机器为准。
# 1) 驱动与驱动支持的最高 CUDA 版本
nvidia-smi
# 关注右上角 "CUDA Version: 12.2" —— 这是驱动能支持的上限,不是已安装运行时
# 2) 运行时版本(两种方式互相印证)
nvcc --version
# 或
cat /usr/local/cuda/version.json 2>/dev/null | head -20
# 3) 运行时库实际被链接的版本
ldd ./your_app | grep cudart
# 4) 设备计算能力
nvidia-smi --query-gpu=name,compute_cap --format=csv
把结果填入下表,形成“版本三角”快照。判定规则:驱动 CUDA Version ≥ 运行时版本,且编译时的 -arch 覆盖设备 compute capability,两者同时成立才算一致。
| 检查项 | 命令/来源 | 示例值 | 判定要点 |
|---|---|---|---|
| 驱动版本 | nvidia-smi | 535.104.05 | 记录 Driver Version |
| 驱动支持上限 | nvidia-smi 右上角 | CUDA 12.2 | 运行时不得高于此值 |
| 运行时版本 | nvcc --version | release 12.4 | 与上限比较 |
| 链接的 cudart | ldd | libcudart.so.12 | 确认实际加载库 |
| 设备算力 | compute_cap | 8.6 | 对应 sm_86 |
| 编译目标 | nvcc -arch | sm_86 / sm_80 | 须覆盖设备算力 |
第二步:用最小程序复现并定位失败点
写一个只做“查询版本 + 启动空核函数”的最小程序,把失败从业务代码中隔离出来。若此程序报 no kernel image is available,即可确认是版本/架构问题而非算法问题。
// check_env.cu
#include <cstdio>
#include <cuda_runtime.h>
__global__ void empty_kernel() {}
int main() {
int rt = 0, drv = 0;
cudaRuntimeGetVersion(&rt);
cudaDriverGetVersion(&drv);
printf("runtime=%d driver=%d\n", rt, drv);
int dev = 0;
cudaDeviceProp prop;
cudaGetDeviceProperties(&prop, dev);
printf("device=%s sm_%d%d\n", prop.name, prop.major, prop.minor);
empty_kernel<<<1, 1>>>();
cudaError_t err = cudaGetLastError();
if (err != cudaSuccess) {
printf("kernel launch failed: %s\n", cudaGetErrorString(err));
return 1;
}
printf("kernel launch OK\n");
return 0;
}
编译时显式指定目标架构,避免默认架构与设备不匹配:
nvcc -arch=sm_86 check_env.cu -o check_env
./check_env
若设备算力为 8.6 而编译用了 sm_80,SASS 不含 sm_86 时可能回退到 PTX JIT;若驱动过旧无法 JIT 新 PTX,就会报 no kernel image is available。此时把 -arch 改为 sm_86 或使用 -gencode arch=compute_86,code=sm_86 重新编译即可验证。
第三步:给出可执行的降级或升级方案
根据版本三角的缺口选择方案,优先选择改动面小、可回退的路径:
- 驱动上限低于运行时(如驱动支持 12.2,运行时为 12.4):降级 CUDA 运行时/工具链到 12.2,或升级驱动到支持 12.4 的版本。生产机优先降级工具链,避免动驱动影响其他任务。
- 编译架构不覆盖设备:调整
-arch或-gencode,加入设备实际 SM;若需兼容多卡,使用多目标-gencode组合。 - 多版本共存:用
update-alternatives或环境变量CUDA_HOME、PATH、LD_LIBRARY_PATH切换,避免全局覆盖。
# 降级示例:切换到已安装的 CUDA 12.2 工具链
export CUDA_HOME=/usr/local/cuda-12.2
export PATH=$CUDA_HOME/bin:$PATH
export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH
nvcc --version # 确认已切换
# 重新编译并运行 check_env 验证
验证通过标准:
check_env 输出 kernel launch OK,且 runtime 值不高于 nvidia-smi 显示的 CUDA Version,设备 SM 与编译目标一致。不要用“重装驱动”作为第一反应。先记录当前驱动版本与业务依赖,确认降级工具链可行后再决定是否动驱动;驱动变更可能影响同机其他容器的运行时。