Über das Linux-Subsystem Performance Counters erlaubt der Kernel Performance-Analysen mit Bordmitteln. Perf ist leicht zu bedienen und genießt wegen der Innenperspektive gegenüber anderen Tools Vorteile.
Systeme schneller zu machen, das gehört zum Kerngeschäft der IT. Dessen Betreiber wollen in der Regel Ressourcen in Rechenzentren optimieren, Energie, Platz und Kosten sparen, den Start von Entertainmentsystemen im Wohnzimmer oder Auto beschleunigen oder, in der Wissenschaft, Algorithmen eleganter implementieren.
Bei komplexen Systemen mit vielen Komponenten ergeben sich Performance-Probleme meist aus unterschiedlichen Ursachen. Hardware-seitig tragen wahlweise die CPU, der Arbeitsspeicher, die Busauslastung, das Speichersystem (Block-I/O) oder das Netzwerk dazu bei. Software-seitig erzeugen das Betriebssystem, die Ausführungsumgebung der Programmiersprache, Bibliotheken oder die entsprechende Anwendung Engpässe. Die Sache erschwert, dass diese Komponenten sich häufig noch gegenseitig beeinflussen. Obwohl die Systeme für sich genommen problemlos arbeiten, führt die Interaktion zu Reibungen.
Den Fehler im Zusammenspiel all dieser Komponenten zu erkennen, verlangt vom Beobachter einerseits eine Vogelperspektive einzunehmen, andererseits aber auch über detailliertes Wissen zu allen beteiligten Bereichen zu verfügen. Nicht viele IT-Profis vereinen diese Fähigkeiten, was Performance-Optimierung zu einer spannenden, aber auch anspruchsvollen Tätigkeit macht.
Zum Glück existieren auch hier, wie für viele IT-Bereiche, eine Menge Werkzeuge, die sich auf solche Aufgaben spezialisieren. Typische Beispiele sind die bekannten Ps, Stat, Top, Htop, Oprofile [1], Systemtap [2] und so weiter.
Auftritt: Perf
Das im Artikel vorgestellte Werkzeug Perf [3] ist hingegen seit Version 2.6.31 direkt in den Kernel integriert, verwendet dessen Performance-Counters-Subsystem und beherrscht sowohl Profiling als auch Tracing.
Beim Profiling wertet Perf Daten der Hardware-Register aus, die bestimmte Hardware-Events zählen. So erzeugt es zu bestimmten Zeitpunkten Statistiken, um einen Eindruck vom System zu gewinnen. Die Genauigkeit hängt dabei von der Messhäufigkeit ab.
Beim Tracing hingegen protokolliert Perf über Tracepoints bestimmte Ereignisse. Zu diesen zählen Software-Events, etwa Kontextwechsel, aber auch Hardware-Events, zum Beispiel ausgeführte Instruktionen, Cache-Anfragen und so weiter. Im weitesten Sinne gehören auch die Systemmeldungen dazu.
Admins und Entwickler sollten dabei beachten, dass Tracing das System sehr stark beeinflussen kann. Beispielsweise läuft »dd« unter Strace deutlich langsamer als ohne. Generell müssen sie berücksichtigen, dass ihre Messungen die Messergebnisse beeinflussen können.
Installation
Das Programm »perf« ist Teil des Linux-Kernels und steckt im Verzeichnis »tools/perf«. Es lässt sich – wie die Ausgabe von »make tools/help« zeigt – mit »make -C perf_install« installieren. Der Anwender kann aber auch einfach in das Verzeichnis »/usr/src/«Linux-Version»/tools/perf« wechseln und dort »make« ausführen.
Weil bestimmte Perf-Funktionen vom Linux-ABI abhängen, liefern die Distributionen oft ein Paket pro Kernelversion aus. Unter Ubuntu 18.10 installiert das Paket »linux-tools-generic« stets die passende Perf-Version.
Hofft der Admin auf aussagekräftige Ausgaben, muss er im Vorfeld – wie beim Debugger – auch die Debug-Symbole für die zu untersuchenden Programme installieren. Diese stecken meist in separaten Archiven. Die automatisch generierten Pakete tragen unter Debian und Ubuntu 18.10 die Endung »-dbgsym«, die manuell erzeugten die Endung »-dbg«.
Workflow
Perf kennt mehr als zwei Dutzend Subkommandos. Eine Übersicht liefert die Eingabe des Befehls ohne Parameter oder [4]. Wer Perf verwendet, startet in der Regel mit »perf list«. Das zeigt die verfügbaren Ereignisse an (Listing 1), die der Anwender dann mit »perf stat« zählt. Der Befehl »record« schreibt Daten auf die Festplatte, »report« zeigt diese zum Durchsuchen an. Mit »script« lassen sich die Daten am Ende weiter auswerten.
Listing 1
Ausgabe von Hardware-Ereignissen (Auszug)
01 $ sudo perf list hardware 02 03 List of pre-defined events (to be used in -e): 04 05 branch-instructions OR branches [Hardware event] 06 branch-misses [Hardware event] 07 bus-cycles [Hardware event] 08 cache-misses [Hardware event] 09 [...]
Ereignisse
Wie Listing 1 auch zeigt, gibt der Admin »perf list« auf Wunsch ein optionales Argument mit auf den Weg. Das darf der Typ des Events sein, zum Beispiel »hw« oder »tracepoint«, oder ein regulärer Ausdruck wie in Listing 2.
Listing 2
Ereignissen auf Blockebene (Auszug)
01 $ sudo perf list 'block:*' 02 03 List of pre-defined events (to be used in -e): 04 05 block:block_bio_backmerge [Tracepoint event] 06 block:block_bio_bounce [Tracepoint event] 07 block:block_bio_complete [Tracepoint event] 08 block:block_bio_frontmerge [Tracepoint event] 09 block:block_bio_queue [Tracepoint event] 10 [...]
Jedes Zeilenende enthält den Typ des Ereignisses in eckigen Klammern. Zudem muss der Admin meistens in den Quelltext schauen, um die genaue Bedeutung des Ereignisses zu erkennen. Den meisten Perf-Kommandos gibt er dann über den Schalter »–events« oder »-e« die zu berücksichtigenden Ereignisse mit.
Top auf Steroiden
Ein paar Beispiele. Zunächst lässt sich mit »perf top« ein Performance-Counter-Profil in Echtzeit erzeugen (Abbildung 1). Die Übersicht gleicht der von Top, allerdings kann der Nutzer hier direkt in die einzelnen Events springen.

Abbildung 1: Der Konsolenbrowser von »perf top –sort=comm,dso« auf einem Intel-Kabylake-System mit Ubuntu 18.10 und Gnome 3.30.1.
»perf stat« zählt die Ereignisse des Gesamtsystems, bis der Anwender es mit [Strg]+[C] abbricht oder der angegebene Befehl sich beendet. Listing 3 zeigt das Subkommando in Aktion, das zwei Ereignisse zum Befehl »factor« auflistet.
Listing 3
Ausgabe von perf stat
01 $ sudo perf stat -e branches -e branch-misses factor 120808125801214124898080833 02 120808125801214124898080833: 13 29 911 7589 21089 77471 28369829 03 04 Performance counter stats for 'factor 120808125801214124898080833': 05 06 191.242 branches 07 10.332 branch-misses # 5,40% of all branches 08 09 0,000649438 seconds time elapsed 10 11 0,000699000 seconds user 12 0,000000000 seconds sys
Daten-Rekorder
Der Perf-Befehl »record« kann ein Performance-Counter-Profil für ein bestimmtes Kommando generieren. Will sich der Anwender einen Überblick über das Gesamtsystem verschaffen oder ist der zu untersuchende Prozess unbekannt, spannt er einfach den Befehl »sleep« vor den Karren:
sudo perf record -ag sleep 5
Diese Zeile erzeugt die Standarddatei »perf.data« im aktuellen Verzeichnis. Der Schalter »-a« sorgt dafür, dass Perf alle CPUs berücksichtigt, und »-g« generiert einen Call Graph. Über »-i« lässt sich »perf record« mit einer Datei füttern.
Das Kommando »perf report« wertet die gespeicherten Daten aus und nutzt dafür die Datei »perf.data«. Wie bei »perf top« präsentiert der Befehl eine Übersicht. Über einen Druck auf [Eingabe] erhält der Nutzer zudem die Details zu den jeweiligen Funktionen.
Übrigens sorgt der Schalter »–sort= comm,dso« (wie in Abbildung 1) für eine bessere Übersicht. Abbildung 2 zeigt die Ausgabe eines Intel-Kabylake-Systems mit Gnome 3.30.1 beim Abspielen eines Videos in Firefox 63.0.3. Das Bild verdeutlicht, dass beim Dekodieren die CPU und nicht die GPU zum Einsatz kommt.
Event-getrieben
Wenn nur bestimmte Ereignisse interessieren, hilft der Schalter »-e« weiter. Listing 4 zeigt die Ausgabe auf einem System mit laufendem Rsync.
Listing 4
Events verfolgen
01 $ sudo perf report --stdio 02 [...] 03 # Samples: 1K of event 'block:block_rq_issue' 04 # Event count (approx.): 1741 05 # 06 # Children Self Command Shared Object Symbol 07 # ........ .... ........... ................ .................... 08 # 09 93.74% 93.74% rsync kernel.kallsyms] [k] blk_peek_request 10 | 11 |--89.20%-- __lxstat64 12 | blk_peek_request 13 | 14 |--3.45%-- __GI___mkdir 15 | blk_peek_request 16 | 17 |--0.63%-- 0x646c6975622f3930 18 | __GI___link 19 | blk_peek_request 20 | 21 --0.46%-- 0x6d492f636f642f65 22 __GI___link 23 blk_peek_request 24 25 89.20% 0.00% rsync libc-2.27.so [.] __lxstat64 26 | 27 ---__lxstat64 28 blk_peek_request 29 [...]
Dank »–stdio« gibt Perf die Übersicht als reinen Text direkt auf der Konsole aus. Das aufgezeichnete Ereignis war dabei eine Anfrage an den Blocklayer des Kernels. Die Befehlszeile lautete:
sudo perf record -e block:block_rq_issue -ag
Doch auch hübsche Grafiken lassen sich mit Perf erzeugen.
On Fire
Flamegraphs gelten zurzeit als letzter Schrei. Dank ihnen ermitteln Admins und Entwickler die am häufigsten verwendeten Pfade einer Software. Auch die in die Browser integrierten Entwicklerwerkzeuge erzeugen mittlerweile solche Grafiken (Abbildung 3).
Die x-Achse zeigt die Auslastung der einzelnen Prozesse, die y-Achse die Auflösung jedes Funktionsaufrufs. Je breiter die Blöcke, desto mehr Ressourcen beanspruchen deren Prozesse. Das macht deutlich, welche Bereiche problematisch sind und sich zu optimieren lohnen.
Auch aus den Perf-Daten erzeugen Admins Flamegraphs. Die Skripte dafür müssen Anwender nicht selbst schreiben, sie warten teils auf Github [5]:
git clone https://github.com/brendangregg/FlameGraph
Die Befehle aus Listing 5 zeichnen die Performance-Daten auf und erzeugen mit »perf script« einen Flamegraph (Abbildung 4). Der zeigt: Obwohl der Browser ein 720p-Video abspielt, bleibt der Kernel meist im Ruhezustand. Im Browser lassen sich einzelne Abschnitte des Flamegraphen vergrößern und verkleinern.

Abbildung 4: Der per Skript erzeugte Flamegraph aus Perf-Daten: Ihn darf der Anwender auf Wunsch per Mausklick vergrößern und verkleinern.
Listing 5
Befehle zum Erzeugen eines Flamegraph
01 sudo perf record -F 99 -a -g -- sleep 10 02 sudo perf script > out.perf 03 ./stackcollapse-perf.pl out.perf > out.folded 04 ./flamegraph.pl out.folded > out.svg 05 firefox out.svg
Dynamisches Tracing
Über das Perf-Subkommando »probe« und den Schalter »–add« legen Admins nicht zuletzt so genannte sdynamische Tracepoints fest. Listing 6 zeigt das Vorgehen stellvertretend für die Linux-Funktion »tcp_sendmsg()«.
Listing 6
tcp_sendmsg als dynamischer Tracepoint
01 $ sudo perf probe --add='tcp_sendmsg' 02 Added new event: 03 probe:tcp_sendmsg (on tcp_sendmsg) 04 [...] 05 $ sudo perf record -e probe:tcp_sendmsg -aR sleep 5 06 [ perf record: Woken up 1 times to write data ] 07 $ sudo perf report --stdio 08 [...]
Dynamisches Duo
Das Linux-Subsystem Perf und die Werkzeugsammlung »perf« bieten viele Möglichkeiten, ein System zu analysieren. Ohne große Umstände erheben Admins Daten und werten diese mit den vorhandenen Werkzeugen und Skripten aus, um einen Überblick zu erhalten.
Die richtige Interpretation der Daten erfordert etwas Wissen sowohl über das System als auch über die zahlreichen Möglichkeiten des Framework. Das ist jedoch bei anderen Werkzeugen, etwa Debuggern, nicht anders.
Praktisch ist, dass der Linux-Kernel Perf direkt mitliefert, ohne dass der Nutzer externe Module benötigt. Das stellt nicht nur sicher, dass Perf auch zukünftig Pflege erhält, sondern erlaubt es auch, User- und Kernelspace gleichermaßen abzudecken.
Lesestoff
Obwohl als Suchbegriff eigentlich eher ungeeignet, finden sich zu Perf dennoch schnell zahlreiche Ressourcen im Netz. Allen voran sicherlich die Seiten von Brendan Gregg [6], der bei Sun an Dtrace mitgearbeitet hat und der Perf jetzt bei Netflix als Performance-Engineer intensiv nutzt. Sein Buch “System Performance” [7] gilt in diesem Bereich als eines der Standardwerke.
Auch Admins und Entwickler profitieren davon, die grundlegenden Fähigkeiten von Perf zu kennen, um Probleme schneller zu analysieren. Einige Entwicklungsumgebungen integrieren Perf bereits, es gibt auch ein paar Schulungsanbieter. Klar scheint: Performance-Optimierungen spielen in der Systemadministration auch künftig eine wichtige Rolle. Mit Bpftrace (siehe Kasten “BPF-Trace”, [8]) wartet schon das nächste spannende Projekt in der Pipeline.
BPF-Trace
Anfang Herbst 2018 veröffentlichte Alastair Robertson die Hochsprache BPF-Trace [8], deren Kompilat in der EBPF-VM des Linux-Kernels läuft. Somit kann der Kernel gewisse Operationen, beispielsweise Filterprozesse, direkt im Kernelspace starten. Das spart Kontextwechsel zwischen Kernel- und Userspace, was das System deutlich weniger belastet.
Infos
-
Oprofile: http://oprofile.sourceforge.net
-
Systemtap: https://sourceware.org/systemtap/
-
Offizielle Kernel-Dokumentation zu Perf: https://perf.wiki.kernel.org/index.php/Main_Page
-
Perf-Subkommandos: https://perf.wiki.kernel.org/index.php/Tutorial
-
Flamegraph-Skript: https://github.com/brendangregg/FlameGraph
-
Brendan Gregg zu Perf: http://www.brendangregg.com/perf.html
-
Brendan Gregg, “System Performance”, Prentice Hall, 2012: http://www.brendangregg.com/sysperfbook.html
-
BPF-Trace: https://github.com/iovisor/bpftrace/








