CUDAグリッドの寸法、ブロックの寸法、スレッドの構成について(簡単な説明)[終了]


161

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


CUDAプログラミングガイドは、これを始めるのに適した場所です。こちらからCUDAの紹介もご覧になることをお勧めします
トム・

回答:


287

ハードウェア

たとえば、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;

11
各ブロックが768スレッドを実行できる場合、なぜ64のみを使用するのですか?上限の768を使用すると、ブロックが少なくなり、パフォーマンスが向上します。
Aliza

10
@Aliza:ブロックは論理的であり、物理的な処理ユニットごとに768スレッドの制限があります。スレッドに作業を分散するために、問題の仕様に従ってブロックを使用します。すべての問題に対して常に768スレッドのブロックを使用できるとは限りません。64x64の画像(4096ピクセル)を処理する必要があると想像してください。4096/768 = 5.333333ブロック?
cibercitizen1 2011年

1
ブロックは論理的ですが、各ブロックはコアに割り当てられています。コアよりも多くのブロックがある場合、ブロックはコアが解放されるまでキューに入れられます。あなたの例では、6つのブロックを使用して、追加のスレッドが何もしないようにすることができます(6番目のブロックのスレッドの2/3)。
Aliza

3
@ cibercitizen1-Alizaのポイントは良いことだと思います。可能であれば、ブロックごとにできるだけ多くのスレッドを使用したいと思います。必要なスレッドの数が少ない制約がある場合は、2番目の例でその可能性がある理由を説明することをお勧めします(ただし、最初に、より単純でより望ましいケースを説明します)。

6
@thouisはい、多分。ただし、各スレッドが必要とするメモリの量は、アプリケーションによって異なります。たとえば、私の最後のプログラムでは、各スレッドが最小二乗最適化関数を呼び出し、「大量の」メモリを必要とします。多くの場合、そのブロックは4x4スレッドを超えることはできません。それでも、得られたスピードアップは、順次バージョンと比較して劇的でした。
cibercitizen1

9

9800GT GPUを想定します。

  • 14個のマルチプロセッサ(SM)
  • 各SMには8つのスレッドプロセッサ(別名ストリームプロセッサ、SPまたはコア)があります。
  • ブロックあたり最大512スレッドを許可
  • warpsizeは32です(これは、14x8 = 112の各スレッドプロセッサが最大32のスレッドをスケジュールできることを意味します)。

https://www.tutorialspoint.com/cuda/cuda_threads.htm

ブロックは512を超えるアクティブスレッドを持つことができないため、__syncthreads限られた数のスレッドのみを同期できます。つまり、600スレッドで以下を実行するとします。

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

その場合、カーネルは2回実行する必要があり、実行順序は次のようになります。

  1. func1は最初の512スレッドに対して実行されます
  2. func2は最初の512スレッドに対して実行されます
  3. func1は残りのスレッドに対して実行されます
  4. func2は残りのスレッドに対して実行されます

注意:

主なポイントは__syncthreadsブロック全体の操作であり、すべてのスレッドを同期するわけではありません。


__syncthreads512スレッドを超えるブロックを作成して、ワープにスケジューリングを処理させることができるため、同期できるスレッドの正確な数についてはわかりません。私の理解では、より正確です:func1は少なくとも最初の512スレッドに対して実行さます。

この回答を編集する前に(2010年に戻って)、14x8x32スレッドがを使用して同期されて__syncthreadsいることを測定しました。

より正確な情報を得るために、誰かがこれをもう一度テストしていただければ幸いです。


func2()がfunc1()の結果に依存するとどうなりますか。これは間違っていると思います
Chris

@Chrisこれは7年前に書いたものですが、正しく思い出せば、これについてテストを行ったところ、gpuよりもスレッド数の多いカーネルはこのように動作するという結論に達しました。このケースをテストして別の結果に達した場合は、この投稿を削除する必要があります。
ビザン

申し訳ありませんが、これは間違っていると思います。また、GPUが同時に実行できるのは112スレッドのみです。
Steven Lu

@StevenLuやってみましたか?また、112の同時スレッドがGPUに意味をなさないと思います。112はストリームプロセッサの数です。私は今CUDAをほとんど思い出せません:)
Bizhan

1
@StevenLuスレッドの最大数はここで__syncthreadsは問題ではなく、ブロック全体の操作であり、実際にすべてのスレッドを同期しないという事実はCUDA学習者にとって厄介です。だから、私はあなたが私に与えた情報に基づいて私の答えを更新しました。ほんとうにありがとう。
ビザン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.