OpenCL-循环的矢量化与线程内
OpenCL - Vectorization vs In-thread for loop
我遇到了一个问题,我需要并行处理已知数量的线程(很好),但每个线程的内部迭代次数可能大不相同(不太好)。在我看来,这样做可以更好地实现这样的内核方案:
__kernel something(whatever)
{
unsigned int glIDx = get_global_id(0);
for(condition_from_whatever)
{
}//alternatively, do while
}
其中id(0)是预先已知的,而不是:
__kernel something(whatever)
{
unsigned int glIDx = get_global_id(0);
unsigned int glIDy = get_global_id(1); // max "unroll dimension"
if( glIDy_meets_condition)
do_something();
else
dont_do_anything();
}
根据这一讨论,它必须在glIDy的完全可能范围内执行,没有办法提前终止:
杀死OpenCL内核
我似乎找不到任何关于内核中动态大小的forloop/do-white语句成本的具体信息,尽管我在Nvidia和AMD的SDK中的内核中随处可见。我记得读过一些关于内核内条件分支的非周期性越强,性能就越差的文章。
实际问题:
在GPU架构上,有没有比我提出的第一个方案更有效的方法来处理这个问题?
我也对这个主题的一般信息持开放态度。
谢谢。
我认为这个问题没有一个通用的答案。这真的取决于你的问题。
然而,这里有一些关于这个主题的注意事项:
for循环/if-else语句可能会也可能不会对内核的性能产生影响。事实上,性能成本不是在内核级别,而是在工作组级别。工作组由一个或多个翘曲(NVIDIA)/波前(AMD)组成。这些扭曲(我将保留NVIDIA的术语,但对AMD来说完全相同)是以锁定步骤执行的。
因此,如果在一个扭曲中,由于if-else(或具有不同迭代次数的for循环)而出现分歧,则执行将被序列化。也就是说,这个经线中沿着第一条路径的线程将完成它们的工作,而其他线程将空闲。一旦他们的工作完成,这些线程将空闲,而其他线程将开始工作。
如果您需要将线程与屏障同步,那么这些语句还会出现另一个问题。如果不是所有线程都碰到了障碍,那么您将有一个未定义的行为。
现在,知道了这一点,并根据您的具体问题,您可能能够以这样一种方式对线程进行分组,即在工作组内没有分歧,尽管工作组之间会有分歧(没有影响)。
还知道一个翘曲是由32个线程和64个波前组成的(可能不是在旧的AMD GPU上——不确定),你可以使组织良好的工作组的大小等于或是这些数字的倍数。请注意,它被简化了,因为应该考虑其他一些问题。例如,看看这个问题和Chanakya.sun给出的答案(也许更多地挖掘这个话题会很好)。
如果你的问题不能像刚才描述的那样组织起来,我建议你考虑在处理分支的CPU上使用OpenCL。如果我还记得的话,通常每个工作组都有一个工作项。在这种情况下,最好查看英特尔和AMD的CPU文档。我也非常喜欢OpenCL的异构计算的第6章,它解释了在编程时将OCL与GPU和CPU一起使用的区别。
我也喜欢这篇文章。这主要是关于通过简单地降低GPU来提高性能的讨论(不是你的问题),但文章的最后一部分也考察了CPU的性能。
最后,关于您对@Oak提供的关于"设备内线程队列支持"的答案的评论,它实际上被称为动态并行。这个功能显然可以解决你的问题,但即使使用CUDA,你也需要一个3.5或更高功能的设备。因此,即使是采用Kepler GK104架构的NVIDIA GPU也不支持它(功能3.0)。对于OCL,动态并行是标准版本2.0的一部分。(据我所知,目前还没有实施)。
我更喜欢第二个版本,因为for
在迭代之间插入了一个错误的依赖项。如果内部迭代是独立的,那么将每个迭代发送到不同的工作项,并让OpenCL实现找出如何最好地运行它们。
两个注意事项:
- 如果平均迭代次数明显低于最大迭代次数,那么这可能不值得额外的虚拟工作项
- 你将有更多的工作项目,你仍然需要计算每个项目的条件。。。如果计算条件很复杂,这可能不是一个好主意。
- 或者,您可以将索引展平到x维度,将所有迭代分组到同一个工作组中,然后每个工作组只计算一次条件,并使用本地内存+屏障进行同步
- 从不同线程使用int64的不同字节安全吗
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 在C++中使用cURL和多线程
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在cuda线程之间共享大量常量数据
- 如何将元素添加到数组的线程安全函数?
- 线程,如果else语句,都是错误的上下文切换后,会发生什么
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- 异常属于C++中的线程还是进程
- C++中的线程安全删除
- C++使用params创建线程函数会导致转换错误
- 类与私有变量的其他类之间的线程安全性
- CoInitialize()在单独的线程上崩溃而不返回
- c++中的线程池
- 普通环路未使用gcc 4.8.5自动矢量化
- 线程之间的布尔停止信号
- 为什么std::async使用同一个线程运行函数
- 用于矢量处理的多个线程
- Xeon phi卸载模式如何利用线程并行性和矢量化