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; }
排查步骤建议
- 先添加错误检查,运行代码,根据错误提示定位具体问题(比如核函数启动失败、内存分配失败等)。
- 修正gridSize计算方式,确保线程数覆盖所有元素。
- 如果是老GPU,改用float类型或者更换支持double的设备。
内容的提问来源于stack exchange,提问作者Soroush Javed
相关产品推荐
相关产品推荐

