Advertisements

Analysieren Sie den Linux-Kernel mit ftrace

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

Weitere Linux-Ressourcen

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:

  1. Schreiben Sie in einige bestimmte Dateien, um die Ablaufverfolgung zu aktivieren/deaktivieren.
  2. Schreiben Sie in bestimmte Dateien, um Filter für die Feinabstimmung der Ablaufverfolgung zu aktivieren/deaktivieren.
  3. Generierte Trace-Ausgabe aus Dateien basierend auf 1 und 2 lesen.
  4. Löschen Sie frühere Ausgaben oder Puffer aus Dateien.
  5. 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
Analysieren Sie den Linux-Kernel mit ftrace

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top