Mit perf top finde ich unter Linux in Sekunden, welche Kernel-Funktionen aktuell die meiste CPU-Zeit binden und wo sich Engpässe bilden. In diesem Leitfaden zeige ich anhand klarer Schritte, wie ich Live-Hotspots erkenne, die Ausgabe sicher deute und daraus schnelle Optimierungen für Scheduler, Netzwerk und Speicher ableite.
Zentrale Punkte
Ich halte die Live-Ansicht von perf top für einen starken Startpunkt, weil sie sofort die größten Zeitfresser sichtbar macht. Die Prozentanteile pro Symbol zeigen mir, ob der Flaschenhals im Kernel oder im Userspace steckt. Aus wiederkehrenden Mustern lese ich ab, ob Locks, IRQs, Netzwerk oder Speicher dominieren. Danach grenze ich den Hotspot mit tieferen Werkzeugen ein und überprüfe Änderungen direkt unter Last. So verbessere ich Schritt für Schritt die CPU-Auslastung und senke Latenzen nachhaltig.
- Live-Hotspots erkennen und priorisieren
- Prozentanteile pro Funktion richtig deuten
- Kernelfokus setzen: IRQs, Locks, Speicher
- Workflow: top → record → report
- Optimierungen gezielt verifizieren
Was ist perf top und wofür nutze ich es?
Ich nutze perf top, um während laufender Last sofort zu sehen, welche Symbole den größten Anteil an CPU-Zeit verbrauchen. Das Tool greift auf Hardware-Performance-Counter zu und zeigt mir in kurzen Intervallen eine aktualisierte Rangliste der teuersten Funktionen. Laut Linux-Magazin beherrscht perf sowohl Profiling als auch Tracing, was die Live-Sicht nahtlos mit tieferen Analysen verbindet. Im üblichen Ablauf ergänze ich die Momentaufnahme mit perf record und perf report, um Callgraphs und genaue Pfade zu untersuchen. So beantworte ich die zentrale Frage: Wo verbringt die CPU gerade ihre Zeit – im Netzwerkstack, im Speicher-Subsystem, im Scheduler oder in einem Treiber?
perf top installieren und starten
Nach der Installation über das Distributionspaket rufe ich perf top in der Regel mit erweiterten Rechten auf, damit Kernel-Symbole und Systemevents sichtbar werden. Ein einfacher Start mit „perf top“ genügt, um eine erste Live-Ansicht aufzubauen und dominante Funktionen zu erfassen. Benötige ich Fokus auf einzelne Prozesse, hänge ich die PID mit -p an; für spezielle CPUs nutze ich -C mit einer Liste oder einem Bereich. Ereignisse lege ich mit -e fest, etwa cpu-cycles, instructions oder branch-misses, je nachdem, welche Fragestellung ich klären will. Für reproduzierbare Ergebnisse starte ich die Messung während einer echten Last, damit sich Hotspots klar zeigen und nicht in Leerlaufrauschen untergehen.
So lese ich die Ausgabe richtig
In der Liste bewerte ich zuerst die Prozentwerte je Symbol, weil sie die relativen Zeitanteile abbilden. Hohe Anteile bei Systemfunktionen deuten auf einen Engpass im Kernel hin, während dominante Userspace-Symbole eher auf App-Logik verweisen. Sehe ich viele Scheduler-Routinen, denke ich an zu viele aktive Threads, ungünstige Affinitäten oder unpassende Prioritäten. Tauchen Speicherfunktionen oben auf, prüfe ich Allokationsmuster, Page-Faults, NUMA-Lokalität und Caches. Bei Netzwerkpfaden schaue ich auf IRQ-Verteilung, Gro/TSO-Einstellungen und Treiberverhalten, weil solche Details die Latenz stark beeinflussen.
Typische Ursachen für Kernel-Hotspots
Viele Hotspots entstehen, weil sich viele kleine Kosten zu einer großen Last summieren. Häufig erhöhen exzessive Kontextwechsel, Lock-Konkurrenz und ungleich verteilte IRQs die CPU-Zeit. Ebenso binden fragmentierte Speicherstrukturen, ineffiziente Slab-Nutzung oder ständiges Paging unnötige Zyklen. Fällt mir ein bestimmter Treiber auf, korreliere ich das mit Workload, Hardware und Version, um Seiteneffekte einzugrenzen. Bei Multicore-Systemen prüfe ich zudem False Sharing, weil geteilte Cache-Linien laut Kernel-Dokumentation schnell für teuren Overhead sorgen können.
Beispielhafte Analyse eines Hotspots
Zeigt mir perf top über längere Zeit hohe Anteile in netzwerkbezogenen Funktionen, trenne ich als Erstes Lastarten: kleine vs. große Pakete, TLS vs. Klartext, viele Verbindungen vs. wenige langlebige Sessions, um die Ursache einzugrenzen. Anschließend vertiefe ich mit perf record und perf report, aktiviere Callgraphs (-g) und vergleiche die Pfade über mehrere Läufe. Taucht stattdessen die Speicherverwaltung auf, prüfe ich Allokator, Huge Pages, THP-Einstellungen und NUMA-Affinität, weil hier schnell unnötige Wege entstehen. Scheduler-Hotspots deute ich oft als Zeichen für zu viele Runnable-Threads oder eine unpassende CPU-Bindung. Ich ändere immer nur einen Parameter pro Durchlauf, damit ich die Wirkung sauber zuordne.
perf top in Hosting-Umgebungen
In Hosting-Szenarien sehe ich oft, wie kleine Kernelkosten die Latenz vieler Dienste aufaddieren. Parallel laufende Container, VMs und Datenbank-Instanzen verschieben das Profil deutlich in Richtung Netzwerk, Storage und Scheduler. Mit perf top erkenne ich, ob die Engpässe eher in IRQ-Handling, Softirq-Verarbeitung oder in Lock-Pfaden liegen. Danach beziehe ich Kernel-Version, NUMA-Layout, IRQ-Affinitäten und Queue-Tiefen in die Prüfung ein, weil diese Faktoren zusammenwirken. Wer tiefer einsteigen will, findet in diesem Leitfaden zu CPU‑Flaschenhälse analysieren weitere praktische Ansatzpunkte, die ich in der Praxis regelmäßig nutze.
Praxisleitfaden für die Analyse
Ich beginne mit einem reproduzierbaren Lastszenario, damit Messungen vergleichbar bleiben und Hotspots stabil auftauchen. Danach starte ich perf top und notiere die dominanten Symbole über mehrere Aktualisierungen hinweg. Diese Momentaufnahme verdichte ich mit perf record/report zu einem klaren Bild über Callgraphs, damit ich den Pfad zur teuren Stelle erkenne. Anschließend ändere ich gezielt nur eine Sache, zum Beispiel eine IRQ-Affinität oder eine Queue-Tiefe, und messe erneut. Erst wenn die Wirkung klar ist, gehe ich zum nächsten Schritt über und dokumentiere die Erkenntnisse für künftige Wartungsfenster.
Wann andere Werkzeuge sinnvoll sind
Für historische Sicht, feinere Callgraphs oder spezifische Ereignisketten greife ich auf perf record/report, ftrace oder eBPF zurück. Tracepoints helfen mir, gezielt Pfade zu beleuchten, während ich mit BPF-Programmen flexible Metriken gewinne. Wenn ich tiefer in Kernelpfade schauen möchte, liefern eBPF-Analysewerkzeuge wertvolle Signale direkt am Ort des Geschehens. Für Cache- und Sharing-Probleme sind perf-c2c und pahole hilfreich, sobald der Hotspot klar benannt ist. So schichte ich die Analyse von der Live-Ansicht zur Ursache, ohne mich in irrelevanten Details zu verlieren.
Sampling-Optionen und Filter in der Praxis
Ich passe die Sampling-Strategie an die Frage an, statt pauschal alles zu messen. Bei sporadischen Spikes erhöhe ich die Sampling-Frequenz und verkürze die Display-Intervalle, um flüchtige Spitzen einzufangen. Für Prozessfokus setze ich -p auf die relevante PID, für CPU-Fokus -C auf die hotten Kerne. Mit -e steuere ich das Event, etwa cpu-cycles für breites Profiling oder cache-misses, wenn Speicherverhalten im Verdacht steht. Callgraphs (-g) nutze ich, sobald ich einen Hotspot grob lokalisiert habe und die Ursache im Stack finden will.
Die folgende Tabelle zeigt praxisnahe Schalter, die ich im Alltag oft kombiniere, sowie typische Einsatzzwecke pro Option:
| Option | Wirkung | Einsatz |
|---|---|---|
| -p PID | Beschränkt Messung auf einen Prozess | App-spezifische Hotspots eingrenzen |
| -C CPU-Liste | Fokus auf ausgewählte Kerne | NUMA/IRQ-Verteilung prüfen |
| -e Event | Wählt Hardware- oder Software-Event | cycles, instructions, cache-misses |
| -g | Aktiviert Callgraph-Sampling | Teure Pfade im Stack erkennen |
| –kernel/–user | Filtert auf Kernel- oder Userspace | Quelle der CPU-Zeit trennen |
| –sort | Sortiert nach Symbol, DSO, dso:symbol | Lesbarkeit der Rangliste erhöhen |
Ich teste Konfigurationen immer kurz an, bevor ich längere Messungen starte, damit die Anzeige stabil bleibt und keine Nebenwirkungen auftreten. Gerade bei hoher Sampling-Frequenz achte ich auf Overhead, um das System nicht unnötig zu belasten. Bei Container-Hosts prüfe ich zusätzlich, ob Namespace- und cgroup-Grenzen die Sicht einschränken. Für reproduzierbare Benchmarks dokumentiere ich alle Schalter, inklusive Kernel- und Treiberversionen. Diese Disziplin spart mir später viel Zeit bei der Einordnung von Veränderungen.
Subsystem-Interpretation: Netz, Speicher, Scheduler
Wenn Netzwerkpfade oben stehen, prüfe ich zuerst IRQ-Affinitäten, RSS/Receive-Side-Scaling und Offloads wie GRO/TSO, weil diese Stellschrauben die Durchsatz-Latenz-Balance verändern. Bei auffälligen Speicherfunktionen schaue ich auf Allokationsmuster, Huge Pages, Slab-Statistiken und Page-Fault-Raten. Scheduler-Last verbinde ich häufig mit überzogenen Thread-Zahlen, fehlender CPU-Affinität oder unfairer Priorisierung. Für gezielte Kernel-Events setze ich zusätzlich Tracepoints oder nutze bpftrace im Hosting, um Hypothesen zu bestätigen. So verknüpfe ich die Live-Sichtung aus perf top mit tieferen Messpunkten und komme schneller zur eigentlichen Ursache.
Voraussetzungen und Sichtbarkeit der Symbole
Damit perf top alle relevanten Kernel-Symbole auflöst, achte ich auf zwei Dinge: passende Berechtigungen und verfügbare Symbolinformationen. Auf produktiven Systemen ist kernel.perf_event_paranoid oft hoch gesetzt. Für tiefe Kernel-Sichten reduziere ich diesen Wert temporär oder arbeite als Root mit den notwendigen Fähigkeiten (CAP_PERFMON/CAP_SYS_ADMIN). Sind Kernel-Adressen verschleiert (kptr_restrict), sehe ich Namen meist trotzdem, aber keine Rohadressen – das reicht mir für die Priorisierung. Für den Userspace installiere ich zugehörige Debuginfo-Pakete, damit perf top Funktionsnamen statt Offsets zeigt. Das reduziert Rätselraten und beschleunigt den Weg zur Ursache.
Prozentwerte und Sampling-Fallstricke
Die Prozentzahlen in der Liste interpretiere ich als relative Anteile der gemessenen Samples, nicht als exakte CPU-Auslastung im Zeitbereich. Wähle ich mehrere Events, kann Multiplexing greifen: Perf verteilt die Counter über die Zeit und normalisiert die Anzeige. Für eine klare Story messe ich zuerst breit mit cpu-cycles oder instructions und schalte Spezial-Events später zu. Kurzzeitige Spikes erwische ich mit höherer Frequenz (-F) und kürzeren Intervallen; bei ruhigen Systemen reicht die Standardfrequenz. Ich beachte außerdem, dass Idle-Phasen und Frequenzwechsel (Turbo, Governor) die Wahrnehmung verzerren können. Für Vergleichsmessungen vereinheitliche ich daher Takt- und Energiesettings.
Callgraphs in der Tiefe
Wenn ich einen Hotspot identifiziert habe, steigere ich die Aussagekraft über Callgraphs. Mit -g und einer passenden Unwinding-Methode bekomme ich den Pfad zur teuren Stelle. Frame-Pointer oder DWARF-Unwinding liefern mir stabile Stacks; wo verfügbar, nutze ich hardwaregestützte Rücksprungpuffer (LBR) für sehr präzise Ketten. Ich erhöhe die mmap-Puffer nur so weit wie nötig, um Overhead flach zu halten. Zeigt der Stack viele Hilfsfunktionen, achte ich auf inclusive vs. exclusive Kosten: Entscheidend ist, ob die Funktion selbst teuer ist oder nur als Transitstrecke dominiert. Diese Unterscheidung spart mir oft Stunden in der Ursachenforschung.
Arbeiten in Containern und VMs
In Container-Umgebungen prüfe ich, ob meine Sicht auf cgroups und Namespaces korrekt ist. Ich fokussiere Messungen auf die relevanten PIDs und CPUs, damit laute Nachbarn das Bild nicht verfälschen. Für VMs kontrolliere ich, ob der virtuelle PMU freigeschaltet ist; sonst fehlen mir präzise Hardwareevents und ich sehe primär Software-Signale. KVM-Hosts erkenne ich häufig an Symbolen rund um kvm_vcpu oder vmx/svm. In solchen Szenarien trenne ich Host- und Guest-Analysen sauber, damit ich nicht Ursache und Wirkung verwechsel.
Erkennbare Muster und schnelle Hypothesen
Im Alltag haben sich bestimmte Muster bewährt, die ich sofort abprüfe:
- Lock-Konkurrenz: Tauchen queued_spin_lock_slowpath oder mutex_spin_on_owner oben auf, sind Datenstrukturen zu grob geschnitten oder Workqueues zu eng. Ich reduziere Contention über Sharding, feinere Sperrgranularität oder veränderte Batchgrößen.
- Scheduler-Druck: Häufen sich schedule(), pick_next_task_fair oder Wakeup-Pfade, trimme ich Thread-Anzahl, Affinitäten und Prioritäten. Häufig genügt es, “Talkative” Threads zu beruhigen oder CPU-Setzungen sauber zu definieren.
- Netzwerk-Softirqs: Spitzen bei net_rx_action, napi_poll oder Checksum-Offloads deuten auf Paketstürme oder suboptimale RSS- und IRQ-Verteilung. Ich lege IRQs auf passende Kerne und justiere GRO/TSO für das gewünschte Durchsatz/Latenz-Profil.
- Speicherpfade: Viel Zeit in do_page_fault, copy_user_* oder Slab-Funktionen lässt mich Allokationsmuster, THP/Huge Pages und NUMA-Lokalität prüfen. Falsche Platzierung kostet hier unbemerkt sehr viele Zyklen.
- RCU und Timers: Dominieren rcu_core oder Timer-Callbacks, überdenke ich Polling- und Batch-Strategien meiner Dienste, um das System ruhiger zu fahren.
Messdisziplin und Reproduzierbarkeit vertiefen
Für sauber vergleichbare Runs halte ich Umgebungsfaktoren konstant: CPU-Governor, Turbo-States, Hintergrundjobs, sogar Raumtemperatur bei dichten Knoten. Ich binde Testlasten an definierte Kerne und isoliere optional Hot-CPUs, damit Scheduler-Entscheidungen stabil bleiben. Änderungen dokumentiere ich samt Kernel-, Treiber- und Firmwareständen. Bei riskanteren Tweaks plane ich Rücksprungpunkte ein und messe unmittelbar nach dem Eingriff erneut. So bekomme ich eine belastbare Before/After-Geschichte, die ich auch Monate später noch nachvollziehen kann.
Praxisrezepte: Befehle, die ich häufig nutze
Je nach Frage verwende ich kompakte Rezepturen:
- Breites Scoping unter Last: perf top -e cpu-cycles –kernel –user
Schneller Überblick, ob Kernel oder Userspace die Töne angibt. - Prozessfokus mit Callgraph: perf top -p PID -g –kernel –user
Zeigt mir Live-Pfade der relevanten Anwendung, ohne Systemlärm. - CPU-Fokus: perf top -C 2-5 -e cpu-cycles -g
Hilft bei NUMA- oder IRQ-Hotspots, wenn nur wenige Kerne “glühen”. - Speicherverdacht: perf top -e cache-misses -e cycles -g –kernel
Lässt Speicherpfade im Verhältnis zu Zyklen aufblitzen. - Flüchtige Spikes anheften: perf top -F 999 -I 1000 -e cycles
Höhere Frequenz und kürzere Anzeigeintervalle fangen kurze Peaks ein.
Interpretationshilfen für konkrete Subsysteme
Beim Netzwerk beobachte ich neben NAPI und RX/TX-Pfaden auch TLS/crypto-Anteile, die bei hohem Handshake-Aufkommen dominieren können. Ich prüfe, ob Zero-Copy bzw. coalescing sinnvoll greift und ob große Segmente (TSO/GSO) meine Latenzbudgets sprengen. Im Speicher-Bereich schaue ich auf THP: Hilft es meiner Last, oder verursachen Split/Merge-Events Störfeuer? Bei Storage deute ich blk_mq-Symbole und io_uring-Pfade als Hinweis auf Queue-Tiefen und Merge-Strategien. Beim Scheduler verknüpfe ich Wakeup-Lawinen mit Lock- oder IO-Ketten und entzerre die Pfade durch Backpressure statt “mehr Threads”.
Grenzen von perf top und wann ich umschwenke
Weil perf top samplingbasiert ist, sehe ich Durchschnittsbilder besser als Einzelereignisse. Für deterministische Ablaufketten switche ich auf Tracepoints, ftrace oder eBPF, um präzise Kausalitäten zu belegen. Brauche ich exakte Quantifizierung (z. B. Instructions per Request), kombiniere ich mit perf stat oder offline-Analysen aus perf record/report. Treffe ich auf unklare Stacks (fehlende Symbole, fehlerhaftes Unwinding), behebe ich zuerst die Sichtbarkeit – alles andere wäre Stochern im Nebel.
Kurz zusammengefasst
Mit perf top erkenne ich in Echtzeit, wo die CPU im Kernel Zeit lässt und welche Symbole ich zuerst untersuchen sollte. Aus den Prozentwerten, wiederkehrenden Mustern und der Trennung von Kernel- und Userspace leite ich gezielte nächste Schritte ab. Dann verdichte ich die Erkenntnisse mit perf record/report, verifiziere Veränderungen unter Last und dokumentiere meine Messkette. In Hosting-Umgebungen zahlt sich diese Vorgehensweise besonders aus, weil viele Dienste und Container voneinander profitieren, sobald Kernelpfade effizienter laufen. Wer diesen Ablauf verinnerlicht, spart Diagnosetage, senkt Latenzen und erreicht spürbar stabilere Antwortzeiten unter realer Last.


