技能创建器
skill-creator
创建、改进和评估自定义技能,把专业流程转化为可重复使用的 AI 能力。
analyze-kernel-bottleneck【数据与研究】Systematically identify whether a GPU kernel is compute-bound, memory-bound, or latency-bound using roofline analysis, occupancy calculations, compute/load ratio per tile, and SASS instruction inspection. Produces a decision matrix for optimization strategy selection (cp.async, warp interleaving, tiling, double-buffering, or CuAssembler hand-tuning).
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
GPU カーネルが compute-bound、memory-bound、latency-bound のいずれであるかを体系的に特定する。ベースライン性能の測定、ルーフライン上での分類、占有率(occupancy)とタイルあたりの compute/load 比の計算、SASS 命令ミックスとストールコードの検査、共有メモリのクリフ確認、そして適切な最適化戦略を選択する決定マトリクスの適用を行う。
.cubin、またはビルドコマンド付きの .cu ソース)CUDA イベント(BenchTimer)でカーネルを実行し、ミリ秒単位の時間を記録する。実効スループット指標を計算する:
nvcc --cubin -arch=sm_86 -O2 -o kernel.sm_86.cubin kernel.cu
nvcc -arch=sm_86 -O2 -o bench bench.cu -lcuda -I../../phase2/common
./bench 4096 4096 4096
effective_gflops = (2 * M * N * K) / (time_ms / 1000) / 1e9effective_bw = total_bytes / (time_ms / 1000) / 1e9effective_gflops = (4 * batch * heads * seq_len^2 * head_dim) / (time_ms / 1000) / 1e9期待結果: ベースライン値: カーネル時間(ms)、実効 GFLOPS、実効帯域幅。
失敗時: カーネルがエラーなく起動することを確認する(CHECK_CU マクロ)。ウォームアップ実行が計測前にあることを検証する。問題次元が GPU を飽和させるのに十分大きいことを確認する(小さい問題は起動オーバーヘッドで律速されうる)。
算術強度を計算し、マシンのバランス点と比較してカーネルを分類する:
AI = FLOPs / bytes_loaded_from_global_memory。DRAM からロードされる一意なバイト数のみを数える(共有メモリやレジスタ再利用は数えない)。balance = peak_compute / peak_bandwidth。AI < balance ならカーネルは memory-bound。AI > balance ならカーネルは compute-bound。GA104 (RTX 3070 Ti) リファレンス値:
| Resource | Peak | Unit |
|---|---|---|
| FP32 FFMA | 21.7 | TFLOPS |
| FP16 Tensor Core (HMMA) | 174 | TFLOPS |
| INT8 Tensor Core (IMMA) | 696 | TOPS |
| DRAM Bandwidth | 608 | GB/s |
| L2 Cache | 4 | MB |
| SMs | 48 |
導出されるバランス点:
| Precision | Balance Point (FLOP/byte) |
|---|---|
| FP32 FFMA | 21700 / 608 = 35.7 |
| FP16 TC | 174000 / 608 = 286.2 |
| INT8 TC | 696000 / 608 = 1144.7 |
attained = effective_throughput / peak_throughput。memory-bound なら実効帯域幅を 608 GB/s と比較。compute-bound なら実効 GFLOPS を該当ピークと比較。期待結果: compute-bound、memory-bound、latency-bound(占有率の低さで計算も帯域も飽和していない)のいずれかへの分類と、その数値的根拠。
失敗時: バイト数の数え方を再確認する。冗長な再読み込みに注意する(例: im2col なしの直接 conv2d は 9 倍)。計算も帯域も飽和していなければ、おそらく latency-bound である(ステップ3を参照)。
起動構成とリソース使用量から、SM あたりのアクティブ warp 数を求める:
nvcc --cubin -arch=sm_86 -O2 --resource-usage -o kernel.sm_86.cubin kernel.cu 2>&1 | grep -E 'registers|smem'
warps_per_block = threads_per_block / 32。floor(65536 / (registers_per_thread * threads_per_block))floor(available_smem_per_SM / smem_per_block) — クリフはステップ6を参照floor(48 / warps_per_block)(GA104 最大: 48 warps/SM)min(register_limit, smem_limit, warp_limit, block_limit)。blocks_per_SM * warps_per_block。期待結果: blocks/SM、アクティブ warps/SM、制約要因(レジスタ、smem、warp)を示す占有率テーブル。
失敗時: 動的共有メモリには cuFuncSetAttribute を確認する。--resource-usage レポートが実際の起動構成と一致することを検証する。レジスタ数が予想外に多ければ、--maxrregcount=N でレジスタを制限してみる(レジスタスピルと占有率のトレードオフ)。
ソースコードではなく SASS から、K タイルあたりの compute 命令とロードバイト数を数える:
cuobjdump -sass kernel.sm_86.cubin > kernel.sass
grep -c 'HMMA' kernel.sass — FP16 Tensor Core 演算grep -c 'IMMA' kernel.sass — INT8 Tensor Core 演算grep -c 'FFMA' kernel.sass — FP32 fused multiply-addgrep -c 'LDG' kernel.sass — グローバルメモリロードcompute_ops / load_ops。期待結果: Compute/load 比とその分類(high/medium/low)、そして cp.async の推奨。
失敗時: ソースではなく SASS 逆アセンブルから数える — コンパイラが命令を融合・除去・並べ替えする可能性がある。内側ループ(K タイル反復)内の命令だけを数えていることを確認する、カーネル全体ではない。
完全な SASS 命令ミックスとストールコードを精査する:
cuobjdump -sass kernel.sm_86.cubin > kernel.sass
grep -c 'HMMA.16816' kernel.sass # FP16 Tensor Core
grep -c 'IMMA.16816' kernel.sass # INT8 Tensor Core
grep -c 'FFMA' kernel.sass # FP32 fused multiply-add
grep -c 'LDGSTS' kernel.sass # cp.async (global->shared)
grep -c 'LDG' kernel.sass # Global load
grep -c 'STS' kernel.sass # Shared store
grep -c 'LDS' kernel.sass # Shared load
grep -c 'BAR.SYNC' kernel.sass # Barrier synchronization
grep -c 'SHFL' kernel.sass # Warp shuffle (reductions)
grep -c 'MUFU' kernel.sass # Special function unit
grep 'HMMA' kernel.sass | head -5 # Expect S08 minimum (hardware constraint)
grep 'IMMA' kernel.sass | head -5 # Compiler emits S04, reducible to S02 via CuAssembler
grep 'FFMA' kernel.sass | head -5 # Check for S04 (reducible to S01 on independent FFMAs)
期待結果: 命令カウント表とストールコード概要、特定された最適化対象。
失敗時: cuobjdump のアーキテクチャがカーネルのコンパイル対象に一致することを保証する(両方とも sm_86 でなければならない)。SASS 出力が空なら cubin が壊れている可能性がある — 再コンパイルする。
共有メモリ使用量がアーキテクチャ固有の占有率クリフを跨ぐかを判定する:
--resource-usage 出力(ステップ3)または cuobjdump --res-usage kernel.sm_86.cubin から。期待結果: smem/block 値、blocks/SM、50 KB クリフ超過の明示的記述。
失敗時: クリフを跨いでおり占有率がボトルネックなら、最適化戦略を変えなければならない: タイルサイズを減らして smem を 50 KB 未満にする、または 1 block/SM を受け入れてタイルあたりの compute/load 比を上げて補償する(より多くのレジスタ再利用、より長い K タイル)。
ステップ2-6の発見を最適化戦略へと統合する:
| Condition | Strategy |
|---|---|
| Memory-bound + low compute/load ratio (<5:1) + smem under cliff | Software pipelining with cp.async (LDGSTS). Overlap global loads with compute. |
| Memory-bound + high compute/load ratio (>20:1) + 8+ warps | Warp interleaving already hides latency. Focus on algorithmic changes: implicit GEMM, split-Q, im2col. |
| Compute-bound + FFMA-heavy | CuAssembler stall code tightening: S04 -> S01 on independent FFMAs. |
| Compute-bound + HMMA-heavy | S08 is hardware minimum, cannot reduce. Increase tile reuse (larger M/N tiles, longer K-loop). |
| Compute-bound + IMMA-heavy | CuAssembler: S04 -> S02 on IMMA instructions (compiler is conservative). |
| Latency-bound (low occupancy, neither saturated) | Reduce smem or registers to get more blocks/SM. Get above 8 warps/SM. |
| Smem above cliff | Reduce tile size or restructure to get smem/block under 50 KB (GA104). |
期待結果: 推奨最適化のランク付きリスト、予測利得幅、潜在的コンフリクト。
失敗時: 明確な勝者が出てこない場合、各戦略を分離したマイクロベンチマーク(例: cp.async 単独テスト、タイル縮小単独テスト)を実行し、組み合わせ前に実際の影響を計測する。
構造化されたボトルネックレポートを作成する:
## Bottleneck Analysis Report: [kernel_name]
### Baseline
- Problem: [dimensions]
- Kernel time: [X] ms
- Effective GFLOPS: [Y] | Effective BW: [Z] GB/s
### Roofline Classification
- Arithmetic intensity: [AI] FLOP/byte
- Balance point: [BP] FLOP/byte ([precision])
- Classification: **[compute|memory|latency]-bound**
- Attained fraction: [X]% of peak
### Occupancy
| Resource | Per Block | Limit/SM | Blocks/SM |
|----------|-----------|----------|-----------|
| Registers | [N]/thread | 65536 | [B] |
| Shared mem | [X] KB | 100 KB (cliff: 50 KB) | [B] |
| Warps | [W] | 48 | [B] |
| **Limiting** | | | **[min(B)]** |
- Active warps/SM: [W] ([sufficient|insufficient] for latency hiding)
### Compute/Load Ratio
- Compute ops/tile: [N] [HMMA|IMMA|FFMA]
- Load bytes/tile: [N] bytes ([N] LDG x [N] bytes)
- Ratio: [X]:1 — **[high|medium|low]**
- cp.async recommendation: [beneficial|neutral|detrimental]
### SASS Instruction Mix
| Instruction | Count | Notes |
|-------------|-------|-------|
| HMMA.16816 | [N] | Stall: S08 (hardware min) |
| IMMA.16816 | [N] | Stall: S04 (reducible to S02) |
| FFMA | [N] | Stall: S04 (reducible to S01) |
| LDG | [N] | |
| LDGSTS | [N] | cp.async |
| BAR.SYNC | [N] | |
### Smem Cliff
- Smem/block: [X] KB — [under|over] 50 KB cliff
- Blocks/SM: [B] — [no occupancy loss|occupancy halved]
### Recommended Optimizations (ranked)
1. [Strategy] — estimated [X-Y]% gain
2. [Strategy] — estimated [X-Y]% gain
3. [Strategy] — estimated [X-Y]% gain
期待結果: kernel-optimizer エージェントまたは人間開発者が消費可能な、完全な markdown レポート。
失敗時: 異なる問題サイズ(例: 1024、2048、4096、8192)で再実行し、発見がサイズ固有でないことを確認する。小さい問題は latency-bound に見えても、スケール時の真のボトルネックがメモリ帯域であることがある。
cuobjdump -sass 出力から数える。pipeline-gpu-kernel — 解析が低い compute/load 比の memory-bound カーネルを特定したとき、cp.async によるソフトウェアパイプライニングを実装するsimulate-cpu-architecture — ホスト・デバイス間ワークフローにおける CPU 側ボトルネックの相補的アーキテクチャ解析