16

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

订购执行内核的工作项的加载和存储。

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

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

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

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

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

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

谢谢。

规范,供参考。

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

4

3 回答 3

6

为了更清楚地说明(希望如此),

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 节记忆栅栏功能

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

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

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

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

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

我希望这有点道理。这令人困惑。

于 2011-10-06T15:33:58.493 回答
1

这就是我的理解(我仍在尝试验证它)

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

barrier on the other hand will stop execution, period. And will only proceed after all threads reach that point AND all the memory transactions have been cleared.

In other words, barrier is a superset of mem_fence. barrier can prove more expensive in terms of performance than mem_fence.

于 2016-05-17T00:32:58.817 回答
0

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

于 2013-02-22T19:30:41.353 回答