スレッドは、スケジュールが異なる 3 つのレベルにグループ化されます。Warps は SIMD を利用して計算密度を高めます。スレッド ブロックは、マルチスレッド化を利用してレイテンシの許容度を高めます。グリッドは、SM 間でロード バランシングを行うための独立した大まかな作業単位を提供します。
たて糸
ハードウェアはワープの 32 スレッドを一緒に実行します。1 つの命令を異なるデータで 32 回実行できます。スレッドが異なる制御フローを取る場合、すべてが同じ命令を実行するわけではないため、命令の実行中は 32 の実行リソースの一部がアイドル状態になります。これは、CUDA リファレンスでは制御発散と呼ばれます。
カーネルが多くの制御の相違を示す場合、このレベルで作業を再分配する価値があるかもしれません。これにより、ワープ内ですべての実行リソースをビジー状態に保つことで、作業のバランスが取れます。以下に示すように、スレッド間で作業を再割り当てできます。
// Identify which data should be processed
if (should_do_work(threadIdx.x)) {
int tmp_index = atomicAdd(&tmp_counter, 1);
tmp[tmp_index] = threadIdx.x;
}
__syncthreads();
// Assign that work to the first threads in the block
if (threadIdx.x < tmp_counter) {
int thread_index = tmp[threadIdx.x];
do_work(thread_index); // Thread threadIdx.x does work on behalf of thread tmp[threadIdx.x]
}
ブロック内ワープ
SM では、ハードウェア スケジュールが実行ユニットにワープします。一部の命令は完了するまでに時間がかかるため、スケジューラは複数のワープの実行をインターリーブして、実行ユニットをビジー状態に保ちます。一部のワープの実行準備ができていない場合、それらはスキップされ、パフォーマンスが低下することはありません。
通常、このレベルで負荷分散を行う必要はありません。スレッド ブロックごとに十分な数のワープが利用可能であることを確認するだけで、スケジューラーはいつでも実行可能なワープを見つけることができます。
グリッド内のブロック
ランタイム システムはブロックを SM にスケジュールします。SM では複数のブロックを同時に実行できます。
通常、このレベルで負荷分散を行う必要はありません。すべての SM を数回埋めるのに十分なスレッド ブロックが使用可能であることを確認してください。一部の SM がアイドル状態で、スレッド ブロックを実行する準備ができていない場合、カーネルの最後で負荷の不均衡を最小限に抑えるために、スレッド ブロックをオーバープロビジョニングすると便利です。