所以我已经编写了一个代码并且可以正常工作,现在我想做的是多次调用clEnqueueNDRangeKernel(),每次执行后我都想用该输出更新缓冲区(缓冲区Y)。我写了下面的代码,我想知道它是否正确。 我没有为此编写单独的setkernelArg()命令。
for (int a = 0; a < 100; a++)
{
ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, globalws, NULL, 0, NULL, NULL);
if (ret != CL_SUCCESS) {
printf("Failed to enqueueNDRangeKernel.\n");
exit(1);
}
clEnqueueReadBuffer(command_queue, bufferC, CL_TRUE, 0, M*N * sizeof(float), (void *)C, 0, NULL, NULL);
clEnqueueWriteBuffer(command_queue, bufferY, CL_TRUE, 0, 1 * N * sizeof(float), (void *)C, 0, NULL, NULL);
for (int i = 0; i < N; i++) {
printf("%f, ", C[i]);
}
}
答案 0 :(得分:0)
您应该等待每个OpenCL Api调用。为每个呼叫创建事件。因此,您可以确保在开始下一个执行之前,每个执行都已完成。例如,内核有可能在GPU上进行一些计算,但是同时启动clEnqueueReadBuffer并在内核完成向输出缓冲区的写入之前读取输出缓冲区。还有可能在clEnqueueReadBuffer完成之前写入GPU。 OpenCL Api调用开始在GPU上执行,但是主机编程也继续进行。
有了事件,您的程序可能看起来像这样:
cl_event evKernel, evReadBuf, evWriteBuf;
for(int a = 0; a < 100; a++)
{
ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, globalws, NULL, 0, NULL, &evKernel);
if (ret != CL_SUCCESS) {
printf("Failed to enqueueNDRangeKernel.\n");
exit(1);
}
clWaitForEvents(1, &evKernel);
clEnqueueReadBuffer(command_queue, bufferC, CL_TRUE, 0, M*N * sizeof(float), (void *)C, 0, NULL, &evReadBuf);
clWaitForEvents(1, &evReadBuf);
clEnqueueWriteBuffer(command_queue, bufferY, CL_TRUE, 0, 1 * N * sizeof(float), (void *)C, 0, NULL, &evWriteBuf);
clWaitForEvents(1, &evWriteBuf);
for (int i = 0; i < N; i++) {
printf("%f, ", C[i]);
}
}
有了事件,循环的执行时间就会增加。
在clEnqueueWriteBuffer调用中,您从主机内存( M*N*sizeof(float) )
编写,该内存大于设备缓冲区(1*N*sizeof(float) )
。(也许您是指(M*N*sizeof(float))
?)主机端的程序会崩溃(无效的内存访问),但是OpenCL不会抱怨它并复制数据。我不确定,但是将来可能会引起问题。
我不知道您的内核会做什么,但是如果内核仅将数据写入主机端所需的Output-Buffer会更好。您将bufferC复制到C,但是仅将C的一部分复制到bufferY,这似乎是下一个内核的输入。也许您可以在内核中进行更改。
将数据从主机复制到设备或将设备复制到主机是昂贵的部分。因此,出于性能方面的考虑,您不应复制不需要进行进一步计算的数据。