技能创建器
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 快照 · 自动分类 · 以原作者文档为准
Identifica sistemáticamente si un kernel de GPU está limitado por cómputo, memoria o latencia midiendo el rendimiento de referencia, clasificándolo en el roofline, calculando la ocupación y la razón cómputo/carga por tile, inspeccionando la mezcla de instrucciones SASS y los códigos de stall, verificando el acantilado de memoria compartida, y aplicando una matriz de decisión para seleccionar la estrategia de optimización correcta.
.cubin o fuente .cu con comando de build)Ejecutar el kernel con eventos CUDA (BenchTimer), registrar tiempo en milisegundos. Calcular métricas efectivas de rendimiento:
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) / 1e9Esperado: Números de referencia: tiempo del kernel en ms, GFLOPS efectivos y ancho de banda efectivo.
En caso de fallo: Verificar que el kernel se lanza sin error (macro CHECK_CU). Verificar que las ejecuciones de calentamiento preceden a la medición. Asegurar que las dimensiones del problema son lo suficientemente grandes para saturar la GPU (problemas pequeños pueden tener cuello de botella en la sobrecarga de lanzamiento).
Calcular la intensidad aritmética y compararla con el punto de equilibrio de la máquina para clasificar el kernel:
AI = FLOPs / bytes_loaded_from_global_memory. Contar solo bytes únicos cargados desde DRAM (no memoria compartida ni reuso de registros).balance = peak_compute / peak_bandwidth.AI < balance, el kernel está limitado por memoria. Si AI > balance, el kernel está limitado por cómputo.Valores de Referencia GA104 (RTX 3070 Ti):
| Recurso | Pico | Unidad |
|---|---|---|
| FP32 FFMA | 21.7 | TFLOPS |
| FP16 Tensor Core (HMMA) | 174 | TFLOPS |
| INT8 Tensor Core (IMMA) | 696 | TOPS |
| Ancho de banda DRAM | 608 | GB/s |
| Caché L2 | 4 | MB |
| SMs | 48 |
Puntos de Equilibrio Derivados:
| Precisión | Punto de Equilibrio (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. Si está limitado por memoria: comparar el ancho de banda efectivo con 608 GB/s. Si está limitado por cómputo: comparar GFLOPS efectivos con el pico relevante.Esperado: Clasificación como limitado por cómputo, memoria o latencia (baja ocupación que causa que ni el cómputo ni la memoria se saturen) con justificación numérica.
En caso de fallo: Recontar bytes. Atención a re-lecturas redundantes (p. ej., 9x en conv2d directo sin im2col). Si ni el cómputo ni la memoria están saturados, el kernel probablemente está limitado por latencia (ver Paso 3).
Determinar warps activos por SM a partir de la configuración de lanzamiento y el uso de recursos:
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) -- ver Paso 6 para el acantiladofloor(48 / warps_per_block) (GA104 max: 48 warps/SM)min(register_limit, smem_limit, warp_limit, block_limit).blocks_per_SM * warps_per_block.Esperado: Tabla de ocupación que muestra blocks/SM, warps activos/SM y el factor limitante (registros, smem o warps).
En caso de fallo: Verificar cuFuncSetAttribute para memoria compartida dinámica. Verificar que los reportes de --resource-usage coincidan con la configuración de lanzamiento real. Si el conteo de registros es inesperadamente alto, probar --maxrregcount=N para limitar registros (intercambiando spills de registros por ocupación).
Contar instrucciones de cómputo y bytes de carga por K-tile desde SASS (no código fuente):
cuobjdump -sass kernel.sm_86.cubin > kernel.sass
grep -c 'HMMA' kernel.sass -- ops FP16 Tensor Coregrep -c 'IMMA' kernel.sass -- ops INT8 Tensor Coregrep -c 'FFMA' kernel.sass -- multiplicación-suma fusionada FP32grep -c 'LDG' kernel.sass -- cargas de memoria globalcompute_ops / load_ops por tile.Esperado: Razón cómputo/carga con clasificación (alto/medio/bajo) y recomendación de cp.async.
En caso de fallo: Contar desde el desensamblado SASS, no desde el código fuente -- el compilador puede fusionar, eliminar o reordenar instrucciones. Asegurarse de contar instrucciones únicamente dentro del bucle interno (la iteración del K-tile), no del kernel completo.
Examinar la mezcla completa de instrucciones SASS y los códigos de stall:
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)
Esperado: Tabla de conteo de instrucciones y resumen de códigos de stall con objetivos de optimización identificados.
En caso de fallo: Asegurar que la arquitectura de cuobjdump coincide con el objetivo de compilación del kernel (ambos deben ser sm_86). Si la salida SASS está vacía, el cubin puede estar corrupto -- recompilar.
Determinar si el uso de memoria compartida cruza el acantilado de ocupación específico de la arquitectura:
--resource-usage (Paso 3) o cuobjdump --res-usage kernel.sm_86.cubin.Esperado: Valor smem/block con conteo blocks/SM y declaración explícita de si el acantilado de 50 KB se cruza.
En caso de fallo: Si está por encima del acantilado y la ocupación es el cuello de botella, la estrategia de optimización debe cambiar: reducir el tamaño del tile para tener smem por debajo de 50 KB, o aceptar 1 block/SM y compensar con una razón cómputo/carga más alta por tile (más reuso de registros, K-tiles más largos).
Sintetizar los hallazgos de los Pasos 2-6 en una estrategia de optimización:
| Condición | Estrategia |
|---|---|
| Limitado por memoria + razón cómputo/carga baja (<5:1) + smem bajo el acantilado | Software pipelining con cp.async (LDGSTS). Solapar cargas globales con cómputo. |
| Limitado por memoria + razón cómputo/carga alta (>20:1) + 8+ warps | Warp interleaving ya oculta latencia. Enfocarse en cambios algorítmicos: implicit GEMM, split-Q, im2col. |
| Limitado por cómputo + pesado en FFMA | Ajuste de códigos de stall con CuAssembler: S04 -> S01 en FFMAs independientes. |
| Limitado por cómputo + pesado en HMMA | S08 es mínimo de hardware, no se puede reducir. Aumentar reuso de tile (tiles M/N más grandes, K-loop más largo). |
| Limitado por cómputo + pesado en IMMA | CuAssembler: S04 -> S02 en instrucciones IMMA (el compilador es conservador). |
| Limitado por latencia (baja ocupación, ninguno saturado) | Reducir smem o registros para obtener más blocks/SM. Subir por encima de 8 warps/SM. |
| Smem por encima del acantilado | Reducir el tamaño del tile o reestructurar para tener smem/block bajo 50 KB (GA104). |
Esperado: Lista clasificada de optimizaciones recomendadas con rango de ganancia predicho y conflictos potenciales.
En caso de fallo: Si no emerge un ganador claro, ejecutar micro-benchmarks aislando cada estrategia (p. ej., probar cp.async solo, probar tamaño de tile reducido solo) para medir el impacto real antes de combinar.
Producir un reporte estructurado del cuello de botella:
## 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
Esperado: Reporte markdown completo consumible por un agente kernel-optimizer o desarrollador humano.
En caso de fallo: Re-ejecutar con diferentes tamaños de problema (p. ej., 1024, 2048, 4096, 8192) para confirmar que los hallazgos no son específicos del tamaño. Problemas pequeños pueden parecer limitados por latencia cuando el cuello de botella real a escala es el ancho de banda de memoria.
cuobjdump -sass.pipeline-gpu-kernel -- implementar software pipelining con cp.async cuando el análisis identifica un kernel limitado por memoria con razón cómputo/carga bajasimulate-cpu-architecture -- análisis de arquitectura complementario para cuellos de botella del lado CPU en flujos de trabajo host-device