Skip to content

Grafici a Fiamma

A cosa servono i grafici a fiamma?

I grafici a fiamma sono un modo per visualizzare il tempo CPU speso nelle funzioni. Possono aiutarti a individuare dove impieghi troppo tempo in operazioni sincrone.

Come creare un grafico a fiamma

Potresti aver sentito dire che creare un grafico a fiamma per Node.js è difficile, ma non è più vero. Non sono più necessarie le macchine virtuali Solaris per i grafici a fiamma!

I grafici a fiamma sono generati dall'output di perf, che non è uno strumento specifico di Node.js. Sebbene sia il modo più potente per visualizzare il tempo CPU speso, potrebbe avere problemi con il modo in cui il codice JavaScript è ottimizzato in Node.js 8 e versioni successive. Vedi la sezione problemi di output perf qui sotto.

Utilizzo di uno strumento pre-confezionato

Se desideri un singolo passaggio che produca un grafico a fiamma localmente, prova 0x

Per la diagnostica delle distribuzioni di produzione, leggi queste note: server di produzione 0x.

Creare un grafico a fiamma con gli strumenti perf di sistema

Lo scopo di questa guida è mostrare i passaggi coinvolti nella creazione di un grafico a fiamma e mantenerti il controllo di ogni passaggio.

Se vuoi capire meglio ogni passaggio, dai un'occhiata alle sezioni che seguono, dove approfondiremo l'argomento.

Ora mettiamoci al lavoro.

  1. Installa perf (di solito disponibile tramite il pacchetto linux-tools-common se non già installato)
  2. Prova ad eseguire perf - potrebbe lamentarsi di moduli del kernel mancanti, installali anche tu
  3. Esegui Node.js con perf abilitato (vedi problemi di output perf per suggerimenti specifici sulle versioni di Node.js)
bash
perf record -e cycles:u -g -- node --perf-basic-prof app.js
  1. Ignora gli avvisi a meno che non dicano che non puoi eseguire perf a causa di pacchetti mancanti; potresti ottenere alcuni avvisi sull'impossibilità di accedere ai campioni del modulo del kernel che comunque non ti interessano.
  2. Esegui perf script > perfs.out per generare il file di dati che visualizzerai tra un momento. È utile applicare una pulizia per un grafico più leggibile
  3. Installa stackvis se non ancora installato npm i -g stackvis
  4. Esegui stackvis perf < perfs.out > flamegraph.htm

Ora apri il file del grafico a fiamma nel tuo browser preferito e guardalo bruciare. È codificato a colori in modo da poterti concentrare prima sulle barre arancioni più sature. È probabile che rappresentino funzioni ad alta intensità di CPU.

Vale la pena menzionare: se fai clic su un elemento di un grafico a fiamma, uno zoom sull'ambiente verrà visualizzato sopra il grafico.

Utilizzo di perf per campionare un processo in esecuzione

Questo è ottimo per registrare dati del flame graph da un processo già in esecuzione che non si desidera interrompere. Immaginate un processo di produzione con un problema difficile da riprodurre.

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

A cosa serve sleep 3? Serve a mantenere perf in esecuzione - nonostante l'opzione -p punti a un PID diverso, il comando deve essere eseguito su un processo e terminare con esso. perf si esegue per tutta la durata del comando che gli si passa, indipendentemente dal fatto che si stia effettivamente profilando quel comando. sleep 3 garantisce che perf venga eseguito per 3 secondi.

Perché -F (frequenza di profilazione) è impostato su 99? È un valore predefinito ragionevole. È possibile regolarlo se lo si desidera. -F99 indica a perf di eseguire 99 campionamenti al secondo; per una maggiore precisione, aumentare il valore. Valori inferiori dovrebbero produrre un output minore con risultati meno precisi. La precisione necessaria dipende da quanto durano realmente le funzioni intensive della CPU. Se si cerca la causa di un rallentamento notevole, 99 frame al secondo dovrebbero essere più che sufficienti.

Dopo aver ottenuto la registrazione perf di 3 secondi, si procede con la generazione del flame graph con gli ultimi due passaggi di cui sopra.

Filtraggio delle funzioni interne di Node.js

Di solito, si desidera solo esaminare le prestazioni delle proprie chiamate, quindi il filtraggio delle funzioni interne di Node.js e V8 può rendere il grafico molto più facile da leggere. È possibile ripulire il file perf con:

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

Se si legge il flame graph e sembra strano, come se mancasse qualcosa nella funzione chiave che occupa la maggior parte del tempo, provare a generare il flame graph senza i filtri - forse si è verificato un caso raro di un problema con Node.js stesso.

Opzioni di profilazione di Node.js

--perf-basic-prof-only-functions e --perf-basic-prof sono le due opzioni utili per il debug del codice JavaScript. Altre opzioni vengono utilizzate per la profilazione di Node.js stesso, che esula dall'ambito di questa guida.

--perf-basic-prof-only-functions produce meno output, quindi è l'opzione con il minor sovraccarico.

Perché ne ho bisogno?

Beh, senza queste opzioni, otterrai comunque un flame graph, ma con la maggior parte delle barre etichettate v8::Function::Call.

Problemi con l'output di Perf

Cambiamenti nella pipeline V8 di Node.js 8.x

Node.js 8.x e versioni successive includono nuove ottimizzazioni nella pipeline di compilazione JavaScript del motore V8 che a volte rendono i nomi/riferimenti delle funzioni irraggiungibili per perf. (Si chiama Turbofan)

Il risultato è che potresti non ottenere i nomi delle tue funzioni corretti nel flame graph.

Noterai ByteCodeHandler: dove ti aspetteresti i nomi delle funzioni.

0x ha alcune mitigazioni integrate per questo.

Per i dettagli vedi:

Node.js 10+

Node.js 10.x risolve il problema con Turbofan usando il flag --interpreted-frames-native-stack.

Esegui node --interpreted-frames-native-stack --perf-basic-prof-only-functions per ottenere i nomi delle funzioni nel flame graph indipendentemente da quale pipeline V8 ha usato per compilare il tuo JavaScript.

Etichette danneggiate nel flame graph

Se vedi etichette simili a questa

bash
node`_ZN2v88internal11interpreter17BytecodeGenerator15VisitStatementsEPMS0_8Zone

significa che il perf Linux che stai usando non è stato compilato con il supporto demangle, vedi https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1396654 ad esempio

Esempi

Esercitati a catturare da solo i flame graph con un esercizio sui flame graph!