【问题标题】:OpenCL, C - Leibniz Formula for PiOpenCL,C - Pi 的莱布尼茨公式
【发布时间】:2018-02-21 15:15:15
【问题描述】:

我正在尝试获得一些 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);
    }

如果我在这里结束函数并将!get_global_id(0)result 设置为pi[get_local_id(0)](如第一组的缩减),打印result 打印-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 会返回 -nan 或一个非常大的数字,显然不是 pi 的近似值。

我无法确定这是我遗漏的 OpenCL 概念还是一般的并行执行概念。任何帮助表示赞赏。

链接

缩减模板:OpenCL float sum reduction

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

【问题讨论】:

    标签: c parallel-processing opencl pi approximation


    【解决方案1】:

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

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

    【讨论】:

    • 我完全不知道本地屏障对space[] 没有影响。我将按照您的建议拆分功能以使其正常工作,谢谢您的回答。
    • 另外,在这样的条件中包含barrier 将无法正常工作。屏障的规则是工作组中的每个工作项都必须击中它。有了你的条件,他们不会。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-11
    • 1970-01-01
    • 2013-10-21
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多