clEnqueueBarrier和clFinish有什么区别?

7

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上。欢迎提出任何相关评论。
1个回答

8

如果你正在编写一个乱序队列,并希望确保依赖关系,那么需要使用clEnqueueBarrier。另外,你也可以使用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,所以您不需要每次都调用它。

1
感谢您的答案。总结一下:两者都是相同的,但clEnqueueBarrier()是异步函数,因此它立即继续执行主机代码。我测试了这两种解决方案,看是否有更多的时间要求,但似乎没有这样的问题。 - laszlo.endre
我不知道clEnqueueBarrier是否实际上等同于clEnqueueMarker后跟clEnqueueWaitForEvents?还是有一些微小的细节我忽略了? - Tomi Aarnio
2
@TomiAarnio 可能这是 clEnqueueBarrier 的一种实现方式,但我不确定 clEnqueueMarker 在乱序队列中的工作方式会如何影响这两者的语义。对于顺序队列,我认为很可能是这种情况。 - KLee1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接