说我有3个共享内存阵列:a b c。我不确定跟随线程安排是否会导致控制分歧,
if (threadIdx < 64)
{
if (threadIdx == 1)
for (int i = 0; i < N; i++)
c += a[threadIdx]*a[threadIdx];
else
for (int i = 0; i < N; i++)
c += a[threadIdx]*b[threadIdx];
}
如果确实如此,它对性能的影响有多大?有没有有效的方法来处理这个问题?感谢
答案 0 :(得分:10)
根据块的尺寸,第一个条件threadIdx.x < 64
(注意.x
)可能不会导致任何分歧。例如,如果您有一个维度为(128,1,1)
的块,则前两个warp(以锁定步骤执行的32个线程组)将进入if
块,而最后两个将绕过它。由于整个 warp以某种方式运行,因此没有分歧。
像threadIdx.x == 1
这样的条件会引起分歧,但成本会非常适中。实际上,在许多情况下,CUDA将能够使用单个指令实现条件表达式。例如,min
,max
和abs
等操作通常会使用单个指令实现,并且绝对不会产生分歧。您可以在PTX Manual。
一般情况下,您不应过分关注如上所述的适度控制流量偏差。在像
这样的情况下,分歧会让你陷入困境if (threadIdx.x % 4 == 0)
// do expensive operation
else if (threadIdx.x % 4 == 1)
// do expensive operation
else if (threadIdx.x % 4 == 2)
// do expensive operation
else
// do expensive operation
其中“昂贵的操作”是需要10或100条指令的操作。在这种情况下,由if
语句引起的分歧会使效率降低75%。
请记住,线程分歧比(1)高级算法选择和(2)内存局部性/合并更少关注。很少有CUDA程序员应该关注你的例子中的那种分歧。
答案 1 :(得分:8)
如果每个块有多个线程,我会期望每个块的一个warp中的分歧(无论哪个块保存线程1)。
但是,两个循环之间的区别仅在于访问哪个内存,而不是在指令中。所以,我会这样做......
if (threadIdx.x < 64)
{
//this conditional might diverge
if (threadIdx.x == 1)
ptr = a;
else
ptr = b;
//but obviously this part will not
for (int i = 0; i < N; i++)
c += a[threadIdx]*ptr[threadIdx];
}