web-dev-qa-db-ja.com

cudaブロックの同期

私にはb個のブロックがあり、各ブロックにはt個のスレッドがあります。私は使えます

 __syncthreads()

特定のブロックにあるスレッドを同期します。例えば

__global__ void aFunction()
{
    for(i=0;i<10;i++)
    {
       //execute something
        __syncthreads();
    }
}

しかし、私の問題は、すべてのブロックのすべてのスレッドを同期させることです。これどうやってするの?

31
user570593

CUDA 9では、NVIDIAが協調グループの概念を導入し、そのグループに属するすべてのスレッドを同期できるようにしています。このようなグループは、グリッド内のすべてのスレッドにまたがることができます。このようにして、すべてのブロックのすべてのスレッドを同期することができます。

grid_group g = this_grid();
g.sync();

グリッドを同期するには、Pascalまたはより新しいアーキテクチャが必要です。

スレッドブロックより小さいワープ粒度までのグループの同期などの基本機能は、すべてのアーキテクチャでサポートされていますが、PascalおよびVolta GPUは、グリッド全体およびマルチGPUの新しい同期グループを有効にします。

ソース: https://devblogs.nvidia.com/parallelforall/cuda-9-features-revealed/


CUDA 9以前は、すべてのブロックのすべてのスレッドを同期するネイティブな方法はありませんでした。実際、CUDAのブロックの概念は、他のいくつかのブロックがすでに作業を終了した後にのみ起動できるというものです。たとえば、実行中のGPUが弱すぎてすべてを並行して処理できない場合などです。

生成するブロックが多すぎないことを確認したら、ブロック間ですべてのブロックを同期させてみてください。アトミック操作を使用してアクティブに待機する。ただし、これは遅く、GPUメモリコントローラーを使い果たし、「ハッキング」と見なされ、回避する必要があります。

したがって、Pascal(またはそれ以降)アーキテクチャを対象としない場合、私が提案できる最善の方法は、同期ポイントでカーネルを終了し、新しいカーネルを起動して、ジョブを続行することです。ほとんどの状況では、実際には前述のハックを使用するよりも高速に(または少なくとも-同等の速度で)実行されます。

42
CygnusX1