Eventi sconosciuti in nodejs / v8 flamegraph usando perf_events

Provo a fare un po ‘di analisi dei nodes usando Linux perf_events come descritto da Brendan Gregg qui .

Il stream di lavoro sta seguendo:

  1. eseguire il nodo> 0.11.13 con --perf-basic-prof , che crea il file /tmp/perf-(PID).map dove vengono scritti i mapping dei simboli JavaScript.
  2. Cattura stack usando perf record -F 99 -p `pgrep -n node` -g -- sleep 30
  3. Piega gli stack usando stackcollapse-perf.pl script stackcollapse-perf.pl da questo repository
  4. Generare il grafico della fiamma svg usando flamegraph.pl script flamegraph.pl

Ottengo risultati seguenti (che sembrano molto belli all’inizio): inserisci la descrizione dell'immagine qui

Il problema è che ci sono molti elementi [unknown] , che suppongo dovrebbero essere le mie chiamate alla funzione nodejs. Presumo che l’intero processo fallisca nel punto 3, dove i dati perf dovrebbero essere piegati usando le mappature generate da node / v8 eseguite con --perf-basic-prof . /tmp/perf-PID.map file /tmp/perf-PID.map viene creato e alcuni mapping vengono scritti durante l’esecuzione del nodo.

Come risolvere questo problema?

Sto usando CentOS 6.5 x64, e ho già provato questo con il nodo 0.11.13, 0.11.14 (sia pre-compilato che compilato) senza successo.

In primo luogo, cosa significa “[sconosciuto]” significa che il campionatore non è in grado di capire il nome della funzione, perché è una funzione di sistema o libreria. Se è così, va bene – non ti interessa, perché stai cercando cose responsabili per il tempo nel tuo codice, non nel codice di sistema.

In realtà, sto suggerendo che questa è una di quelle domande XY . Anche se ottieni una risposta diretta a ciò che hai chiesto, è probabile che sia di scarsa utilità. Ecco i motivi per cui:

1. Il profilo della CPU è di scarsa utilità in un programma associato all’I / O

Le due torri a sinistra nel tuo grafico di fiamme stanno facendo I / O, quindi probabilmente richiedono molto più tempo per la parete rispetto alla grande pila sulla destra. Se questo grafico di fiamma fosse derivato da campioni di tempo di parete, piuttosto che da campioni di tempo CPU, potrebbe apparire più simile al secondo grafico sottostante, che indica dove va effettivamente il tempo:

inserisci la descrizione dell'immagine qui

Quello che era un grosso mucchio dall’aspetto succoso sulla destra si è ridotto, quindi non è neanche lontanamente significativo. D’altra parte, le torri I / O sono molto larghe. Qualsiasi di quelle strisce arancioni larghe, se è nel codice, rappresenta una possibilità di risparmiare molto tempo, se alcuni degli I / O potrebbero essere evitati.

2. Indipendentemente dal fatto che il programma sia legato alla CPU o agli I / O, le opportunità di accelerazione possono facilmente nascondersi dai grafici delle fiamme

Supponiamo che ci sia qualche funzione che Foo sta facendo davvero qualcosa di dispendioso, che se lo sapessi, potresti risolvere il problema. Supponiamo nel grafico della fiamma, è un colore rosso scuro. Supponiamo che sia chiamato da numerosi punti nel codice, quindi non è tutto raccolto in un punto nel grafico della fiamma. Piuttosto appare in più piccoli luoghi mostrati qui da contorni neri:

inserisci la descrizione dell'immagine qui

Nota: se tutti questi rettangoli sono stati raccolti, puoi vedere che rappresenta l’11% del tempo, il che significa che vale la pena guardare. Se riuscissi a dimezzare il tempo, potresti risparmiare complessivamente il 5,5%. Se quello che sta facendo potrebbe essere evitato del tutto, potresti risparmiare l’11% complessivo. Ciascuno di quei piccoli rettangoli si ridurrebbe a nulla e trascinerebbe il resto del grafico alla sua destra, con esso.

Ora ti mostrerò il metodo che uso . Prendo un numero moderato di campioni di stack casuali ed esamino ciascuno per le routine che potrebbero essere velocizzate. Ciò corrisponde al prelievo di campioni nel grafico della fiamma in questo modo:

inserisci la descrizione dell'immagine qui

Le linee verticali sottili rappresentano venti campioni di pila a caso. Come puoi vedere, tre di questi sono contrassegnati da una X. Quelli sono quelli che passano attraverso Foo . Questo è il numero giusto, perché l’11% delle volte 20 è 2.2.

(Confuso? OK, qui c’è una piccola probabilità per te: se lanci una moneta 20 volte, e ha una probabilità dell’11% di arrivare a testa, quante teste potresti ottenere? Tecnicamente è una distribuzione binomiale. otterrebbe è 2, i prossimi numeri più probabili sono 1 e 3. (Se ne prendi solo 1 continui finché non ottieni 2.) Ecco la distribuzione 🙂

inserisci la descrizione dell'immagine qui

(Il numero medio di campioni che devi prendere per vedere Foo due volte è 2 / 0,11 = 18,2 campioni.)

Guardare quei 20 campioni potrebbe sembrare un po ‘scoraggiante, perché corrono tra i 20 ei 50 livelli di profondità. Tuttavia, puoi sostanzialmente ignorare tutto il codice che non è tuo . Esaminali per il tuo codice . Vedrai esattamente come passi il tempo e avrai una misura molto approssimativa di quanto. Gli stack profondi sono sia cattive notizie sia buone notizie: significano che il codice potrebbe avere un sacco di spazio per gli acceleratori e ti mostreranno cosa sono.

Qualunque cosa tu veda che potresti accelerare, se la vedi su più di un campione , ti garantirà una sana accelerazione, garantita. Il motivo per cui devi vederlo su più di un campione è, se lo vedi solo su un campione, sai solo che il suo tempo non è zero. Se la vedi su più di un campione, non sai ancora quanto tempo ci vuole, ma sai che non è piccolo. Ecco le statistiche.

In generale è una ctriggers idea non essere d’accordo con un esperto in materia ma (con il massimo rispetto) eccoci qui!

SO sollecita la risposta a fare quanto segue:

“Per favore assicurati di rispondere alla domanda, fornisci dettagli e condividi le tue ricerche!”

Quindi la domanda è stata, almeno la mia interpretazione di ciò è, perché ci sono frame [sconosciuti] nell’output di script perf (e come faccio a trasformare questi frame [sconosciuti] in nomi significativi? Questa domanda potrebbe riguardare “come migliorare le prestazioni del mio sistema?” ma non lo vedo in questo caso particolare. C’è un vero problema qui su come i dati perf record sono stati postati.

La risposta alla domanda è che sebbene la configurazione dei prerequisiti sia corretta: la versione corretta del nodo, era presente l’argomento corretto per generare i nomi delle funzioni (–perf-basic-prof), il file della mappa perf generato deve essere di proprietà di root per lo script perf per produrre l’output atteso.

Questo è tutto!

Scrivendo alcuni nuovi script oggi ho colpito apon questo indirizzandomi a questa domanda SO.

Ecco un paio di riferimenti aggiuntivi:

https://yunong.io/2015/11/23/generating-node-js-flame-graphs/

https://github.com/jrudolph/perf-map-agent/blob/d8bb58676d3d15eeaaf3ab3f201067e321c77560/bin/create-java-perf-map.sh#L22

[A volte i file non root possono essere forzati] http://www.spinics.net/lists/linux-perf-users/msg02588.html