我最近开始使用C ++中的OpenCL,我试图完全理解如何使用2D和3D NDRange。我目前正在OpenCL中实现逆距离权重,但我的问题很普遍。
下面是计算权重的串行函数,它由嵌套循环组成。
void computeWeights(int nGrids, int nPoints, double *distances, double *weightSum, const double p) {
for (int i = 0; i < nGrids; ++i) {
double sum = 0;
for (int j = 0; j < nPoints; ++j) {
double weight = 1 / pow(distances[i * nPoints + j], p);
distances[i * nPoints + j] = weight;
sum += weight;
}
weightSum[i] = sum;
}
}
我想要的是使用2D NDRange实现上述功能,第一个是nGrids,第二个是nPoints。但是,我不明白,如何将权重的总和处理为weightSum [i]。我知道我可能不得不以某种方式使用并行和减少。
答案 0 :(得分:1)
当使用2D全局工作空间调度内核时,OpenCL会创建工作项网格。每个工作项都执行内核并在这两个维度中获得唯一的ID。
(x,y)|________________________
| (0,0) (0,1) (0,2) ...
| (1,0) (1,1) (1,2)
| (2,0) (2,1) (2,2)
| ...
工作项也分为几组,并在这些工作组中获得独特的ID。例如。适用于工作组(2,2):
(x,y)|________________________
| (0,0) (0,1) (0,0) ...
| (1,0) (1,1) (1,0)
| (0,0) (0,1) (0,0)
| ...
您可以安排工作组,以便每个工作组执行缩减。
你的SDK可能有样本,并行减少就是其中之一。
为了帮助您入门,这是一个解决您问题的内核。它是最简单的形式,适用于每行一个工作组。
// cl::NDRange global(nPoints, nGrids);
// cl::NDRange local(nPoints, 1);
// cl::Local data(nPoints * sizeof (double));
kernel
void computeWeights(global double *distances, global double *weightSum, local double *data, double p)
{
uint nPoints = get_global_size(0);
uint j = get_global_id(0);
uint i = get_global_id(1);
uint lX = get_local_id(0);
double weight = 1.0 / pow(distances[i * nPoints + j], p);
distances[i * nPoints + j] = weight;
data[lX] = weight;
for (uint d = get_local_size(0) >> 1; d > 0; d >>= 1)
{
barrier(CLK_LOCAL_MEM_FENCE);
if (lX < d)
data[lX] += data[lX + d];
}
if (lX == 0)
weightSum[i] = data[0];
}
每一行工作项(即每个工作组)计算grid i
的权重(及其总和)。每个工作项计算权重,将其存储回distances
,并将其加载到本地内存中。然后每个工作组执行本地内存的减少,最后结果存储在weightSum
。