OpenCL 中的障碍
Posted
技术标签:
【中文标题】OpenCL 中的障碍【英文标题】:Barriers in OpenCL 【发布时间】:2011-10-16 22:42:28 【问题描述】:在OpenCL中,我的理解是可以使用barrier()
函数来同步工作组中的线程。我确实(通常)了解它们的用途以及何时使用它们。我也知道工作组中的所有线程都必须遇到障碍,否则会出现问题。但是,到目前为止,每次我尝试使用障碍时,似乎都会导致我的视频驱动程序崩溃,或者出现有关访问某种无效内存的错误消息。到目前为止,我已经在 2 个不同的显卡(1 个 ATI,1 个 NVIDIA)上看到了这一点。
所以,我的问题是:
-
知道为什么会发生这种情况吗?
barrier(CLK_LOCAL_MEM_FENCE)
和barrier(CLK_GLOBAL_MEM_FENCE)
有什么区别?我阅读了文档,但我并不清楚。
是否有关于何时使用barrier(CLK_LOCAL_MEM_FENCE)
和barrier(CLK_GLOBAL_MEM_FENCE)
的一般规则?
是否曾经使用错误的参数类型调用 barrier()
会导致错误?
【问题讨论】:
【参考方案1】:正如您所说,屏障只能同步同一工作组中的线程。无法同步内核中的不同工作组。
现在回答你的问题,我也不清楚规范,但在我看来,第 6.11.9 节包含答案:
CLK_LOCAL_MEM_FENCE – 屏障函数将刷新任何 存储在本地内存中的变量或排队内存栅栏以确保 将内存操作正确排序到本地内存。
CLK_GLOBAL_MEM_FENCE – 屏障函数将内存栅栏排队 以确保对全局内存的内存操作正确排序。 这在工作项(例如,写入缓冲区或 图像内存对象,然后想读取更新的数据。
因此,据我了解,在写入和读取__local
内存空间时应使用 CLK_LOCAL_MEM_FENCE,在写入和读取__global
内存空间时应使用 CLK_GLOBAL_MEM_FENCE。
我还没有测试过这是否更慢,但是大多数时候,当我需要一个屏障并且我怀疑哪个内存空间受到影响时,我只是使用两者的组合,即:
barrier(CLK_LOCAL_MEM_FENCE | CLK_GLOBAL_MEM_FENCE);
这样你就不应该有任何内存读\写顺序问题(只要你确定组中的每个线程都通过障碍,但你知道这一点)。
希望对你有帮助。
【讨论】:
显然 CLK_GLOBAL_MEM_FENCE 通常比 CLK_LOCAL_MEM_FENCE 慢。原因是块内的所有线程都必须等待内存访问完成。并且等待全局内存访问完成比本地内存访问要昂贵得多。当然,这并不总是正确的,它取决于访问模式(Fermi 现在有缓存,这意味着全局访问可以缓存在 L1 上,与共享内存有相似的延迟),内核中全局/本地内存访问的数量、占用、银行冲突、合并等。【参考方案2】:在这里恢复一个旧线程。我自己在使用 barrier() 时遇到了一点麻烦。
关于你的崩溃问题,一个潜在的原因可能是你的障碍是否在一个条件内。我读到,当您使用屏障时,组中的所有工作项都必须能够访问该指令,否则它将挂起您的内核 - 通常会导致崩溃。
if(someCondition)
//do stuff
barrier(CLK_LOCAL_MEM_FENCE);
//more stuff
else
//other stuff
我的理解是,如果一个或多个工作项满足 someCondition,则所有工作项都必须满足该条件,否则会有一些会跳过障碍。障碍会等到所有工作项都达到该点。要修复上面的代码,我需要对其进行一些重构:
if(someCondition)
//do stuff
barrier(CLK_LOCAL_MEM_FENCE);
if(someCondition)
//more stuff
else
//other stuff
现在所有工作项都将到达屏障。
我不知道这在多大程度上适用于循环;如果一个工作项从 for 循环中中断,它会遇到障碍吗?我不确定。
更新:我已经成功地使一些 ocl 程序在一个 for 循环中崩溃了。确保所有工作项同时退出 for 循环 - 或者更好的是,将屏障放在循环之外。
(来源:使用 OpenCL 进行异构计算第 5 章,p90-91)
【讨论】:
感谢您的评论。我也不确定,但我怀疑如果该工作组中的任何线程都遇到障碍,则工作组中的所有线程都必须遇到障碍。所以,在循环的情况下,如果一个工作组中的所有线程在遇到障碍之前都中断了,没问题。但是,如果工作组中的至少一个线程在循环的特定迭代中遇到障碍,那么(来自该工作组的)所有线程也必须如此。 文档似乎跳过的另一种情况是在这两种情况下都有 if/else 并调用屏障的情况。这似乎不会使程序崩溃,但似乎也没有任何效果。我发现,AMD 的示例代码让所有线程都在 for 循环中运行,即使有些线程没有任何目的,只是为了撞到障碍。以上是关于OpenCL 中的障碍的主要内容,如果未能解决你的问题,请参考以下文章