【问题标题】:What is the difference between clEnqueueBarrier and clFinish?clEnqueueBarrier 和 clFinish 有什么区别?
【发布时间】:2012-11-03 02:22:15
【问题描述】:

OpenCL 1.1 规范说:

cl_int clEnqueueBarrier(cl_command_queue command_queue)

clEnqueueBarrier 是一个同步点,可确保 command_queue 中的所有排队命令都已完成执行,然后才能开始执行下一批命令。

cl_int clFinish(cl_command_queue command_queue)

阻塞,直到 command_queue 中所有先前排队的 OpenCL 命令都发送到相关设备并完成。 clFinish 在 command_queue 中所有排队的命令都被处理和完成之前不会返回。 clFinish 也是一个同步点。

应该对按顺序或无序执行做一些事情,但我看不出有什么区别。如果我有顺序执行,他们是否需要?目前我正在做类似的事情:

...
for(...){
    clEnqueuNDRangeKernel(...);
    clFlush(command_queue);
    clFinish(command_queue);
}
...

在 Nvidia GPU 上。任何相关评论表示赞赏。

【问题讨论】:

    标签: opencl gpu


    【解决方案1】:

    如果您正在编写乱序队列作为确保依赖关系的一种方法,则需要将屏障加入队列。您还可以使用cl_event 对象来确保命令队列中命令的正确顺序。

    如果您正在编写代码,以便在每次内核调用后调用clFinish,那么使用clEnqueueBarrier 不会对您的代码产生任何影响,因为您已经确保了排序。

    使用clEnqueueBarrier 的意义如下:

    clEnqueueNDRangeKernel(queue, kernel1);
    clEnqueueBarrier(queue);
    clEnqueueNDRangeKernel(queue, kernel2);
    

    在这种情况下,kernel2 依赖于 kernel1 的结果。如果这个队列是无序的,那么在没有屏障的情况下,kernel2 可以在 kernel1 之前执行,从而导致不正确的行为。您可以通过以下方式实现相同的排序:

    clEnqueueNDRangeKernel(queue, kernel1);
    clFinish(queue);
    clEnqueueNDRangeKernel(queue, kernel2);
    

    因为clFinish 会一直等到队列为空(所有内核/数据传输都已完成)。但是,clFinish 将等到 kernel1 完成,在这种情况下,clEnqueueBarrier 应立即将控制权返回给应用程序(允许您将更多内核加入队列或执行其他有用的工作。

    作为旁注,我认为clFinish 会隐式调用clFlush,因此您不需要每次都调用它。

    【讨论】:

    • 感谢您的回答。所以总结一下:两者都做同样的事情,但是 clEnqueueBarrier() 是一个异步函数,所以它会立即继续托管代码。如果一个解决方案的时间要求比另一个解决方案多,我测试了这两种解决方案,但似乎没有这样的问题。
    • 我想知道 clEnqueueBarrier 实际上是否等同于 clEnqueueMarker 后跟 clEnqueueWaitForEvents?还是我忽略了一些细节?
    • @TomiAarnio 这可能是 clEnqueueBarrier 的实现,但我不确定 clEnqueueMarker 在乱序队列中如何工作,这可能会影响两者的语义。对于有序队列,我想说这很可能是这种情况。
    猜你喜欢
    • 2010-10-02
    • 2011-12-12
    • 2010-09-16
    • 2012-03-14
    • 2012-02-06
    • 2011-02-25
    • 2011-11-22
    • 2015-03-26
    • 2013-08-19
    相关资源
    最近更新 更多