OpenCL中的障碍

OpenCL中的障碍,opencl,Opencl,在OpenCL中,我的理解是可以使用barrier()函数同步工作组中的线程。我(通常)理解它们的用途和使用时间。我还知道,工作组中的所有线程都必须达到障碍,否则就会出现问题。然而,到目前为止,每次我尝试使用屏障时,似乎都会导致我的视频驱动程序崩溃,或者出现关于访问某种无效内存的错误消息。到目前为止,我已经在2个不同的视频卡(1个ATI,1个NVIDIA)上看到了这一点 因此,我的问题是: 你知道为什么会这样吗 barrier(CLK\u LOCAL\u MEM\u FENCE)和barrier

在OpenCL中,我的理解是可以使用
barrier()
函数同步工作组中的线程。我(通常)理解它们的用途和使用时间。我还知道,工作组中的所有线程都必须达到障碍,否则就会出现问题。然而,到目前为止,每次我尝试使用屏障时,似乎都会导致我的视频驱动程序崩溃,或者出现关于访问某种无效内存的错误消息。到目前为止,我已经在2个不同的视频卡(1个ATI,1个NVIDIA)上看到了这一点

因此,我的问题是:

  • 你知道为什么会这样吗
  • barrier(CLK\u LOCAL\u MEM\u FENCE)
    barrier(CLK\u GLOBAL\u MEM\u FENCE)
    之间有什么区别?我读了文档,但不清楚
  • 关于何时使用
    屏障(CLK\U本地成员围栏)
    屏障(CLK\U全球成员围栏)
    是否有一般规则
  • 是否有过使用错误的参数类型调用
    barrier()
    会导致错误的情况

  • 如前所述,屏障只能同步同一工作组中的线程。无法同步内核中的不同工作组

    现在回答您的问题,我也不清楚规范,但在我看来,第6.11.9节包含了答案:

    CLK_LOCAL_MEM_围栏–屏障功能将冲洗任何 存储在本地内存中的变量或将内存栅栏排队以确保 内存操作对本地内存的正确顺序

    CLK_GLOBAL_MEM_FENCE–屏障功能将对内存围栏进行排队 确保内存操作对全局内存的顺序正确。 例如,当工作项写入缓冲区或 图像内存对象,然后要读取更新的数据

    因此,据我所知,在写入和读取
    \uuu LOCAL
    内存空间时,您应该使用CLK\u LOCAL\u MEM\u FENCE,在写入和读取
    \uu GLOBAL
    内存空间时,您应该使用CLK\u GLOBAL\u MEM\u FENCE

    我没有测试这是否较慢,但大多数情况下,当我需要一个屏障,并且我怀疑哪一个内存空间受到影响时,我只是将两者结合使用,即:

    barrier(CLK_LOCAL_MEM_FENCE | CLK_GLOBAL_MEM_FENCE);
    
    这样,您就不会有任何内存读写排序问题(只要您确定组中的每个线程都通过了障碍,但您知道这一点)


    希望能有所帮助。

    在这里重现一条古老的线索。我自己也有点麻烦

    关于您的碰撞问题,一个潜在的原因可能是您的屏障处于某种状态。我了解到,当您使用barrier时,组中的所有工作项都必须能够到达该指令,否则它将挂起您的内核—通常会导致崩溃

    if(someCondition){
      //do stuff
      barrier(CLK_LOCAL_MEM_FENCE);
      //more stuff
    }else{
      //other stuff
    }
    
    我的理解是,如果一个或多个工作项满足某个条件,则所有工作项都必须满足该条件,否则会有一些工作项跳过障碍。屏障将等待所有工作项到达该点。要修复上述代码,我需要对其进行一些重构:

    if(someCondition){
      //do stuff
    }
    barrier(CLK_LOCAL_MEM_FENCE);
    if(someCondition){
      //more stuff
    }else{
      //other stuff
    }
    
    现在所有工作项都将到达屏障

    我不知道这在多大程度上适用于循环;如果一个工作项从for循环中断,它是否会遇到障碍?我不确定

    更新:我已经成功地使一些ocl程序在for循环中遇到障碍而崩溃。确保所有工作项同时退出for循环——或者更好的是,将屏障置于循环之外


    (来源:异构计算与OpenCL第5章,第90-91页)

    显然,CLK_GLOBAL_MEM_FENCE通常比CLK_LOCAL_MEM_FENCE慢。原因是块内的所有线程都必须等待内存访问完成。等待全局内存访问完成比本地内存访问要昂贵得多。当然,这并不总是正确的,这取决于访问模式(费米现在有缓存,这意味着全局访问可以缓存在L1上,L1与共享内存具有相似的延迟)、内核中全局/本地内存访问的数量、占用率、银行冲突、合并等。感谢您的评论。我也不确定,但我怀疑,如果某个工作组中的任何线程都遇到了障碍,那么该工作组中的所有线程都必须遇到障碍。因此,在循环情况下,如果一个工作组中的所有线程都在遇到障碍之前中断,则没有问题。但是,如果一个工作组中至少有一个线程在循环的某个特定迭代中遇到了障碍,那么所有线程(来自该工作组)也必须如此。文档似乎跳过的另一种情况是,在这两种情况下都有if/else并调用障碍。这似乎不会使程序崩溃,但似乎也没有任何效果。我发现,AMD的示例代码使所有线程都在for循环中运行,尽管有些线程没有目的,只是为了达到障碍。