GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Kernel-Tracing mit trace-cmd

In meinem vorherigen Artikel habe ich erklärt, wie man ftrace verwendet um Kernel-Funktionen zu verfolgen. Verwenden von ftrace durch das Schreiben und Lesen von Dateien kann mühsam werden, also habe ich einen Wrapper darum verwendet, um Befehle mit Optionen zum Aktivieren und Deaktivieren der Ablaufverfolgung, zum Festlegen von Filtern, zum Anzeigen der Ausgabe, zum Löschen der Ausgabe und mehr auszuführen.

Der Befehl trace-cmd ist ein Dienstprogramm, das Ihnen dabei hilft. In diesem Artikel verwende ich trace-cmd um die gleichen Aufgaben auszuführen, die ich in meinem ftrace gemacht habe Artikel. Da ich häufig auf diesen Artikel zurückgreife, empfehle ich Ihnen, ihn zu lesen, bevor Sie diesen lesen.

trace-cmd installieren

Ich führe die Befehle in diesem Artikel als Root-Benutzer aus.

Der ftrace Mechanismus ist in den Kernel eingebaut, und Sie können überprüfen, ob er aktiviert ist mit:

# mount | grep tracefs
none on /sys/kernel/tracing type tracefs (rw,relatime,seclabel)
ein

Sie müssen jedoch das trace-cmd installieren Dienstprogramm manuell.

# dnf install trace-cmd -y

Verfügbare Tracer auflisten

Bei Verwendung von ftrace , müssen Sie den Inhalt einer Datei anzeigen, um zu sehen, welche Tracer verfügbar sind. Aber mit trace-cmd , erhalten Sie diese Informationen mit:

# trace-cmd list -t
hwlat blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop

Funktions-Tracer aktivieren

In meinem früheren Artikel habe ich zwei Tracer verwendet, und ich werde das Gleiche hier tun. Aktivieren Sie Ihren ersten Tracer, function , mit:

$ trace-cmd start -p function
  plugin 'function'

Trace-Ausgabe anzeigen

Sobald der Tracer aktiviert ist, können Sie die Ausgabe mit show anzeigen Argumente. Dies zeigt nur die ersten 20 Zeilen, um das Beispiel kurz zu halten (siehe meinen früheren Artikel für eine Erklärung der Ausgabe):

# trace-cmd show | head -20
## tracer: function
#
# entries-in-buffer/entries-written: 410142/3380032   #P:8
#
#                                _-----=> irqs-off
#                               / _----=> need-resched
#                              | / _---=> hardirq/softirq
#                              || / _--=> preempt-depth
#                              ||| /     delay
#           TASK-PID     CPU#  ||||   TIMESTAMP  FUNCTION
#              | |         |   ||||      |         |
           gdbus-2606    [004] ..s. 10520.538759: __msecs_to_jiffies <-rebalance_domains
           gdbus-2606    [004] ..s. 10520.538760: load_balance <-rebalance_domains
           gdbus-2606    [004] ..s. 10520.538761: idle_cpu <-load_balance
           gdbus-2606    [004] ..s. 10520.538762: group_balance_cpu <-load_balance
           gdbus-2606    [004] ..s. 10520.538762: find_busiest_group <-load_balance
           gdbus-2606    [004] ..s. 10520.538763: update_group_capacity <-update_sd_lb_stats.constprop.0
           gdbus-2606    [004] ..s. 10520.538763: __msecs_to_jiffies <-update_group_capacity
           gdbus-2606    [004] ..s. 10520.538765: idle_cpu <-update_sd_lb_stats.constprop.0
           gdbus-2606    [004] ..s. 10520.538766: __msecs_to_jiffies <-rebalance_domains

Beenden Sie die Ablaufverfolgung und leeren Sie den Puffer

Die Ablaufverfolgung läuft im Hintergrund weiter, und Sie können die Ausgabe weiterhin mit show anzeigen .

Um die Ablaufverfolgung zu beenden, führen Sie trace-cmd aus mit der stop Argument:

# trace-cmd stop

Um den Puffer zu löschen, führen Sie ihn mit clear aus Argument:

# trace-cmd clear

Funktionsgraph-Tracer aktivieren

Aktivieren Sie den zweiten Tracer, function_graph , indem Sie Folgendes ausführen:

# trace-cmd start -p function_graph
  plugin 'function_graph'

Sehen Sie sich die Ausgabe erneut mit show an Streit. Wie erwartet weicht die Ausgabe etwas von der ersten Trace-Ausgabe ab. Diesmal enthält es einen function calls Kette:

# trace-cmd show | head -20
## tracer: function_graph
#
# CPU  DURATION                  FUNCTION CALLS
# |     |   |                     |   |   |   |
 4)   0.079 us    |        } /* rcu_all_qs */
 4)   0.327 us    |      } /* __cond_resched */
 4)   0.081 us    |      rcu_read_unlock_strict();
 4)               |      __cond_resched() {
 4)   0.078 us    |        rcu_all_qs();
 4)   0.243 us    |      }
 4)   0.080 us    |      rcu_read_unlock_strict();
 4)               |      __cond_resched() {
 4)   0.078 us    |        rcu_all_qs();
 4)   0.241 us    |      }
 4)   0.080 us    |      rcu_read_unlock_strict();
 4)               |      __cond_resched() {
 4)   0.079 us    |        rcu_all_qs();
 4)   0.235 us    |      }
 4)   0.095 us    |      rcu_read_unlock_strict();
 4)               |      __cond_resched() {

Verwenden Sie die stop und clear Befehle zum Stoppen der Ablaufverfolgung und zum Löschen des Puffers:

# trace-cmd stop
# trace-cmd clear

Optimieren Sie die Ablaufverfolgung, um die Tiefe zu erhöhen

Wenn Sie mehr Tiefe in den Funktionsaufrufen sehen möchten, können Sie den Tracer anpassen:

# trace-cmd start -p function_graph --max-graph-depth 5
  plugin 'function_graph'

Wenn Sie nun diese Ausgabe mit dem vergleichen, was Sie vorher gesehen haben, sollten Sie mehr verschachtelte Funktionsaufrufe sehen:

# trace-cmd show | head -20
## tracer: function_graph
#
# CPU  DURATION                  FUNCTION CALLS
# |     |   |                     |   |   |   |
 6)               |        __fget_light() {
 6)   0.804 us    |          __fget_files();
 6)   2.708 us    |        }
 6)   3.650 us    |      } /* __fdget */
 6)   0.547 us    |      eventfd_poll();
 6)   0.535 us    |      fput();
 6)               |      __fdget() {
 6)               |        __fget_light() {
 6)   0.946 us    |          __fget_files();
 6)   1.895 us    |        }
 6)   2.849 us    |      }
 6)               |      sock_poll() {
 6)   0.651 us    |        unix_poll();
 6)   1.905 us    |      }
 6)   0.475 us    |      fput();
 6)               |      __fdget() {

Lernen Sie verfügbare Funktionen zum Tracen

Wenn Sie nur bestimmte Funktionen verfolgen und den Rest ignorieren möchten, müssen Sie die genauen Funktionsnamen kennen. Sie können sie mit der list abrufen Argument gefolgt von -f . Dieses Beispiel sucht nach der allgemeinen Kernel-Funktion kmalloc , die verwendet wird, um Speicher im Kernel zuzuweisen:

# trace-cmd list -f | grep kmalloc
bpf_map_kmalloc_node
mempool_kmalloc
__traceiter_kmalloc
__traceiter_kmalloc_node
kmalloc_slab
kmalloc_order
kmalloc_order_trace
kmalloc_large_node
__kmalloc
__kmalloc_track_caller
__kmalloc_node
__kmalloc_node_track_caller
[...]

Hier ist die Gesamtzahl der auf meinem Testsystem verfügbaren Funktionen:

# trace-cmd list -f | wc -l
63165

Sie können auch Funktionen verfolgen, die sich auf ein bestimmtes Kernelmodul beziehen. Stellen Sie sich vor, Sie möchten kvm verfolgen Kernel-Modul-bezogene Funktionen. Stellen Sie sicher, dass das Modul geladen ist:

# lsmod  | grep kvm_intel
kvm_intel             335872  0
kvm                   987136  1 kvm_intel

Führen Sie trace-cmd aus wieder mit der list Argument und aus der Ausgabe grep für Zeilen, die auf ] enden . Dadurch werden die Kernelmodule herausgefiltert. Dann grep das Kernelmodul kvm_intel , und Sie sollten alle Funktionen sehen, die sich auf dieses Kernelmodul beziehen:

# trace-cmd list -f | grep ]$  | grep kvm_intel
vmx_can_emulate_instruction [kvm_intel]
vmx_update_emulated_instruction [kvm_intel]
vmx_setup_uret_msr [kvm_intel]
vmx_set_identity_map_addr [kvm_intel]
handle_machine_check [kvm_intel]
handle_triple_fault [kvm_intel]
vmx_patch_hypercall [kvm_intel]

[...]

vmx_dump_dtsel [kvm_intel]
vmx_dump_sel [kvm_intel]

Weitere Linux-Ressourcen

  • Spickzettel für Linux-Befehle
  • Spickzettel für fortgeschrittene Linux-Befehle
  • Kostenloser Online-Kurs:RHEL Technical Overview
  • Spickzettel für Linux-Netzwerke
  • SELinux-Spickzettel
  • Spickzettel für allgemeine Linux-Befehle
  • Was sind Linux-Container?
  • Unsere neuesten Linux-Artikel

Verfolgen Sie bestimmte Funktionen

Jetzt, da Sie wissen, wie man interessante Funktionen findet, wenden Sie dieses Wissen an einem Beispiel an. Versuchen Sie wie im vorherigen Artikel, dateisystembezogene Funktionen zu verfolgen. Das Dateisystem, das ich auf meinem Testsystem hatte, war ext4 .

Dieses Verfahren ist etwas anders; statt start , führen Sie den Befehl mit dem record aus -Argument, gefolgt vom "Muster" der Funktionen, die Sie verfolgen möchten. Sie müssen auch den gewünschten Tracer angeben; in diesem Fall ist das function_graph . Der Befehl zeichnet den Trace so lange auf, bis Sie ihn mit Strg+C stoppen . Drücken Sie also nach ein paar Sekunden Strg+C So beenden Sie die Ablaufverfolgung:

# trace-cmd list -f | grep ^ext4_

# trace-cmd record -l ext4_* -p function_graph
  plugin 'function_graph'
Hit Ctrl^C to stop recording
^C
CPU0 data recorded at offset=0x856000
    8192 bytes in size
[...]

Aufgezeichneten Trace ansehen

Um die zuvor aufgezeichnete Ablaufverfolgung anzuzeigen, führen Sie den Befehl mit report aus Streit. Aus der Ausgabe geht hervor, dass der Filter funktioniert hat, und Sie sehen nur die ext4-bezogene Funktionsablaufverfolgung:

# trace-cmd report | head -20
[...]
cpus=8
       trace-cmd-12697 [000] 11303.928103: funcgraph_entry:                   |  ext4_show_options() {
       trace-cmd-12697 [000] 11303.928104: funcgraph_entry:        0.187 us   |    ext4_get_dummy_policy();
       trace-cmd-12697 [000] 11303.928105: funcgraph_exit:         1.583 us   |  }
       trace-cmd-12697 [000] 11303.928122: funcgraph_entry:                   |  ext4_create() {
       trace-cmd-12697 [000] 11303.928122: funcgraph_entry:                   |    ext4_alloc_inode() {
       trace-cmd-12697 [000] 11303.928123: funcgraph_entry:        0.101 us   |      ext4_es_init_tree();
       trace-cmd-12697 [000] 11303.928123: funcgraph_entry:        0.083 us   |      ext4_init_pending_tree();
       trace-cmd-12697 [000] 11303.928123: funcgraph_entry:        0.141 us   |      ext4_fc_init_inode();
       trace-cmd-12697 [000] 11303.928123: funcgraph_exit:         0.931 us   |    }
       trace-cmd-12697 [000] 11303.928124: funcgraph_entry:        0.081 us   |    ext4_get_dummy_policy();
       trace-cmd-12697 [000] 11303.928124: funcgraph_entry:        0.133 us   |    ext4_get_group_desc();
       trace-cmd-12697 [000] 11303.928124: funcgraph_entry:        0.115 us   |    ext4_free_inodes_count();
       trace-cmd-12697 [000] 11303.928124: funcgraph_entry:        0.114 us   |    ext4_get_group_desc();

Verfolge eine bestimmte PID

Angenommen, Sie möchten Funktionen nachverfolgen, die sich auf einen bestimmten persistenten Bezeichner (PID) beziehen. Öffnen Sie ein weiteres Terminal und notieren Sie sich die PID der laufenden Shell:

# echo $$
10885

Führen Sie den record aus Befehl erneut und übergeben Sie die PID mit -P Möglichkeit. Lassen Sie diesmal das Terminal laufen (d. h. drücken Sie nicht Strg+C noch):

# trace-cmd record -P 10885 -p function_graph
  plugin 'function_graph'
Hit Ctrl^C to stop recording

Führen Sie eine Aktivität auf der Shell aus

Gehen Sie zurück zum anderen Terminal, wo Sie eine Shell mit einer bestimmten PID ausgeführt haben, und führen Sie einen beliebigen Befehl aus, z. B. ls Dateien auflisten:

# ls
Temp-9b61f280-fdc1-4512-9211-5c60f764d702
tracker-extract-3-files.1000
v8-compile-cache-1000
[...]

Gehen Sie zurück zu dem Terminal, in dem Sie die Ablaufverfolgung aktiviert haben, und drücken Sie Strg+C So beenden Sie die Ablaufverfolgung:

# trace-cmd record -P 10885 -p function_graph
  plugin 'function_graph'
Hit Ctrl^C to stop recording
^C
CPU1 data recorded at offset=0x856000
    618496 bytes in size
[...]

In der Ausgabe des Trace sehen Sie links die PID und die Bash-Shell und rechts die zugehörigen Funktionsaufrufe. Dies kann sehr praktisch sein, um Ihre Ablaufverfolgung einzugrenzen:

# trace-cmd report  | head -20

cpus=8
          <idle>-0     [001] 11555.380581: funcgraph_entry:                   |  switch_mm_irqs_off() {
          <idle>-0     [001] 11555.380583: funcgraph_entry:        1.703 us   |    load_new_mm_cr3();
          <idle>-0     [001] 11555.380586: funcgraph_entry:        0.493 us   |    switch_ldt();
          <idle>-0     [001] 11555.380587: funcgraph_exit:         7.235 us   |  }
            bash-10885 [001] 11555.380589: funcgraph_entry:        1.046 us   |  finish_task_switch.isra.0();
            bash-10885 [001] 11555.380591: funcgraph_entry:                   |  __fdget() {
            bash-10885 [001] 11555.380592: funcgraph_entry:        2.036 us   |    __fget_light();
            bash-10885 [001] 11555.380594: funcgraph_exit:         3.256 us   |  }
            bash-10885 [001] 11555.380595: funcgraph_entry:                   |  tty_poll() {
            bash-10885 [001] 11555.380597: funcgraph_entry:                   |    tty_ldisc_ref_wait() {
            bash-10885 [001] 11555.380598: funcgraph_entry:                   |      ldsem_down_read() {
            bash-10885 [001] 11555.380598: funcgraph_entry:                   |        __cond_resched() {

Probieren Sie es aus

Diese kurzen Beispiele zeigen die Verwendung von trace-cmd anstelle des zugrunde liegenden ftrace Der Mechanismus ist sowohl einfach zu bedienen als auch reich an Funktionen, darunter viele, die ich hier nicht behandelt habe. Um mehr zu erfahren und besser darin zu werden, konsultieren Sie die Manpage und probieren Sie die anderen nützlichen Befehle aus.


Linux
  1. Fehler beim Laden des Moduls Btusb mit Kernel 4.10.0-20-generic?

  2. CentOS / RHEL :Ausschluss mit Yum für Kernel-Updates

  3. Wie debuggt man den Linux-Kernel mit GDB und QEMU?

  4. Wie baut man ein Linux-Kernel-Modul so, dass es mit allen Kernel-Releases kompatibel ist?

  5. Kompilieren von GNU/Linux mit -O3-Optimierung

Linux-Kernel vs. Mac-Kernel

Verwalten und überwachen Sie Linux-Kernel-Module mit Kmon

Patchen Sie den Raspberry Pi Linux Kernel mit KernelCare KOSTENLOS!

Zeigen Sie Linux-Kernel-Modulinformationen mit dem Modinfo-Befehl an

Eingefrorenes Linux-System? Hier sind 3 Möglichkeiten, damit umzugehen

Debuggen des Linux-Kernels mit QEMU