CUDA上的并行归约与索引查找
我有一个20K值的数组,我将它减少到50个块,每个块有400个线程。块数=50,块大小=400 我的代码如下所示:CUDA上的并行归约与索引查找,cuda,Cuda,我有一个20K值的数组,我将它减少到50个块,每个块有400个线程。块数=50,块大小=400 我的代码如下所示: getmax <<< num_blocks,block_size >>> (d_in, d_out1, d_indices); __global__ void getmax(float *in1, float *out1, int *index) { // Declare arrays to be in shared memory.
getmax <<< num_blocks,block_size >>> (d_in, d_out1, d_indices);
__global__ void getmax(float *in1, float *out1, int *index)
{
// Declare arrays to be in shared memory.
__shared__ float max[threads];
int nTotalThreads = blockDim.x; // Total number of active threads
float temp;
float max_val;
int max_index;
int arrayIndex;
// Calculate which element this thread reads from memory
arrayIndex = gridDim.x*blockDim.x*blockIdx.y + blockDim.x*blockIdx.x + threadIdx.x;
max[threadIdx.x] = in1[arrayIndex];
max_val = max[threadIdx.x];
max_index = blockDim.x*blockIdx.x + threadIdx.x;
__syncthreads();
while(nTotalThreads > 1)
{
int halfPoint = (nTotalThreads >> 1);
if (threadIdx.x < halfPoint)
{
temp = max[threadIdx.x + halfPoint];
if (temp > max[threadIdx.x])
{
max[threadIdx.x] = temp;
max_val = max[threadIdx.x];
}
}
__syncthreads();
nTotalThreads = (nTotalThreads >> 1); // divide by two.
}
if (threadIdx.x == 0)
{
out1[num_blocks*blockIdx.y + blockIdx.x] = max[threadIdx.x];
}
if(max[blockIdx.x] == max_val )
{
index[blockIdx.x] = max_index;
}
}
getmax>(数据输入、数据输出1、数据索引);
__全局无效getmax(浮点*in1,浮点*out1,整数*index)
{
//声明数组在共享内存中。
__共享_uuuu浮点最大值[线程];
int ntotatalThreads=blockDim.x;//活动线程的总数
浮子温度;
浮动最大值;
int max_指数;
数组索引;
//计算此线程从内存中读取的元素
arrayIndex=gridDim.x*blockDim.x*blockIdx.y+blockDim.x*blockIdx.x+threadIdx.x;
max[threadIdx.x]=in1[arrayIndex];
max_val=max[threadIdx.x];
max_index=blockDim.x*blockIdx.x+threadIdx.x;
__同步线程();
而(线程数>1)
{
int halfPoint=(nTotalThreads>>1);
if(螺纹IDX.x<半点)
{
温度=最大值[螺纹内径x.x+半点];
如果(温度>最大值[threadIdx.x])
{
最大[threadIdx.x]=温度;
max_val=max[threadIdx.x];
}
}
__同步线程();
nTotalThreads=(nTotalThreads>>1);//除以二。
}
if(threadIdx.x==0)
{
out1[num_blocks*blockIdx.y+blockIdx.x]=max[threadIdx.x];
}
if(max[blockIdx.x]==max_val)
{
索引[blockIdx.x]=最大索引;
}
}
这里的问题是,在某种程度上,“nTotalThreads”并不是2的幂,这会导致索引的垃圾值。数组out1给出了每个块中的最大值,该值是正确且经过验证的。但该指数的值是错误的。例如:第一个块中的最大值出现在index=40时,但内核给出的index值为15。类似地,第二个块中的max值为440,但内核给出416
有什么建议吗?你确定你真的需要这个“问题”吗?“nTotalThreads”不是2的幂? 这会降低代码的可读性,我认为这也会影响性能。 无论如何,如果你替换 nTotalThreads=(nTotalThreads>>1) 与 nTotalThreads=(nTotalThreads+1)>>1 它应该解决一个关于这个“问题”的bug
弗朗西斯科赞同杰夫的建议
看一看,与手工调优的内核相比,它的效率高达95%,而且非常灵活,易于使用。应该很容易确保nTotalThreads始终是2的幂 将第一次缩减作为一个特例,使nTotalThreads的幂为2。例如,由于您在一个块中以400个线程开始,因此使用256个线程进行第一次缩减。线程0-199将从两个值减少,而线程200-255不必在这个初始步骤中进行减少。从那以后你就没事了。看看我的。您可以将blockresults放入数组(可以在全局内存中),并在全局内存中获得结果 看看我如何在主机代码中调用它:
sumSeries<<<dim3(blockCount),dim3(threadsPerBlock)>>>(deviceSum,threadsPerBlock*blockCount);
sumSeries(deviceSum,threadsPerBlock*blockCount);
许多常见模式(如并行缩减)都是在CUDA的高度优化库中实现的,如推力或CUDPP,您有没有为您的任务查看过这些模式?如果您不介意的话,为什么每个块有400个线程?