Der Kernel eines Betriebssystems ist eine der am schwersten fassbaren Softwarekomponenten. Es läuft immer im Hintergrund, sobald Ihr System eingeschaltet wird. Jeder Benutzer erledigt seine Rechenarbeit mit Hilfe des Kernels, interagiert aber nie direkt mit ihm. Die Interaktion mit dem Kernel erfolgt, indem Systemaufrufe getätigt werden oder diese Aufrufe im Namen des Benutzers von verschiedenen Bibliotheken oder Anwendungen ausgeführt werden, die sie täglich verwenden.
Ich habe in einem früheren Artikel beschrieben, wie Systemaufrufe verfolgt werden können mit strace
. Allerdings mit strace
, Ihre Sichtbarkeit ist eingeschränkt. Es ermöglicht Ihnen, die mit bestimmten Parametern aufgerufenen Systemaufrufe anzuzeigen und nach Abschluss der Arbeit den Rückgabewert oder den Status anzuzeigen, der anzeigt, ob sie erfolgreich waren oder fehlgeschlagen sind. Aber Sie hatten keine Ahnung, was während dieser Zeit im Kernel passierte. Abgesehen davon, dass Sie nur Systemaufrufe ausführen, passieren viele andere Aktivitäten im Kernel, die Sie nicht bemerken.
Ftrace-Einführung
Dieser Artikel zielt darauf ab, etwas Licht in die Verfolgung der Kernel-Funktionen zu bringen, indem ein Mechanismus namens . verwendet wird ftrace
. Es macht das Kernel-Tracing für jeden Linux-Benutzer leicht zugänglich, und mit seiner Hilfe können Sie viel über die Interna des Linux-Kernels lernen.
Die vom . erzeugte Standardausgabe ftrace
ist oft massiv, da der Kernel immer beschäftigt ist. Um Platz zu sparen, habe ich die Ausgabe auf ein Minimum beschränkt und in vielen Fällen die Ausgabe vollständig gekürzt.
Ich verwende Fedora für diese Beispiele, aber sie sollten auf jeder der neuesten Linux-Distributionen funktionieren.
ftrace aktivieren
Ftrace
ist jetzt Teil des Linux-Kernels, und Sie müssen nichts mehr installieren, um ihn zu verwenden. Wenn Sie ein aktuelles Linux-Betriebssystem verwenden, ist es wahrscheinlich, dass ftrace
ist bereits aktiviert. Um zu überprüfen, ob die ftrace
Einrichtung verfügbar ist, führen Sie den Befehl mount aus und suchen Sie nach tracefs
. Wenn Sie eine ähnliche Ausgabe wie unten sehen, ftrace
aktiviert ist, und Sie können den Beispielen in diesem Artikel leicht folgen. Diese Befehle müssen als Root-Benutzer ausgeführt werden (sudo
ist ungenügend.)
# mount | grep tracefs
none on /sys/kernel/tracing type tracefs (rw,relatime,seclabel)
Gebrauch machen von ftrace
, müssen Sie zuerst zu dem speziellen Verzeichnis navigieren, wie im obigen Mount-Befehl angegeben, von wo aus Sie die restlichen Befehle im Artikel ausführen:
# cd /sys/kernel/tracing
Allgemeiner Arbeitsablauf
Zuallererst müssen Sie den allgemeinen Arbeitsablauf beim Erfassen eines Trace und Erhalten der Ausgabe verstehen. Wenn du verwendest ftrace
direkt, es gibt nichts besonderes ftrace-
bestimmte Befehle auszuführen. Stattdessen schreiben Sie im Grunde in einige Dateien und lesen aus einigen Dateien mit Standard-Befehlszeilen-Linux-Dienstprogrammen.
Die allgemeinen Schritte:
- Schreiben Sie in einige bestimmte Dateien, um die Ablaufverfolgung zu aktivieren/deaktivieren.
- Schreiben Sie in bestimmte Dateien, um Filter für die Feinabstimmung der Ablaufverfolgung zu aktivieren/deaktivieren.
- Generierte Trace-Ausgabe aus Dateien basierend auf 1 und 2 lesen.
- Löschen Sie frühere Ausgaben oder Puffer aus Dateien.
- Schränken Sie Ihren spezifischen Anwendungsfall ein (Kernelfunktionen zum Nachverfolgen) und wiederholen Sie die Schritte 1, 2, 3, 4.
Arten von verfügbaren Tracern
Ihnen stehen verschiedene Arten von Tracern zur Verfügung. Wie bereits erwähnt, müssen Sie sich in einem bestimmten Verzeichnis befinden, bevor Sie einen dieser Befehle ausführen, da die gewünschten Dateien dort vorhanden sind. Ich verwende in meinen Beispielen relative Pfade (im Gegensatz zu absoluten Pfaden).
Sie können den Inhalt der available_tracers
Datei, um alle verfügbaren Tracer-Typen anzuzeigen. Sie können einige unten aufgeführt sehen. Machen Sie sich noch keine Sorgen um alle:
# pwd
/sys/kernel/tracing
# cat available_tracers
hwlat blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop
Von allen angegebenen Tracern konzentriere ich mich auf drei spezifische: function
und function_graph
um die Rückverfolgung zu ermöglichen, und nop
um die Verfolgung zu deaktivieren.
Identifizieren Sie den aktuellen Tracer
Normalerweise ist der Tracer standardmäßig auf eingestellt nop
. Das heißt, “Keine Operation” in der speziellen Datei current_tracer
, was normalerweise bedeutet, dass die Ablaufverfolgung derzeit deaktiviert ist:
# pwd
/sys/kernel/tracing
# cat current_tracer
nop
Tracing-Ausgabe anzeigen
Bevor Sie die Ablaufverfolgung aktivieren, sehen Sie sich die Datei an, in der die Ablaufverfolgungsausgabe gespeichert wird. Sie können den Inhalt der Datei mit dem Namen anzeigen trace
mit dem cat-Befehl:
# cat trace
# tracer: nop
#
# entries-in-buffer/entries-written: 0/0 #P:8
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
Funktion Tracer aktivieren
Sie können Ihren ersten Tracer namens aktivieren function
indem du schreibst function
zur Datei current_tracer
(sein früherer Inhalt war nop
, was darauf hinweist, dass die Ablaufverfolgung deaktiviert war.) Stellen Sie sich diesen Vorgang als eine Möglichkeit vor, die Ablaufverfolgung zu aktivieren:
# pwd
/sys/kernel/tracing
# cat current_tracer
nop
# echo function > current_tracer
# cat current_tracer
function
Aktualisierte Ablaufverfolgungsausgabe für Funktions-Tracer anzeigen
Nachdem Sie die Ablaufverfolgung aktiviert haben, können Sie die Ausgabe anzeigen. Wenn Sie den Inhalt der trace
Datei, sehen Sie, wie viele Daten kontinuierlich in sie geschrieben werden. Ich habe die Ausgabe weitergeleitet und schaue mir derzeit nur die oberen 20 Zeilen an, um die Dinge überschaubar zu halten. Wenn Sie den Überschriften in der Ausgabe links folgen, können Sie sehen, welche Task und Prozess-ID auf welcher CPU laufen. Auf der rechten Seite der Ausgabe sehen Sie die genaue Kernelfunktion, gefolgt von ihrer übergeordneten Funktion. Es gibt auch Zeitstempelinformationen in der Mitte:
# sudo cat trace | head -20
# tracer: function
#
# entries-in-buffer/entries-written: 409936/4276216 #P:8
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
<idle>-0 [000] d... 2088.841739: tsc_verify_tsc_adjust <-arch_cpu_idle_enter
<idle>-0 [000] d... 2088.841739: local_touch_nmi <-do_idle
<idle>-0 [000] d... 2088.841740: rcu_nocb_flush_deferred_wakeup <-do_idle
<idle>-0 [000] d... 2088.841740: tick_check_broadcast_expired <-do_idle
<idle>-0 [000] d... 2088.841740: cpuidle_get_cpu_driver <-do_idle
<idle>-0 [000] d... 2088.841740: cpuidle_not_available <-do_idle
<idle>-0 [000] d... 2088.841741: cpuidle_select <-do_idle
<idle>-0 [000] d... 2088.841741: menu_select <-do_idle
<idle>-0 [000] d... 2088.841741: cpuidle_governor_latency_req <-menu_select
Denken Sie daran, dass die Ablaufverfolgung aktiviert ist, was bedeutet, dass die Ausgabe der Ablaufverfolgung weiterhin in die Ablaufverfolgungsdatei geschrieben wird, bis Sie die Ablaufverfolgung deaktivieren.
Nachverfolgung deaktivieren
Das Deaktivieren der Ablaufverfolgung ist einfach. Alles was Sie tun müssen, ist ersetzen function
Tracer mit nop
in dem current_tracer
Datei und Ablaufverfolgung wird deaktiviert:
# cat current_tracer
function
# echo nop > current_tracer
# cat current_tracer
nop
Funktion_Graph-Tracer aktivieren
Versuchen Sie nun den zweiten Tracer, genannt function_graph
. Sie können dies mit den gleichen Schritten wie zuvor aktivieren: schreiben function_graph
zum current_tracer
Datei:
# echo function_graph > current_tracer
# cat current_tracer
function_graph
Tracing-Ausgabe von function_graph tracer
Beachten Sie, dass das Ausgabeformat der trace
Datei hat sich geändert. Jetzt können Sie die CPU-ID und die Dauer der Ausführung der Kernelfunktion sehen. Als nächstes sehen Sie geschweifte Klammern, die den Beginn einer Funktion anzeigen und welche anderen Funktionen von ihr aufgerufen wurden:
# cat trace | head -20
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
6) | n_tty_write() {
6) | down_read() {
6) | __cond_resched() {
6) 0.341 us | rcu_all_qs();
6) 1.057 us | }
6) 1.807 us | }
6) 0.402 us | process_echoes();
6) | add_wait_queue() {
6) 0.391 us | _raw_spin_lock_irqsave();
6) 0.359 us | _raw_spin_unlock_irqrestore();
6) 1.757 us | }
6) 0.350 us | tty_hung_up_p();
6) | mutex_lock() {
6) | __cond_resched() {
6) 0.404 us | rcu_all_qs();
6) 1.067 us | }
Aktivieren Sie die Trace-Einstellungen, um die Trace-Tiefe zu erhöhen
Sie können den Tracer jederzeit leicht anpassen, um mehr Tiefe der Funktionsaufrufe zu sehen, indem Sie die folgenden Schritte ausführen. Danach können Sie den Inhalt der trace
Datei und sehen Sie, dass die Ausgabe etwas detaillierter ist. Aus Gründen der Lesbarkeit wird die Ausgabe dieses Beispiels weggelassen:
# cat max_graph_depth
0
# echo 1 > max_graph_depth ## or:
# echo 2 > max_graph_depth
# sudo cat trace
Finden von Funktionen zum Nachverfolgen
Die obigen Schritte reichen aus, um mit dem Tracing zu beginnen. Allerdings ist die Menge an erzeugtem Output enorm, und Sie können sich oft verirren, wenn Sie versuchen, interessante Dinge zu finden. Oft möchten Sie nur bestimmte Funktionen verfolgen und den Rest ignorieren. Aber woher wissen Sie, welche Prozesse Sie verfolgen müssen, wenn Sie ihre genauen Namen nicht kennen? Es gibt eine Datei, die Ihnen dabei helfen kann –available_filter_functions
stellt Ihnen eine Liste der verfügbaren Funktionen zum Tracing zur Verfügung:
# wc -l available_filter_functions
63165 available_filter_functions
Suche nach allgemeinen Kernelfunktionen
Versuchen Sie nun, nach einer einfachen Kernelfunktion zu suchen, die Ihnen bekannt ist. User-Space hat malloc
Speicher zuzuweisen, während der Kernel seine kmalloc
Funktion, die eine ähnliche Funktionalität bietet. Unten sind alle kmalloc
verwandte Funktionen:
# grep kmalloc available_filter_functions
debug_kmalloc
mempool_kmalloc
kmalloc_slab
kmalloc_order
kmalloc_order_trace
kmalloc_fix_flags
kmalloc_large_node
__kmalloc
__kmalloc_track_caller
__kmalloc_node
__kmalloc_node_track_caller
[...]
Suche nach Kernelmodul- oder treiberbezogenen Funktionen
Aus der Ausgabe von available_filter_functions
, sehen Sie einige Zeilen, die mit Text in Klammern enden, wie zum Beispiel [kvm_intel]
im Beispiel unten. Diese Funktionen beziehen sich auf das Kernelmodul kvm_intel
, die gerade geladen wird. Sie können die lsmod
Befehl zur Überprüfung:
# grep kvm available_filter_functions | tail
__pi_post_block [kvm_intel]
vmx_vcpu_pi_load [kvm_intel]
vmx_vcpu_pi_put [kvm_intel]
pi_pre_block [kvm_intel]
pi_post_block [kvm_intel]
pi_wakeup_handler [kvm_intel]
pi_has_pending_interrupt [kvm_intel]
pi_update_irte [kvm_intel]
vmx_dump_dtsel [kvm_intel]
vmx_dump_sel [kvm_intel]
# lsmod | grep -i kvm
kvm_intel 335872 0
kvm 987136 1 kvm_intel
irqbypass 16384 1 kvm
Nur Trace-spezifische Funktionen
Um die Verfolgung bestimmter Funktionen oder Muster zu ermöglichen, können Sie die set_ftrace_filter
-Datei, um anzugeben, welche Funktionen aus der obigen Ausgabe Sie verfolgen möchten.
Diese Datei akzeptiert auch die *
Muster, das mit dem angegebenen Muster um zusätzliche Funktionen erweitert wird. Als Beispiel verwende ich die ext4
Dateisystem auf meinem Rechner. ich kann angeben ext4
bestimmte Kernelfunktionen mit den folgenden Befehlen zu verfolgen:
# mount | grep home
/dev/mapper/fedora-home on /home type ext4 (rw,relatime,seclabel)
# pwd
/sys/kernel/tracing
# cat set_ftrace_filter
#### all functions enabled ####
$
$ echo ext4_* > set_ftrace_filter
$
$ cat set_ftrace_filter
ext4_has_free_clusters
ext4_validate_block_bitmap
ext4_get_group_number
ext4_get_group_no_and_offset
ext4_get_group_desc
[...]
Wenn Sie jetzt die Ablaufverfolgungsausgabe sehen, können Sie nur Funktionen sehen ext4
bezogen auf Kernelfunktionen, für die Sie zuvor einen Filter gesetzt hatten. Alle anderen Ausgaben werden ignoriert:
# cat trace |head -20
## tracer: function
#
# entries-in-buffer/entries-written: 3871/3871 #P:8
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
cupsd-1066 [004] .... 3308.989545: ext4_file_getattr <-vfs_fstat
cupsd-1066 [004] .... 3308.989547: ext4_getattr <-ext4_file_getattr
cupsd-1066 [004] .... 3308.989552: ext4_file_getattr <-vfs_fstat
cupsd-1066 [004] .... 3308.989553: ext4_getattr <-ext4_file_getattr
cupsd-1066 [004] .... 3308.990097: ext4_file_open <-do_dentry_open
cupsd-1066 [004] .... 3308.990111: ext4_file_getattr <-vfs_fstat
cupsd-1066 [004] .... 3308.990111: ext4_getattr <-ext4_file_getattr
cupsd-1066 [004] .... 3308.990122: ext4_llseek <-ksys_lseek
cupsd-1066 [004] .... 3308.990130: ext4_file_read_iter <-new_sync_read
Funktionen von der Verfolgung ausschließen
Sie wissen nicht immer, was Sie verfolgen möchten, aber Sie wissen sicherlich, was Sie nicht verfolgen möchten. Dafür gibt es diese Datei passend benannt set_ftrace_notrace
-beachte das “Nein” darin. Sie können Ihr gewünschtes Muster in diese Datei schreiben und das Tracing aktivieren, woraufhin alles außer dem genannten Muster verfolgt wird. Dies ist oft hilfreich, um allgemeine Funktionen zu entfernen, die unsere Ausgabe überladen:
# cat set_ftrace_notrace
#### no functions disabled ####
Gezieltes Tracing
Bisher haben Sie alles verfolgt, was im Kernel passiert ist. Aber das hilft uns nicht, wenn Sie Ereignisse im Zusammenhang mit einem bestimmten Befehl verfolgen möchten. Um dies zu erreichen, können Sie die Ablaufverfolgung bei Bedarf ein- und ausschalten und dazwischen unseren bevorzugten Befehl ausführen, damit Sie keine zusätzliche Ausgabe in Ihrer Ablaufverfolgungsausgabe erhalten. Sie können das Tracing aktivieren, indem Sie schreiben 1
zu tracing_on
, und 0
um es auszuschalten:
# cat tracing_on
0
# echo 1 > tracing_on
# cat tracing_on
1
### Run some specific command that we wish to trace here ###
# echo 0 > tracing_on
# cat tracing_on
0
Verfolgung spezifischer PID
Wenn Sie Aktivitäten im Zusammenhang mit einem bestimmten bereits laufenden Prozess verfolgen möchten, können Sie diese PID in eine Datei namens . schreiben set_ftrace_pid
und aktivieren Sie dann die Verfolgung. Auf diese Weise ist das Tracing nur auf diese PID beschränkt, was in einigen Fällen sehr hilfreich ist:
# echo $PID > set_ftrace_pid
Abschluss
Ftrace
ist eine großartige Möglichkeit, mehr über die interne Funktionsweise des Linux-Kernels zu erfahren. Mit etwas Übung können Sie die Feinabstimmung lernen ftrace
und grenzen Sie Ihre Suche ein. Verstehen ftrace
Weitere Einzelheiten und seine fortgeschrittene Verwendung finden Sie in diesen hervorragenden Artikeln des Hauptautors von ftrace
selbst – Steven Rostedt.
- Debuggen des Linux-Kernels, Teil 1
- Debuggen des Linux-Kernels, Teil 2
- Debuggen des Linux-Kernels, Teil 3