使用OpenCL在2D中嵌套循环求和

时间:2015-06-06 09:26:51

标签: c++ opencl reduction

我最近开始使用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]。我知道我可能不得不以某种方式使用并行和减少。

1 个答案:

答案 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