我是OpenCL编程的新手。在我的一个OpenCL应用程序中,我在启动每个内核后使用clWaitForEvents。
案例1:
time_start();
cl_event event;
cl_int status = clEnqueueNDRangeKernel(queue, ..., &event);
clWaitForEvents(1, &event);
time_end();
所用时间:250毫秒(使用clWaitForEvents)
如果我删除了clWaitForEvents(),我的内核运行速度会相同。
案例2:
time_start();
cl_event event;
cl_int status = clEnqueueNDRangeKernel(queue, ..., &event);
time_end();
所用时间:220毫秒(不含clWaitForEvents)
我要按顺序启动10个不同的内核。每个内核都依赖于以前内核的输出。在每个内核之后使用clWaitForEvent会使我的执行时间增加几百毫秒。
如果我不使用clWaitForEvents,输出会出错吗?我想了解如果我不使用clWaitForEvents或clFinish可能会出现什么问题。
任何指针都表示赞赏。
答案 0 :(得分:2)
希望答案稍微复杂一点:
我要按顺序启动10个不同的内核。每个内核都依赖于前一个内核的输出。
如果您未在clCreateCommandQueue()调用中显式设置CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE属性(=通常情况),则它将是有序队列。你不需要在它们中同步命令(实际上你不应该,因为你看它可能会大大减慢执行速度)。请参阅docs:
If the CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE property of a command-queue is not set, the commands enqueued to a command-queue execute in order. For example, if an application calls clEnqueueNDRangeKernel to execute kernel A followed by a clEnqueueNDRangeKernel to execute kernel B, the application can assume that kernel A finishes first and then kernel B is executed. If the memory objects output by kernel A are inputs to kernel B then kernel B will see the correct data in memory objects produced by execution of kernel A.
如果我不使用clWaitForEvents或clFinish,我想了解可能出现的问题。
如果您在单个有序队列中执行简单操作,则根本不需要clWaitForEvents()。如果您想等待来自多个队列的多个事件,或者您正在使用无序队列,或者您想要排队20个命令但等待第4个或类似的东西,那么它最有用。
对于单个有序队列,在clFinish()返回后,所有命令都将完成,任何&所有事件的状态都将更新为完成或失败。因此,在最简单的情况下,您根本不需要处理事件,只需将您需要的所有内容排入队列(尽管检查排队的错误)并调用clFinish()。
请注意,如果您不使用任何形式的等待/刷新(WaitForEvents / Finish / a blocking命令),则实现可能需要花费尽可能多的时间来实际将这些命令推送到设备。如果您必须 1)使用WaitForEvents或Finish,或2)将阻止命令(读/写/地图/取消映射)排入最后命令。
答案 1 :(得分:1)
In-order-queue
隐式地按照它们排队的顺序等待每个命令完成,但仅在设备端。这意味着主人不知道发生了什么。
Out-of-order-queue
不保证任何地方的任何命令顺序,并且可能有问题。
'等待换事件'在主机端等待命令事件。
'完成'等待主机端,直到所有命令都完成。
'非阻塞缓冲区读/写'不要在主持人那边等。
'阻止缓冲区读/写'在主机端等待,但不等待其他命令。
推荐的解决方案:
在有序队列中排队1个非阻塞缓冲区写入+ 1000个内核+ 1个阻塞缓冲区,可以在初始数据上成功执行1000个内核链,并在主机端获取最新结果。