
2026/06/17 23:35
AMD MI355X の Occupancy マス:ファースト・プリンシプルから始めるガイド
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
AMD MI300X および MI325X GPU の最適化は従来、「占有率(occupancy)」の最大化を必要としました。占有率は、プロセッサの実行レーンがアクティブなタスクでどれだけ埋まっているかを測定する指標です。しかし、新しい MI355X アーキテクチャにおいてこの戦略はピーク性能のために必要不再となっています。蓄積器が通常のデータと共有スペースを持つ統一されたレジスタファイル設計により、ボトルネックはメモリの記憶容量からベクターレジスタ(VGPRs)の利用可能数へシフトしました。重要な点は、これらの広範なウェーブ構造が、実行スレッド数が如何であるかに依存せず、高度なマトリクスコアを飽和させることができるためです。これにより、生の占有率は速度の予測不正確となります。したがって、開発者は注力を「算術強度(arithmetic intensity)」の増大—単位メモリあたりの計算量を増加化し—and 遅延を隠すために大きなタイルサイズを活用することへ転換させるべきです。このアーキテクチャシフトもまた、AMD が NVIDIA の32 スレッドワープとは別に、64 スレッド広範ウェーブを使用していることを示しています。適応するためには、エンジニアは占有率統計のみならず、
MfmaUtil(マトリクス乗算利用率)のような特定ハルウェアメトリクスを追跡するプロファイリングワークフローを更新する必要があります。これらの粒度の高い「フライト中性能(performance-in-flight)」指標に焦点を当てることで、企業は陳腐化した最適化ヒューリスティクスに惑わされることなく、現代的なマトリクスエンジンの真の可能性を発揮することができます。本文
GPU カーネルの最適化と占有率 (Occupancy):MI355X/CDNA4 を中心とした第一原理からの解析
GPU カーネルエンジニアの間で「占有率(Occupancy)」という言葉はよく使われますが、これは単なる不透明な指標ではありません。占有率は、固定されたハードウェア制限とカーネルのリソース使用量から完全に手計算可能です。この理解は、チューニングのアプローチそのものを変えます。
本ガイドでは、AMD Instinct MI355X(CDNA4, gfx950)を題材に、占有率の定義、計算方法、そして「低い占有率で高い性能を出す」逆説的な真実について解説します。
1. MI355X のアーキテクチャと資源
占有率を理解するには、**プライベート(SIMD 固有)と共有(CU 全体)**のリソースを区別することが不可欠です。MI355X は以下の構造を持っています。
チップ全体の構成
- 構成要素: 8 つのアクセルレクス・ダイ (XCD) で構成。総計 256 個の計算ユニット (CU)、クロック最大 2.4 GHz。
- メモリ階層:
- L2 スライス(各 XCD 独自)
- Infinity Cache (256 MB)
- HBM3E (288 GB, 8 TB/s)
- 重要: 占有率の計算ではCU 単位のみを考慮します。ダイレベルやメモリエループはデータ移動を統制しますが、リソース割り当定の決定的要因ではありません。
計算ユニット (CU) 内部のリソース
1 つの CU は 4 つの SIMD ヌニットと共有インフラストラクチャで構成され、以下のようなプライベートなレジスタファイルを所有しています。
| リソース | 規模・性質 | 役割 | 備考 |
|---|---|---|---|
| VGPRs (ベクトル通用レジスタ) | 1 レインあたり 512 エントリ(SIMD 固有) | 占有率を制限する主要な資源。オペランド、ループ変数、蓄積器。 | 通常の VGPR と蓄積用 AccVGPR は同じ 512 エントリのファイルを共有します。CDNA4 では物理的に分離せず、合計で最大 512 まで使用可能。 |
| SGPRs (スカラー通用レジスタ) | 〜800 エントリ(SIMD 固有) | スカラー計算用。稀に制限要因になる。 | バインディング制限にはならないことが多い。 |
| LDS (共有メモリ) | CU 全体で 160 KBを共有 | ワークグループ間通信、蓄積バッファ。 | CDNA4 で 64KB → 160KB に拡大。占有率計算では を制限として扱う。 |
スレッド、レーン、ウェーブフロント
- 実行単位: ハードウェアはスレッド単体ではなく、**ウェーブフロント(64 スレッド)**を同期して実行します(NVIDIA の Warp に相当)。
- レジデント (Resident): 1 シムド (SIMD) あたり最大 8 つのウェーブフロントがレジスタに駐在できます。
- 占有率の定義:
(per SIMD)。CU 全体では最大 32 ウェーブまで拡張されます。resident ウェーブ数 / 8- 注意: これは「作業をしているウェーブ」ではなく、「駐車されているウェーブ」の数です。
CUDA との対応表 (Rosetta Stone)
直感的に理解するために、AMD用語と NVIDIA 用語を対応付けます。
| AMD (CDNA4) | NVIDIA | 備考 |
|---|---|---|
| CU | SM | MI355X では 256 個 |
| SIMD (1 CU に 4 個) | SM サブパーティション | それぞれ 64 レーン |
| Wavefront (64 スレッド) | Warp (32 スレッド) | AMD は 2 倍広い |
| VGPR/AccVGPR | Registers | **共有するファイル(512/lane)**が重要 |
| LDS (160 KB/CU) | Shared Memory | CU 全体で共有 |
| Matrix Core / MFMA | Tensor Core | per SIMD のレジデントウェーブ数 |
2. 占有率の算術と計算方法
占有率は、
resident ウェーブ数 / 8 で定義されます。これは単なる比ではなく、最初に枯渇する 4 つの制限因子の最小値で決まります。
4 つの制限因子
各因は
floor( 固定予算 / カーネル消費量 ) の形式を持ちます。単位を合わせるため、すべて waves/SIMD に換算する必要があります。
- VGPR 制限:
- 式:
floor( 512 / total-VGPRs-per-lane )
= 通常のレジスタ数 + 蓄積器 (AccVGPR) 数。total-VGPRs- CDNA4 では両者が同じ 512 ファイルを共有するため、合計が重要です。
- 式:
- SGPR 制限:
- 式:
floor( ~800 / SGPRs-per-wave )
- 式:
- LDS 制限:
- 式:
floor( 160 KB / LDS-per-workgroup ) - ここが per-CU 資源であるため、ワークグループ数を計算し、**「各 SIMDS に分配されるウェーブ数」**に換算します。
- 例: ワークグループ(4 ウェーブ)× 6 ワークグループ = 24 ウェーブ → per-SIMD に展開されれば 6 ウェーブ/SIMD。
- 式:
- ワークグループ/バリアースロット:
- ハードウェア上のスロット制限(ハードキャップ)。
手計算の例:MXFP8 GEMM タイル比較
コンパイルされたコードオブジェクトから実際の使用量を抽出し、理論値を計算します。
設定条件:
- ワークグループサイズ:256 スレッド (4 ウェーブ)
- レーンあたり VGPR 総数:128 (通常レジスタのみ利用)
- レーンあたり SGPR: 50
- LDS 使用量:32 KB/ワークグループ
A. CDNA3 (MI300X, LDS=64KB)
計算: - VGPR limit: floor(512 / 128) = 4 waves/SIMD - SGPR limit: floor(800 / 50) = 16 waves/SIMD (制限にならない) - LDS limit: workgroups/CU = floor(64KB / 32KB) = 2 個 per-SIMD waves = 2 * (ウェーブ/グループ) = 2 * 4 = 8 -> ただし上限考慮等 ※実際には計算単位での制限になるため、例では VGPR の方が劣る場合が多いが、 ここは簡略化のため最小値を想定。実例では LDS がボトルネックになる設定あり。 最終的なボトルネック: LDS または VGPR による限界に達しやすい 占有率 = 25% (LDS-bound)
B. CDNA4 (MI355X, LDS=160KB)
計算: - VGPR limit: floor(512 / 128) = 4 waves/SIMD - SGPR limit: 16 waves/SIMD (同上) - LDS limit: workgroups/CU = floor(160KB / 32KB) = 5 個 per-SIMD waves = 5 * 4 = 20 waves -> 上限 8 でカランプされる場合ありが、 ここでは VGPR がボトルネックとなるケース。 結果: - min(VGPR 4, LDS 20, ...) = 4 waves/SIMD 占有率 = 4 / 8 = **50%** (Register-bound)
考察: MI355X の大きな LDS は天井値を押し上げ、ボトルネックを「共有メモリ」から「レジスタファイル(VGPR)」に移しました。
粒度(Granularity)による現実とのズレ
手計算は理想値ですが、ハードウェアは固定ブロック(VGPR:8, SGPR:16 など)で割り当てます。
- 例: レーンあたり 100 VGPR を報告。
- 手計算:
(62.5%)floor(512 / 100) = 5.12 -> 5 waves - 実態(粒度 8 の丸め上げ):100 は 104 に丸め →
(50%)floor(512 / 104) = 4 waves
- 手計算:
- 知見: バイナリ (
) から直接丸められた数字を読み取るのが最も正確です。llvm-objdump
測定方法
理論値と実際を確認するためのコマンド:
# コンパイル時のリソース使用量確認 hipcc -Rpass-analysis=kernel-resource-usage kernel.cpp # コードオブジェクトから直接 VGPR/SGPR/LDS の値を抽出 llvm-objdump --disassemble --mcpu=gfx950 kernel.hsaco | grep -iE "vgpr_count|agpr_count|sgpr_count"
- 重要: 蓄積器 (AccVGPR) も通常 VGPR と同じファイルから消費されるため、
は両者の合計です。vgpr_count - ROCm プロファイラ (
) で確認する項目:rocprofv3
またはOccupancyPercentMeanOccupancyPerCU
(行列コアの飽和度) ← これこそが真の指標MfmaUtil
3. 低い占有率でも高性能が出る理由
ここが最も重要です。「占有率を最大化するのは誤ったゴール」である可能性が高いです。
リトルの法則 (Little's Law) と並列性
遅延 (Latency) を隠すための必要な並列性は、以下の式で決まります:
in-flight parallelism = latency × throughput
- TLP (Thread-Level Parallelism): 多くのレジデントウェーブ。異なるウェーブから独立性を得る(占有率依存)。
- ILP (Instruction-Level Parallelism): 少ないウェーブだが、1 ウェーブ内で複数の独立な演算を行う。
CDNA4 では、行列コアは in-flight の独立 MFMA 数によって飽和します。単にウェーブを増やす(TLP)だけでなく、1 ウェーブ内の蓄積器タイル数を増やせば(ILP)、同じ占有率でもより高い性能が出ます。
グルオン (Gluon) / HIP ベンチの結果
- 低い占有率 (~6%) でさえも: ILP を活用すれば、ピーク性能の 97%~99% に達します。
- 逆説: 多くのウェーブを駐在させる(高占有率)よりも、広いロードや ILP でレイテンシを隠す方が効率的です。
160 KB LDS の正体
CDNA4 の大きな LDS は「高速レジスタの代わり」として使うのではなく、深いソフトウェアパイプライン用のプリフェッチバッファとして使用します。
- 蓄積器はレジスタ (VGPR) にある: 絶対に LDS には書かせないこと。
- LDS の役割: HBM からのデータ転送を計算待ちの間に行い、ロードと算術のギャップを埋める(ロードレイトの向上)。
レジスタ vs タイルサイズという非対称性
レジスタファイル (512 VGPR/lane) は固定です。ここにタイルサイズを広げることで、算術強度を増やし、より多くの MFMA を独立させられます。
- 占有率を下げる(レジスタをタイルに使う): 算術強度が上がり、行列コアが飽和しやすくなる。
- 占有率を上げる(小さいタイルでウェーブ増やす): 帯域制限に近づき、性能はむしろ落ちる。
最適化の指針:
- レジスタファイルをタイルに費やし、算術強度を買う。
- ILP を使って独立演算を増やし、レイテンシを隠す。
- 残りのレイテンシを LDS の深さ(プリフェッチ)でカバーする。
4. 結論とアクションプラン
占有率は診断ツールであり、目標ではありません。
- 低い占有率でも行列コアが飽和していれば、問題は「駐車されたウェーブの数」ではなく、「in-flight の独立演算不足」か「帯域制限」です。
- 最適化すべきは: レジスタresident タイルを最大化し、ILP を活用することです。
最適化ワークフローのステップ
- 測定:
で VGPR/SGPR/LDS の実質消費量を調べる。粒度丸めを考慮する。llvm-objdump - 計算: 4 つの制限因子 (VGPR, SGPR, LDS, WG) を換算し、最小値(天井値)を導出する。
- 評価:
でrocprofv3
と共に**OccupancyPercent
**をチェックする。MfmaUtil- MfmaUtil がピークに近い場合 → 占有率は気にせず、タイルサイズや ILP を最適化。
- 修正:
- レイテンシ制限:ILP の増加(独立タイル)、広いロードを使用。
- 帯域制限:レジスタ resident タイルを大きくし、計算強度を上げ、HBM 依存を減らす。
MI355X 占有率 チートシート (gfx950)
- VGPR Budget: 1 レインあたり 512 エントリ(通常+蓄積器共有)。
- SGPR Budget: 約 800 エントリ/レーン。
- LDS Budget: CU あたり 160 KB。
- ウェーブ上限: 4 waves/CU (per SIMD)。
重要な視点: 天井値を計算し、それを「どこまで下げられるか」を決めるのは、資源の限界ではなく、算術強度と帯域のバランスです。占有率そのものを最大化することを目指さないでください。