我正在使用OpenCL。我感兴趣的是如何在以下示例中执行工作项。
我的一维范围为10000,工作组大小为512.内核是以下内容:
__kernel void
doStreaming() {
unsigned int id = get_global_id(0);
if (!isExecutable(id))
return;
/* do some work */
}
这里检查是否需要继续使用以下id的元素。
假设执行以第一个512大小的工作组开始,其中20个被isExecutable
拒绝。 GPU是否继续执行其他20个元素而不等待前492个元素?
没有任何障碍或其他同步技术。
答案 0 :(得分:2)
当一些工作项目远离通常/ *做一些工作* /时,他们可以通过从下一个wavefront(amd)或下一个warp(nvidia)获取指令来使用管道占用优势,因为当前warp / wavefront工作项目正忙着做其他事情。但这会导致内存访问序列化并清除工作组的访问顺序,从而降低性能。
避免使用不同的warp / wavefron :如果你在循环中执行if语句,那么它真的很糟糕,你可以找到另一种方式。
如果工作组中的每个工作项具有相同的分支,那么就可以了。
如果每个工作项在每百个计算中进行的分支很少,那就没关系。
尝试为所有工作项(为了实现并行数据/算法)生成相同的条件,以利用gpu带来的功能。
我知道摆脱最简单的branch-vs-compute情况的最佳方法是使用全局yes-no数组。 0 =是,1 =否:总是计算,然后将结果乘以工作项的yes-no元素。通常,每个核心添加1字节元素内存访问要比每个核心执行一次分支要好得多。实际上,在添加这个1字节后,使对象长度为2的幂可能会更好。
答案 1 :(得分:1)
是和否。以下详细说明基于NVIDIA的文档,但我怀疑它在ATI硬件上有什么不同(尽管实际数字可能有所不同)。通常,工作组的线程在所谓的warp中执行,warp是工作组大小的子块。在NVIDIA硬件上,每个工作组分为32个线程的warp。并且这些warp中的每一个都是以锁定步骤执行的,因此完全并行执行(它可能不是实时并行的,这意味着可能有16个并行线程,然后直接再次16个,但从概念上讲它们运行完全并行) 。因此,如果这32个线程中只有一个执行该附加代码,则其他线程将等待它。但是所有其他经线中的线程都不会关心这一切。
所以是的,可能会有不必要的线程等待其他线程,但这种情况发生的规模小于整个工作组的规模(任何NVIDIA硬件上都是32)。这就是为什么应该尽可能避免内部扭曲分支偏差的原因,这也是为什么保证在单个warp内工作的代码不需要任何同步的原因。共享内存访问(算法的常见优化)。