不使用 clWaitForEvents 的影响

Effect of not using clWaitForEvents

我是 OpenCL 编程的新手。在我的一个 OpenCL 应用程序中,我在启动每个内核后使用 clWaitForEvents。

案例一:

time_start();
cl_event event;
cl_int status = clEnqueueNDRangeKernel(queue, ..., &event);
clWaitForEvents(1, &event);
time_end();

耗时:250 毫秒(使用 clWaitForEvents)

如果我删除 clWaitForEvents(),我的内核在相同的输出下运行得更快。

案例二:

time_start();
cl_event event;
cl_int status = clEnqueueNDRangeKernel(queue, ..., &event);
time_end();

耗时:220 毫秒(没有 clWaitForEvents)

我必须依次启动 10 个不同的内核。每个内核都依赖于前一个内核的输出。在每个内核之后使用 clWaitForEvent 会使我的执行时间增加几百毫秒。

如果我不使用 clWaitForEvents,输出会出错吗?我想了解如果我不使用 clWaitForEvents 或 clFinish 可能会出现什么问题。

不胜感激。

In-order-queue 隐式等待每个命令按照它们入队的顺序完成,但仅在设备端。这意味着宿主无法知道发生了什么。

Out-of-order-queue 不保证在任何地方的任何命令顺序,并且可能会出现问题。

'Wait-for-event' 在主机端等待命令事件。

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

'Non blocking buffer read/write' 不在主机端等待。

'Blocking buffer read/write' 在主机端等待,但不等待其他命令。


推荐的解决方案:

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

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

希望答案稍微简单一点:

I've to launch 10 different kernels sequentially. Every kernel is dependent on the output of the previous kernel.

如果您没有在 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.

I would like to understand what might possibly go wrong if I do not use clWaitForEvents or clFinish.

如果您在单个有序队列上执行简单操作,则根本不需要 clWaitForEvents()。如果你想等待来自多个队列的多个事件,或者你正在使用无序队列,或者你想排队 20 个命令但等待第 4 个,或类似的东西,它最有用。

对于单个有序队列,在 clFinish() returns 之后,所有命令都将完成并且所有事件的状态都将更新为完成或失败。因此,在最简单的情况下,您根本不需要处理事件,只需将您需要的所有内容入队(尽管检查入队是否有错误)并调用 clFinish()。

请注意,如果您不使用任何形式的 wait/flush(WaitForEvents / Finish / 阻塞命令),实施可能需要尽可能多的时间才能将这些命令实际推送到设备。 IOW 您 必须 1) 使用 WaitForEvents 或 Finish,或 2) 将阻塞命令 (read/write/map/unmap) 作为 last 命令排队。