我有一个20K值的数组,我将它减少超过50个块,每个400个线程。 num_blocks = 50,block_size = 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.
__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;
}
}
这里的问题是,在某些时候“nTotalThreads”并不是2的幂,导致索引的垃圾值。数组out1给出了每个块中的最大值,这是正确和有效的。但索引的价值是错误的。例如:第一个块中的最大值出现在index = 40,但内核给出的索引值为15.类似地,第二个块中max的值为440,但内核给出416。
有什么建议吗?
答案 0 :(得分:2)
应该很容易确保nTotalThreads始终是2的幂。
使第一次缩减成为一个特殊情况,使nTotalThreads的幂为2.例如,因为你从一个块中的400个线程开始,所以用256个线程进行第一次缩减。线程0-199将从两个值减少,并且线程200-255将不必在该初始步骤中减少。从那时起你就没事了。
答案 1 :(得分:1)
你确定你真的需要'问题'“nTotalThreads”并不是2的强大功能吗? 它使代码的可读性降低,我认为它也会干扰性能。 无论如何,如果你替换
nTotalThreads =(nTotalThreads&gt;&gt; 1);
带
nTotalThreads =(nTotalThreads +1)&gt;&gt; 1;
它应该解决一个关于这个'问题'的错误。
弗朗西斯
答案 2 :(得分:1)
杰夫的第二个建议。
看一下the CUDA Thrust Library's reduce function.与经过大量手动调整的内核相比,这被证明效率高达95 + +,非常灵活且易于使用。
答案 3 :(得分:-1)
检查我的kernel。您可以将块结果放入数组(可以在全局内存中)并将结果存入全局内存
看看我如何在主机代码中调用它:
sumSeries<<<dim3(blockCount),dim3(threadsPerBlock)>>>(deviceSum,threadsPerBlock*blockCount);