OpenCL,C - Pi的Leibniz公式

时间:2018-02-21 15:15:15

标签: c parallel-processing opencl pi approximation

我试图获得一些 OpenCL 的经验,环境已经设置好,我可以创建和执行内核。我目前正在尝试使用 Leibniz公式并行计算pi,但收到了一些奇怪的结果。

内核如下:

__kernel void leibniz_cl(__global float *space, __global float *result, int chunk_size) 
{
    __local float pi[THREADS_PER_WORKGROUP];
    pi[get_local_id(0)] = 0.;

    for (int i = 0; i < chunk_size; i += THREADS_PER_WORKGROUP) {
        // `idx` is the work item's `i` in the grander scheme
        int idx = (get_group_id(0) * chunk_size) + get_local_id(0) + i;
        float idx_f = 1 / ((2 * (float) idx) + 1);

        // Make the fraction negative if needed
        if(idx & 1)
            idx_f = -idx_f;

        pi[get_local_id(0)] += idx_f;
    }

    // Reduction within workgroups (in `pi[]`)
    for(int groupsize = THREADS_PER_WORKGROUP / 2; groupsize > 0; groupsize >>= 1) { 
        if (get_local_id(0) < groupsize) 
            pi[get_local_id(0)] += pi[get_local_id(0) + groupsize];

        barrier(CLK_LOCAL_MEM_FENCE);
    }

如果我在此结束此功能并将result设置为pi[get_local_id(0)] !get_global_id(0)(与第一组的缩减相同),则打印result会打印{{1} }。

内核的剩余部分:

-nan

返回 // Reduction amongst workgroups (into `space[]`) if(!get_local_id(0)) { space[get_group_id(0)] = pi[get_local_id(0)]; for(int groupsize = get_num_groups(0) / 2; groupsize > 0; groupsize >>= 1) { if(get_group_id(0) < groupsize) space[get_group_id(0)] += space[get_group_id(0) + groupsize]; barrier(CLK_LOCAL_MEM_FENCE); } } barrier(CLK_LOCAL_MEM_FENCE); if(get_global_id(0) == 0) *result = space[get_group_id(0)] * 4; } 会返回space[get_group_id(0)] * 4或非常大的数字,这显然不是pi的近似值。

我无法确定它是否是一个我缺失的OpenCL概念或一般的并行执行。任何帮助表示赞赏。

链接

减少模板:OpenCL float sum reduction

莱布尼兹公式:https://www.wikiwand.com/en/Leibniz_formula_for_%CF%80

1 个答案:

答案 0 :(得分:0)

也许这些不是代码中最关键的问题,但它们可能是问题的根源:

  1. 你肯定应该在本地减少之前使用barrier(CLK_LOCAL_MEM_FENCE);。如果只知道工作组大小等于或小于并行运行相同指令的wavefront中的线程数,则可以避免这种情况 - 对于AMD GPU为64,对于NVidia GPU为32。
  2. 全局缩减必须在多次启动内核中完成,因为barrier()仅适用于同一工作组的工作项。将屏障插入内核的清晰且100%的工作方式是在需要全局条件的地方将其拆分为两个。