不使用clWaitForEvents的影响

时间:2017-12-21 08:42:51

标签: opencl

我是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可能会出现什么问题。

任何指针都表示赞赏。

2 个答案:

答案 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不保证任何地方的任何命令顺序,并且可能有问题。

'等待换事件'在主机端等待命令事件。

'完成'等待主机端,直到所有命令都完成。

'非阻塞缓冲区读/写'不要在主持人那边等。

'阻止缓冲区读/写'在主机端等待,但不等待其他命令。

推荐的解决方案:

  • 命令间同步(使用命令输出作为下一个命令的输入)
    • 有序队列。
    • 或将命令事件传递给另一个命令(如果它是一个无序队列)
  • 队列间(或无序队列)同步(用于重叠缓冲区副本和内核执行)
    • 将事件从命令传递到另一个命令
  • 设备 - 主机同步(用于将最新数据传输到RAM(或从RAM获取第一个数据)或暂停主机)
    • 启用缓冲区命令的阻止选项
    • 或添加clFinish
    • 或使用clWaitForEvent
  • 在命令完成时通知(出于基准测试等原因)
    • 使用事件回调
    • 或不断查询事件状态(CPU / pci-e使用量增加)

在有序队列中排队1个非阻塞缓冲区写入+ 1000个内核+ 1个阻塞缓冲区,可以在初始数据上成功执行1000个内核链,并在主机端获取最新结果。