CUDA程序无提示失败排查:cudaMemcpyDeviceToHost始终返回全零值
CUDA程序无提示失败排查:cudaMemcpyDeviceToHost始终返回全零值
我太懂这种想验证CUDA环境却卡壳的憋屈感了!你这个程序跑出来全零的问题,一眼就能看到几个关键漏洞,咱们一步步捋:
最核心的问题:核函数根本没被调用!
你定义了write4这个GPU核函数,但在main里完全没启动它啊!GPU端的代码不会自动执行,必须用CUDA专属的核函数启动语法<<<网格大小, 块大小>>>来触发。GPU没干活,设备内存d_out里全是未初始化的垃圾值,拷贝回主机自然是零(或者随机值,你这里刚好是零而已)。
第二大问题:错误检查太不完整
你只给cudaMalloc写了半截错误检查,但核函数启动、cudaMemcpy、cudaFree这些步骤都没加错误判断——CUDA很多操作是异步的,出问题了不会主动报错,你得主动查,不然连哪一步崩了都不知道。
给你修正后的完整可运行代码
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <assert.h> #include <cuda.h> #include <cuda_runtime.h> #define N 10000000 #define MAX_ERR 1e-6 __global__ void write4(float *out, int n) { int index = threadIdx.x; int stride = blockDim.x; for(int i = index; i < n; i += stride){ out[i] = 4.0; } } int main(){ float *out, *d_out; cudaError_t err; // 分配主机内存 out = (float*)malloc(sizeof(float) * N); if (out == NULL) { fprintf(stderr, "主机内存分配失败!\n"); return 1; } // 分配设备内存 err = cudaMalloc((void**)&d_out, sizeof(float) * N); if(err != cudaSuccess){ fprintf(stderr, "cudaMalloc 失败:%s\n", cudaGetErrorString(err)); free(out); return 1; } // 启动核函数!这里用1个块,256个线程(常规配置) write4<<<1, 256>>>(d_out, N); // 检查核函数启动是否成功(核函数启动是异步的,必须用这个函数查) err = cudaGetLastError(); if(err != cudaSuccess){ fprintf(stderr, "核函数启动失败:%s\n", cudaGetErrorString(err)); free(out); cudaFree(d_out); return 1; } // 等待GPU任务完成(拷贝前确保GPU干完活) cudaDeviceSynchronize(); // 从设备拷贝回主机 err = cudaMemcpy(out, d_out, sizeof(float) * N, cudaMemcpyDeviceToHost); if(err != cudaSuccess){ fprintf(stderr, "cudaMemcpy 失败:%s\n", cudaGetErrorString(err)); free(out); cudaFree(d_out); return 1; } // 验证结果(抽样检查,不用全遍历省时间) for(int i = 0; i < 10; i++){ assert(fabs(out[i] - 4.0) < MAX_ERR); } // 检查中间位置 assert(fabs(out[N/2] - 4.0) < MAX_ERR); // 检查末尾 assert(fabs(out[N-1] - 4.0) < MAX_ERR); printf("所有抽样检查通过!CUDA环境正常工作~\n"); // 释放内存 free(out); cudaFree(d_out); return 0; }
额外的环境验证小技巧
如果还是有问题,先跑CUDA自带的deviceQuery工具(一般在CUDA安装目录的samples文件夹里),它能直接告诉你GPU是否被正确识别,驱动和CUDA工具链版本是否匹配,这是快速排查环境问题的利器。
备注:内容来源于stack exchange,提问作者Gillespie
相关产品推荐
相关产品推荐

