在OpenCL中使用本地内存进行并行缩减

时间:2015-02-16 16:56:10

标签: opencl

我在OpenCL中实现了一个reduce内核,以总结大小为input的{​​{1}}向量中的所有条目。为了便于测试,我使用N初始化input向量。所以结果应该是1.0f。但事实并非如此!

这是我的N - 内核:

reduce

以下是OpenCL的设置:

kernel void reduce(global float* input, global float* output, const unsigned int N, local float* cache)
{
    const uint local_id = get_local_id(0);
    const uint global_id = get_global_id(0);
    const uint local_size = get_local_size(0);

    cache[local_id] = (global_id < N) ? input[global_id] : 0.0f;
    barrier(CLK_LOCAL_MEM_FENCE);

    for (unsigned int s = local_size >> 1; s > 0; s >>= 1) {
        if (local_id < s) {
            cache[local_id] += cache[local_id + s];
        }
        barrier(CLK_LOCAL_MEM_FENCE);
    }

    if (local_id == 0) output[local_size] = cache[0];
}

结果取决于工作组大小。我究竟做错了什么?它是内核本身还是OpenCL的设置?

2 个答案:

答案 0 :(得分:2)

在将总和写回全局内存时,您应该使用该组的ID。

if (local_id == 0) output[local_size] = cache[0];

该行将重复写入输出[512]。您需要每个工作组写入输出中的专用位置。

kernel void reduce(global float* input, global float* output, const unsigned int N, local float* cache)
{
    const uint local_id = get_local_id(0);
    const uint global_id = get_global_id(0);
    const uint group_id = get_group_id(0);
    const uint local_size = get_local_size(0);

    cache[local_id] = (global_id < N) ? input[global_id] : 0.0f;
    barrier(CLK_LOCAL_MEM_FENCE);

    for (unsigned int s = local_size >> 1; s > 0; s >>= 1) {
        if (local_id < s) {
            cache[local_id] += cache[local_id + s];
        }
        barrier(CLK_LOCAL_MEM_FENCE);
    }

    if (local_id == 0) output[group_id] = cache[0];
}

然后,您需要对主机上的输出中的值求和。请注意&#39; b&#39;在主机代码中不需要保存N个元素。每个工作组只使用一个元素。

//replace (globalSize/localSize) with the pre-calculated/known number of work groups
for (i=1; i<(globalSize/localSize); i++) {
    b[0] += b[i];
}

现在b [0]是你的总计。

答案 1 :(得分:1)

在简化循环中,你需要这个:

for(unsigned int s = localSize >> 1; s > 0; s >>= 1)

在初始化s时,你的位数比你应该多一点。

在解决之后,让我们看看你的内核在做什么。主机代码使用globalSize为8192和localSize为512执行它,从而生成16个工作组。在内核中,首先对索引2 * global_id处的两个连续内存位置的数据求和。对于id为15的工作组,工作项0,它将位于索引15 * 512 * 2 = 15,360和15,361,它位于输入数组的边界之外。我很惊讶你不会崩溃。同时,这也解释了为什么你有两倍的期望值。

要解决此问题,您可以执行以下操作:

cache[localID] = input[globalID];

或者指定一个全局大小,它是当前大小的一半。

相关问题