Cuda 有没有一种有效的方法来优化我的序列化代码?
这个问题缺乏细节。所以,我决定创建另一个问题,而不是编辑这个问题。新问题在这里: 我有一个在CUDA中运行的程序,其中一段代码在一个循环中运行(序列化,如下所示)。这段代码是包含地址和/或空指针的数组中的搜索。所有线程都执行下面的代码Cuda 有没有一种有效的方法来优化我的序列化代码?,cuda,gpgpu,Cuda,Gpgpu,这个问题缺乏细节。所以,我决定创建另一个问题,而不是编辑这个问题。新问题在这里: 我有一个在CUDA中运行的程序,其中一段代码在一个循环中运行(序列化,如下所示)。这段代码是包含地址和/或空指针的数组中的搜索。所有线程都执行下面的代码 while (i < n) { if (array[i] != NULL) { return array[i]; } i++; } return NULL; while(i
while (i < n) {
if (array[i] != NULL) {
return array[i];
}
i++;
}
return NULL;
while(i
其中n
是数组的大小,数组位于共享内存中。我只对第一个不同于NULL(第一个匹配)的地址感兴趣
整个代码(我只发布了一部分,整个代码很大)运行得很快,但代码的“核心”(即重复次数较多的部分)是序列化的,如您所见。我想知道我是否可以用一些优化算法来并行这部分(搜索)
正如我所说,该程序已经在CUDA中(以及设备中的阵列),因此它不会从主机到设备进行内存传输,反之亦然
我的问题是:n
不是很大。它很难大于8
我曾尝试将其并行化,但我的“新”代码比上面的代码花费了更多的时间
我曾研究过归约和最小运算,但我检查过它在n
较大时是否有用
那么,有什么建议吗?我能有效地并行化它吗,也就是说,以较低的开销?保持简单,GPGPU代码的主要限制因素之一是内存管理。在大多数计算机中,将内存复制到设备(GPU)是一个缓慢的过程
如图所示:
“获得有效信息的关键要求
GPU子例程库的加速是
主机和GPU之间的I/O。“
这是因为主机和设备之间的I/O操作很慢
把这与你的问题联系起来,在GPU上运行是没有意义的,因为你提到的数据量太小了。首先,运行memcpy例程的时间比在CPU上运行要多,尤其是因为您提到您只对第一个匹配感兴趣
许多人有一个常见的误解,那就是“如果我在GPU上运行它,它会有更多的内核,所以会运行得更快”,而事实并非如此
在决定是否值得移植到CUDA或OpenCL时,您必须考虑该进程是否本质上是并行的-您是否正在处理大量数据等?因为您说数组是一个共享内存资源,所以此搜索的结果对于块的每个线程都是相同的。这意味着第一个简单的优化就是只让一个线程进行搜索。这将使除了块的第一个扭曲之外的所有扭曲都不必做任何工作(它们仍然需要等待结果,但不必浪费任何计算资源):
当然,该示例假定n
为2的幂(并且数组
相应地填充NULL
s),但是请根据您的需要调整它并进一步优化它。我不明白您在这里问什么。“数组如何具有多个地址”?如果“它将大于8”,为什么会有困难?不清楚您想做什么,为什么您所做的是不可接受的,以及该方法是什么。当您说array
可能有多个地址时,您的意思是array
元素可以假定对应于多个地址值的值吗?但是,不管怎样,您可能是在自己回答您的问题:当涉及到大型阵列时,GPU很方便。粗略地说,CPU比GPU快,而且当阵列很小时,设置内核启动的开销会太大。因此,尽管您没有提供您的方法,但根据一些常识,我想说,移植代码不值得,我不会感到惊讶。@Talonmes,我为我的错误问题道歉。我说这是CPU代码,因为代码以序列化的方式运行,就像CPU代码一样。很抱歉我已经更改了有关数组和地址的短语。看看你现在是否明白了,我问的方式真的很混乱。现在编辑好了。@Jackolanten,我为我提问的方式道歉。我编辑了它。现在我解释得更好了。我知道,也许我已经回答了我的问题。但这就是我想知道的,如果有一个针对小型n
的优化算法。很抱歉我写问题的方式,它真的很混乱。@b如果只是对同一问题的更详细描述,你可以更新这个问题而不是打开另一个问题。我编辑了我的问题,我说这是CPU代码,因为它像CPU一样序列化运行。但它已经在GPU中,所以我不会在主机和设备之间进行内存传输。但是我想知道是否有一种方法可以有效地并行化n
small(n<8)的“首次匹配搜索”。感谢您的帮助。我的观点是-对于小n来说,尝试为它实现并行实现是没有意义的。这不是GPU的设计目的。如果您只搜索第一个匹配项,那么整个过程本质上就是一个串行过程。即使你能同时做这件事,事情肯定会过于复杂。n太小了,似乎不值得。这只是我对形势的理解。特詹克斯,我写了另一个问题,其中有更多的细节。如果您阅读并回答您的想法,无论是否正确,我将不胜感激。谢谢:这段代码很脆弱,如果硬件或编译器优化发生重大变化(过去发生过,将来也会发生),那么很可能会失败。另外,对于单翘曲情况,您可以使用一行代码来完成:\uufs(\ub
__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;
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];