Я пытаюсь сделать асинхронные вызовы ядра в GPGPU с использованием CUDAfy .NET.Запуск ядра с CUDAfy .NET с использованием OpenCL асинхронно
Когда я передаю значения ядру и копирую их обратно на хост, я не всегда получаю ожидаемое значение.
У меня есть структура Foo с байтовой Bar:
[Cudafy]
public struct Foo {
public byte Bar;
}
И у меня есть ядро, я хочу назвать:
[Cudafy]
public static void simulation(GThread thread, Foo[] f)
{
f[0].Bar = 3;
thread.SyncThreads();
}
У меня есть один поток с StreamID = 1 (я пробовал используя несколько потоков, и заметил проблему. Сокращение до одного потока, похоже, не устранило проблему).
//allocate
streamID = 1;
count = 1;
gpu.CreateStream(streamID);
Foo[] sF = new Foo[count];
IntPtr hF = gpu.HostAllocate<Foo>(count);
Foo[] dF = gpu.Allocate<Foo>(sF);
while (true)
{
//set value
sF[0].Bar = 1;
byte begin = sF[0].Bar;
//host -> pinned
GPGPU.CopyOnHost<Foo>(sF, 0, hF, 0, count);
sF[0].Bar = 2;
lock (gpu)
{
//pinned -> device
gpu.CopyToDeviceAsync<Foo>(hF, 0, dF, 0, count, streamID);
//run
gpu.Launch().simulation(dF);
//device -> pinned
gpu.CopyFromDeviceAsync<Foo>(dF, 0, hF, 0, count, streamID);
}
//WAIT
gpu.SynchronizeStream(streamID);
//pinned -> host
GPGPU.CopyOnHost<Foo>(hF, 0, sF, 0, count);
byte end = sF[0].Bar;
}
//de-allocate
gpu.Free(dF);
gpu.HostFree(hF);
gpu.DestroyStream(streamID);
Сначала создаю поток на графическом процессоре.
Я создаю регулярную структуру массива Foo размера 1 (sF) и устанавливаю его значение в баре 1. Затем я создаю закрепленную память на хосте (hF) для Foo. Я также создаю память на устройстве для Foo (dF).
Я инициализирую значение бара структуры до 1, затем копирую его в закрепленную память (в качестве проверки я установил значение 2 для структуры после копирования, чтобы зафиксировать ее, вы поймете, почему позже). Затем я использую блокировку, чтобы обеспечить полный доступ к графическому процессору, и я ставлю копию в dF, запуск для ядра и копию из dF. На данный момент я не знаю, когда все это будет выполняться на GPU ... поэтому я могу вызвать SynchronizeStream, чтобы ждать на хосте до тех пор, пока устройство не будет выполнено.
Когда все будет готово, я могу скопировать закрепленную память (hF) в общую память (sF). Когда я получаю значение, обычно это 3 (который был установлен на устройстве) или 1 (что означает, что либо значение не было установлено в ядре, либо новое значение не было скопировано в закрепленную память). Я знаю, что закрепленная память копируется в структуру, потому что структура никогда не имеет значения 2.
В течение многих прогонов небольшое количество пробегов приводит к чему-то другому, кроме begin = 1 и end = 3. Он всегда будет begin = 1, end = 1, и это происходит примерно в 5-10% времени.
Я понятия не имею, почему это происходит. Я знаю, что это обычно подчеркивает состояние гонки, но, позвонив по вызовам синхронизации, я ожидал бы, что асинхронные вызовы будут работать предсказуемым образом.
Зачем мне возникать проблема с этим кодом?
Большое вам спасибо!
-Phil