Depuração de OOM em JAX a partir de um capture

Use quando um programa JAX / XLA esgotou a memória da GPU (RESOURCE_EXHAUSTED, "Out of memory while trying to allocate", OOM no primeiro passo ou após N passos) ou usa mais memória do que o esperado, e um capture jax.profiler / XProf (.xplane.pb) da execução está disponível.

O que é Depuração de OOM em JAX a partir de um capture?

Esta skill permite diagnosticar a causa de um erro de memória (OOM) em programas JAX/XLA analisando um capture de perfil (arquivo `.xplane.pb`) gerado pelo jax.profiler ou XProf. Em vez de exigir a recriação do modelo ou uma nova execução, o script `scripts/oom_report.py` extrai do capture tanto o plano de memória do XLA (buffers de cada módulo, parâmetros, temperatura, pico de heap) quanto os eventos do alocador BFC em tempo de execução (capacidade, bytes em uso, retry de alocação, execuções sem lançamento de kernel). O relatório gerado fornece linhas de diagnóstico – cada uma etiquetada como 'medido' ou 'inferido' – que apontam diretamente para a causa raiz e sugerem correções com estimativas de economia de memória. A skill suporta plataformas onde JAX roda com GPUs NVIDIA, AMD (testada em MI355X) e CPUs, mas não foi testada em CUDA nem em TPUs (que só fornecem totais do plano, sem pico de heap). O script usa apenas a biblioteca padrão do Python e processa o capture em 2 a 5 segundos.

Funciona com~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 Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que Depuração de OOM em JAX a partir de um capture faz?

Visão geral

Um passo jitted do JAX obtém toda a sua memória temporária como um único bloco temp planejado. Portanto, a memória do passo é o plano do XLA, e o arquivo .xplane.pb contém tanto esse plano quanto os eventos do alocador em tempo de execução. O script scripts/oom_report.py lê ambos em 2 a 5 segundos, usando apenas a biblioteca padrão:

  • plano: a atribuição de buffers de cada módulo, a partir de /host:metadata. Ele fornece os parâmetros (e quanto é doado), as saídas não aliadas, o bloco temp e o pico de heap. Para os buffers ativos nesse pico, ele informa tamanho, formato, função e linha Python. A função vem da pilha de nomes JAX: jvp( é forward (mantido para o backward), transpose( é backward, as saídas de custom-call s8 são workspace de biblioteca.
  • tempo de execução: os eventos do alocador BFC. Eles fornecem a capacidade, bytes em uso no início de cada execução, o pico, esperas AllocatorRetry, execuções que nunca lançaram um kernel e os eventos do host entre as duas últimas execuções. Eles também fornecem o que estava ativo quando a última execução começou, agrupado pelo evento do host que o alocou: outputs of jit_step execution 3, BufferFromHostBuffer(s32[…]) (um device_put), ou "alocado antes do início do capture".

O relatório termina com linhas de diagnóstico, cada uma etiquetada como medido ou inferido. Execute-o primeiro:

python3 -P <diretório base desta skill>/scripts/oom_report.py <diretório do capture ou .xplane.pb> [--module 'jit_train_step(123)'] [--top 25] [--json out.json]
python3 -P <diretório base desta skill>/scripts/oom_report.py --self-test

Por padrão, ele detalha o módulo cuja última execução nunca lançou um kernel. Se não houver nenhum, ele pega o maior módulo que executou. Use --module para escolher outro, por exemplo, um passo de avaliação.

Da linha de diagnóstico à causa e correção

Linha de diagnósticoCausaCorreção a propor; a economia vem dos bytes do relatório
o passo em si não cabeo plano sozinho excede o poolSiga a divisão de funções no pico (abaixo)
↳ principalmente forward, kept for the backward passativações: crescem com batch × seq; atenção ingênua adiciona B·H·S·S por camadajax.checkpoint / remat no bloco (economiza a maioria dos bytes forward-mantidos, custa cerca de um passo forward extra); um micro-batch menor com acúmulo de gradientes; uma sequência mais curta (buffers S² encolhem 4× quando S é reduzido à metade). Ofereça atenção fundida apenas como "verifique se os buffers B·H·S·S saem do plano"
↳ principalmente backwardgradientes e seus temporáriosFragmentar (FSDP) ou acumular; verifique cópias f32 de gradientes bf16
↳ workspaceworkspace de biblioteca GEMM / convGeralmente pequeno; no ROCm são 64 MiB por GEMM hipBLASLt no gfx950
cresce X MiB por execução, = 1,00x as saídas não aliadaso programa mantém as saídas de cada passo vivas (um vazamento entre passos): a lista de ativos mostra outputs of … execution 1, 2, …Encontre o detentor nos eventos do host entre execuções (ex.: $<unknown> append = list.append). Em seguida, remova a referência, reduza dentro do passo (uma norma, não a árvore) ou faça jax.device_get. Um pool maior só atrasa o OOM
nenhum parâmetro é doado … pode economizar até Xparâmetros antigos e novos / estado do otimizador estão vivos juntosdonate_argnums nos argumentos de estado
outros arrays ativos ocupam espaço; o maior … veio de Xarrays fora do passo: um dataset ou cópia de avaliação colocados na GPU, pré-busca, outras saídas jitMantenha no host e faça streaming, libere ou reduza seu dtype. "Alocado antes do início do capture" significa perfilhar mais cedo para nomeá-lo
AllocatorRetry … mais longo N s, não lançou nenhumo OOM ocorreu dentro do captureApenas evidência. A requisição com falha geralmente é o bloco temp desse módulo ou uma saída
XLA já rematerializou N instruçõeso próprio remat do XLA já foi executado contra o limiteEspere que a correção venha do programa, não do XLA

Dê a cada correção sua economia estimada e seu custo, etiquetado como inferido. Verifique a estimativa contra a capacidade. "Aumente XLA_PYTHON_CLIENT_MEM_FRACTION" corrige um plano que não cabe apenas se a GPU tiver espaço. Capacidade bem abaixo do HBM sugere que a fração está definida; o capture não registra variáveis de ambiente.

Anatomia da memória do playbook em termos JAX

O Ultra-Scale Playbook ("Profiling the memory usage") divide a memória de treinamento em pesos, gradientes, estado do otimizador e ativações. No relatório:

  • Pesos + estado do otimizador = os parâmetros do passo. Adam em fp32 são 12 B por parâmetro (p, m, v). Doado significa sem segunda cópia.
  • Gradientes = a função backward no pico, mais saídas se o passo as retornar.
  • Ativações = forward, kept for the backward pass. Modelos com Scan / nn.scan mantêm-nas como buffers empilhados [camadas, …] em um loop while.
  • "Passo 1 cabe, passo N falha": em PyTorch isso é estado do otimizador criado no primeiro passo. Em JAX o estado existe antes do passo 1, então procure pela linha de crescimento. A primeira chamada também compila e faz autotune, portanto um pico antes da primeira execução é tempo de compilação.

Regras

  • Use apenas o capture. Não reconstrua o modelo nem reexecute a carga de trabalho para testar uma correção: estime-a a partir dos bytes do plano e diga como confirmá-la (jit(...).lower(...).compile().memory_analysis() no lado do usuário).
  • Não escreva dentro do diretório do capture. Os conversores do XProf (xspace_to_tool_names, memory_viewer, CLI xprof) escrevem arquivos de cache *.hlo_proto.pb ao lado do .xplane.pb. Se precisar de visualizações do XProf, copie o .xplane.pb para um diretório temporário primeiro.
  • Etiquete cada número como medido, lido ou inferido.

Referência medida (um único MI355X, pools pequenos, 2026-11-06)

CaptureO que o relatório mostra
plano de atenção muito grandeprecisa de 3,72 GiB > 2,79 GiB; pico de heap 81,6% forward-mantido; f32[8,8,1024,1024] ×5 na linha softmax; bloco temp 3.495 MiB = o "3,41 GiB" do erro; AllocatorRetry 10 s; 89 instruções de remat
gradientes mantidos a cada passoem uso no início do passo 316 → 1.252 MiB, +104,0 MiB por passo = 1,00× as saídas não aliadas; plano 788 MiB cabe; $<unknown> append entre passos
sem doaçãoprecisa de 3,88 GiB > 2,79 GiB; 1.902 MiB de parâmetros + 1.902 MiB de saídas, 0 doados; temp apenas 172 MiB
MaxText llama2-7b, 8 GPUs, FSDP (cabe)temp 61,9 GiB; pico de heap 57% forward-mantido, os stacks do scan bf16[32,4,4096,11008] ×2 via while.50

Limitações

  • Um host por arquivo: execuções multi-host têm um .xplane.pb por host; portanto, execute em cada um.
  • Apenas HBM: apenas o espaço de memória 0 é detalhado. Offload de host aparece como memory space 5.
  • Contiguidade: "cabe" compara bytes. BFC também precisa de um bloco contíguo, portanto uma situação marginal ainda pode falhar por fragmentação.
  • Função "other": buffers definidos por operações criadas pelo XLA sem pilha de nomes JAX e sem aliasing que tenha uma.
  • CUDA: não testado. Usa os mesmos eventos BFC e XLA, mas os nomes não foram verificados.
  • TPU / eager: captures de TPU fornecem apenas totais do plano, sem pico de heap e sem execuções. Programas eager (op-por-op) aparecem como muitos módulos pequenos; portanto, leia a seção de tempo de execução nesses casos.

Individual skills in this repo

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

Habilidades Relacionadas