1. GPU科学计算环境自检与驱动兼容性排查

先建立“版本三角”再谈核函数报错

核函数启动失败(如 CUDA error: no kernel image is available for execution on the device 或 invalid device function)在科学计算环境里经常不是代码问题,而是驱动、CUDA 运行时、编译器三者版本关系断裂。排查顺序应是:先确认 GPU 与驱动支持的最高 CUDA 版本,再确认运行时与编译器实际版本,最后核对编译产物中的目标架构(SM 版本)是否被当前驱动/设备接受。

驱动层 nvidia-smi Driver Version CUDA Version (上限) 运行时层 nvcc --version cudaRuntimeGetVersion libcudart.so 编译层 nvcc -arch=sm_XX PTX / SASS compute capability 须 ≥ 须匹配 GPU 设备 compute capability cudaGetDeviceProperties 目标架构须被支持 一致:核函数可正常启动 驱动上限 ≥ 运行时版本,且 SASS/PTX 覆盖设备 SM → 继续排查代码与启动配置 不一致:核函数启动失败 驱动上限 < 运行时版本,或 SASS 不含设备 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-smi535.104.05记录 Driver Version
驱动支持上限nvidia-smi 右上角CUDA 12.2运行时不得高于此值
运行时版本nvcc --versionrelease 12.4与上限比较
链接的 cudartlddlibcudart.so.12确认实际加载库
设备算力compute_cap8.6对应 sm_86
编译目标nvcc -archsm_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 与编译目标一致。
不要用“重装驱动”作为第一反应。先记录当前驱动版本与业务依赖,确认降级工具链可行后再决定是否动驱动;驱动变更可能影响同机其他容器的运行时。