核函数中的合并访问

在计算直方图的时候会遇到这样一段代码:

在核函数中有下面过程:
d是global的内存指针
global ker(d)
{
int con为计算求得,的无规则索引位置
a=d+con;
计算q,w,e,r,t;
a[0]+=q;
a[1]+=w;
a[2]+=e;
a[3]+=r;
a[4]+=t;
}

我在寻求使其对a连续地址上合并访问,否则光在最后的五条语句就占用了大量时间。
矛盾在于:
1.如果合并访问就要多开辟线程,这样前面计算qwert的部分是重复的。线程浪费了
2.计算q,w,e,r,t的过程和写入a的过程很难分解成两个核函数。

所以在线程数量和合并访问上产生了矛盾。请教这种问题是否有好的解决办法。

另外:在开普勒的动态并行中,上述的核函数是否可以通过开辟新的核函数来实现合并访问?

谢谢!

楼主您好,您试图将分散的a[0],a[1],a[2],a[3],a[4]的多次读取和写入作为合并的读取和写入,那么您无需“多开辟线程”,您看这样:

通过shared memory,在您的计算完毕q,w,e,r,t后,通过shared memory,多个线程完成连续的读取到shared memory, 然后您特定的线程执行加法,然后在完成协作的从shared memory写入到global memory. 这样您可以完成合并的读取和写入(至少5个元素,20B, 在kepler上可以将L2传输的利用率从4B/64B提升到20B/64B, 即最坏可以从6%提升到约30%)

关于使用DP, 新开kernel完成这5个的写入,建议不要这样,因为很可能新开kernel的代价要远大于您的写入操作。但请以实践为准。

感谢莅临。

多谢版主。我还在理解这个过程,是说,计算完qwert之后,全都放入shared memory中么?有一点我忘了说,由于直方图太大,a实际的尺寸超出了shared memory的大小。所以无法把整个直方图全部放入。

LZ您好:

您并没有理解2#横扫斑竹的意图,请您参照原文再考虑一下。

横扫斑竹并没有说要把您的“直方图”放入shared memory,实际上2#明显表示该直方图在global memory中,否则何来所谓合并访问和L2效率的讨论呢?

2#只是要您利用线程合作的方法,将生成的q,w,e,r,t合并访问地写入global memory。
您当前的执行逻辑是:单个线程生成q,w,e,r,t——单个线程写入自己的q,w,e,r,t。
建议的执行逻辑是:每个线程生成自己的一组q,w,e,r,t——多个线程都将自己的那组q,w,e,r,t写入shared memory——多个线程合作将shared memory中的数据写入global memory(此时保证是合并访问)

简而言之就是将生成数据和写入数据的两部分分开,使用shared memory作为中转。生成数据过程还和原先一样,而写入数据部分使用多个线程协作。

大致这样,祝您编码顺利~

顺便补充一下,这种做法只需要用shared memory缓冲当前正在运作的线程所生成的q,w,e,r,t数据,这个一般是无问题的。

谢ice版主,我的确是对这个算法还没有理解,主要是最后一个过程,如何从shared memory中线程合并的写入global。我贴了个图,表示我所理解的共享内存到全局的写入过程。可是不是很清楚该如何采取多个线程协作。关于线程合作,我所理解的是线程ID是连续的,所访问的global空间也是连续的。而这里的线程id虽然连续,可计算出的con使其所访问的global不一致。是不是我在线程合作的概念上理解有偏差。

global ker(d)
{
share sh[10000]
int con为计算求得,的无规则索引位置
a=d+con;
计算q,w,e,r,t;

sh[p+0]=q;
sh[p+1]=w;
sh[p+2]=e;
sh[p+3]=r;
sh[p+4]=t;

?




}
[attach]3352[/attach]

LZ您好:

您依然陷于自己固有的理解中,请您仔细揣摩下2#,4#的相关说法。

以您顶楼的代码为例,虽然每个a指向的是一个无规律的位置,但是a[0]~a[4]这5个元素却是一段连续的空间。线程合作能保证这一段空间的合并访问。这虽然不是一个warp的完全合并访问,但比您之前的写法要好得多。

此外,您的算法还需要保证每次操作的这一段存储空间无重叠,无重复等,否则可能还需要原子操作保证正确性。

大致如此,供您参考。

祝您调试顺利~

多谢两位版主,我现在开始理解你们的意思了。
实际上是用现有的线程以新的组合方式来实现合并访问。的确是个好办法。
我先试下。

嗯嗯,确实是这样的,哪种线程的组合形式有利,就用哪种。

祝您编码顺利~