为什么用位操作替换if-else在CUDA中速度较慢?

为什么用位操作替换if-else在CUDA中速度较慢?,cuda,bitwise-operators,Cuda,Bitwise Operators,我代替 if((nMark >> tempOffset) & 1){nDuplicate++;} else{nMark = (nMark | (1 << tempOffset));} if((nMark>>tempOffset)&1){nDuplicate++;} else{nMark=(nMark |(1>tempOffset)&1); nMark=(nMark |(1在黑暗中拍摄,但在后一个实现中,您现在总是递增/重新赋值给NDUCLIPLATE变量,因为如

我代替

if((nMark >> tempOffset) & 1){nDuplicate++;}
else{nMark = (nMark | (1 << tempOffset));}
if((nMark>>tempOffset)&1){nDuplicate++;}
else{nMark=(nMark |(1>tempOffset)&1);

nMark=(nMark |(1在黑暗中拍摄,但在后一个实现中,您现在总是递增/重新赋值给NDUCLIPLATE变量,因为如果if语句中的测试之前为false,您没有递增/赋值给它。猜测开销来自于此,但您没有描述您的测试数据集,因此我不知道是否已经存在情况是这样的。

您的程序是否表现出显著的分支分歧?如果您正在运行例如100个扭曲,只有5个有分歧行为,并且它们在5个SMs中运行,您将只看到21个时间周期(预期为20个)…5%的增长很容易通过在每个线程中做2倍的工作来避免罕见的分歧而被击败

除此之外,520是一款相当现代的图形卡,可能会结合现代SIMT调度技术,例如动态扭曲形成和线程块压缩,以隐藏SIMT暂停。可能会研究体系结构特征(规格)或编写一个简单的基准来生成n向分支发散并测量减速

除此之外,请检查变量所在的位置。共享变量是否会影响性能/结果?因为您总是在第二个和第一个变量中访问所有变量可以避免访问nDimension,因此缓慢(非平衡全局?)的内存访问可以解释这一点


只需要考虑一些事情。

对于低级优化,直接查看内核的低级程序集(SASS)通常很有帮助。您可以使用作为CUDA工具包的一部分分发的
cuobjdump
工具执行此操作。基本用法是在nvcc中使用
-keep
进行编译,然后执行以下操作:

cuobjdump -sass mykernel.cubin

然后你可以看到指令的精确序列并比较它们。我不确定为什么版本1会比版本2快,但SASS清单可能会给你一个线索。

GPU的本机指令集通过谓词非常有效地处理小条件。此外,ISET指令转换条件将代码注册为值为0或1的整数,这自然符合条件增量

我的猜测是,第一个和第二个公式之间的关键区别在于,您实际上隐藏了一个事实,即它是if/else


确切地说,您可以使用cuobjdump查看为这两种情况生成的微码:specify--keep To nvcc并在.cubin文件上使用cuobjdump查看反汇编的微码。

您确定这些事情的计时方式足够精确,以至于5毫秒的差异在统计上是显著的吗?它应该是精确的。我有e运行内核几次。结果相差大约5毫秒。这里的问题是位操作比其他操作慢。我很困惑。可能那些移位操作会消耗更多的时间。你知道吗?那么我会责怪在第二个版本中,你总是对
nDupl执行
+=
操作在第一个版本中,
add
store
操作并不总是触发,可能只是稍微快一点。谢谢你的评论,aroth。谢谢你Drew。我只是运行了两个内核函数几次,其中包含数百个线程。然后我发现位操作比其他操作慢。在SIMT架构,我曾考虑过删除if-else。但我被证明是错的……啊,很好的发现。希望这能为将来尝试相同微优化的人回答这个问题。;)
cuobjdump -sass mykernel.cubin