这个问题缺乏细节。所以,我决定创建另一个问题而不是编辑这个问题。新问题出现在: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
很大时它是有用的。
那么,有什么提示吗?我可以有效地并行化它,即低开销吗?
答案 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
总是 64>,那么您可以在单个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时,您必须考虑该过程是否本质上是并行的 - 您是否正在处理大量数据等?