executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
analyze-kernel-bottleneck系统化识别 GPU 内核是计算受限、内存受限还是延迟受限,使用 roofline 分析、 占用率计算、按 tile 计算的计算/加载比以及 SASS 指令检查。产出用于优化 策略选择(cp.async、warp 交错、tiling、双缓冲或 CuAssembler 手工调优)的 决策矩阵。
Independent GitHub snapshot · Automated classification · Original documentation governs
通过测量基线性能、在 roofline 上分类、计算占用率与每 tile 的计算/加载比、检查 SASS 指令组合与停顿码、检查共享内存悬崖以及应用决策矩阵选择正确的优化策略,系统化识别 GPU 内核是计算受限、内存受限还是延迟受限。
.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预期结果: 基线数字:内核时间(毫秒)、有效 GFLOPS 和有效带宽。
失败处理: 检查内核启动是否无错误(CHECK_CU 宏)。验证预热运行先于测量。确保问题维度足够大以使 GPU 饱和(小问题可能在启动开销上形成瓶颈)。
计算算术强度并与机器平衡点比较以对内核分类:
AI = FLOPs / bytes_loaded_from_global_memory。仅计算从 DRAM 加载的唯一字节(不包括共享内存或寄存器复用)。balance = peak_compute / peak_bandwidth。AI < balance,内核为内存受限。若 AI > balance,内核为计算受限。GA104 (RTX 3070 Ti) 参考值:
| 资源 | 峰值 | 单位 |
|---|---|---|
| FP32 FFMA | 21.7 | TFLOPS |
| FP16 Tensor Core (HMMA) | 174 | TFLOPS |
| INT8 Tensor Core (IMMA) | 696 | TOPS |
| DRAM 带宽 | 608 | GB/s |
| L2 Cache | 4 | MB |
| SMs | 48 |
派生平衡点:
| 精度 | 平衡点 (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。若内存受限:将有效带宽与 608 GB/s 比较。若计算受限:将有效 GFLOPS 与相关峰值比较。预期结果: 分类为计算受限、内存受限或延迟受限(占用率低导致计算和内存均未饱和),并附数值依据。
失败处理: 重新检查字节计数。注意冗余重读(如直接 conv2d 不使用 im2col 时为 9 倍)。若计算和内存均未饱和,内核很可能是延迟受限(见第 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 或 warps)的占用率表。
失败处理: 检查动态共享内存的 cuFuncSetAttribute。验证 --resource-usage 报告与实际启动配置匹配。若寄存器数量异常高,尝试 --maxrregcount=N 限制寄存器(以寄存器溢出换取占用率)。
从 SASS(而非源代码)统计每个 K-tile 的计算指令和加载字节:
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 融合乘加grep -c 'LDG' kernel.sass —— 全局内存加载compute_ops / load_ops。预期结果: 计算/加载比及分类(高/中/低)和 cp.async 建议。
失败处理: 从 SASS 反汇编而非源代码统计 —— 编译器可能融合、消除或重排指令。确保只统计内层循环(K-tile 迭代)内的指令,而非整个内核。
检查完整的 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 输出或 cuobjdump --res-usage kernel.sm_86.cubin 中读取 smem/block。预期结果: Smem/block 值与 blocks/SM 数量,并显式说明是否跨越 50 KB 悬崖。
失败处理: 若高于悬崖且占用率是瓶颈,必须改变优化策略:减小 tile 大小以使 smem 低于 50 KB,或接受 1 block/SM 并通过更高的每 tile 计算/加载比补偿(更多寄存器复用、更长的 K-tiles)。
将第 2-6 步的发现综合为优化策略:
| 条件 | 策略 |
|---|---|
| 内存受限 + 低计算/加载比 (<5:1) + smem 低于悬崖 | 使用 cp.async (LDGSTS) 进行软件流水。重叠全局加载与计算。 |
| 内存受限 + 高计算/加载比 (>20:1) + 8+ warps | warp 交错已隐藏延迟。专注算法变更:implicit GEMM、split-Q、im2col。 |
| 计算受限 + FFMA 密集 | CuAssembler 停顿码收紧:独立 FFMA 上 S04 -> S01。 |
| 计算受限 + HMMA 密集 | S08 是硬件最小值,无法降低。增加 tile 复用(更大 M/N tiles,更长 K-loop)。 |
| 计算受限 + IMMA 密集 | CuAssembler:IMMA 指令上 S04 -> S02(编译器保守)。 |
| 延迟受限(占用率低,均未饱和) | 减少 smem 或寄存器以获得更多 blocks/SM。达到 8 以上 warps/SM。 |
| Smem 高于悬崖 | 减小 tile 大小或重构以使 smem/block 低于 50 KB(GA104)。 |
预期结果: 推荐优化的有序列表,附预测增益范围和潜在冲突。
失败处理: 若没有明确赢家,运行隔离每个策略的微基准(如单独测试 cp.async、单独测试减小的 tile 大小),在组合之前测量实际影响。
产出结构化的瓶颈报告:
## 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
预期结果: 完整的 markdown 报告,可被内核优化代理或人类开发者使用。
失败处理: 使用不同问题规模(如 1024、2048、4096、8192)重新运行以确认发现非规模特定。小问题可能看起来延迟受限,但实际规模化的瓶颈是内存带宽。
cuobjdump -sass 输出统计。pipeline-gpu-kernel —— 当分析识别出低计算/加载比的内存受限内核时,使用 cp.async 实现软件流水simulate-cpu-architecture —— 主机-设备工作流中 CPU 端瓶颈的互补架构分析