【发布时间】:2017-08-01 22:51:32
【问题描述】:
我正在尝试实现一个 CUDA 内核,即计算两个向量的点积。对于小的向量大小,代码可以正常工作并且我得到正确的结果,但对于更大的向量,它只是计算错误。 我正在实施三种不同的方法来计算点积:
- serial 版本(直接在 c++ 中,没有任何优化)
- CUDA 内核
- CUBLAS 版本
我在 cpp 文件中的主要内容如下所示:
float *h_x,*h_y;
float res1=0.0, res2=0.0, res3=0.0;
h_x=(float*)malloc(Main::N*sizeof(float)); random_ints_Vec(h_x);
h_y=(float*)malloc(Main::N*sizeof(float)); random_ints_Vec(h_y);
double serialTimer;
double cublasTimer;
double cudaTimer;
res1=serial_dotProd(h_x,h_y,&serialTimer);
res2=cublas_dotProd(h_x,h_y,&cublasTimer);
res3=cuda_dotProd(h_x,h_y,&cudaTimer);
free(h_x); free(h_y);
系列版本:
float Main::serial_dotProd(float* x, float* y, double* time){
std::clock_t start;
start = std::clock();
float res1=0.0;
for (int i=0;i<Main::N;++i) {
res1+=x[i]*y[i];
}
*time= ( std::clock() - start ) / (double) CLOCKS_PER_SEC;
return res1;}
CUDA版本:
float Main::cuda_dotProd(float *h_x,float *h_y,double* time){
float *d_x,*d_y,*d_res, *h_res;
h_res=(float*)malloc(Main::BLOCKS_PER_GRID*sizeof(float));
size_t bfree, afree, total;
cudaMemGetInfo(&bfree,&total);
cudaMalloc((void**) &d_x,Main::N*sizeof(float));
cudaMalloc((void**) &d_y,Main::N*sizeof(float));
cudaMalloc((void**) &d_res,Main::BLOCKS_PER_GRID*sizeof(float));
cudaCheckErrors("cuda malloc fail");
cudaMemGetInfo(&afree,&total);
std::cout<<" > memory used for cuda-version:"<< (bfree -afree)/1048576<< "MB ("<<total/1048576 <<"MB)" <<"\n";
cudaMemcpy(d_x,h_x,Main::N*sizeof(float),cudaMemcpyHostToDevice);
cudaMemcpy(d_y,h_y,Main::N*sizeof(float),cudaMemcpyHostToDevice);
std::clock_t start;
start = std::clock();
DotProdWrapper(d_x,d_y,d_res,(Main::N+Main::THREADS_PER_BLOCK-1)/Main::THREADS_PER_BLOCK,Main::THREADS_PER_BLOCK,Main::N);
*time= ( std::clock() - start ) / (double) CLOCKS_PER_SEC;
cudaMemcpy(h_res,d_res,Main::BLOCKS_PER_GRID*sizeof(float),cudaMemcpyDeviceToHost);
float c= 0;
for (int i=0;i<Main::BLOCKS_PER_GRID;++i){
c+=h_res[i];
}
cudaFree(d_x);
cudaFree(d_y);
cudaFree(d_res);
free(h_res);
return c;}
CUDA 内核:
__global__ void DotProd(float* x, float* y, float* scalar,unsigned long int N){
extern __shared__ float cache[];
int tid = threadIdx.x+ blockIdx.x*blockDim.x;
int cacheIndex = threadIdx.x;
float temp=0;
while (tid<N){
temp+=x[tid]*y[tid];
tid +=blockDim.x*gridDim.x;
}
cache[cacheIndex]=temp;
__syncthreads();
int i=blockDim.x/2;
while(i!=0){
if (cacheIndex<i)
cache[cacheIndex]+=cache[cacheIndex+i];
__syncthreads();
i/=2;
}
if(cacheIndex==0)
scalar[blockIdx.x]=cache[cacheIndex];
}
CUBLAS 版本:
float Main::cublas_dotProd(float *h_x,float *h_y, double* time){
float *d_x,*d_y;
float *res;
float result=0.0;
cublasHandle_t h;
cublasCreate(&h);
cublasSetPointerMode(h, CUBLAS_POINTER_MODE_DEVICE);
size_t bfree, afree, total;
cudaMemGetInfo(&bfree,&total);
cudaMalloc((void**) &d_x,Main::N*sizeof(float));
cudaMalloc((void**) &d_y,Main::N*sizeof(float));
cudaMalloc( (void **)(&res), sizeof(float) );
cudaCheckErrors("cublas malloc fail");
cudaMemGetInfo(&afree,&total);
cudaMemcpy(d_x, h_x, Main::N*sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(d_y, h_y, Main::N*sizeof(float), cudaMemcpyHostToDevice);
cublasSetVector(Main::N,sizeof(float),h_x,1,d_x,1);
cublasSetVector(Main::N,sizeof(float),h_y,1,d_y,1);
std::clock_t start;
start = std::clock();
cublasSdot(h,Main::N,d_x,1,d_y,1,res);
*time= ( std::clock() - start ) / (double) CLOCKS_PER_SEC;
cudaMemcpy(&result, res, sizeof(float), cudaMemcpyDeviceToHost);
cudaFree(d_x);
cudaFree(d_y);
cudaFree(res);
return result;
}
列出了我在使用不同设置进行计算后得到的结果:
- N=204800,THREADS_PER_BLOCK:512,BLOCKS_PER_GRID:400 serial_dotProd=4.15369e+06 ; cublas_dotProd=4.15369e+06 ; cuda_dotProd=4.15369e+06
- N=20480000, THREADS_PER_BLOCK:512, BLOCKS_PER_GRID:40000 serial_dotProd=4.04149e+08 ; cublas_dotProd=4.14834e+08 ; cuda_dotProd=4.14833e+08
我不知道为什么,但是在我的向量达到一定大小后,我得到了错误的结果。这些向量确实适合 SDRAM,并且每个块的共享内存也有足够的空间来分配内存。 非常感谢。
【问题讨论】:
-
你怎么知道正确的结果是什么?尝试使用双精度变量运行串行版本,以获得启发性实验的运行总和。与此同时,我将寻找解释这一点的 CUDA 文档的链接。
-
我认为串行版本是直截了当的,因此假设这是正确的结果。我尝试了双精度,但仍然得到相同的结果。
-
如果你得到相同的结果,我有理由确定你在
double测试中做错了什么。 here 是我这么说的原因。我有理由相信,如果您正确地将串行版本转换为double,您会看到结果在数字上与 CUDA/CUBLASfloat结果一致。 -
这个问题实际上是在问“为什么这段代码不起作用?”对于that type 的问题,您应该提供minimal reproducible example 您目前提供的不是一个。
-
成功了。非常感谢。 @RobertCrovella 我会在以后的帖子中记住这一点。