如何在不同分支之间同步Cuda?

时间:2019-03-19 23:58:36

标签: c++ cuda synchronization

我有希望使用Cuda C ++处理的数据,我一次处理四个像素,这四个像素都共享一个角。例如,对于字段中的所有位置,我将一起对四个+像素进行操作:

------------
--------++--
--------++--
------------
------------

因此,为了避免内存冲突,我决定将工作分四次运行,因为每次飞行都可以并行运行而不会与其他线程发生冲突,因为没有两个线程同时在相同的像素上工作:

// We break the threads up into four flights:
//
//     0: even X and even Y
//     1:  odd X and even Y
//     2: even X and  odd Y
//     3:  odd X and  odd Y
const int flight = ( threadIdx.x % 2 + ( ( threadIdx.y % 2 ) << 1 ) );

for (int idx = 0; idx < flight; ++idx) {
  __syncthreads();
 }

doWork( pixel[ threadIdx.x +     threadIdx.y * blockDim.x ],
        pixel[ threadIdx.x + 1 + threadIdx.y * blockDim.x ],
        pixel[ threadIdx.x + 1 + (threadIdx.y + 1) * blockDim.x ],
        pixel[ threadIdx.x +     (threadIdx.y + 1) * blockDim.x ]);

for (int idx = 3; idx > flight; --idx) {
  __syncthreads();
 }

目标是将工作分解为四个同步的飞行,如下所示:

什至X /甚至Y航班:

doWork(...);
__syncthreads("one");
__syncthreads("two");
__syncthreads("three");

奇数X /偶数Y航班:

__syncthreads("one");
doWork(...);
__syncthreads("two");
__syncthreads("three");

什至X /奇Y航班:

__syncthreads("one");
__syncthreads("two");
doWork(...);
__syncthreads("three");

奇数X /奇数Y航班:

__syncthreads("one");
__syncthreads("two");
__syncthreads("three");
doWork(...);

但是,我认为__syncthreads()不会做我想要的事情,因为我的应用程序似乎无法正常工作。

我能以某种方式标识我的同步点吗(如按名称),以便代码如上面的示例所示在成对的航班之间具有三个同步?或者在Cuda中有更好的方法可以做到这一点?


启动配置如下:

const int32_t pixelBlockSize = <argument to function>;
const int32_t pixelGridSize  = <argument to function>;

const size_t scratch   = (pixelBlockSize * pixelBlockSize + 2) * sizeof( float );
const dim3 dimBlock( pixelBlockSize, pixelBlockSize );
const dim3 dimGrid( pixelGridSize, pixelGridSize );

CallKernel<<< dimGrid, dimBlock, scratch >>> ( ... )

2 个答案:

答案 0 :(得分:1)

__syncthreads() 一个同步点。没有办法让几个单独的线程通过__syncthreads()进行同步。每个__syncthreads()是一个障碍,导致块中的每个所有线程等待,直到该块的所有个线程到达__syncthreads()的地步。分支中不能包含__syncthreads()。块必须的所有(未退出)线程都到达每个__syncthreads();否则,行为是不确定的。尽管在PTX级别,there would be ways进行了更细粒度的屏障同步,但我认为这些并不是真正的答案。如果我正确理解了您的问题,那么您所寻找的似乎只是

doWork(…)
__syncthreads();
doWork(…)
__syncthreads();
doWork(…)
__syncthreads();
doWork(…)

每个块的所有线程并行运行初始doWork(…)。您要等到所有线程都完成为止。然后,您运行下一个doWork(…),依此类推……

通常,您可能还想看看cooperative groups library,它在基本CUDA同步原语的基础上提供了一个不错的抽象层。

答案 1 :(得分:0)

根据迈克尔·肯泽尔的答案:

// We break the threads up into four flights:
//
//     0: even X and even Y
//     1:  odd X and even Y
//     2: even X and  odd Y
//     3:  odd X and  odd Y
const int flight = ( threadIdx.x % 2 + ( ( threadIdx.y % 2 ) << 1 ) );

auto Process = [&](const bool run) {
  if ( run )
    {
      doWork( pixel[ threadIdx.x +     threadIdx.y * blockDim.x ],
              pixel[ threadIdx.x + 1 + threadIdx.y * blockDim.x ],
              pixel[ threadIdx.x + 1 + (threadIdx.y + 1) * blockDim.x ],
              pixel[ threadIdx.x +     (threadIdx.y + 1) * blockDim.x ]);
    }
};

Process( 0 == flight ); __syncthreads();
Process( 1 == flight ); __syncthreads();
Process( 2 == flight ); __syncthreads();
Process( 3 == flight );