GPUメモリ階層と実行モデル図
GPUカーネルが遅い原因の多くは、実行階層とメモリ階層の対応を取り違えた配置にあります。グリッド/ブロック/ワープと各メモリのスコープを整理し、最適化の勘所を掴めます。
- 1.実行階層はグリッド→ブロック→ワープ→スレッドの入れ子で、各層が固有のメモリスコープ(レジスタ=スレッド、共有メモリ=ブロック、グローバル=グリッド)に対応する。
- 2.メモリ階層はレジスタ→共有メモリ/L1→L2→グローバル(VRAM/HBM)の順に遅く広くなり、レイテンシは数百倍、帯域はオンチップが桁違いに大きい。
- 3.高速化は『データを必要なスコープまで引き上げ、ブロック内で再利用する』こと。共有メモリへのタイリングとコアレスアクセスが要になる。
2つの階層を重ねて見る
GPU プログラミングが難しいのは、実行の階層とメモリの階層という独立した2軸を、頭の中で重ね合わせる必要があるからです。スレッドの束ね方(実行)と、データの置き場所(メモリ)を別々に最適化することはできません。両者はスコープという概念で結びついています。
実行階層は次の入れ子構造です。
グリッド(Grid) ← カーネル起動1回ぶんの全スレッド
└─ ブロック(Block) ← 1つのSM上で協調する数百スレッドの集団
└─ ワープ(Warp, 32本) ← 1命令を全レーンに流す実行単位(SIMT)
└─ スレッド(Thread) ← 個々のレーン
グリッドは複数のブロックから成り、各ブロックは1つの SM(Streaming Multiprocessor) に割り当てられて、そこに常駐したまま実行されます。ブロック内のスレッドはハードウェアによって自動的に 32 本ずつのワープへ刻まれ、ワープ単位で命令が発行されます。SIMT 実行そのものはGPUアーキテクチャの原理で詳しく扱っているので、ここでは「どの層がどのメモリを見るか」に絞ります。
実行スコープとメモリのマップ
各メモリ空間は、上の実行階層のどの層から共有されるかで性質が決まります。これが GPU メモリ階層の本質です。
| メモリ空間 | 可視スコープ | 物理的な位置 | 相対レイテンシ | 管理 |
|---|---|---|---|---|
| レジスタ | 1スレッド | SM内レジスタファイル | 1(最速) | コンパイラ |
| 共有メモリ | 1ブロック | SM内オンチップSRAM | 数~十数 | プログラマ |
| L1キャッシュ | 1ブロック(SM内) | 共有メモリと同一SRAM | 数~十数 | ハード |
| L2キャッシュ | グリッド全体 | 全SMで共有 | 数十~百 | ハード |
| グローバル(VRAM/HBM) | グリッド全体+ホスト | オフチップDRAM | 数百 | プログラマ |
ポイントは、可視スコープと速度が連動していることです。狭いスコープ(スレッド/ブロック)に閉じたメモリほど物理的に演算器の近くにあり、速くて狭い。広いスコープ(グリッド全体)から見えるメモリほど遠くにあり、遅くて広い。最適化とは、データをできるだけ狭いスコープに引き上げて再利用することに他なりません。
多くの世代で、SM 内のオンチップ SRAM は共有メモリと L1 キャッシュに分割して使われます(容量配分が設定可能なこともある)。両者はほぼ同じ速さで、違いは管理主体です。共有メモリはプログラマが明示的に載せる「ソフトウェア制御キャッシュ」、L1 はハードウェアが自動で埋めます。意図したデータ再利用には共有メモリ、偶発的な局所性には L1、と使い分けます。
レイテンシと帯域の桁感
数字の桁を押さえると判断が速くなります。具体値は世代で変わりますが、比の構造は安定しています。
アクセスコスト(おおよその比)
レジスタ : ~1サイクル
共有メモリ/L1 : ~20-30サイクル
L2 : ~200サイクル
グローバル(HBM) : ~400-600サイクル(DRAM行ミス時はさらに)
帯域(おおよその比)
レジスタ/共有メモリ(オンチップ集計) >> HBM帯域
グローバルメモリ(VRAM。近年のハイエンドは HBM=広帯域メモリを積層で接続)は、TB/s 級の帯域を持つ一方でレイテンシは数百サイクルあります。GPU はこの遅延をキャッシュで縮めるより、待機ワープへの切替で別の仕事を詰めて隠す設計です(占有率による隠蔽)。とはいえ帯域は有限なので、グローバルへの往復回数そのものを減らすことが効きます。
HBM はピンを大量に並べて帯域を稼ぐ仕組みで、1アクセスあたりの遅延を短くするものではありません。「HBM だから速い」は帯域律速のカーネルにのみ当てはまり、レイテンシ律速(依存連鎖が長く並列度が低い)なカーネルでは効果が薄い点に注意します。
再利用パターン:グローバル→共有のタイリング
実行階層とメモリ階層を結ぶ典型例がタイリングです。行列積を例に、擬似コードで「どの層がどのメモリに触るか」を示します。
// ブロック内の全スレッドで協調してタイルを共有メモリへ載せる
__shared__ float tileA[16][16]; // スコープ=ブロック
__shared__ float tileB[16][16];
float acc = 0; // スコープ=スレッド(レジスタ)
for (各タイル k) {
// 1) グローバル(HBM)から共有メモリへ、コアレスして読み込む
tileA[ty][tx] = A_global[...]; // 隣接スレッドが隣接アドレス
tileB[ty][tx] = B_global[...];
__syncthreads(); // ブロック内の全ワープを同期
// 2) 以降は高速な共有メモリから何度も読む(再利用)
for (i in 0..15) acc += tileA[ty][i] * tileB[i][tx];
__syncthreads();
}
C_global[...] = acc; // 結果を1回だけグローバルへ書く
この構造では、各グローバル要素を1回だけ読んで共有メモリに置き、ブロック内で何度も再利用します。素朴な実装が同じ行・列を繰り返しグローバルから読むのに対し、タイリングはグローバルアクセスをタイル幅ぶんの一回に圧縮します。__syncthreads() がブロックという実行スコープと共有メモリというメモリスコープを噛み合わせる関節です。ブロックを超えた同期は(原則)できないため、ブロック粒度がタイルの自然な単位になります。
グローバルからの読み込み段(上の 1)では、ワープ内の隣接スレッドが連続整列アドレスを触るように添字を組むと、ハードウェアが少数の広いトランザクションへまとめます(メモリコアレッシング)。これはメモリが固定幅のキャッシュライン/バースト単位で動くためで、CPU の局所性と同じ原理をワープ全体で同時に満たす形です。
容量はスコープで奪い合う
メモリ階層のもう一つの制約は容量の有限性です。SM 上のレジスタファイルと共有メモリは、そこに常駐する全ワープで分け合います。
- 1スレッドが使うレジスタ数が多い → SM に同時に載るスレッド数(=ワープ数)が減る
- 1ブロックが使う共有メモリが多い → SM に同時に載るブロック数が減る
どちらも同時常駐ワープ数(占有率)を下げ、遅延を隠す余力を削ります。逆に共有メモリを使わなさすぎると再利用が起きずグローバル帯域で詰まります。この**「オンチップ資源を再利用に回す」対「常駐数を確保する」のトレードオフ**こそ、GPU チューニングの中心です。
頻出は次の対応関係です。「レジスタ=スレッドスコープで最速」「共有メモリ=ブロックスコープでプログラマ制御」「L2=グリッド全体でハード制御」「グローバル(VRAM/HBM)=最も遠く数百サイクル」。さらに「タイリングで再利用を稼ぐ」「コアレスで帯域を稼ぐ」「占有率で遅延を隠す」の3手が定番です。HBM は帯域を稼ぐ仕組みでレイテンシは縮まらない点も問われます。
まとめ
- 実行はグリッド→ブロック→ワープ→スレッドの入れ子、メモリはレジスタ→共有/L1→L2→グローバルの階層で、両者は可視スコープで対応する。
- スコープが狭いメモリほど演算器に近く速くて狭く、広いメモリほど遠く遅くて広い。最適化はデータを狭いスコープへ引き上げる作業に等しい。
- 共有メモリへのタイリングでグローバル往復を減らし、コアレスアクセスで帯域を使い切り、占有率で残る遅延を隠す。
- オンチップのレジスタ・共有メモリは全ワープで奪い合うため、再利用と常駐数のトレードオフを実測で詰める。
要するに GPU 性能は「どの層に何を置き、どの層から何回触るか」というスコープ設計の問題です。土台となるキャッシュメモリの原理と、束ね方を扱うSIMTとワープ実行を合わせて押さえると、最適化の判断が速くなります。
CPU/メモリ/ディスク Article
GPUメモリ階層と実行モデル図を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
GPU
比較で見る軸
難易度: advanced / カテゴリ: CPU/メモリ/ディスク / タグ数: 6
導入後に効く点
メモリ階層はレジスタ→共有メモリ/L1→L2→グローバル(VRAM/HBM)の順に遅く広くなり、レイテンシは数百倍、帯域はオンチップが桁違いに大きい。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- CPU/メモリ/ディスク
- タグ数
- 6
判断チェックリスト
- 自社の用途が「GPU / メモリ階層」に近いか確認する。
- 強みである「実行階層はグリッド→ブロック→ワープ→スレッドの入れ子で、各層が固有のメモリスコープ(レジスタ=スレッド、共有メモリ=ブロック、グローバル=グリッド)に対応する。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。