我是OpenCL的新手。但是,我理解C / C ++基础知识和OOP。 我的问题如下:是否有可能并行运行和计算任务?理论上可行吗?下面我将描述我试图做的事情:
任务是,例如:
double* values = new double[1000]; //let's pretend it has some random values inside
double sum = 0.0;
for(int i = 0; i < 1000; i++) {
sum += values[i];
}
我在OpenCL内核中尝试做的事情(我觉得这是错误的,因为它可能同时从不同的线程/任务访问相同的“sum”变量):
__kernel void calculate2dim(__global float* vectors1dim,
__global float output,
const unsigned int count) {
int i = get_global_id(0);
output += vectors1dim[i];
}
这段代码错了。如果理论上有可能并行运行这样的任务,如果有的话,我会非常感谢有人回答我 - 如何!
答案 0 :(得分:0)
如果要以并行方式对数组的值求和,则应确保减少争用,并确保跨线程没有数据依赖性。
数据依赖性将导致线程必须彼此等待,从而产生争用,这是您希望避免实现真正的并行化。
你可以做的一种方法是将数组拆分为N个数组,每个数组包含原始数组的一些子部分,然后使用每个不同的数组调用OpenCL内核函数。
最后,当所有内核完成了艰苦的工作时,您可以将每个数组的结果总结为一个。 CPU可以轻松完成此操作。
关键是在每个内核中完成的计算之间没有任何依赖关系,因此您必须分割数据并进行相应的处理。
我不知道您的数据是否与您的问题有任何实际的依赖关系,但这是您要弄清楚的。
答案 1 :(得分:-1)
我提供的参考代码应该可以完成这项工作。
E.g。您有 N 元素,工作组的大小为 WS = 64 。我假设 N 是 2 * WS 的倍数(这很重要,一个工作组计算2 * WS元素的总和)。然后你需要运行内核指定:
globalSizeX = 2*WS*(N/(2*WS));
因此, sum 数组将具有 2 * WS 元素的部分总和。 (例如 sum [1] - 将包含索引从 2 * WS 到 4 * WS-1 的元素之和。
如果你的globalSizeX 2 * WS 或更少(这意味着你只有一个工作组),那么你就完成了。结果只使用 sum [0] 。 如果不是 - 您需要重复此过程,这次使用 sum 数组作为输入数组并输出到其他数组(创建2个数组和它们之间的乒乓)。等等,直到你只有一个工作组。
也搜索Hilli Steele / Blelloch并行算法。 This文章也很有用
以下是实际示例:
__kernel void par_sum(__global unsigned int* input, __global unsigned int* sum)
{
int li = get_local_id(0);
int groupId = get_group_id(0);
__local int our_h[2 * get_group_size(0)];
our_h[2*li + 0] = hist[2*get_group_size(0)*blockId + 2*li + 0];
our_h[2*li + 1] = hist[2*get_group_size(0)*blockId + 2*li + 1];
// sweep up
int width = 2;
int num_el = 2*get_group_size(0)/width;
int wby2 = width>>1;
for(int i = 2*BLK_SIZ>>1; i>0; i>>=1)
{
barrier(CLK_LOCL_MEM_FENCE);
if(li < num_el)
{
int idx = width*(li+1) - 1;
our_h[idx] = our_h[idx] + our_h[(idx - wby2)];
}
width<<=1;
wby2 = width>>1;
num_el>>=1;
}
barrier(CLK_LOCL_MEM_FENCE);
// down-sweep
if(0 == li)
sum[groupId] = our_h[2*get_group_size(0)-1]; // save sum
}