Skip to content

Gráficos Flame

Para que serve um gráfico flame?

Gráficos flame são uma forma de visualizar o tempo de CPU gasto em funções. Eles podem ajudá-lo a identificar onde você gasta muito tempo realizando operações síncronas.

Como criar um gráfico flame

Você pode ter ouvido dizer que criar um gráfico flame para Node.js é difícil, mas isso não é verdade (mais). Máquinas virtuais Solaris não são mais necessárias para gráficos flame!

Gráficos flame são gerados a partir da saída do perf, que não é uma ferramenta específica do Node. Embora seja a maneira mais poderosa de visualizar o tempo de CPU gasto, pode ter problemas com a forma como o código JavaScript é otimizado no Node.js 8 e superior. Consulte a seção problemas de saída do perf abaixo.

Use uma ferramenta pré-empacotada

Se você deseja uma única etapa que produza um gráfico flame localmente, tente 0x

Para diagnosticar implantações de produção, leia estas notas: servidores de produção 0x.

Criar um gráfico flame com ferramentas de sistema perf

O objetivo deste guia é mostrar as etapas envolvidas na criação de um gráfico flame e mantê-lo no controle de cada etapa.

Se você quiser entender melhor cada etapa, dê uma olhada nas seções a seguir, onde detalharemos mais.

Agora vamos começar a trabalhar.

  1. Instale perf (geralmente disponível por meio do pacote linux-tools-common se ainda não estiver instalado)
  2. Tente executar perf - ele pode reclamar sobre módulos do kernel ausentes, instale-os também
  3. Execute o Node com perf habilitado (consulte problemas de saída do perf para dicas específicas para versões do Node.js)
bash
perf record -e cycles:u -g -- node --perf-basic-prof app.js
  1. Ignore os avisos, a menos que eles estejam dizendo que você não pode executar o perf devido a pacotes ausentes; você pode receber alguns avisos sobre não conseguir acessar amostras de módulos do kernel, o que você não está buscando de qualquer maneira.
  2. Execute perf script > perfs.out para gerar o arquivo de dados que você visualizará em breve. É útil aplicar alguma limpeza para um gráfico mais legível
  3. Instale o stackvis se ainda não estiver instalado npm i -g stackvis
  4. Execute stackvis perf < perfs.out > flamegraph.htm

Agora abra o arquivo do gráfico flame em seu navegador favorito e assista-o queimar. Ele é codificado por cores para que você possa se concentrar primeiro nas barras laranja mais saturadas. Elas provavelmente representarão funções pesadas da CPU.

Vale mencionar - se você clicar em um elemento de um gráfico flame, um zoom em seus arredores será exibido acima do gráfico.

Usando perf para amostrar um processo em execução

Isso é ótimo para registrar dados de gráficos de chamadas de um processo já em execução que você não deseja interromper. Imagine um processo de produção com um problema difícil de reproduzir.

bash
perf record -F99 -p `pgrep -n node` -- sleep 3

Para que serve o sleep 3? Ele serve para manter o perf em execução — apesar da opção -p apontar para um PID diferente, o comando precisa ser executado em um processo e terminar com ele. O perf roda durante a vida útil do comando que você passa a ele, esteja ou não perfilando esse comando. sleep 3 garante que o perf rode por 3 segundos.

Por que -F (frequência de amostragem) está definido como 99? É um padrão razoável. Você pode ajustar se quiser. -F99 diz ao perf para tirar 99 amostras por segundo; para maior precisão, aumente o valor. Valores mais baixos devem produzir menos saída com resultados menos precisos. A precisão de que você precisa depende de quanto tempo suas funções intensivas em CPU realmente rodam. Se você está procurando a razão para uma desaceleração perceptível, 99 quadros por segundo devem ser mais do que suficientes.

Depois de obter esse registro de 3 segundos do perf, prossiga gerando o gráfico de chamadas com os dois últimos passos acima.

Filtrando funções internas do Node.js

Normalmente, você só quer observar o desempenho de suas chamadas, então filtrar as funções internas do Node.js e do V8 pode tornar o gráfico muito mais fácil de ler. Você pode limpar seu arquivo perf com:

bash
sed -i -r \
    -e '/(_libc_start|LazyCompile) |v8::internal::BuiltIn|Stub|LoadIC:\\[\\[' \
    -e '/^$/d' \
    perf.data > perf.out

Se você ler seu gráfico de chamadas e ele parecer estranho, como se algo estivesse faltando na função principal que consome mais tempo, tente gerar seu gráfico de chamadas sem os filtros — talvez você tenha um caso raro de um problema com o próprio Node.js.

Opções de perfil do Node.js

--perf-basic-prof-only-functions e --perf-basic-prof são as duas úteis para depurar seu código JavaScript. Outras opções são usadas para perfilar o próprio Node.js, o que está fora do escopo deste guia.

--perf-basic-prof-only-functions produz menos saída, então é a opção com menor sobrecarga.

Por que preciso delas?

Bem, sem essas opções, você ainda obterá um flame graph, mas com a maioria das barras rotuladas como v8::Function::Call.

Problemas na saída do Perf

Alterações no pipeline do V8 do Node.js 8.x

O Node.js 8.x e superior vem com novas otimizações para o pipeline de compilação JavaScript no mecanismo V8, o que torna os nomes/referências de funções inacessíveis para o perf às vezes. (É chamado de Turbofan)

O resultado é que você pode não obter os nomes das suas funções corretamente no flame graph.

Você notará ByteCodeHandler: onde esperaria nomes de funções.

0x possui algumas mitigações para isso integradas.

Para detalhes, consulte:

Node.js 10+

O Node.js 10.x resolve o problema com o Turbofan usando a flag --interpreted-frames-native-stack.

Execute node --interpreted-frames-native-stack --perf-basic-prof-only-functions para obter os nomes das funções no flame graph, independentemente de qual pipeline o V8 usou para compilar seu JavaScript.

Rótulos quebrados no flame graph

Se você estiver vendo rótulos como este

bash
node`_ZN2v88internal11interpreter17BytecodeGenerator15VisitStatementsEPMS0_8Zone

significa que o Linux perf que você está usando não foi compilado com suporte de desmantelamento, consulte https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1396654 por exemplo

Exemplos

Pratique a captura de flame graphs você mesmo com um exercício de flame graph!