2015-01-08 7 views
6

Ich versuche, einige Nodejs Profilerstellung mit Linux perf_events wie von Brendan Gregg here beschrieben.Unbekannte Ereignisse in nodejs/v8 flamegraph mit perf_events

-Workflow folgt:

  1. Laufknoten> 0.11.13 mit --perf-basic-prof, die /tmp/perf-(PID).map-Datei erstellt, wo JavaScript Symbol-Mapping geschrieben werden.
  2. Capture-Stapel perf record -F 99 -p `pgrep -n node` -g -- sleep 30
  3. Falten Stapel mit stackcollapse-perf.pl Skript von this Repository
  4. generieren svg Flamme Graph mit flamegraph.pl Skript

Ich bekomme folgendes Ergebnis (die am Anfang wirklich schön aussehen) mit: enter image description here

Problem ist, dass es viele [unknown] Elemente gibt, die vermutlich meine nodejs Funktion sein sollten Ionenrufe. Ich nehme an, dass der gesamte Prozess an Punkt 3 fehlschlägt, wo perf-Daten mit Hilfe von Mappings gefaltet werden sollten, die von node/v8 generiert wurden, das mit --perf-basic-prof ausgeführt wird. /tmp/perf-PID.map Datei wird erstellt und während der Knotenausführung werden einige Mappings darauf geschrieben.

Wie löst man dieses Problem?

Ich benutze CentOS 6.5 x64, und das bereits mit Knoten 0.11.13, 0.11.14 (sowohl prebuild, als auch kompiliert) mit keinem Erfolg.

Antwort

13

Zuerst einmal, was "[unknown]" bedeutet, ist, dass der Sampler den Namen der Funktion nicht herausfinden konnte, weil es eine System- oder Bibliotheksfunktion ist. Wenn ja, das ist in Ordnung - es ist Ihnen egal, weil Sie für die Zeit in Ihre Code, nicht System-Code für die Dinge verantwortlich suchen suchen.

Eigentlich schlage ich vor, dies ist einer dieser XY questions. Selbst wenn Sie eine direkte Antwort auf das bekommen, was Sie gefragt haben, wird es wahrscheinlich von wenig Nutzen sein. Hier sind die Gründe, warum:

1. CPU Profilieren von geringem Nutzen in einem I/O-gebundene Programm

Die beiden Türme auf die in der Flamme Graph verließ ich tun/O, so dass sie wahrscheinlich viel mehr Mauerzeit als der große Haufen rechts. Wenn diese Flamme Graph von Wand-Zeitproben abgeleitet wurden, anstatt CPU-Zeit Proben, es ist wie die zweite Grafik unten aussehen könnte, die Ihnen sagt, wo die Zeit tatsächlich geht:

enter image description here

What a war der große, saftig aussehende Haufen auf der rechten Seite ist geschrumpft, also ist er nicht annähernd so bedeutend. Auf der anderen Seite sind die E/A-Türme sehr breit. Jeder dieser breiten orangefarbenen Streifen, wenn er in Ihrem Code enthalten ist, stellt eine Chance dar, viel Zeit zu sparen, wenn einige der I/O vermieden werden könnten.

2.Ob das Programm CPU- oder I/O-gebunden ist, können Speedup Möglichkeiten verstecken leicht aus Flamme Graphen

Angenommen, es gibt eine Funktion Foo ist, die wirklich etwas verschwenderisch tun, dass, wenn man darüber weiß, Sie beheben können. Angenommen, in der Flammenkurve ist es eine dunkelrote Farbe. Angenommen, es wird von zahlreichen Stellen im Code aufgerufen, so dass nicht alle an einer Stelle im Flammengraphen erfasst werden. Vielmehr scheint es in mehreren kleinen Orten hier von schwarzen Konturen gezeigt:

enter image description here

Hinweis, wenn alle diese Rechtecke gesammelt wurden, konnte man sehen, dass es für 11% der Zeit ausmacht, was bedeutet, es lohnt ein Blick auf . Wenn Sie die Zeit halbieren könnten, könnten Sie insgesamt 5,5% sparen. Wenn das, was es tut, tatsächlich vollständig vermieden werden könnte, könnten Sie insgesamt 11% sparen. Jedes dieser kleinen Rechtecke würde zu nichts schrumpfen und den Rest des Graphen damit nach rechts ziehen.

Jetzt zeige ich Ihnen the method I use. Ich nehme eine moderate Anzahl von zufälligen Stack-Samples und untersuche jeden für Routinen, die beschleunigt werden könnten. Das entspricht Proben in der Flamme Graphen zu nehmen, so wie:

enter image description here

Die schlanken vertikalen Linien repräsentieren zwanzig Zufallszeitstapel Proben. Wie Sie sehen können, sind drei von ihnen mit einem X markiert. Das sind diejenigen, die Foo durchlaufen. Das ist ungefähr die richtige Zahl, denn 11% mal 20 ist 2.2.

(Verwirrt? OK, hier ist eine kleine Wahrscheinlichkeit für Sie. Wenn Sie eine Münze 20 Mal umdrehen, und es hat eine 11% ige Chance Köpfe kommen, wie viele Köpfe würden Sie bekommen? Es ist technisch eine Binomialverteilung. Die am wahrscheinlichsten Zahl, die Sie erhalten würden, ist 2, die nächste am wahrscheinlichsten Zahlen 1 und 3 (Wenn Sie nur 1 bekommen Sie weiter, bis Sie 2 bekommen) Hier ist die Verteilung :)

enter image description here

(die durchschnittliche Anzahl der Proben, die Sie nehmen müssen, um Foo zweimal zu sehen ist 2/0,11 = 18,2 Proben.)

Wenn man sich diese 20 Stichproben ansieht, mag das etwas abschreckend erscheinen, da sie zwischen 20 und 50 Stufen tief sind. Sie können jedoch grundsätzlich ignorieren den ganzen Code, der nicht deins ist. Überprüfen Sie sie einfach für Ihren Code. Sie werden genau sehen, wie Sie Zeit verbringen, und Sie werden eine sehr grobe Messung davon haben, wie viel. Deep Stacks sind sowohl schlechte Nachrichten als auch gute Nachrichten - sie meinen, der Code kann viel Platz für die Beschleunigung haben, und sie zeigen Ihnen, was diese sind.

Alles, was Sie sehen, dass Sie beschleunigen könnten, , wenn Sie es auf mehr als einer Probe sehen, wird Ihnen eine gesunde Beschleunigung, garantiert. Der Grund, warum Sie es in mehr als einer Probe sehen müssen, ist, wenn Sie es nur an einer Probe sehen, wissen Sie nur, dass seine Zeit nicht Null ist. Wenn Sie es in mehr als einer Probe sehen, wissen Sie immer noch nicht, wie viel Zeit es braucht, aber Sie wissen, dass es nicht klein ist.Im Allgemeinen Here are the statistics.

+0

Kamil Z versuchen Profilierung off-cpu kann, wenn die Aufgabe ist I/O-gebunden, Gregg hat gerade die Skripte veröffentlicht - http://stackoverflow.com/a/28784580/196561 Auch "zufällige Stack-Samples" (zB mit gdb oder sogar mit "perf record -g", dann 'perf script' Rohstapelproben zu nehmen, dann mehrere zufällige Stapel zur manuellen Untersuchung zu nehmen) kann hier nicht helfen, weil 1) es schwierig sein kann, an kurzlebiges Programm anzuhängen (Tracing mit LTTng kann da helfen ...) 2) gdb (oder perf Record) wird immer noch keine Symbolnamen melden, immer noch das Y-Problem von Kamil. Interner node.js/v8 Debugger kann helfen, sie zu lösen. – osgx

+0

@osgx: Bei der manuellen Abtastung müssen Sie sich nicht darum kümmern, ob der E/A-Anschluss gebunden ist oder nicht, es funktioniert genauso. Sie müssen sich nicht darum kümmern, ob eine Routine kurzlebig ist - wenn sie oft genug aufgerufen wird, um einen signifikanten Bruchteil der Zeit zu nutzen, werden Stichproben sie treffen. (Wenn das gesamte Programm zu schnell beendet wird, um eine Probe zu erstellen, füge ich eine temporäre äußere Schleife hinzu.) Ich gehe davon aus, dass man sich in der Position eines Programmierers mit Quellcode und einem Debugger befindet. Für andere Situationen biete ich keinen Rat an. –

+0

@MikeDunlavey Der erste Punkt ist mir nicht klar. Tritt dieses Problem nicht nur auf, wenn der Thread, der profiliert wird, derselbe Thread ist, der die Beispiele generiert? Mit anderen Worten, der Grund dafür, dass der erste Graph keine Wartezeiten für den I/O zeigt, ist, dass er wartet und keine Samples aufgezeichnet haben kann. Wenn andererseits ein anderer Thread die Abtastwerte erzeugt, hätte er die gesamte Warte- und Verarbeitungszeit des Ziel-Threads erfasst, und der zweite Graph würde erzeugt werden. –

8

spricht es eine schlechte Idee ist, mit einem Fachexperten anderer Meinung zu sein, aber (mit dem größten Respekt) hier gehen wir!

drängt SO die Antwort folgendes zu tun: „! Achten Sie darauf, die Frage zu beantworten Details und Ihrer Forschung teilen“

Also die Frage war, zumindest meine Interpretation davon ist, warum gibt es [unbekannte] Frames in der Perf-Skript-Ausgabe (und wie verwandle ich diese [unbekannte] Frames in sinnvolle Namen)? Diese Frage könnte über "wie die Leistung meines Systems zu verbessern?" aber ich sehe es in diesem speziellen Fall nicht so. Hier besteht ein echtes Problem darüber, wie die Perf-Record-Daten nachbearbeitet wurden.

Die Antwort auf die Frage ist, dass, obwohl die Voraussetzung eingerichtet ist richtig: die richtige Knoten-Version, das richtige Argument vorhanden war, die Funktionsnamen zu generieren (--perf-basic-prof), die erzeugte perf Karte Datei muss im Besitz von Root sein für Perf-Skript, um die erwartete Ausgabe zu produzieren.

Das war's!

Heute schreibe ich ein paar neue Skripte Ich traf Apon, der mich auf diese Frage hinweist.

Hier ein paar weitere Referenzen:

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

[Nicht-Root-Dateien können manchmal gezwungen werden] http://www.spinics.net/lists/linux-perf-users/msg02588.html