尽管工作效率高的版本需要更多步骤,但活动线程数减少得更快,并且所有迭代中活动线程的总数要小得多,这一事实抵消了这一点。如果一个warp在迭代过程中没有活动线程,则该warp只会跳到下一个障碍并被挂起,从而允许其他warp运行。因此,较少的活动扭曲通常可以在执行时间上获得回报。(这隐含的是,需要以这样的方式设计GPU代码:将活动线程打包到尽可能少的线程束中-您不希望它们分散地散布,因为即使一个活动线程也会强制整个线程束保持活跃。)
考虑朴素算法中活动线程的数量。请看图2中的一篇文章中,你可以看到,所有的线程是活动的,除了前2 ķ在ķ次迭代。因此,对于N个线程,活动线程的数量大约为N − 2 k。例如,如果N = 1024,则每次迭代的活动线程数为:
1023, 1022, 1020, 1016, 1008, 992, 960, 896, 768, 512
如果将其转换为活动的翘曲数(除以32并四舍五入),则会得到:
32, 32, 32, 32, 32, 31, 30, 28, 24, 16
总数为289。另一方面,高效的算法从一半的线程开始,然后将每次迭代的活动线程数量减半,直到降至1,然后开始加倍,直到恢复至再次将数组大小减半:
512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512
将其转换为活动变形:
16, 8, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 8, 16
总和为71,仅为总数的四分之一。因此,您可以看到,在整个操作过程中,使用高效工作算法的活动经纱数量要少得多。(实际上,对于中间的长时间运行,只有很少的活动扭曲,这意味着大部分芯片都没有被占用。如果还有其他计算任务在运行,例如来自其他CUDA流,它们可以扩展以填充空置的空间。)