while(t<tid)
ワープのすべてのスレッドが無期限にループし、行に到達しない分岐分岐のために、カーネルがあなたがしようとしていることを実行できるとは思いません++t
。
長い説明
スレッド、ブロック、ワープについて既に知っている場合は、重要なものについて「重要な部分」までスクロールします。
(私はまだ Kepler アーキテクチャの経験がありません。Fermi を使用していない場合、これらの数値の一部は異なる場合があります。)
次のセクションを理解するために、いくつかの用語について説明する必要があります。
- スレッド – 単一の実行スレッド。
- ブロック – 同じカーネルを実行する複数のスレッドのグループ。
- grid – ブロックのグループ。
次の用語は、物理 (ハードウェア アーキテクチャに依存する物理) スレッドに関連しています。
- コア – 単一の計算コア。1 つのコアは一度に 1 つの命令を正確に実行します。
- ワープ – ハードウェア上で並行して実行されるスレッドのグループ。ワープは、現世代の CUDA ハードウェア上の 32 のスレッドで構成されます。
カーネルは、1 つ以上のストリーミング マルチプロセッサ (SM) によって実行されます。Fermi ファミリ (GeForce 400 および GeForce 500 シリーズ) の典型的なミッドエンドからハイエンドの GeForce カードには、単一の GPU に 8 ~ 16 個の SM があります [ Fermi ホワイトペーパー]。各 SM は 32 個の CUDA コア (コア) で構成されます。スレッドは、ワープ スケジューラによって実行されるようにスケジュールされます。各 SM には、ロックステップ方式で動作する 2 つのワープ スケジューラ ユニットがあります。ワープ スケジューラがスケジュールできる最小単位はワープと呼ばれ、執筆時点でこれまでにリリースされたすべての CUDA ハードウェアの 32 スレッドで構成されます。各 SM で一度に実行できるワープは 1 つだけです。
CUDA のスレッドは CPU スレッドよりもはるかに軽量であり、コンテキスト スイッチは安価であり、ワープのすべてのスレッドが同じ命令を実行するか、ワープの他のスレッドが命令を実行する間待機する必要があります。これは、単一命令マルチ スレッド ( SIMT) であり、SSE、AVX、NEON、Altivec などの従来の CPU SIMD (Single Instruction Multiple Data) 命令に似ています。
解決するために 32 を超えるスレッドを必要とする問題を可能にするために、CUDA スレッドは、ソフトウェア開発者によって定義されたサイズのブロックおよびグリッドと呼ばれる論理グループに配置されます。ブロックはスレッドの 3 次元の集合であり、ブロック内の各スレッドには独自の 3 次元識別番号があり、開発者はカーネル コード内のスレッドを区別できます。単一ブロック内のスレッドは、共有メモリを介してデータを共有できます。これにより、グローバル メモリの負荷が軽減されます。共有メモリは、グローバル メモリよりもレイテンシがはるかに低くなりますが、限られたリソースです。ユーザーは、(ブロックごとに) 16 kB の共有メモリと 48 kB の L1 キャッシュ、または 48 kB の共有メモリと 16 kB の L1 キャッシュのいずれかを選択できます。
スレッドのいくつかのブロックは、グリッドにグループ化できます。グリッドは、ブロックの 3 次元配列です。最大ブロック サイズは利用可能なハードウェア リソースに関連付けられていますが、グリッドは (ほぼ) 任意のサイズにすることができます。グリッド内のブロックは、レイテンシが最も高いオン GPU メモリであるグローバル メモリを介してのみデータを共有できます。
Fermi GPU は、SM ごとに一度に 48 のワープ (1536 スレッド) をアクティブにすることができます。これは、スレッドがローカル メモリと共有メモリをほとんど使用せず、同時にすべてに適合するためです。レジスタがスレッドに割り当てられているため、スレッド間のコンテキストの切り替えは高速であり、したがって、スレッドの切り替え間でレジスタと共有メモリを保存および復元する必要はありません。その結果、ストールが発生するたびにワープ スケジューラが現在アクティブなワープを切り替えることにより、カーネル内のメモリ ストールが隠蔽されるため、ハードウェアを過剰に割り当てることが実際に望まれます。
重要な部分
スレッド ワープは、同じストリーミング マルチプロセッサ(SM) 上で実行されるスレッドのハードウェア グループです。ワープのスレッドは、スレッド間で共通のプログラム カウンターを共有することと比較できます。したがって、すべてのスレッドがプログラム コードの同じ行を実行する必要があります。コードに次のような分岐ステートメントがある場合if ... then ... else
ワープは最初のブロックに入るスレッドを最初に実行する必要があり、ワープの他のスレッドは待機し、次のブロックに入るスレッドは他のスレッドが待機している間に実行されます。この動作のため、GPU コードでは条件付きステートメントをできるだけ避ける必要があります。ワープのスレッドが異なる実行ラインに従う場合、それは分岐スレッドを持つと呼ばれます。条件付きブロックは CUDA カーネル内で最小限に抑える必要がありますが、同じワープのすべてのスレッドがif ... then ... else
ブロック内の単一の実行パスのみをたどるようにステートメントを並べ替えて、この制限を緩和できる場合があります。
while
andfor
ステートメントは分岐ステートメントなので、 に限定されませんif
。