CUDA上的并行缩减和查找索引

时间:2010-10-06 22:49:37

标签: cuda

我有一个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。

有什么建议吗?

4 个答案:

答案 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);