GNU/Linux >> Linux Esercitazione >  >> Linux

Traccia del kernel con trace-cmd

Nel mio precedente articolo, ho spiegato come usare ftrace per tracciare le funzioni del kernel. Usando ftrace scrivere e leggere dai file può diventare noioso, quindi ho usato un wrapper attorno ad esso per eseguire comandi con opzioni per abilitare e disabilitare la traccia, impostare filtri, visualizzare l'output, cancellare l'output e altro.

Il comando trace-cmd è un'utilità che ti aiuta a fare proprio questo. In questo articolo, utilizzo trace-cmd per eseguire le stesse attività che ho svolto nel mio ftrace articolo. Dato che rimando spesso a quell'articolo, ti consiglio di leggerlo prima di leggere questo.

Installa trace-cmd

Eseguo i comandi in questo articolo come utente root.

Il ftrace il meccanismo è integrato nel kernel e puoi verificare che sia abilitato con:

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

Tuttavia, devi installare trace-cmd utilità manualmente.

# dnf install trace-cmd -y

Elenca i traccianti disponibili

Quando si utilizza ftrace , è necessario visualizzare il contenuto di un file per vedere quali traccianti sono disponibili. Ma con trace-cmd , puoi ottenere queste informazioni con:

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

Abilita la funzione di traccia

Nel mio precedente articolo, ho usato due traccianti e farò lo stesso qui. Abilita il tuo primo tracciante, function , con:

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

Visualizza l'output della traccia

Una volta abilitato il tracciante, puoi visualizzare l'output utilizzando il show argomenti. Questo mostra solo le prime 20 righe per mantenere l'esempio breve (vedi il mio articolo precedente per una spiegazione dell'output):

# 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

Interrompi la traccia e cancella il buffer

La traccia continua a essere eseguita in background e puoi continuare a visualizzare l'output utilizzando show .

Per interrompere la traccia, esegui trace-cmd con la stop argomento:

# trace-cmd stop

Per cancellare il buffer, eseguilo con clear argomento:

# trace-cmd clear

Abilita il function_graph tracciante

Abilita il secondo tracciante, function_graph , eseguendo:

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

Ancora una volta, visualizza l'output usando show discussione. Come previsto, l'output è leggermente diverso dal primo output di traccia. Questa volta include una function calls catena:

# 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() {

Usa la stop e clear comandi per interrompere la traccia e cancellare il buffer:

# trace-cmd stop
# trace-cmd clear

Modifica il tracciato per aumentare la profondità

Se vuoi vedere più profondità nelle chiamate di funzione, puoi modificare il tracciante:

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

Ora, quando confronti questo output con quello che hai visto prima, dovresti vedere più chiamate di funzione nidificate:

# 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() {

Impara le funzioni disponibili per tracciare

Se si desidera tracciare solo alcune funzioni e ignorare il resto, è necessario conoscere i nomi esatti delle funzioni. Puoi ottenerli con l'list argomento seguito da -f . Questo esempio cerca la funzione comune del kernel kmalloc , che viene utilizzato per allocare memoria nel kernel:

# 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
[...]

Ecco il conteggio totale delle funzioni disponibili sul mio sistema di test:

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

Puoi anche tracciare le funzioni relative a uno specifico modulo del kernel. Immagina di voler tracciare kvm funzioni relative ai moduli del kernel. Assicurati che il modulo sia caricato:

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

Esegui trace-cmd di nuovo con la list argomento e dall'output, grep per le righe che terminano con ] . Questo filtrerà i moduli del kernel. Quindi grep il modulo del kernel kvm_intel e dovresti vedere tutte le funzioni relative a quel modulo del kernel:

# 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]

Più risorse Linux

  • Comandi Linux cheat sheet
  • Cheat sheet sui comandi avanzati di Linux
  • Corso online gratuito:Panoramica tecnica RHEL
  • Cheat sheet della rete Linux
  • Cheat sheet di SELinux
  • Cheat sheet dei comandi comuni di Linux
  • Cosa sono i container Linux?
  • I nostri ultimi articoli su Linux

Traccia funzioni specifiche

Ora che sai come trovare le funzioni di interesse, metti questa conoscenza per lavorare con un esempio. Come nell'articolo precedente, prova a tracciare le funzioni relative al filesystem. Il filesystem che avevo sul mio sistema di test era ext4 .

Questa procedura è leggermente diversa; invece di start , esegui il comando con il record argomento seguito dal "pattern" delle funzioni che si desidera tracciare. Devi anche specificare il tracciante che desideri; in questo caso, è function_graph . Il comando continua a registrare la traccia finché non la interrompi con Ctrl+C . Quindi, dopo alcuni secondi, premi Ctrl+C per interrompere la traccia:

# 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
[...]

Visualizza la traccia registrata

Per visualizzare la traccia che hai registrato in precedenza, esegui il comando con il report discussione. Dall'output, è chiaro che il filtro ha funzionato e vedi solo la traccia della funzione relativa a ext4:

# 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();

Traccia un PID specifico

Supponiamo di voler tracciare le funzioni relative a uno specifico identificatore persistente (PID). Apri un altro terminale e annota il PID della shell in esecuzione:

# echo $$
10885

Esegui il record comando di nuovo e passare il PID utilizzando il -P opzione. Questa volta, lascia funzionare il terminale (cioè non premere Ctrl+C ancora):

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

Esegui alcune attività sulla shell

Torna all'altro terminale in cui avevi una shell in esecuzione con un PID specifico ed esegui qualsiasi comando, ad esempio ls per elencare i file:

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

Torna al terminale in cui hai abilitato il tracciamento e premi Ctrl+C per interrompere la traccia:

# 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
[...]

Nell'output della traccia, puoi vedere il PID e la shell Bash a sinistra e le chiamate di funzione ad esso correlate a destra. Questo può essere molto utile per restringere il tracciamento:

# 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() {

Fai una prova

Questi brevi esempi mostrano come utilizzare trace-cmd invece del sottostante ftrace meccanismo è sia facile da usare che ricco di funzionalità, tra cui molte che non ho trattato qui. Per saperne di più e migliorarlo, consulta la sua pagina man e prova i suoi altri utili comandi.


Linux
  1. Analizza il kernel Linux con ftrace

  2. Patchare un binario con Dd?

  3. Bloccare gli aggiornamenti del kernel con Dpkg?

  4. Come eseguire il debug del kernel Linux con GDB e QEMU?

  5. Compilazione di GNU/Linux con ottimizzazione -O3

Kernel Linux vs. Kernel Mac

Gestisci e monitora i moduli del kernel Linux con Kmon

Patch del kernel Linux Raspberry Pi con KernelCare GRATIS!

Visualizza le informazioni sul modulo del kernel Linux con il comando Modinfo

Sistema Linux congelato? Ecco 3 modi per affrontarlo

Linux Centos con timestamp dmesg