使用分支优化CUDA代码

时间:2015-01-22 23:39:48

标签: c++ cuda branch

我有一个CUDA代码,我想优化它。我的内核正在使用dim3 grid=(35,48)dim3 threads=(18,18)。首先,每个块执行独立的290向量计算,其中每个线程执行1个向量计算(其为1024次加法 - 乘法)。

但是,此计算的前17 * 17 = 289的输入数据存储在共享数组im1中,最后一个数据存储在im2中(输出数组也不同)。之后,我使用所有获得的数据进行进一步的计算。

我按如下方式实施:

if ((threadIdx.x < 17) && (threadIdx.y < 17)){
    **instructions for 289s vector calculations**
}
else if ((threadIdx.x == 17) && (threadIdx.y == 17)){
    **instruction for 290 vector calculation**
}
__syncthreads();
***further calculations***

所以,如果我理解正确,我的第一个289跟随1分支,而#324跟随另一个分支。只要第一组线程在warp#0,1,..,10中,并且线程#324在warp#11中,就没有发散的分支。但是,我读到,通常最好避免在这些内核中使用任何if语句,并用strided索引替换它们,或类似的东西。那么,我能以某种方式改进这些代码吗?

我的GPU是带有cc 5.2的GTX 980,我使用VS2013进行编码。

谢谢,米哈伊尔

2 个答案:

答案 0 :(得分:1)

让我们考虑一个18 * 18个线程的块,编号从0(0,0)到323(17,17)。

So, if I understand correct, my first 289 follow 1 branch [...]

如果通过&#34;第289&#34;你指的是从0(0,0)到288(16,16)编号的线程,然后是no,并非所有线程都采用第一个分支。例如,线程17(0,17)不采用分支(参见下图)。然而,在一个块的范围内,289个线程确实占用了该分支。

[...] and thread #324 follows another

这是正确的,线程323(17,17)采用第二个分支。

线程17(0,17),35(1,17)...... 305(16,17)和306(17,0),307(17,1)...... 322(17,16)(总共35个线程)不占用任何分支并且浪费了。从表现的角度来看,这很糟糕,但也不是灾难性的。

但请考虑以下您正在做的模式:

    0  1  2  … 15 16 17     
0   *  *  *  *  *  *  -      * represents a thread that takes branch 1
1   *  *  *  *  *  *  -      X represents a thread that takes branch 2
2   *  *  *  *  *  *  -      - represents a thread that takes no branch
…   *  *  *  *  *  *  -
15  *  *  *  *  *  *  -
16  *  *  *  *  *  *  -
17  -  -  -  -  -  -  X

请记住,warp由32个线程组成。所以线程0..31,32..63等以锁步执行。您可能会注意到上面的架构,每18个线程有一个非活动线程。换句话说,这意味着所有你的warp发散。

但是,它可能不是一个巨大的性能影响(如果有的话),因为其中一个分支总是&#34;什么都不做&#34;。话虽这么说,我肯定会鼓励你修改你的设计,我相信你可以注意到性能的提高(更多是由于内存访问模式而不是分歧本身)。

一个显而易见的解决方案是仅启动290个线程而不是324个线程,并自行映射到x和y坐标,但是最后一个warp会以明显的方式发散。

另一个解决方案是启动足够的warp来覆盖前289个线程(这意味着10个warp,最后一个浪费31个线程)并运行一个补充warp,其中你使用一个线程用于第二个分支(最后一个,例如)。这将是11次经线,352次线程,62次浪费。这在效率方面可能看起来更糟,但由于存储器访问模式,它实际上比这更复杂,所以试一试。

另请注意,如果if/else语句的主体在代码上实际上没有差异,但在数据上(因为您似乎暗示......),那么使用分支是没有意义的。只是玩指针。可能会出现其他问题(与内存访问合并有关),但不存在代码流分歧。

我建议进行更多改进,但如果没有看到您的代码或了解您的数据是如何布局的,那么它就是在黑暗中拍摄的。你在评论中说,你不能让NSIGHT工作:我强烈建议你把它作为优先事项。

答案 1 :(得分:0)

按照我的理解,如果要优化分支,数据必须提前处理(即那些位于18号的数据要提前聚在一起,在原来的位置删除)。