OpenCL 奇怪的行为

OpenCL strange behavior

美好的一天,

我想我已尽一切努力找出问题所在,但我做不到。我有以下主机代码:

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);
    }
}

因此,在每个 "step" 处,我只需将每组的距离 [group_id] 加一个 1 1000 次。然后我只是从 global_id == 1 的线程中读取结果。 在每一步我都应该有以下文本:

step: 59; group: 0; data: 500
step: 59; group: 1; data: 500

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

step: 4; group: 0; data: 500
step: 4; group: 1; data: 210
step: 5; group: 0; data: 500
step: 5; group: 1; data: 214

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

您知道为什么会发生这种情况吗?

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

barrier(CLK_GLOBAL_MEM_FENCE);

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

打印结果的代码中的循环将只有工作组 0 的正确值,因为它在工作组 0 中只有 运行。如果您真的希望此代码工作,循环打印结果必须在单独的 NDRange 中,并在 NDRange 之间进行适当的同步。

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