GNU/Linux >> Linux Esercitazione >  >> Linux

Analizza il kernel Linux con ftrace

Il kernel di un sistema operativo è uno dei software più elusivi in ​​circolazione. È sempre in esecuzione in background dal momento dell'accensione del sistema. Ogni utente realizza il proprio lavoro di elaborazione con l'aiuto del kernel, ma non interagisce mai direttamente con esso. L'interazione con il kernel avviene effettuando chiamate di sistema o facendole effettuare per conto dell'utente da varie librerie o applicazioni che utilizza quotidianamente.

Ho spiegato come tracciare le chiamate di sistema in un articolo precedente usando strace . Tuttavia, con strace , la tua visibilità è limitata. Consente di visualizzare le chiamate di sistema invocate con parametri specifici e, al termine del lavoro, vedere il valore o lo stato restituito indicando se sono state superate o non riuscite. Ma non avevi idea di cosa fosse successo all'interno del kernel durante questo periodo. Oltre a servire solo le chiamate di sistema, all'interno del kernel si verificano molte altre attività di cui sei ignaro.

Introduzione a Ftrace

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

Questo articolo mira a fare luce sul tracciamento delle funzioni del kernel utilizzando un meccanismo chiamato ftrace . Rende la traccia del kernel facilmente accessibile a qualsiasi utente Linux e con il suo aiuto puoi imparare molto sugli interni del kernel Linux.

L'output predefinito generato da ftrace è spesso massiccio, dato che il kernel è sempre occupato. Per risparmiare spazio, ho ridotto al minimo l'output e, in molti casi, ho troncato completamente l'output.

Sto usando Fedora per questi esempi, ma dovrebbero funzionare su una qualsiasi delle ultime distribuzioni Linux.

Abilitazione di ftrace

Ftrace fa ora parte del kernel Linux e non è più necessario installare nulla per usarlo. È probabile che, se utilizzi un sistema operativo Linux recente, ftrace è già abilitato. Per verificare che il ftrace è disponibile, esegui il comando mount e cerca tracefs . Se vedi un output simile a quello che segue, ftrace è abilitato e puoi facilmente seguire gli esempi in questo articolo. Questi comandi devono essere eseguiti come utente root (sudo è insufficiente.)

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

Per utilizzare ftrace , devi prima passare alla directory speciale come specificato nel comando mount sopra, da dove eseguirai il resto dei comandi nell'articolo:

# cd /sys/kernel/tracing 

Flusso di lavoro generale

Prima di tutto, è necessario comprendere il flusso di lavoro generale per acquisire una traccia e ottenere l'output. Se stai usando ftrace direttamente, non esiste alcun ftrace- speciale comandi specifici da eseguire. Invece, in pratica scrivi su alcuni file e leggi da alcuni file usando le utilità Linux standard da riga di comando.

I passaggi generali:

  1. Scrivi su alcuni file specifici per abilitare/disabilitare la traccia.
  2. Scrivi su alcuni file specifici per impostare/disimpostare i filtri per ottimizzare la traccia.
  3. Legge l'output di traccia generato dai file basati su 1 e 2.
  4. Cancella l'output precedente o il buffer dai file.
  5. Restringi il tuo caso d'uso specifico (funzioni del kernel da tracciare) e ripeti i passaggi 1, 2, 3, 4.

Tipi di traccianti disponibili

Sono disponibili diversi tipi di traccianti. Come accennato in precedenza, è necessario trovarsi in una directory specifica prima di eseguire uno qualsiasi di questi comandi perché i file di interesse sono presenti lì. Uso i percorsi relativi (anziché i percorsi assoluti) nei miei esempi.

Puoi visualizzare i contenuti dei available_tracers file per vedere tutti i tipi di traccianti disponibili. Puoi vederne alcuni elencati di seguito. Non preoccuparti ancora di tutti:

# pwd
/sys/kernel/tracing

# cat available_tracers
hwlat blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop

Tra tutti i traccianti forniti, mi concentro su tre specifici:function e function_graph per abilitare la traccia e nop per disabilitare la traccia.

Identifica il tracciante corrente

Di solito, per impostazione predefinita, il tracciante è impostato su nop . Cioè, "Nessuna operazione" nel file speciale current_tracer , che in genere significa che la traccia è attualmente disattivata:

# pwd
/sys/kernel/tracing

# cat current_tracer
nop

Visualizza output di tracciamento

Prima di abilitare qualsiasi traccia, dai un'occhiata al file in cui viene archiviato l'output di traccia. Puoi visualizzare il contenuto del file denominato trace usando il comando cat:

# traccia del gatto

# tracciante:nop
#
# voci-nel-buffer/voci-scritte:0/0   #P:8
#
#                                _-----=> irqs-off
#                               / _----=> necessario resched
#                          / _---=> hardirq/softirq
#                              || / _--=> profondità di prelazione
#                              ||| /     ritardo
#           TASK-PID     CPU#  |||| FUNZIONE TIMESTAMP
#              | | | |||| | |

Abilita funzione di tracciamento

Puoi abilitare il tuo primo tracciante chiamato function scrivendo function nel file current_tracer (il suo contenuto precedente era nop , indicando che la traccia era disattivata.) Pensa a questa operazione come a un modo per abilitare la traccia:

# pwd
/sys/kernel/tracing

# cat current_tracer
nop

# funzione echo> current_tracer

# cat current_tracer
funzione

Visualizza l'output di traccia aggiornato per la funzione di traccia

Ora che hai abilitato la traccia, è il momento di visualizzare l'output. Se visualizzi il contenuto della trace file, vedi molti dati che vengono scritti continuamente su di esso. Ho reindirizzato l'output e attualmente sto visualizzando solo le prime 20 righe per mantenere le cose gestibili. Se segui le intestazioni nell'output a sinistra, puoi vedere quale attività e Process ID sono in esecuzione su quale CPU. Verso il lato destro dell'output, vedi l'esatta funzione del kernel in esecuzione, seguita dalla sua funzione padre. Ci sono anche informazioni sul timestamp al centro:

# traccia del gatto sudo | head -20

# tracciante:funzione
#
# voci-nel-buffer/voci-scritte:409936/4276216   #P:8
#
#                                _-----=> irqs-off
#                               / _----=> necessario resched
#                           | / _---=> hardirq/softirq
#                              || / _--=> profondità di prelazione
#                              ||| /     ritardo
#           TASK-PID     CPU#  |||| FUNZIONE TIMESTAMP
#              | | | |||| | |
          -0       [000] d...  2088.841739:tsc_verify_tsc_adjust <-arch_cpu_idle_enter
          -0       [000] d...  2088.841739:local_touch_nmi
          idle>-0       [000] d...  2088.841740:rcu_nocb_flush_deferred_wakeup <-do_idle
          -0       [000] d...  2088.841740:tick_check_broadcast_expired <-do_idle
          -0       [000] d...  2088.841740:cpuidle_not_available <-do_idle
          -0   47 ... :cpuidle_select <-do_idle
          -0       [000] d...  2088.841741:menu_select <-do_idle
          -0       [000] d...  2088.841741:cpuidle_governor <-latency_select /pre>

Ricorda che la traccia è attiva, il che significa che l'output della traccia continua a essere scritto nel file di traccia finché non disattivi la traccia.

Disattiva traccia

Disattivare la traccia è semplice. Tutto quello che devi fare è sostituire la function tracciante con nop nel current_tracer il file e la traccia vengono disattivati:

# cat current_tracer
funzione

# echo nop> current_tracer

# cat current_tracer
nop

Abilita function_graph tracciante

Ora prova il secondo tracciante, chiamato function_graph . Puoi abilitarlo usando gli stessi passaggi di prima:scrivi function_graph al current_tracer file:

# echo function_graph> current_tracer

# cat current_tracer
function_graph

Traccia l'output di function_graph tracciante

Nota che il formato di output della trace il file è cambiato. Ora puoi vedere l'ID CPU e la durata dell'esecuzione della funzione del kernel. Successivamente, vengono visualizzate le parentesi graffe che indicano l'inizio di una funzione e quali altre funzioni sono state chiamate al suo interno:

# traccia di gatto | head -20

# tracciante:function_graph
#
#  DURATA DELLA CPU                  CHIAMATE DI FUNZIONE
# | | | | | | |
 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    | }

Abilita le impostazioni del tracciato per aumentare la profondità del tracciato

Puoi sempre modificare leggermente il tracciante per vedere una maggiore profondità delle chiamate di funzione usando i passaggi seguenti. Dopodiché, puoi visualizzare il contenuto della trace file e vedere che l'output è leggermente più dettagliato. Per leggibilità, l'output di questo esempio viene omesso:

# cat max_graph_depth
0

# echo 1> max_graph_depth ## oppure:
# echo 2> max_graph_depth

# sudo cat trace

Trovare le funzioni da tracciare

I passaggi precedenti sono sufficienti per iniziare con la traccia. Tuttavia, la quantità di output generata è enorme e spesso puoi perderti mentre cerchi di scoprire elementi di interesse. Spesso si desidera la possibilità di tracciare solo funzioni specifiche e ignorare il resto. Ma come fai a sapere quali processi tracciare se non conosci i loro nomi esatti? C'è un file che può aiutarti in questo:available_filter_functions fornisce un elenco di funzioni disponibili per il tracciamento:

# wc -l available_filter_functions  
63165 available_filter_functions

Cerca le funzioni generali del kernel

Ora prova a cercare una semplice funzione del kernel di cui sei a conoscenza. Lo spazio utente ha malloc per allocare memoria, mentre il kernel ha il suo kmalloc funzione, che fornisce funzionalità simili. Di seguito sono riportati tutti i kmalloc funzioni correlate:

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

Cerca il modulo del kernel o le funzioni relative al driver

Dall'output di available_filter_functions , puoi vedere alcune righe che terminano con del testo tra parentesi, come [kvm_intel] nell'esempio qui sotto. Queste funzioni sono correlate al modulo del kernel kvm_intel , che è attualmente caricato. Puoi eseguire lsmod comando per verificare:

# 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

Traccia solo funzioni specifiche

Per abilitare il tracciamento di funzioni o modelli specifici, puoi utilizzare il set_ftrace_filter per specificare quali funzioni dall'output precedente si desidera tracciare.

Questo file accetta anche il * pattern, che si espande per includere funzioni aggiuntive con il pattern specificato. Ad esempio, sto usando ext4 filesystem sulla mia macchina. Posso specificare ext4 funzioni specifiche del kernel da tracciare utilizzando i seguenti comandi:

# monta | grep home
/dev/mapper/fedora-home on /home type ext4 (rw,relatime,seclabel)

# pwd
/sys/kernel/tracing

# cat set_ftrace_filter

#### tutte le funzioni abilitate ####
$
$ 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
[...]

Ora, quando vedi l'output di traccia, puoi vedere solo le funzioni ext4 relativo alle funzioni del kernel per le quali avevi impostato un filtro in precedenza. Tutti gli altri output vengono ignorati:

# cat trace |head -20

## tracciante:funzione
#
# voci-nel-buffer/voci-scritte:3871/3871   #P:8
#
#                                _-----=> irqs-off
#                               / _----=> necessario resched
#                              / _---=> hardirq/softirq
#                              || / _--=> profondità di prelazione
#                              ||| /     ritardo
#           TASK-PID     CPU#  |||| FUNZIONE TIMESTAMP
#              | | | |||| | |
CUPSD-1066 [004] .... 3308.989545:ext4_file_getattr <-vfs_fstat
CUPSD-1066 [004] .... 3308.989547:3308.989547:ext4_getattr <--ext4_file_getattr
CUPSD-1066 [004 ] .... 3308.989552:ext4_file_getattr <-vfs_FSTAT
CUCSD-1066 [004] .... 3308.989553: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

Escludi funzioni dalla traccia

Non sempre sai cosa vuoi tracciare, ma sicuramente sai cosa non vuoi tracciare. Per questo, esiste questo file giustamente chiamato set_ftrace_notrace —notare il "no" lì dentro. Puoi scrivere il modello desiderato in questo file e abilitare la traccia, su cui viene tracciato tutto tranne il modello menzionato. Questo è spesso utile per rimuovere le funzionalità comuni che ingombrano il nostro output:

# cat set_ftrace_notrace
#### nessuna funzione disabilitata ####

Tracciamento mirato

Finora, hai tracciato tutto ciò che è successo nel kernel. Ma questo non ci aiuterà se desideri tracciare eventi relativi a un comando specifico. Per ottenere ciò, puoi attivare e disattivare la traccia su richiesta e, in mezzo, eseguire il nostro comando preferito in modo da non ottenere output aggiuntivo nell'output della traccia. Puoi abilitare il tracciamento scrivendo 1 a tracing_on e 0 per spegnerlo:

# cat tracing_on
0

# echo 1> tracing_on

# cat tracing_on
1

## # Esegui un comando specifico che desideriamo tracciare qui ###

# echo 0> tracing_on

# cat tracing_on
0

Tracciamento di PID specifico

Se desideri tracciare l'attività relativa a un processo specifico già in esecuzione, puoi scrivere quel PID in un file denominato set_ftrace_pid e quindi abilitare la traccia. In questo modo, la traccia è limitata solo a questo PID, il che è molto utile in alcuni casi:

# echo $PID > set_ftrace_pid 

Conclusione

Ftrace è un ottimo modo per saperne di più sul funzionamento interno del kernel Linux. Con un po' di pratica, puoi imparare a mettere a punto ftrace e restringe le tue ricerche. Per capire ftrace in modo più dettagliato e sul suo utilizzo avanzato, consulta questi eccellenti articoli scritti dall'autore principale di ftrace se stesso—Steven Rostedt.

  • Debug del kernel Linux, parte 1
  • Debug del kernel Linux, parte 2
  • Debug del kernel Linux, parte 3

Linux
  1. Pianificazione delle attività con il comando cron di Linux

  2. Pianifica un'attività con il comando Linux at

  3. Fai calcoli nella shell Linux con GNU bc

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

  5. Debug del kernel Linux con QEMU

Impara Linux con Raspberry Pi

Iniziare con il window manager i3 su Linux

Come controllare la versione del kernel in Linux

Lavorare con il kernel in tempo reale per Red Hat Enterprise Linux

Come trovare file con il comando fd in Linux

Proteggi Linux con il file Sudoers