web-dev-qa-db-ja.com

CUDAグリッドディメンション、ブロックディメンション、およびスレッド構成について(簡単な説明)

スレッドはどのように編成されてGPUで実行されますか?

154
cibercitizen1

ハードウェア

たとえば、GPUデバイスに4つのマルチプロセッシングユニットがあり、それぞれが768スレッドを実行できる場合、特定の瞬間に実際に並列で実行されるのは4 * 768スレッド以下です(さらに多くのスレッドを計画している場合、それらは待機します彼らの番)。

ソフトウェア

スレッドはブロックで構成されています。ブロックは、マルチプロセッシングユニットによって実行されます。ブロックのスレッドは、1Dimension(x)、2Dimensions(x、y)、または3Dimインデックス(x、y、z)を使用して識別(インデックス)できますが、いずれの場合もx y z <= 768この例では(x、y、zには他の制限が適用されます。ガイドとデバイスの機能を参照してください)。

明らかに、4 * 768以上のスレッドが必要な場合は、4ブロック以上必要です。ブロックには、1D、2D、または3Dのインデックスを付けることもできます。 GPUに入るのを待機しているブロックのキューがあります(この例では、GPUには4つのマルチプロセッサがあり、同時に実行されるのは4つのブロックのみであるため)。

シンプルなケース:512x512画像の処理

1つのスレッドで1つのピクセル(i、j)を処理するとします。

それぞれ64スレッドのブロックを使用できます。次に、512 * 512/64 = 4096ブロックが必要です(したがって、512x512スレッド= 4096 * 64になります)

BlockDim = 8 x 8(ブロックあたり64スレッド)を持つ2Dブロックのスレッドを整理する(イメージのインデックス付けを容易にする)のは一般的です。私は、それをthreadsPerBlockと呼ぶことを好みます。

dim3 threadsPerBlock(8, 8);  // 64 threads

2D gridDim = 64 x 64ブロック(4096ブロックが必要)。私はそれをnumBlocksと呼ぶことを好みます。

dim3 numBlocks(imageWidth/threadsPerBlock.x,  /* for instance 512/8 = 64*/
              imageHeight/threadsPerBlock.y); 

カーネルは次のように起動します。

myKernel <<<numBlocks,threadsPerBlock>>>( /* params for the kernel function */ );       

最後に、「4096ブロックのキュー」のようなものがあります。このブロックでは、GPUのマルチプロセッサの1つが割り当てられて64スレッドが実行されるのを待っています。

カーネルでは、スレッドによって処理されるピクセル(i、j)は次のように計算されます。

uint i = (blockIdx.x * blockDim.x) + threadIdx.x;
uint j = (blockIdx.y * blockDim.y) + threadIdx.y;
276
cibercitizen1

9800GT GPU:14個のマルチプロセッサがあり、それぞれが8個のスレッドプロセッサを持ち、warpsizeが32であると仮定すると、各スレッドプロセッサは最大32個のスレッドを処理します。 14 * 8 * 32 = 3584は、実際のcuncurrentスレッドの最大数です。

このカーネルを3584を超えるスレッド(たとえば4000スレッドで実行する場合、ブロックとグリッドの定義方法は重要ではありません。gpuはそれらを同じように扱います):

func1();
__syncthreads();
func2();
__syncthreads();

これらの2つの関数の実行順序は次のとおりです。

1.func1は最初の3584スレッドに対して実行されます

2. func2は最初の3584スレッドに対して実行されます

3. func1は残りのスレッドに対して実行されます

4. func2は残りのスレッドに対して実行されます

7
Bizhan