MCP HubMCP Hub
Retour aux compétences

analyze-kernel-bottleneck

pjt222
Mis à jour 2 days ago
3 vues
17
2
17
Voir sur GitHub
Autregeneral

À propos

Cette compétence analyse les noyaux GPU pour les classer comme limités par le calcul, par la mémoire ou par la latence, en utilisant l'analyse roofline et les métriques d'occupation. Elle fournit une matrice de décision pour recommander des stratégies d'optimisation spécifiques comme le tuilage ou le double buffering. Utilisez-la pour le profilage avancé de noyaux CUDA afin de guider les efforts d'optimisation des performances.

Installation rapide

Claude Code

Recommandé
Principal
npx skills add pjt222/agent-almanac -a claude-code
Commande PluginAlternatif
/plugin add https://github.com/pjt222/agent-almanac
Git CloneAlternatif
git clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/analyze-kernel-bottleneck

Copiez et collez cette commande dans Claude Code pour installer cette compétence

Documentation

Analyze Kernel Bottleneck

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.

Cuándo Usar

  • Antes de optimizar cualquier kernel CUDA -- establecer la línea base y clasificar el tipo de cuello de botella
  • Después de escribir una primera versión funcional de un kernel para identificar la ruta de optimización
  • Cuando un kernel rinde por debajo de las expectativas relativas al pico teórico
  • Al decidir entre cp.async, tiles más grandes o reestructuración algorítmica

Entradas

  • Requerido: Kernel compilado (.cubin o fuente .cu con comando de build)
  • Requerido: Arnés de benchmark que lanza el kernel con temporización por eventos CUDA
  • Requerido: Dimensiones del problema (p. ej., M, N, K para GEMM; seq_len, heads, head_dim para attention)
  • Opcional: Arquitectura de GPU objetivo (predeterminado: GA104 / sm_86 / RTX 3070 Ti)
  • Opcional: Porcentaje de utilización pico esperado para comparación
  • Opcional: Datos de profiling previos (informes de Nsight Compute)

Procedimiento

Paso 1: Medir Rendimiento de Referencia

Ejecutar el kernel con eventos CUDA (BenchTimer), registrar tiempo en milisegundos. Calcular métricas efectivas de rendimiento:

  1. Compilar el kernel si aún no está construido:
    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
    
  2. Ejecutar con tamaños de problema representativos, asegurando que las ejecuciones de calentamiento precedan a la medición:
    ./bench 4096 4096 4096
    
  3. Registrar el tiempo del kernel en ms desde eventos CUDA (no reloj de pared).
  4. Calcular GFLOPS efectivos y ancho de banda efectivo:
    • GEMM: effective_gflops = (2 * M * N * K) / (time_ms / 1000) / 1e9
    • Kernels limitados por ancho de banda: effective_bw = total_bytes / (time_ms / 1000) / 1e9
    • Flash Attention: effective_gflops = (4 * batch * heads * seq_len^2 * head_dim) / (time_ms / 1000) / 1e9

Esperado: 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).

Paso 2: Clasificar en el Roofline

Calcular la intensidad aritmética y compararla con el punto de equilibrio de la máquina para clasificar el kernel:

  1. Calcular intensidad aritmética: AI = FLOPs / bytes_loaded_from_global_memory. Contar solo bytes únicos cargados desde DRAM (no memoria compartida ni reuso de registros).
  2. Buscar el punto de equilibrio de la máquina: balance = peak_compute / peak_bandwidth.
  3. Clasificar: Si 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):

RecursoPicoUnidad
FP32 FFMA21.7TFLOPS
FP16 Tensor Core (HMMA)174TFLOPS
INT8 Tensor Core (IMMA)696TOPS
Ancho de banda DRAM608GB/s
Caché L24MB
SMs48

Puntos de Equilibrio Derivados:

PrecisiónPunto de Equilibrio (FLOP/byte)
FP32 FFMA21700 / 608 = 35.7
FP16 TC174000 / 608 = 286.2
INT8 TC696000 / 608 = 1144.7
  1. Calcular fracción alcanzada: 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).

Paso 3: Calcular la Ocupación

Determinar warps activos por SM a partir de la configuración de lanzamiento y el uso de recursos:

  1. Extraer uso de recursos:
    nvcc --cubin -arch=sm_86 -O2 --resource-usage -o kernel.sm_86.cubin kernel.cu 2>&1 | grep -E 'registers|smem'
    
  2. Desde la configuración de lanzamiento: warps_per_block = threads_per_block / 32.
  3. Calcular blocks/SM desde cada factor limitante:
    • Límite de registros: floor(65536 / (registers_per_thread * threads_per_block))
    • Límite de smem: floor(available_smem_per_SM / smem_per_block) -- ver Paso 6 para el acantilado
    • Límite de warps: floor(48 / warps_per_block) (GA104 max: 48 warps/SM)
    • Límite de bloques: 16 bloques/SM máximo en GA104
  4. Bloques/SM reales = min(register_limit, smem_limit, warp_limit, block_limit).
  5. Warps activos/SM = blocks_per_SM * warps_per_block.
  6. Umbral clave: 8 warps/SM es suficiente para ocultar latencia en GA104. Por debajo de 8 = problema estructural que causa comportamiento limitado por latencia.

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).

Paso 4: Calcular la Razón Cómputo/Carga Por Tile

Contar instrucciones de cómputo y bytes de carga por K-tile desde SASS (no código fuente):

  1. Desensamblar:
    cuobjdump -sass kernel.sm_86.cubin > kernel.sass
    
  2. Contar instrucciones de cómputo por tile (el bucle interno sobre un K-tile):
    • grep -c 'HMMA' kernel.sass -- ops FP16 Tensor Core
    • grep -c 'IMMA' kernel.sass -- ops INT8 Tensor Core
    • grep -c 'FFMA' kernel.sass -- multiplicación-suma fusionada FP32
  3. Contar cargas globales por tile:
    • grep -c 'LDG' kernel.sass -- cargas de memoria global
    • Multiplicar por bytes por carga (típicamente 16 bytes para LDG.128)
  4. Calcular razón: compute_ops / load_ops por tile.
  5. Clasificar usando el umbral de decisión cp.async (de gpu_reflections.md Insight 2):
    • Alto (>20:1): cp.async es netamente negativo; warp interleaving ya oculta la latencia DRAM. Enfocarse en cambios algorítmicos. Referencia: Flash Attention tiene 64 HMMA por tile = razón alta, cp.async medido -5%.
    • Medio (5-20:1): cp.async puede ayudar, hacer benchmark de ambas rutas.
    • Bajo (<5:1): cp.async fuertemente beneficioso; las cargas dominan y la copia asíncrona oculta la latencia. Referencia: IGEMM tiene 8 IMMA por tile = razón baja, cp.async medido +35%.

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.

Paso 5: Inspeccionar Instrucciones SASS

Examinar la mezcla completa de instrucciones SASS y los códigos de stall:

  1. Desensamblar (si no se hizo en el Paso 4):
    cuobjdump -sass kernel.sm_86.cubin > kernel.sass
    
  2. Contar tipos de instrucciones clave:
    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
    
  3. Verificar códigos de stall en instrucciones críticas:
    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)
    
  4. Identificar objetivos de optimización:
    • Stalls HMMA S08: mínimo de hardware en Ampere, no se puede reducir. Enfocarse en otra parte.
    • Stalls IMMA S04: el compilador es conservador. CuAssembler puede ajustar a S02 (15-20% de ganancia medida).
    • Stalls FFMA S04: si son independientes, reducibles a S01 vía CuAssembler.
    • BAR.SYNC excesivo: puede indicar sobre-sincronización entre etapas del pipeline.

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.

Paso 6: Verificar el Acantilado de Smem

Determinar si el uso de memoria compartida cruza el acantilado de ocupación específico de la arquitectura:

  1. Leer smem/block desde la salida de --resource-usage (Paso 3) o cuobjdump --res-usage kernel.sm_86.cubin.
  2. Comparar con el umbral del acantilado:
    • GA104 (sm_86): 100 KB max smem/SM. Acantilado en 50 KB/block.
    • Confirmado empíricamente: 48 KB/block -> 2 blocks/SM (bueno), 56 KB/block -> 1 block/SM (regresión 2x).
  3. Si está por encima del acantilado (smem > 50 KB/block):
    • Blocks/SM cae a 1, warps activos caen a warps_per_block (típicamente 4).
    • Se espera regresión de rendimiento 2x por stalls de DRAM expuestos.
  4. Verificar el impacto del double-buffering: El double-buffering duplica el uso de smem. Si la smem actual es 30 KB, double-buffered = 60 KB, lo cual cruza el acantilado. Evaluar si el beneficio asíncrono supera la pérdida de ocupación.
  5. Registrar smem/block, blocks/SM y si el acantilado se cruza.

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).

Paso 7: Construir la Matriz de Decisión

Sintetizar los hallazgos de los Pasos 2-6 en una estrategia de optimización:

CondiciónEstrategia
Limitado por memoria + razón cómputo/carga baja (<5:1) + smem bajo el acantiladoSoftware pipelining con cp.async (LDGSTS). Solapar cargas globales con cómputo.
Limitado por memoria + razón cómputo/carga alta (>20:1) + 8+ warpsWarp interleaving ya oculta latencia. Enfocarse en cambios algorítmicos: implicit GEMM, split-Q, im2col.
Limitado por cómputo + pesado en FFMAAjuste de códigos de stall con CuAssembler: S04 -> S01 en FFMAs independientes.
Limitado por cómputo + pesado en HMMAS08 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 IMMACuAssembler: 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 acantiladoReducir el tamaño del tile o reestructurar para tener smem/block bajo 50 KB (GA104).
  1. Clasificar las estrategias aplicables por ganancia esperada, usando los datos de razón cómputo/carga y ocupación.
  2. Estimar el rango de ganancia para cada estrategia basándose en cuán lejos está el kernel del techo relevante.
  3. Marcar conflictos: p. ej., cp.async duplica smem (puede cruzar el acantilado), tiles más grandes aumentan la presión de registros (puede reducir la ocupación).

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.

Paso 8: Documentar Hallazgos

Producir un reporte estructurado del cuello de botella:

  1. Línea base: tiempo del kernel, GFLOPS efectivos, ancho de banda efectivo, dimensiones del problema.
  2. Posición en el roofline: intensidad aritmética, clasificación, fracción alcanzada del pico.
  3. Ocupación: blocks/SM, warps activos/SM, factor limitante.
  4. Razón cómputo/carga: valor de la razón, clasificación (alto/medio/bajo), recomendación de cp.async.
  5. Resumen SASS: tabla de conteo de instrucciones, hallazgos de códigos de stall, objetivos de CuAssembler.
  6. Acantilado smem: smem/block, blocks/SM, estado del acantilado.
  7. Recomendación: estrategias de optimización clasificadas con estimaciones de ganancia.
## 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.

Validación

  • Línea base medida con eventos CUDA (no reloj de pared)
  • Clasificación en el roofline determinada (limitado por cómputo/memoria/latencia)
  • Ocupación calculada con factor limitante identificado
  • Razón cómputo/carga por tile calculada desde SASS
  • Mezcla de instrucciones SASS y códigos de stall documentados
  • Acantilado smem verificado contra el umbral de la arquitectura
  • Matriz de decisión aplicada con recomendación de estrategia
  • Hallazgos documentados en reporte estructurado

Errores Comunes

  • Multiplicación de re-lecturas: Conv2d directo lee cada peso 9x sin im2col, inflando el conteo de bytes 9x. Usar bytes únicos reales cargados desde DRAM, no instrucciones de carga totales, al calcular la intensidad aritmética.
  • Confundir el pico FP16 Tensor Core con el pico FP32: El pico FP16 TC es 174 TFLOPS, el pico FP32 FFMA es 21.7 TFLOPS -- una diferencia de 8x. Usar el pico equivocado hace la clasificación del roofline carezca de sentido.
  • Usar 64 KB como acantilado smem en lugar de 50 KB en GA104: GA104 (sm_86) tiene 100 KB max smem/SM. El acantilado está en 100/2 = 50 KB/block, no 64 KB. Esto es específico de la arquitectura; otras GPUs difieren.
  • Ignorar warp interleaving al evaluar cp.async: 8 warps con fases de cómputo largas (razón cómputo/carga alta) ya ocultan la latencia DRAM mediante el scheduling de warps. Añadir cp.async en este régimen añade presión de smem y sobrecarga de barrera sin beneficio (medido -5% en Flash Attention).
  • Contar instrucciones desde código fuente en lugar de SASS: El compilador puede fusionar operaciones, eliminar código muerto, desenrollar bucles de manera diferente o reordenar instrucciones. Siempre contar desde la salida de cuobjdump -sass.
  • No ejecutar iteraciones de calentamiento: El primer lanzamiento del kernel incluye sobrecarga de compilación JIT y efectos de caché frío. Siempre ejecutar 2-5 iteraciones de calentamiento antes de la ejecución medida.

Habilidades Relacionadas

  • 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 baja
  • simulate-cpu-architecture -- análisis de arquitectura complementario para cuellos de botella del lado CPU en flujos de trabajo host-device

Dépôt GitHub

pjt222/agent-almanac
Chemin: i18n/es/skills/analyze-kernel-bottleneck
0
agentsagentskillsai-assisted-developmentclaude-codeskillsteams

Compétences associées

llamaguard

Autre

LlamaGuard est le modèle de Meta, doté de 7 à 8 milliards de paramètres, conçu pour modérer les entrées et sorties des LLM selon six catégories de sécurité comme la violence et les discours haineux. Il offre une précision de 94 à 95 % et peut être déployé avec vLLM, Hugging Face ou Amazon SageMaker. Utilisez cette compétence pour intégrer facilement le filtrage de contenu et des garde-fous de sécurité dans vos applications d'IA.

Voir la compétence

cost-optimization

Autre

Cette compétence de Claude aide les développeurs à optimiser les coûts du cloud grâce au redimensionnement des ressources, aux stratégies d'étiquetage et à l'analyse des dépenses. Elle fournit un cadre pour réduire les dépenses cloud et mettre en œuvre une gouvernance des coûts sur AWS, Azure et GCP. Utilisez-la lorsque vous devez analyser les coûts d'infrastructure, redimensionner les ressources ou respecter des contraintes budgétaires.

Voir la compétence

quantizing-models-bitsandbytes

Autre

Cette compétence quantifie les LLMs en précision 8 bits ou 4 bits à l'aide de bitsandbytes, permettant une réduction de 50 à 75 % de la mémoire utilisée avec une perte de précision minime. Elle est idéale pour exécuter des modèles plus volumineux sur une mémoire GPU limitée ou pour accélérer l'inférence, prenant en charge des formats comme INT8, NF4 et FP4. La compétence s'intègre à HuggingFace Transformers et permet l'entraînement QLoRA ainsi que l'utilisation d'optimiseurs en 8 bits.

Voir la compétence

dispatching-parallel-agents

Autre

Cette compétence Claude déploie plusieurs agents pour enquêter et résoudre simultanément 3 problèmes indépendants ou plus. Elle est conçue pour des scénarios impliquant des défaillances non liées qui peuvent être résolues sans état partagé ni dépendances. La capacité fondamentale est la résolution de problèmes en parallèle, en assignant un agent par domaine problématique indépendant afin de maximiser l'efficacité.

Voir la compétence