У меня есть только процессор Core i3 с двумя ядрами, поэтому я могу работать только с процессором, а не с графическим процессором. Я хочу протестировать простой пример с помощью OpenCL с простым ядром add. Но вот моя проблема:Неполная задача до того, как HOST заканчивается процессором
После выделения платформы, устройство процессора и т.д., я следующее:
1) clEnqueueNDRange() ставит в очереди задачи ядра и назначает событие для выполнения этой задачи с помощью последнего параметр.
2) clSetEventCallback() с использованием CL_COMPLETE связывает функцию обратного вызова с вышеупомянутым событием.
Как правило, функция callback должна вызываться, когда задача завершается. Но это не так. В самом деле, задача INCOMPLETE в конце события, если хост как много материала, чтобы сделать до окончания. Может ли кто-нибудь сказать мне, почему?
Вот мой минимальный код:
/** Simple add kernel */
private static String programSource0 =
"__kernel void vectorAdd(" +
" __global const float *a,"+
" __global const float *b, " +
" __global float *c)"+
"{"+
" int gid = get_global_id(0);"+
" c[gid] = a[gid]+b[gid];"+
"}";
/** The entry point of this sample */
public static void main(String args[])
{
/** Callback function */
EventCallbackFunction kernelCommandEvent = new EventCallbackFunction()
{
@Override
public void function(cl_event event, int event_status, Object user_data)
{
System.out.println("Callback: task COMPLETED");
}
};
// Initialize the input data
int n = 1000000;
float srcArrayA[] = new float[n];
float srcArrayB[] = new float[n];
float dstArray0[] = new float[n];
Array.fill(srcArrayA, 1,0f);
Array.fill(srcArrayB, 1,0f);
// .
// (hidden) Allocation of my Intel platform, CPU device, kernel, commandQueue, and memory buffer, set the argument to kernel etc...
// .
// Set work-item dimensions and execute the kernels
long globalWorkSize[] = new long[]{n};
// I pass an event on completion of the command queue.
cl_event[] myEventID = new cl_event[1];
myEventID[0] = new cl_event();
clEnqueueNDRangeKernel(commandQueue, kernel0, 1, null, globalWorkSize, null, 0, null, myEventID[0]);
// I link the event to the callback function "kernelCommandEvent", and pass 10 as parameter
clSetEventCallback(myEventID[0], CL_COMPLETE, kernelCommandEvent, new Integer(10));
// host does some very long stuff !!
// Normally, my device task should be completed
int[] ok = new int[1];
Arrays.fill(ok, 0);
clGetEventInfo(myEventID[0], CL_EVENT_COMMAND_EXECUTION_STATUS, Sizeof.cl_int, Pointer.to(ok), null);
if (ok[0] == CL_COMPLETE) System.out.println("Task COMPLETE");else System.out.println("Task INCOMPLETE");
}
Хорошо, спасибо за ответ, он отлично работал. Кстати, я заметил на другом компьютере, что для устройства NVIDIA GPU этот вызов clFlush() не нужен, поэтому это связано с тем, что вы сказали о драйверах, зависящих от реализации. Поэтому я думаю, что какое бы устройство мы ни использовали, хорошо подумать, что всегда вызывайте функцию clFlush(), чтобы убедиться, что задача выполняется, правильно? Большое спасибо в любом случае DarkZeros – Algernon2
Зависит, например, в случае только процессора. Выполнение всей обработки при блокирующем вызове экономит некоторое время, поскольку оно минимизирует количество контекстных переключателей вашего приложения. Хотя в устройствах GPU полезно начать работать как можно быстрее. – DarkZeros
Итак, в случае, когда несколько командных очередей принадлежат нескольким различным контекстам, удобнее выполнять все вызовы clEnqueueNDRange(), а затем вызывать только один раз clFlush(), если я правильно понял? – Algernon2