在 OpenCL 中,mem_fence() 与 barrier() 相比做啥?

Posted

技术标签:

【中文标题】在 OpenCL 中,mem_fence() 与 barrier() 相比做啥?【英文标题】:In OpenCL, what does mem_fence() do, as opposed to barrier()?在 OpenCL 中,mem_fence() 与 barrier() 相比做什么? 【发布时间】:2011-12-02 04:55:57 【问题描述】:

barrier()(我想我理解)不同,mem_fence() 不会影响工作组中的所有项目。 OpenCL 规范说(第 6.11.10 节),对于mem_fence()

命令加载和存储执行内核的工作项。

(因此它适用于单个工作项)。

但是,与此同时,在第 3.3.1 节中,它说:

在工作项内存中具有加载/存储一致性。

所以一个工作项内存是一致的。

那么mem_fence() 有什么用呢?它不适用于项目,但在项目中不需要...

请注意,我没有使用原子操作(第 9.5 节等)。 mem_fence() 是与这些结合使用的想法吗?如果是这样,我很乐意看到一个例子。

谢谢。

The spec, for reference.

更新:我可以看到它在使用 barrier() 时有多么有用(隐含,因为屏障调用 mem_fence()) - 但肯定还有更多, 因为它是单独存在的?

【问题讨论】:

本演示文稿提供了一个内存栅栏的示例:它可以防止 e. G。 shared_var=value; lock = false; (people.maths.ox.ac.uk/gilesm/cuda/new_lectures/lec3.pdf) 的重新排序对于单个隔离的工作项,这种重新排序无关紧要,因为对于单个工作项,这些变量之间似乎没有依赖关系 => 在工作项内部给出了所需的一致性。此外,这篇文章被证明是有帮助的:en.wikipedia.org/wiki/Memory_barrier. 【参考方案1】:

为了更清楚地表达(希望如此),

mem_fence() 等待直到调用工作项在 mem_fence() 之前对本地和/或全局内存进行的所有读/写操作对工作组中的所有线程都是可见的。

来自:http://developer.download.nvidia.com/presentations/2009/SIGGRAPH/asia/3_OpenCL_Programming.pdf

内存操作可以重新排序以适应它们运行的​​设备。规范声明(基本上)内存操作的任何重新排序都必须确保内存在单个工作项中处于一致状态。但是,如果您(例如)执行存储操作并且 value 决定暂时位于工作项特定的缓存中,直到有更好的时间来写入本地/全局内存,该怎么办?如果您尝试从该内存中加载,写入该值的工作项会将其保存在其缓存中,所以没问题。但是工作组中的其他工作项没有,因此它们可能会读取错误的值。放置内存栅栏可确保在调用内存栅栏时,本地/全局内存(根据参数)将保持一致(任何缓存都将被刷新,并且任何重新排序都将考虑到您期望其他线程可能之后需要访问这些数据)。

我承认这仍然令人困惑,我不会发誓我的理解是 100% 正确的,但我认为这至少是大体上的想法。

跟进:

我找到了这个关于 CUDA 内存栅栏的链接,但同样的一般想法也适用于 OpenCL:

http://developer.download.nvidia.com/compute/cuda/2_3/toolkit/docs/NVIDIA_CUDA_Programming_Guide_2.3.pdf

查看B.5 Memory Fence Functions 部分

他们有一个代码示例,可以在一次调用中计算一组数字的总和。该代码设置为计算每个工作组中的部分总和。然后,如果还有更多的求和操作,代码让最后一个工作组完成工作。

所以,基本上每个工作组都要做两件事:部分求和,更新全局变量,然后是计数器全局变量的原子增量。

之后,如果还有更多工作要做,将计数器增加到 ("work-group size" - 1) 值的工作组将被视为最后一个工作组。该工作组继续完成。

现在,问题(正如他们解释的那样)是,由于内存重新排序和/或缓存,计数器可能会增加,最后一个工作组可能会在部分总和全局变量之前开始工作已将其最近的值写入全局内存。

内存栅栏将确保该部分总和变量的值在移过栅栏之前对于所有线程都是一致的。

我希望这是有道理的。很混乱。

【讨论】:

但在您给出的示例中,其他线程无法确定数据存储是否没有障碍。所以无论如何你都需要屏障。我想我没有把它放在最初的问题中 - 但我看不出 mem_fence 单独是如何有意义的(当不与屏障一起使用时)。抱歉,如果我遗漏了什么,感谢您的评论... 我在上面添加了更多细节。我希望这会有所帮助。 好的,所以 cuda 示例包含一个原子操作,我怀疑这是 mem_fence 有用所必需的。以供将来参考,此处描述了 opencl 和 cuda 函数之间的等效性 - developer.amd.com/documentation/articles/pages/… 虽然您可能在描述 OpenCL men_fence() 的意图或从类似的 CUDA 函数中推断,但我认为原始发帖人的问题仍未得到解答。 men_fence() 的 OpenCL 规范,即使现在是 1.2,也没有说明它提供了工作组中线程之间的一致性。我还有同样的问题,为什么有 men_fence() 呢? AMD 论坛中的此线程提供了与此答案相矛盾的使用说明和示例。 devgurus.amd.com/message/1242922#1242922【参考方案2】:

我是这样理解的(我还在努力验证)

memory_fence 只会确保内存是一致的并且对组中的所有线程都是可见的,即执行不会停止,直到有另一个内存事务(本地或全局)。这意味着如果memory_fence之后有移动指令或添加指令,设备将继续执行这些“非内存事务”指令。

barrier 另一方面将停止执行,期间。并且只有在所有线程到达该点并且所有内存事务都已清除后才会继续。

换句话说,barriermem_fence 的超集。 barrier 在性能方面可能比 mem_fence 更昂贵。

【讨论】:

【参考方案3】:

栅栏确保在栅栏之前发出的加载和/或存储将在栅栏之后发出的任何加载和/或存储之前完成。仅栅栏就没有暗示任何 sinc。屏障操作支持一个或两个内存空间中的读/写栅栏以及阻塞直到给予者工作组中的所有工作项到达它。

【讨论】:

以上是关于在 OpenCL 中,mem_fence() 与 barrier() 相比做啥?的主要内容,如果未能解决你的问题,请参考以下文章

OpenCL 入队屏障与入队标记 - 有啥区别?

为啥 Cuda/OpenCL 的全局内存中没有银行冲突?

在多 GPU 系统中,给定 PCI 供应商、设备和总线 ID,如何将 OpenCL 设备与特定 GPU 匹配?

OpenCL中的half与float的转换

OpenCL-2-OpenCL事件

OpenCL 计算与顺序算法的输出不匹配