有没有一种有效的方法来优化我的序列化代码?

时间:2013-07-24 17:56:56

标签: cuda gpgpu

这个问题缺乏细节。所以,我决定创建另一个问题而不是编辑这个问题。新问题出现在:Can i parallelize my code or it is not worth?

我有一个在CUDA中运行的程序,其中一段代码在一个循环中运行(序列化,如下所示)。这段代码是一个包含地址和/或NULL指针的数组内的搜索。所有线程都在下面执行此代码。

while (i < n) {
    if (array[i] != NULL) {
        return array[i];
    }
    i++;
}
return NULL;

n的大小为array且数组位于共享内存中。我只对第一个与NULL(第一个匹配)不同的地址感兴趣。

整个代码(我只发布了一段,整个代码很大)运行得很快,但代码的“心脏”(即更重复的部分)是序列化的,正如你所看到的。我想知道我是否可以使用一些优化算法并行化这部分(搜索)。

就像我说的那样,程序已经在CUDA(和设备中的数组)中,所以它不会有从主机到设备的内存传输,反之亦然。

我的问题是:n并不大。很难超过8。

我尝试将其并行化,但我的“新”代码比上面的代码花了更多的时间。

我正在研究减少和最小化操作,但我已经检查过n很大时它是有用的。

那么,有什么提示吗?我可以有效地并行化它,即低开销吗?

2 个答案:

答案 0 :(得分:1)

由于您说array是共享内存资源,因此对于块的每个线程,此搜索的结果都是相同的。这意味着第一个简单的优化只是让一个线程进行搜索。这将释放除块的第一个warp之外的所有工作(他们仍然需要等待结果,但不必浪费任何计算资源):

__shared__ void *result = NULL;
if(tid == 0)
{
    for(unsigned int i=0; i<n; ++i)
    {
        if (array[i] != NULL)
        {
            result = array[i];
            break;
        }
    }
}
__syncthreads();
return result;

然后,进一步的步骤是让线程并行执行搜索,作为经典的块内缩减。如果您保证 n 总是 ,那么您可以在单个warp中执行此操作,并且在搜索期间不需要任何同步(当然,除了最后的完全同步之外。

for(unsigned int i=n/2; i>32; i>>=1)
{
    if(tid < i && !array[tid])
        array[tid] = array[tid+i];
    __syncthreads();
}

if(tid < 32)
{
    if(n > 32 && !array[tid]) array[tid] = array[tid+32];
    if(n > 16 && !array[tid]) array[tid] = array[tid+16];
    if(n > 8 && !array[tid]) array[tid] = array[tid+8];
    if(n > 4 && !array[tid]) array[tid] = array[tid+4];
    if(n > 2 && !array[tid]) array[tid] = array[tid+2];
    if(n > 1 && !array[tid]) array[tid] = array[tid+1];
}

__syncthreads();    
return array[0];

当然,该示例假定n为2的幂(并且array相应地填充NULL),但可以随意调整它以满足您的需求进一步优化。

答案 1 :(得分:0)

保持简单,GPGPU代码的主要限制因素之一是内存管理。在大多数计算机中,将内存复制到设备(GPU)是一个缓慢的过程。

http://www.ncsa.illinois.edu/~kindr/papers/ppac09_paper.pdf所示:

“获得有效的关键要求 GPU子程序库的加速度最小化 主机和GPU之间的I / O。“

这是因为主机和设备之间的I / O操作很慢!

将此问题与您的问题联系起来,因为您提到的数据量非常小,所以在GPU上运行并没有多大意义。你将花费更多的时间来运行memcpy例程,而不是首先在CPU上运行 - 特别是因为你提到你只对第一场比赛感兴趣。

很多人都有一个常见的误解,就是'如果我在GPU上运行它,它会有更多内核,因此运行得更快'而事实并非如此。

在决定是否值得移植到CUDA或OpenCL时,您必须考虑该过程是否本质上是并行的 - 您是否正在处理大量数据等?