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:
- Scrivi su alcuni file specifici per abilitare/disabilitare la traccia.
- Scrivi su alcuni file specifici per impostare/disimpostare i filtri per ottimizzare la traccia.
- Legge l'output di traccia generato dai file basati su 1 e 2.
- Cancella l'output precedente o il buffer dai file.
- 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 connop
nelcurrent_tracer
il file e la traccia vengono disattivati:# cat current_tracer
funzione
# echo nop> current_tracer
# cat current_tracer
nopAbilita function_graph tracciante
Ora prova il secondo tracciante, chiamato
function_graph
. Puoi abilitarlo usando gli stessi passaggi di prima:scrivifunction_graph
alcurrent_tracer
file:# echo function_graph> current_tracer
# cat current_tracer
function_graphTraccia 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 traceTrovare 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_functionsCerca 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 suokmalloc
funzione, che fornisce funzionalità simili. Di seguito sono riportati tutti ikmalloc
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 kernelkvm_intel
, che è attualmente caricato. Puoi eseguirelsmod
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 kvmTraccia 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 usandoext4
filesystem sulla mia macchina. Posso specificareext4
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_readEscludi 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
atracing_on
e0
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
0Tracciamento 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 puntoftrace
e restringe le tue ricerche. Per capireftrace
in modo più dettagliato e sul suo utilizzo avanzato, consulta questi eccellenti articoli scritti dall'autore principale diftrace
se stesso—Steven Rostedt.
- Debug del kernel Linux, parte 1
- Debug del kernel Linux, parte 2
- Debug del kernel Linux, parte 3