OpenCL奇怪的行为

时间:2015-06-02 17:42:23

标签: opencl gpgpu

美好的一天,

我想我已经尝试过一切来弄清楚问题出在哪里,但我无法做到。我有一个主机的以下代码:

cl_mem cl_distances = clCreateBuffer(context, CL_MEM_READ_WRITE, 2 * sizeof(cl_uint), NULL, NULL);
clSetKernelArg(kernel, 0, sizeof(cl_mem), &cl_distances);

cl_event event;
clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, &global_workers, &local_workers, 0, NULL, &event);

clWaitForEvents(1, &event);

对于设备:

__kernel void walk(__global uint *distance_results)
{
    uint global_size = get_global_size(0);
    uint local_size = get_local_size(0);

    uint global_id = get_global_id(0);
    uint group_id = get_group_id(0);
    uint local_id = get_local_id(0);

    for (uint step = 0; step < 500; step++) {
        if (local_id == 0) {
            distance_results[group_id] = 0;
        }

        barrier(CLK_LOCAL_MEM_FENCE);

        for (uint n = global_id; n < 1000; n += global_size) {
            if (local_id == 0) {
                atomic_add(&distance_results[group_id], 1);
            }
        }

        barrier(CLK_GLOBAL_MEM_FENCE);

        if (global_id == 0) {
            for (uint i = 0; i < (global_size / local_size); i++) {
                printf("step: %d; group: %d; data: %d\n", step, i, distance_results[i]);
            }
        }

        barrier(CLK_GLOBAL_MEM_FENCE);
    }
}

所以在每个&#34;步骤&#34;我只是将距离[group_id]一个1添加到每组1000次。然后我只用global_id == 1从线程中读取结果。 在每一步我都应该有以下文字:

  步骤:59;组:0;数据:500
  步骤:59;组:1;数据:500

但实际上有很多字符串包含错误的数据:

  步骤:4;组:0;数据:500
  第4步;组:1;数据:210
  步骤:5;组:0;数据:500
  步骤:5;组:1;数据:214

如果我将global_workers设置为1并将local_workers设置为1,则一切正常。但是如果我将global_workers设置为2并将local_workers设置为1,那么我就会有这种奇怪的行为。

你有什么想法可以解决这个问题吗?

1 个答案:

答案 0 :(得分:2)

这里发生了一些事情,但我认为核心问题来自对OpenCL的一个非常普遍的误解。这个电话:

barrier(CLK_GLOBAL_MEM_FENCE);

这不是一个全球障碍。它是一个具有全球记忆围栏的局部屏障。换句话说,它仍然只在单个工作组中的工作项之间同步,而不在其他工作组中的工作项之间同步。

打印结果的代码中的循环只有工作组0的正确值,因为它只在工作组0中运行。如果你真的想要这个代码工作,打印结果的循环必须在一个单独的NDRange中,NDRanges之间有适当的同步。

内存栅栏只控制将哪些类型的内存写入提交到内存。在这种情况下,您需要两者的全局围栏,因为您试图围绕全局内存写入,而不是本地内存写入。