У меня есть тестовое ядро, которое я вызываю из Julia OpenCL API. Тот факт, что я звоню от Джулии, не важен, это просто то, что я использую для запуска OpenCL, вот код:
using OpenCL
const cl = OpenCL
device, ctx, queue = cl.create_compute_context()
C_buff = cl.Buffer(Float32, ctx, :w, 2)
const testkernel = """kernel void test(global float *C)
{
int gid = get_global_id(0);
int lid = get_local_id(0);
local float x;
if (lid == 0)
{
x = 0.0f;
}
barrier(CLK_LOCAL_MEM_FENCE);
x += 1.0f;
barrier(CLK_LOCAL_MEM_FENCE);
if (lid == 0)
{
C[gid / 2] = x;
}
}
"""
program = cl.Program(ctx, source=testkernel) |> cl.build!
kernel = cl.Kernel(program, "test")
cl.call(queue, kernel, 4, 2, C_buff)
cl.read(queue, C_buff)
То, что я не могу понять, это возвращает вектор [1.0,1.0]
, когда кажется, что он должен вернуть вектор [2.0,2.0]
, Поскольку в основном у меня есть 4 рабочих элемента, разбитых на две рабочие группы (каждая из которых содержит 2 рабочих элемента).
Один местный поплавок x
создается для каждой рабочей группы, и первый рабочий элемент в каждой рабочей группе устанавливает его в 0. Затем каждый рабочий элемент в рабочей группе добавляет 1 к нему, и, поскольку в каждой рабочей группе есть два рабочих элемента должно быть 2, но когда я вернусь C
Вместо этого я получаю вектор единиц.
barrier(CLK_LOCAL_MEM_FENCE); x += 1.0f; barrier(CLK_LOCAL_MEM_FENCE);
Барьеры не мьютексы. У вас есть гонка данных, в которой оба рабочих элемента пытаются записать в одну и ту же переменную одновременно.
Вам придется использовать атомарность или изменить код.
Других решений пока нет …