cuda,虚拟/隐式块同步

时间:2012-07-04 07:47:02

标签: cuda synchronization

我知道无法进行块同步,唯一的方法是启动新内核。

但是,假设我启动X块,其中X对应于我GPU上SM的数量。我应该注意调度程序会为每个SM分配一个块......对吗?如果将GPU用作辅助图形卡(完全专用于CUDA),这意味着理论上没有其他进程可以使用它......对吗?

我的想法如下:隐式同步。

让我们假设有时候我只需要一个块,有时我需要所有的X块。好吧,在我只需要一个块的情况下,我可以配置我的代码,以便第一个块(或第一个SM)可以处理“真实”数据,而其他X-1块(或SM)可以处理“虚拟“数据,执行完全相同的指令,只是一些其他偏移。

所有这些都将继续同步,直到我再次需要它们。

在这种情况下,调度程序是否可靠?或者你可以永远不确定吗?

2 个答案:

答案 0 :(得分:3)

你有一个问题,所以我会尝试单独解决它们。

每个SM一个块

我在nVidia's own forums上回答了一段时间,因为我得到的结果表明这不是发生的事情。显然,如果块的数量等于SM的数量,则块调度程序不会为每个SM分配块。

隐式同步

没有。首先,您不能保证每个块都有自己的SM(见上文)。其次,所有块都无法同时访问全局存储。如果它们完全同步运行,它们将在第一次存储器读/写时失去同步性。

阻止同步

现在有好消息:是的,你可以。 CUDA C Programming Guide的B.11节中描述的原子指令可用于创建障碍。假设您在GPU上同时执行N个阻止。

__device__ int barrier = N;

__global__ void mykernel ( ) {

    /* Do whatever it is that this block does. */
    ...

    /* Make sure all threads in this block are actually here. */
    __syncthreads();

    /* Once we're done, decrease the value of the barrier. */
    if ( threadIdx.x == 0 )
        atomicSub( &barrier , 1 );

    /* Now wait for the barrier to be zero. */
    if ( threadIdx.x == 0 )
        while ( atomicCAS( &barrier , 0 , 0 ) != 0 );

    /* Make sure everybody has waited for the barrier. */
    __syncthreads();

    /* Carry on with whatever else you wanted to do. */
    ...

    }

指令atomicSub(p,i)以原子方式计算*p -= i并且仅由块中的第0个线程调用,即我们只想减少barrier一次。指令atomicCAS(p,c,v)设置*p = v iff *p == c并返回旧值*p。这部分只是循环直到barrier到达0,即直到所有块都越过它。

请注意,您必须将此部分包装在对__synchtreads()的调用中,因为块中的线程不会在严格的锁步中执行,您必须强制它们等待第0个线程。

请记住,如果您多次调用内核,则应将barrier设置回N

<强>更新

在回复jHackTheRipper的答案和Cicada的评论时,我应该指出你不应该尝试启动比GPU上同时安排的更多块!这受到许多因素的限制,您应该使用CUDA Occupancy Calculator来查找内核和设备的最大块数。

从最初的问题来看,只有与SM一样多的区块正在启动,所以这一点没有实际意义。

答案 1 :(得分:-4)

@Pedro肯定是错的!

实现全球同步一直是最近几个研究工作的主题,最后是非Kepler架构(我还没有)。结论总是相同(或应该是):不可能在整个GPU上实现这样的全局同步。

原因很简单:CUDA块无法被抢占,因此,如果您完全占用GPU,则等待屏障rendesz-vous的线程将永远不会允许块终止。因此,它不会从SM中删除,并会阻止剩余的块运行。

因此,您将冻结永远无法摆脱此死锁状态的GPU。

- 编辑以回答佩德罗的评论 -

这些缺点已被其他作者注意到,例如: http://www.openclblog.com/2011/04/eureka.html

由OpenCL的作者在行动

- 编辑以回答佩德罗的第二句话 -

@Jared Hoberock在这篇SO帖子中得出了同样的结论: Inter-block barrier on CUDA