You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CUDA向量加法程序输出全零且无报错,请求问题排查

CUDA向量加法结果全零的问题排查与修复

你的代码存在几个关键问题导致结果异常,下面逐一说明并给出修复方案:

1. 缺失CUDA错误检查

这是定位问题的核心——所有CUDA API调用(内存分配、数据拷贝、核函数启动)都没有错误校验,很多时候错误发生在这些环节但你完全无法感知,比如核函数启动参数非法、内存分配失败等,都会直接导致后续结果异常。

修复方法:添加一个错误检查宏,在所有CUDA操作后验证执行结果:

#define CHECK_CUDA_ERROR(err) \
    if (err != cudaSuccess) { \
        fprintf(stderr, "CUDA错误位于 %s:%d: %s\n", __FILE__, __LINE__, cudaGetErrorString(err)); \
        exit(EXIT_FAILURE); \
    }

然后在每个CUDA调用后追加检查:

  • 内存分配后:CHECK_CUDA_ERROR(cudaMalloc(&d_A, size));
  • 数据拷贝后:CHECK_CUDA_ERROR(cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice));
  • 核函数启动后,需检查启动合法性并同步设备:
    vecADDKernal<<<gridSize, blockSize>>>(d_A, d_B, d_C, n);
    CHECK_CUDA_ERROR(cudaGetLastError()); // 检查核函数启动参数是否合法
    CHECK_CUDA_ERROR(cudaDeviceSynchronize()); // 等待核函数执行完成
    

2. Grid尺寸计算的潜在问题

你当前用ceil(n/blockSize)计算gridSize,但n和blockSize都是整数,整数除法会先截断小数部分再执行ceil,这在n不是blockSize整数倍时会导致gridSize不足(比如n=1048577时,n/blockSize=4096,ceil后还是4096,总线程数无法覆盖所有元素)。虽然你的n=1048576刚好是256的倍数,这次没触发问题,但写法不规范,容易留下隐患。

修复方法:用整数运算替代浮点ceil,确保gridSize足够覆盖所有元素:

int gridSize = (n + blockSize - 1) / blockSize;

3. 老GPU的double类型支持问题

如果你的GPU是Compute Capability 1.x的老旧设备,原生不支持double类型,核函数里的double运算会被静默失效,最终导致结果全为0。

验证方法:把代码中所有double改成float,重新编译运行,如果结果正常,说明就是这个问题。

修复后的完整代码示例

#include <iostream>
#include <cstdlib>
#include <cmath>
using namespace std;

#define CHECK_CUDA_ERROR(err) \
    if (err != cudaSuccess) { \
        fprintf(stderr, "CUDA错误位于 %s:%d: %s\n", __FILE__, __LINE__, cudaGetErrorString(err)); \
        exit(EXIT_FAILURE); \
    }

__global__ void vecADDKernal(double *A, double *B, double *C, int n){
    int id = blockIdx.x*blockDim.x+threadIdx.x;
    if(id < n) C[id] = A[id] + B[id];
}

int main( ){
    int n = 1048576;
    int size = n*sizeof(double);
    double *d_A, *d_B, *d_C;
    double *h_A, *h_B, *h_C;

    h_A = (double*)malloc(size);
    h_B = (double*)malloc(size);
    h_C = (double*)malloc(size);

    CHECK_CUDA_ERROR(cudaMalloc(&d_A, size));
    CHECK_CUDA_ERROR(cudaMalloc(&d_B, size));
    CHECK_CUDA_ERROR(cudaMalloc(&d_C, size));

    // 初始化主机端向量
    for(int i = 0; i < n; i++ ) {
        h_A[i] = 2*i;
        h_B[i] = 3*i;
    }

    CHECK_CUDA_ERROR(cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice));
    CHECK_CUDA_ERROR(cudaMemcpy(d_B, h_B, size, cudaMemcpyHostToDevice));

    int blockSize = 256;
    int gridSize = (n + blockSize - 1) / blockSize;

    vecADDKernal<<<gridSize, blockSize>>>(d_A, d_B, d_C, n);
    CHECK_CUDA_ERROR(cudaGetLastError());
    CHECK_CUDA_ERROR(cudaDeviceSynchronize());

    CHECK_CUDA_ERROR(cudaMemcpy(h_C, d_C, size, cudaMemcpyDeviceToHost));

    // 输出部分结果避免刷屏
    for(int a = 0; a < 10; a++) {
        cout << "h_C[" << a << "] = " << h_C[a] << endl;
    }
    cout << "h_C[" << n-1 << "] = " << h_C[n-1] << endl;

    cudaFree(d_A);
    cudaFree(d_B);
    cudaFree(d_C);
    free(h_A);
    free(h_B);
    free(h_C); // 释放主机端内存
    return 0;
}

排查步骤建议

  1. 先添加错误检查,运行代码,根据错误提示定位具体问题(比如核函数启动失败、内存分配失败等)。
  2. 修正gridSize计算方式,确保线程数覆盖所有元素。
  3. 如果是老GPU,改用float类型或者更换支持double的设备。

内容的提问来源于stack exchange,提问作者Soroush Javed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 14:06:25