CommunityProgramación y desarrollogithub.com

caj401-amd/debugging-jax-oom

Diagnostica la causa de una OOM (fuera de memoria) en JAX/XLA a partir de una captura de perfil (.xplane.pb), indicando el módulo problemático, el tipo de memoria que agota y las correcciones estimadas.

¿Qué es debugging-jax-oom?

Este skill está diseñado para depurar problemas de falta de memoria (OOM) en programas JAX/XLA que ejecutan kernels jitted en GPU. A partir de un archivo de captura de perfil XProf (.xplane.pb), genera un informe detallado en 2-5 segundos usando solo la biblioteca estándar. El informe desglosa la asignación de búferes de cada módulo (parámetros, salidas, bloque temporal, pico del heap), los eventos del asignador BFC en tiempo de ejecución (capacidad, bytes usados, esperas AllocatorRetry) y las transferencias entre el host y el dispositivo. Con esta información, diagnostica causas comunes como que el paso no cabe en memoria (por activaciones, gradientes o espacio de trabajo), fugas entre pasos (crecimiento lineal), falta de donación de argumentos, o arreglos persistentes de otras partes del programa. Para cada diagnóstico, propone correcciones con ahorros estimados y costos, etiquetados como inferidos. El skill también incluye referencias medidas en hardware AMD MI355X y notas sobre límites (solo un host por archivo, solo memoria HBM, no soporta TPU/eager). Se ejecuta con un comando simple de Python y acepta opciones para filtrar por módulo o límite de top buffers.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/cj401-amd/jax-trace-analysis/tree/HEAD/skills/debugging-jax-oom

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Depuración de OOM en JAX a partir de una captura

Resumen

Un paso jitted de JAX obtiene toda su memoria temporal como un bloque planificado. Por lo tanto, la memoria del paso es el plan de XLA, y el .xplane.pb contiene tanto ese plan como los eventos de tiempo de ejecución del asignador. scripts/oom_report.py lee ambos en 2–5 segundos, usando solo la biblioteca estándar:

  • plan: asignación de búferes de cada módulo, desde /host:metadata. Muestra los parámetros (y cuánto se dona), las salidas no aliasadas, el bloque temporal y el pico del heap. Para los búferes activos en ese pico, proporciona tamaño, forma, rol y línea de Python. El rol proviene de la pila de nombres de JAX: jvp( (directo, conservado para la backward), transpose( (backward), las salidas de custom-call s8 son espacio de trabajo de la biblioteca.
  • tiempo de ejecución: los eventos del asignador BFC. Muestran la capacidad, los bytes en uso al inicio de cada ejecución, el pico, las esperas AllocatorRetry, las ejecuciones que nunca lanzaron un kernel y los eventos del host entre las dos últimas ejecuciones. También muestran lo que estaba activo cuando comenzó la última ejecución, agrupado por el evento del host que lo asignó: salidas de jit_step ejecución 3, BufferFromHostBuffer(s32[…]) (un device_put) o "asignado antes de que comenzara la captura".

El informe termina con líneas de diagnóstico, cada una etiquetada como medido o inferido. Ejecútelo primero:

python3 -P <directorio base de esta skill>/scripts/oom_report.py <directorio de captura o .xplane.pb> [--module 'jit_train_step(123)'] [--top 25] [--json out.json]
python3 -P <directorio base de esta skill>/scripts/oom_report.py --self-test

Por defecto, analiza el módulo cuya última ejecución nunca lanzó un kernel. Si no hay ninguno, toma el módulo más grande que se ejecutó. Use --module para elegir otro, por ejemplo un paso de evaluación.

De la línea de diagnóstico a la causa y la corrección

Línea de diagnósticoCausaCorrección a proponer; el ahorro proviene de los bytes del informe
el paso en sí no cabeel plan por sí solo excede el poolSiga la división de roles en el pico (abajo)
↳ principalmente forward, conservado para el backwardactivaciones: crecen con batch × seq; la atención ingenua añade B·H·S·S por capajax.checkpoint / remat en el bloque (ahorra la mayoría de los bytes forward-conservados, cuesta aproximadamente un forward adicional); micro-batch más pequeño con acumulación de gradientes; secuencia más corta (los búferes S² se reducen 4× cuando S se reduce a la mitad). Ofrezca atención fusionada solo como "verificar que los búferes B·H·S·S salgan del plan"
↳ principalmente backwardgradientes y sus temporalesFragmentar (FSDP) o acumular; verificar copias f32 de gradientes bf16
↳ espacio de trabajoespacio de trabajo de GEMM / conv de la bibliotecaGeneralmente pequeño; en ROCm son 64 MiB por GEMM hipBLASLt en gfx950
crece X MiB por ejecución, = 1.00x las salidas no aliasadasel programa mantiene vivas las salidas de cada paso (una fuga entre pasos): la lista de activos muestra salidas de … ejecución 1, 2, …Encuentre el titular en los eventos del host entre ejecuciones (ej. $<unknown> append = list.append). Luego suelte la referencia, reduzca dentro del paso (una norma, no el árbol) o haga jax.device_get. Un pool más grande solo retrasa la OOM
ningún parámetro se dona … puede ahorrar hasta Xlos parámetros/estado del optimizador viejos y nuevos están vivos juntosdonate_argnums en los argumentos de estado
otros arreglos activos ocupan el espacio; el más grande … provino de Xarreglos fuera del paso: conjunto de datos o copia de evaluación en la GPU, precarga, otras salidas de jitManténgalo en el host y transmítalo, libérelo o reduzca su dtype. "Asignado antes de que comenzara la captura" significa perfil más temprano para nombrarlo
AllocatorRetry … más larga N s, no lanzó ningunala OOM ocurrió dentro de la capturaSolo evidencia. La solicitud fallida suele ser el bloque temporal de ese módulo, o una salida
XLA ya rematerializó N instruccionesel remat propio de XLA ya se ejecutó contra el límiteEspere que la corrección provenga del programa, no de XLA

Proporcione a cada corrección su ahorro estimado y su costo, etiquetados como inferidos. Verifique la estimación frente a la capacidad. "Aumente XLA_PYTHON_CLIENT_MEM_FRACTION" corrige un plan que no cabe solo si la GPU tiene espacio. Una capacidad muy por debajo de la HBM sugiere que la fracción está establecida; la captura no registra variables de entorno.

Anatomía de la memoria del manual en términos de JAX

El Manual de Ultra-Escala ("Perfilando el uso de memoria") divide la memoria de entrenamiento en pesos, gradientes, estado del optimizador y activaciones. En el informe:

  • Pesos + estado del optimizador = los parámetros del paso. Adam en fp32 son 12 B por parámetro (p, m, v). Donado significa que no hay segunda copia.
  • Gradientes = el rol backward en el pico, más las salidas si el paso las devuelve.
  • Activaciones = forward, conservado para el backward. Los modelos con Scan / nn.scan las mantienen como búferes apilados [capas, …] en un bucle while.
  • "El paso 1 cabe, el paso N falla": en PyTorch esto es el estado del optimizador creado en el primer paso. En JAX el estado existe antes del paso 1, así que busque la línea de crecimiento. La primera llamada también compila y autoajusta, así que un pico antes de la primera ejecución es tiempo de compilación.

Reglas

  • Use solo la captura. No reconstruya el modelo ni vuelva a ejecutar la carga de trabajo para probar una corrección: estímela a partir de los bytes del plan y diga cómo confirmarla (jit(...).lower(...).compile().memory_analysis() del lado del usuario).
  • No escriba dentro del directorio de captura. Los convertidores de XProf (xspace_to_tool_names, memory_viewer, xprof CLI) escriben archivos de caché *.hlo_proto.pb junto al .xplane.pb. Si necesita vistas de XProf, copie el .xplane.pb a un directorio temporal primero.
  • Etiquete cada número como medido, leído o inferido.

Referencia medida (MI355X único, pools pequeños, 2026-11-06)

CapturaLo que muestra el informe
plan de atención demasiado grandenecesita 3.72 GiB > 2.79 GiB; pico del heap 81.6% forward-conservado; f32[8,8,1024,1024] ×5 en la línea de softmax; bloque temporal 3,495 MiB = el error "3.41GiB"; AllocatorRetry 10 s; 89 instrucciones de remat
gradientes se mantienen cada pasoen uso al inicio del paso 316 → 1,252 MiB, +104.0 MiB por paso = 1.00× las salidas no aliasadas; plan 788 MiB cabe; $<unknown> append entre pasos
sin donaciónnecesita 3.88 GiB > 2.79 GiB; 1,902 MiB parámetros + 1,902 MiB salidas, 0 donados; temp solo 172 MiB
MaxText llama2-7b, 8 GPUs, FSDP (cabe)temp 61.9 GiB; pico del heap 57% forward-conservado, las pilas de scan bf16[32,4,4096,11008] ×2 vía while.50

Limitaciones

  • Un host por archivo: las ejecuciones multi-host tienen un .xplane.pb por host, así que ejecute cada uno.
  • Solo HBM: solo se desglosa el espacio de memoria 0. La descarga al host se muestra como memory space 5.
  • Contigüidad: "cabe" compara bytes. BFC también necesita un fragmento contiguo, por lo que un ajuste cercano aún puede fallar por fragmentación.
  • Rol "other": búferes definidos por operaciones creadas por XLA sin pila de nombres de JAX, y sin alias que la tenga.
  • CUDA: no probado. Usa los mismos eventos BFC y XLA, pero los nombres no están verificados.
  • TPU / eager: las capturas de TPU solo dan totales del plan, sin pico del heap ni ejecuciones. Los programas eager (op por op) se muestran como muchos módulos pequeños, así que lea la sección de tiempo de ejecución allí.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Skills relacionados