GPUアーキテクチャの原理 ─ SIMTとワープ実行
なぜGPUは何千スレッドも同時に走らせて速いのか。SMとワープ、SIMT実行モデルを原理から押さえ、分岐や占有率の性能の勘所を掴めます。
- 1.GPUは多数のスレッドをワープ(32本など)単位でまとめ、1命令を全レーンに流すSIMT方式で実行する。
- 2.ワープ内で分岐が分かれると経路を直列実行するダイバージェンスが起き、連続アドレスへのアクセスをまとめるコアレッシングが帯域を決める。
- 3.占有率を上げて待機ワープを切り替えることで、メモリ遅延を別ワープの計算で隠蔽するのがGPUの基本戦略。
SIMTという実行モデル
GPU は数千本のスレッドを同時に走らせて高いスループットを出します。その心臓部が SM(Streaming Multiprocessor) で、GPU はこの演算ユニットを数十個並べた構造です。各 SM が独立にスレッドの集団を実行します。
鍵は実行の粒度です。SM は個々のスレッドをバラバラに動かすのではなく、ワープ(NVIDIA で 32 スレッド。AMD ではウェーブフロントと呼び 32 または 64)という固定本数の束にまとめ、1つの命令を束の全レーンへ一斉に流します。これが SIMT(Single Instruction, Multiple Threads) です。
ワープ(32スレッド)に対する1命令の発行
命令: FMA r0, r1, r2 ← 1つの命令
レーン: T0 T1 T2 ... T31 ← 32スレッドが各自のレジスタで同時実行
SIMD(1命令で固定長ベクトルを処理)と似ますが、SIMT では各レーンが独立したスレッドのように見え、自分のレジスタ・自分の分岐結果・自分のアドレスを持てます。プログラマは1スレッド分のスカラコードを書き、ハードウェアが裏でレーンに割り当てます。命令フェッチとデコードはワープ単位で1回なので、制御ロジックの面積と電力を 32 レーンで共有でき、演算器にトランジスタを集中させられます。
1命令あたりのフェッチ・デコード・スケジューリングを 32 レーンで割り勘にできるため、同じ電力でより多くの演算器を回せます。CPU がアウトオブオーダー実行で1スレッドのレイテンシを縮めるのに対し、GPU は大量のスレッドのスループットを稼ぐ設計で、最適化の方向が逆です。
分岐ダイバージェンス
SIMT の弱点は条件分岐です。ワープは命令を共有するので、if でレーンごとに行き先が分かれると 1命令で両方を実行できません。これを分岐ダイバージェンスと呼びます。
ハードウェアは実行マスク(どのレーンが有効か示すビット列)で対処します。まず条件が真のレーンだけを有効にして then 側を実行し、次に偽のレーンを有効にして else 側を実行します。両経路を直列に通すため、最悪では実行時間が単純に倍化します。
if (tid % 2 == 0) A(); else B();
ステップ1: マスク=偶数レーン → A() 実行(奇数は待機)
ステップ2: マスク=奇数レーン → B() 実行(偶数は待機)
合流後: マスク=全レーン
重要なのは、ダイバージェンスはワープ内で経路が割れたときだけコストになる点です。32 スレッドが全員 then に行くなら直列化は起きません。したがって、隣接スレッドが同じ分岐を取るようデータを並べる、あるいは分岐自体を算術(条件移動・述語実行)に置き換えるのが定石です。
分岐だけでなく、ワープ内でループ回数がバラつく場合も同様です。最も長いレーンが終わるまでワープ全体が拘束されるため、1本だけ極端に重いスレッドがあると残り 31 レーンが遊びます。負荷をレーン間で均すことが重要です。
メモリコアレッシング
GPU の演算器は飢えやすく、性能はしばしばメモリ帯域で決まります。グローバルメモリ(VRAM)へのアクセスは個別のスレッド単位ではなく、ワープ単位でまとめてメモリトランザクションに変換されます。
このとき、ワープ内の 32 スレッドが連続した整列アドレスを参照していれば、ハードウェアはそれを少数の広いトランザクション(例:128 バイト1回)にまとめられます。これがメモリコアレッシングです。逆にアクセスが飛び飛び(ストライドが大きい、ランダム)だと、1ワープが多数の小トランザクションに分解され、転送した大半のバイトを使い捨てる形になり、実効帯域が桁で落ちます。
| アクセスパターン | ワープのトランザクション | 実効帯域 |
|---|---|---|
| 連続・整列(コアレス) | 少数の広い転送にまとまる | ほぼピーク |
| 大ストライド | スレッド数に比例して分割 | 大きく低下 |
| ランダム | ばらけて多数の小転送 | 最悪 |
実務では「スレッド ID を最内次元(連続方向)に対応づける」のが基本です。たとえば行優先の2次元配列なら、array[row][col] の col を threadIdx.x に割り当て、隣接スレッドが隣接要素を読むようにします。同じデータを何度も使うなら、SM 内の共有メモリ(ソフトウェア管理の高速オンチップ領域)へ一度コアレスして読み込み、以降はそこから使うことで、グローバルメモリへの往復を減らします。
コアレッシングが効く理由は、本質的にはメモリが固定幅のキャッシュライン/バースト単位で動くからです。連続アクセスは1ラインを使い切り、飛び飛びアクセスは各ラインの一部しか使いません。CPU のキャッシュ局所性と同じ原理を、ワープ全体で同時に満たす必要があると考えると理解しやすいです。
占有率による遅延の隠蔽
グローバルメモリのアクセスは数百サイクルかかります。GPU はこの遅延をキャッシュで縮めるのではなく、別の仕事で埋めることで隠します。
SM は同時に多数のワープを抱え、ハードウェアのワープスケジューラが命令発行のたびに「いま実行可能なワープ」を選びます。あるワープがメモリ応答を待ってストールしても、スケジューラは即座に別の準備済みワープへ切り替えて演算器を回し続けます。CPU のスレッド切替と違い、各ワープのレジスタは常駐したままなので、切替コストはほぼゼロです。
この「待機ワープで遅延を埋める」能力を測る指標が占有率(occupancy) です。
占有率 = SMに常駐している実効ワープ数 / SMが扱える最大ワープ数
占有率を上げるには、SM 上に多くのワープを同時に載せる必要があります。ところが SM のレジスタファイルと共有メモリは有限の容量を全ワープで分け合うため、
- 1スレッドが使うレジスタ数が多い
- 1ブロックが使う共有メモリが多い
ほど、同時に載せられるワープ数が減り、占有率が下がります。隠せる遅延が減ると演算器の遊びが増えます。
占有率は遅延を隠す「余力」の指標であって、それ自体が性能ではありません。十分な数のメモリアクセスが飛んでいて遅延が隠せているなら、レジスタを多めに使って低占有率でも高速なことはよくあります(レジスタ増→スピルや再計算の削減)。占有率は上限を引き上げる手段の1つと捉え、実測(メモリ律速か演算律速か)に基づいて調整すべきです。
「GPU はワープ(32スレッド)単位で1命令を全レーンに発行する SIMT 方式」「分岐ダイバージェンスは経路を直列化してコストになる」「コアレッシングは連続整列アクセスをまとめて帯域を稼ぐ」「占有率は待機ワープへの切替でメモリ遅延を隠す余力を表す」の4点が頻出です。SIMT を SIMD と混同しない点に注意。
まとめ
- SM はスレッドをワープ(32本など)に束ね、1命令を全レーンへ流す SIMT で実行する。制御を共有し演算器に資源を集中できる。
- ワープ内で行き先が割れる分岐ダイバージェンスは両経路を直列化するため、隣接スレッドが同じ経路を取るよう設計する。
- メモリコアレッシングは連続整列アクセスを少数の広い転送にまとめ、実効帯域を決める。共有メモリで往復を減らせる。
- 占有率を確保して待機ワープへ切り替えることで、メモリ遅延を別ワープの計算で隠す。ただし高占有率が常に最速とは限らない。
GPU の並列性は、突き詰めれば「束ねて発行し、揃えてアクセスし、待ちを別の仕事で埋める」の3点に集約されます。土台にあるメモリ階層の原理はキャッシュメモリの原理も合わせてどうぞ。
CPU/メモリ/ディスク Article
GPUアーキテクチャの原理 ─ SIMTとワープ実行を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
GPU
比較で見る軸
難易度: advanced / カテゴリ: CPU/メモリ/ディスク / タグ数: 5
導入後に効く点
ワープ内で分岐が分かれると経路を直列実行するダイバージェンスが起き、連続アドレスへのアクセスをまとめるコアレッシングが帯域を決める。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- CPU/メモリ/ディスク
- タグ数
- 5
判断チェックリスト
- 自社の用途が「GPU / SIMT」に近いか確認する。
- 強みである「GPUは多数のスレッドをワープ(32本など)単位でまとめ、1命令を全レーンに流すSIMT方式で実行する。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。