由于我没有收到CUDA论坛的回复,请在这里试试:
在CUDA中完成一些程序后,我们现在开始获得有效带宽。但是我有一些奇怪的结果,例如在下面的代码中,我可以求和向量中的所有元素(无论维度),使用Unroll Code和“normal”代码的带宽似乎具有相同的中值结果(约3000 Gb / s) 我不知道我是做错了什么(AFAIK程序工作正常)但是从我到目前为止所阅读的内容来看,Unroll代码应该有更高的带宽。
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <math.h>
#define elements 1000
#define blocksize 16
__global__ void vecsumkernel(float*input, float*output,int nelements){
__shared__ float psum[blocksize];
int tid=threadIdx.x;
if(tid + blockDim.x * blockIdx.x < nelements)
psum[tid]=input[tid+blockDim.x*blockIdx.x];
else
psum[tid]=0.0f;
__syncthreads();
//WITHOUT UNROLL
int stride;
for(stride=blockDim.x/2;stride>0;stride>>=1){
if(tid<stride)
psum[tid]+=psum[tid+stride];
__syncthreads();
}
if(tid==0)
output[blockIdx.x]=psum[0];
//WITH UNROLL
/*
if(blocksize>=512 && tid<256) psum[tid]+=psum[tid+256];__syncthreads();
if(blocksize>=256 && tid<128) psum[tid]+=psum[tid+128];__syncthreads();
if(blocksize>=128 && tid<64) psum[tid]+=psum[tid+64];__syncthreads();
if (tid < 32) {
if (blocksize >= 64) psum[tid] += psum[tid + 32];
if (blocksize >= 32) psum[tid] += psum[tid + 16];
if (blocksize >= 16) psum[tid] += psum[tid + 8];
if (blocksize >= 8) psum[tid] += psum[tid + 4];
if (blocksize >= 4) psum[tid] += psum[tid + 2];
if (blocksize >= 2) psum[tid] += psum[tid + 1];
}*/
if(tid==0)
output[blockIdx.x]=psum[0];
}
void vecsumv2(float*input, float*output, int nelements){
dim3 dimBlock(blocksize,1,1);
int i;
for(i=((int)ceil((double)(nelements)/(double)blocksize))*blocksize;i>1;i(int)ceil((double)i/(double)blocksize)){
dim3 dimGrid((int)ceil((double)i/(double)blocksize),1,1);
printf("\ni=%d\ndimgrid=%u\n ",i,dimGrid.x);
vecsumkernel<<<dimGrid,dimBlock>>>(i==((int)ceil((double)(nelements)/(double)blocksize))*blocksize ?input:output,output,i==((int)ceil((double)(nelements)/(double)blocksize))*blocksize ? elements:i);
}
}
void printVec(float*vec,int dim){
printf("\n{");
for(int i=0;i<dim;i++)
printf("%f ",vec[i]);
printf("}\n");
}
int main(){
cudaEvent_t evstart, evstop;
cudaEventCreate(&evstart);
cudaEventCreate(&evstop);
float*input=(float*)malloc(sizeof(float)*(elements));
for(int i=0;i<elements;i++)
input[i]=(float) i;
float*output=(float*)malloc(sizeof(float)*elements);
float *input_d,*output_d;
cudaMalloc((void**)&input_d,elements*sizeof(float));
cudaMalloc((void**)&output_d,elements*sizeof(float));
cudaMemcpy(input_d,input,elements*sizeof(float),cudaMemcpyHostToDevice);
cudaEventRecord(evstart,0);
vecsumv2(input_d,output_d,elements);
cudaEventRecord(evstop,0);
cudaEventSynchronize(evstop);
float time;
cudaEventElapsedTime(&time,evstart,evstop);
printf("\ntempo gasto:%f\n",time);
float Bandwidth=((1000*4*2)/10^9)/time;
printf("\n Bandwidth:%f Gb/s\n",Bandwidth);
cudaMemcpy(output,output_d,elements*sizeof(float),cudaMemcpyDeviceToHost);
cudaFree(input_d);
cudaFree(output_d);
printf("soma do vector");
printVec(output,4);
}
答案 0 :(得分:4)
您展开的代码中包含大量分支。我数十个额外的分支机构。通常在GPU上的warp内进行分支是很昂贵的,因为warp中的所有线程都会在分支上等待(分歧)。
有关经线偏差的更多信息,请参见此处:
http://forums.nvidia.com/index.php?showtopic=74842
您是否尝试使用分析器查看发生了什么?
答案 1 :(得分:3)
3000 Gb / s没有意义。每个方向的PCIe最大总线速度为8Gb / s。
请查看本文Parallel Prefix Sum,深入了解如何加快实施速度。 另请注意,thrust库已在Reductions模块
中实现了此功能答案 2 :(得分:1)
您的未展开代码无效。对于stride<32
,同一warp的某些线程进入for循环,而其他线程则不进入for循环。因此,经线的一些(但不是全部)线程击中了__syncthreads()
。 CUDA规范说,当发生这种情况时,行为是未定义的。
可能会发生warp不同步,并且某些线程已经开始加载下一个数据块,在__syncthreads()
的下一个实例上暂停,而之前的线程仍然停留在前一个循环中。
我不确定这是否是你在这个特殊情况下要面对的。
答案 3 :(得分:0)
我看到你在内核中做了减少总和。这是NVIDIA优化presentation以优化GPU的减少。您会注意到本指南中提供 2 GB / s吞吐量的相同代码优化为63 GB / s 。