我正在使用 OpenCL C++ 来实现我的项目。我想从我的 GPU/s 中获得最大速度/性能(取决于我有多个 GPU 还是单个 GPU)。但出于这个问题的目的,让我们假设我只有一台设备。
假设我有一个长度为 100 的数组。
double arr[100];
现在我正在做的是通过以下方法调用内核。
kernelGA(cl::EnqueueArgs(queue[iter],
cl::NDRange(100)),
d_arr, // and some other buffers.
)
现在在内核端。我有一个全局 ID。即:
int idx = get_global_id(0);
我希望我的内核工作的方式如下:
- 100 个工作组中的每个工作组将分别处理一个要素。
每个工作组都使用一些规则来更新数组的元素。例如:
if (arr[idx] < 5) { arr[idx] = 10; // a very simple example. }
对于大多数部分来说,没关系。但是有一点我想交换,我希望线程/工作项相互通信。在这一点上,他们似乎没有工作,他们似乎没有沟通。
例如:
if(arr[idx] < someNumber) {
arr[idx] = arr[idx + 1];
}
此时,似乎没有任何效果。我试图实现一个 for 循环并创建一个障碍
barrier(CLK_LOCAL_MEM_FENCE | CLK_GLOBAL_MEM_FENCE);
但它也不起作用。它不会更改数组元素的值。
我有以下问题:
1. 为什么不起作用?我的实现有误吗?线程似乎正确地更新了它们自己的索引数组元素。但是当涉及到它们之间的通信时,它们不起作用。为什么?
2. 是我实现的障碍和只让一个工作项目出错了吗?有没有更好的方法让一个项目处理这部分,而其他项目等待这个完成?
最佳答案
你写的代码是串行的:
if(arr[idx] < someNumber) {
arr[idx] = arr[idx + 1];
}
worker N 将取 worker N-1 的结果,N-1 取 N-2 的结果,依此类推。 所以这意味着 worker N 需要等待所有其他人完成。这意味着代码不是并行的,而且永远不会。使用 CPU 比使用 GPU 的计算效果要好得多。
OpenCL 设计模型,允许您并行运行多个工作项,但同步模型只允许在工作组内同步。 如果您需要全局同步,则表明您的算法不适用于 OpenCL。
现在,如果我假设您只需要最后一个元素的值。而您真正想要的是对所有数组执行“求和”。那么,这是一个归约问题,可以通过这种方式并行化在 log(N) 时间内执行:
1st step, array[x] = array[x] + array[N/2+x] (x from 0 to N/2)
2nd step, array[x] = array[x] + array[N/4+x] (x from 0 to N/4)
...
log(N) passes
每个步骤都将是一个单独的内核,因此确保在开始下一批之前所有工作项都已完成。
另一个更快的选择是在工作组内部执行缩减,因此如果工作组大小为 256,您可以在每次通过时将 256 个组加在一起。这比每次通过减少 2 更快。
关于c++ - 在单个阵列上的 opencl 中处理工作组及其大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42581203/