I'm trying to run a multithreaded Java application that executes OpenCL kernels. I wanted to notify one of the threads when a Kernel finishes, so I tried to use the clSetEventCallback method.
For that I prepared a method
void runKernel(
cl_program program,
String functionName,
Object... params,
long[] globalWorkSize,
long[] localWorkSize
){
System.out.println(System.currentTimeMillis() +": Preparing Kernel "+kernel+);
int[] errCode = new int[1];
int errno;
cl_kernel kernel = CL.clCreateKernel(program, functionName, errCode);
/******INSERT ALL THE PARAMS******/
System.out.println(System.currentTimeMillis() +": Enqueueing Kernel "+kernel+);
cl_event event = new cl_event();
CL.clEnqueueNDRangeKernel(this.queue, kernel, 1, null, globalWorkSize, localWorkSize, 0, null, event);
CL.clSetEventCallback(event, CL_COMPLETE, new EventCallbackFunction() {
@Override
public void function(cl_event event, int command_exec_callback_type, Object user_data) {
System.out.println(System.currentTimeMillis() +": Finished kernel " + user_data);
}
}, kernel);
}
I call this function to execute three different kernels with a 5 secongs gap inbetween. The code runs fine and I get the expected result. However, when I look at the application output, the callback methods are not executed upon the actual kernel completion but once the program calls again the run method. The callback for the last executed kernel is never executed (the kernel is executed since the results obtained are correct).
1475085785924: Prepared Kernel cl_kernel[0x7f8b28098c90]
1475085785924: Enqueueing Kernel cl_kernel[0x7f8b28098c90]
1475085790925: Prepared Kernel cl_kernel[0x7f8b284fbd50]
1475085790925: Enqueueing Kernel cl_kernel[0x7f8b284fbd50]
1475085790925: Finished kernel cl_kernel[0x7f8b28098c90]
1475085795926: Prepared Kernel cl_kernel[0x7f8b2851abd0]
1475085795926: Enqueueing Kernel cl_kernel[0x7f8b2851abd0]
1475085795926: Finished kernel cl_kernel[0x7f8b284fbd50]
Is there any problem on my code so the callbacks are not executed until the next kernel is enqueued? Did I miss something? Or the JOCL/OpenCL library is not notifying a kernel end properly?
Apparently, there is a bug on the OpenCL implementation that I use.
As a workaround, I'm enqueueing a kernel that does nothing after enqueueing the actual kernel.
I have a cl_program attribute with an empty program.
private cl_program doNothing;
int[] errCode = new int[1];
String blankCode = "__kernel void blank(){}";
doNothing = CL.clCreateProgramWithSource(context, 1, new String[]{blankCode}, new long[]{blankCode.length()}, errCode);
CL.clBuildProgram(doNothing, 1, new cl_device_id[]{deviceId}, null, null, errCode);
And after enqueueing the kernel execution I call the following method that enqueues the blank kernel
private void addBlankKernel() {
int[] errCode = new int[1];
cl_kernel kernel = CL.clCreateKernel(this.doNothing, "blank", errCode);
CL.clEnqueueNDRangeKernel(this.queue, kernel, 1, null, new long[]{1}, new long[]{1}, 0, null, null);
}