CUDA / openCL;将分支重写为非分支表达式

时间:2012-05-15 19:14:31

标签: c++ optimization cuda opencl gpu-programming

大多数情况下,在CUDA或OpenCL程序中需要分支,例如:

for (int i=0; i<width; i++)
{
   if( i % threadIdx.x == 0)
     quantity += i*i;
}

代码总是(或至少在大多数情况下)以非分支样式重写:

for (int i=0; i<width; i++)
{
   quantity += i*i* (i % threadIdx.x != 0);
}

权衡似乎是在单个warp槽中运行而不是在所有线程上执行更多计算(在第二种情况下,总和总是执行,有时值为零)

假设分支操作将为每个可能的分支采用多个warp插槽,可以预期第二个将始终优于第一个,现在我的问题是;我是否可以依赖编译器优化1)2)只要它有意义,或者没有广泛适用的标准,这意味着如果没有尝试和分析,一般不能确定哪一个更好?

3 个答案:

答案 0 :(得分:3)

模数运算相当昂贵:我有理由相信在模数中加入会比使用只有1个线程执行的单个指令花费更多时间。您的单个分支语句if没有else,只会挂起其他线程,而if语句正在执行。因为gpus针对非常快速的上下文切换进行了优化,所以应该花费很少的成本。

建议您不要使用长分支语句:GPU上的串行计算过多(即一个线程完成所有工作)否定了并行性的优势。

答案 1 :(得分:1)

根据我的经验 - 完全由编译器编写者来优化这些边缘情况。

那么我能想到1)无法转向2)的任何情况吗?这是一个:我已经编写了内核,每10个线程或类似的东西运行某些计算部分更有效率,在这种情况下,即使存在可以进行数学运算(除法除法),也无法推断出这样的优化产生相同的结果,不管条件与“全部运行,但产量为零的结果”。

然而,即使检查threadId == 0是一个常见的场景,我也不知道它是否真的被优化了。我敢打赌它取决于实现甚至设备本身(CPU与GPU)。

你必须尝试它才能真正找到最有效的方法,不仅仅是因为上面的原因,还因为工作调度程序可能会因为调度/启动/停止一组线程的成本而有所不同反对让它们全部运行(并且大多数都提供零/同一性结果)。

希望这有帮助!

答案 2 :(得分:0)

我对CUDA没有太多记忆,但为什么不对你的循环进行并行化?您应该使用原子操作[1]来添加计算。我希望这能帮到您!对不起,如果不是这样的话。

  1. 原子操作:http://supercomputingblog.com/cuda/cuda-tutorial-4-atomic-operations/