Spcnet.it Notizie geek e OSS/Linux. Su Telegram: InfoSec ITA Notizie
Home > Articolo > Il comando perf su Linux: guida al profiling della CPU e ai flame graph per sistemisti
Il comando perf su Linux: guida al profiling della CPU e ai flame graph per sistemisti

Quando “il carico è alto” non basta più come diagnosi

top e htop dicono che la CPU è occupata. Non dicono perché. Quando un server web risponde lentamente sotto carico, o un processo consuma più CPU del previsto senza una causa evidente, serve uno strumento che arrivi fino alle singole funzioni e, se necessario, alle istruzioni della CPU. Su Linux questo strumento è perf, il front-end user-space del sottosistema del kernel perf_events, capace di leggere contatori hardware, eventi software e tracepoint del kernel.

In questo articolo vediamo come installare perf, i comandi che un sistemista usa davvero (stat, top, record, report, trace), come interpretare le metriche di profiling della CPU, come generare un flame graph leggibile e quali sono le insidie più comuni — permessi, container, macchine virtuali e simboli di debug mancanti.

Installazione

perf è legato strettamente alla versione del kernel in uso, quindi la procedura di installazione varia per distribuzione:

# Debian/Ubuntu (serve il pacchetto per la specifica versione del kernel)
sudo apt install linux-tools-$(uname -r) linux-tools-generic

# Fedora / RHEL / CentOS
sudo dnf install perf

# Arch Linux
sudo pacman -S perf

Dopo l’installazione, una verifica rapida:

perf --version

Se la versione di perf non è perfettamente allineata a quella del kernel in esecuzione, è normale vedere avvisi di compatibilità: nella maggior parte dei casi lo strumento resta comunque utilizzabile.

I comandi fondamentali

perf stat: contare gli eventi

Il comando più semplice: esegue un programma (o si collega a un processo esistente) e conta gli eventi hardware e software rilevanti.

# Su un comando
perf stat ls /usr

# Su un processo già in esecuzione
sudo perf stat -p PID

# Su eventi specifici (ad esempio cache)
perf stat -e cache-references,cache-misses -p PID

perf top: la vista live

L’equivalente di top ma a livello di funzioni, non di processi: mostra in tempo reale quali funzioni del kernel e dello spazio utente stanno consumando più CPU in questo momento su tutto il sistema.

sudo perf top
sudo perf top -p PID
sudo perf top --cpu 0,1

Durante l’esecuzione, il tasto a permette di annotare il codice della funzione selezionata, utile per capire a quali righe corrisponde il tempo CPU osservato.

perf record e perf report: profilare e analizzare

perf record salva un profilo in un file (perf.data) che può essere analizzato in un secondo momento, anche su un’altra macchina:

# Tutta la macchina per 30 secondi
sudo perf record -g -a sleep 30

# Un processo specifico
sudo perf record -g -p PID

# Un comando dal suo avvio
sudo perf record -g ./myapp

L’opzione -g è quasi sempre da includere: cattura i call graph, cioè chi ha chiamato la funzione “calda” che si vede in cima al report. Senza -g si vede solo quale funzione consuma CPU, non il percorso che l’ha portata ad essere eseguita.

Per analizzare il file registrato:

# Modalità interattiva (TUI)
sudo perf report

# Output testuale, utile per script o CI
sudo perf report --stdio

# Call graph "piatto", più facile da leggere a colpo d'occhio
sudo perf report --call-graph flat

perf trace: tracciare le syscall con basso overhead

Simile a strace, ma pensato per avere un impatto molto più contenuto sulle performance del processo osservato — importante quando non si può permettere di rallentare un servizio in produzione solo per diagnosticarlo:

perf trace -p PID
perf trace -e openat,read,write -p PID
perf trace --summary -p PID sleep 10

perf list: scoprire gli eventi disponibili

perf list | grep cache
perf list | grep net
perf list | grep block

Come leggere le metriche di profiling della CPU

I numeri che perf stat restituisce hanno senso solo se si sa cosa cercare:

  • IPC (instructions per cycle): valori bassi indicano spesso cache miss frequenti o stalli della pipeline, non necessariamente “poca CPU disponibile”.
  • Branch misses: una percentuale elevata segnala che il predittore dei salti condizionali fatica a indovinare il percorso del codice — comune in codice con molte diramazioni dipendenti dai dati di input.
  • Page faults: valori anomali possono indicare pressione sulla memoria, non un problema puramente computazionale.
  • Task-clock: se il rapporto tra CPU utilizzata e tempo reale è inferiore a 1, il processo sta passando tempo in attesa (I/O, lock, scheduling), non calcolando.
  • Rapporto cache-miss / cache-references: è forse l’indicatore più utile per distinguere un’applicazione CPU-bound da una memory-bound.

Su sistemi di produzione, la raccomandazione è di usare una frequenza di campionamento moderata con -F 99 (invece che il default, più aggressivo), per limitare sia l’overhead sia la dimensione dei file generati. Il valore dispari (99 invece di 100) non è un dettaglio estetico: evita che il campionamento si sincronizzi con i timer periodici del sistema, cosa che falserebbe la distribuzione statistica dei risultati.

Dalla registrazione al flame graph

Un report testuale con centinaia di funzioni è difficile da leggere. Il flame graph, ideato da Brendan Gregg, risolve il problema visualizzando gli stack di chiamata come blocchi sovrapposti, dove la larghezza di ogni blocco è proporzionale al tempo CPU consumato da quella funzione (e dai suoi discendenti). I blocchi larghi in cima alla pila sono, quasi sempre, i colli di bottiglia da investigare per primi.

Due modi per generarlo:

# Metodo classico con gli script FlameGraph di Brendan Gregg
perf script > out.perf
./stackcollapse-perf.pl out.perf > out.folded
./flamegraph.pl out.folded > flamegraph.svg

# Dal kernel 5.8 in poi, integrato direttamente in perf
perf script report flamegraph

Il secondo metodo produce un file flamegraph.html interattivo direttamente, ma richiede il template d3-flame-graph disponibile sul sistema. In alternativa, l’applicazione GUI hotspot apre i file perf.data mostrando flame graph integrati senza passaggi intermedi, comoda per chi preferisce un’interfaccia desktop.

Un caso pratico: server web lento sotto carico

Un flusso di troubleshooting tipico per uno stack Nginx + PHP-FPM + MySQL sotto carico:

  1. Generare traffico realistico con ab o wrk mentre si registra il profilo di sistema: sudo perf record -g -a sleep 60.
  2. Analizzare il report con perf report e verificare quale componente domina il tempo CPU.
  3. Se domina Nginx: controllare worker_connections, keepalive_timeout e il costo del TLS. Molti simboli in libcrypto/libssl nel profilo suggeriscono handshake TLS completi troppo frequenti: vale la pena verificare la configurazione della session resumption.
  4. Se domina PHP-FPM: un valore alto su execute_ex punta a codice applicativo “pesante”; valori alti su _emalloc o zend_mm_alloc_* indicano allocazioni di memoria eccessive, spesso sintomo di strutture dati inefficienti o di troppi oggetti temporanei.
  5. Se domina lo stack I/O del kernel: il tempo si concentra nel filesystem o nel block layer, tipicamente a causa di molte letture/scritture piccole e frequenti; i rimedi più comuni sono il batching delle operazioni, l’introduzione di cache applicative e l’ottimizzazione delle query.

Un limite da non sottovalutare: perf record campiona solo il codice effettivamente in esecuzione sulla CPU. Il tempo passato in attesa su disco (I/O wait) non compare nel profilo. Se la CPU risulta bassa ma il servizio è comunque lento, la causa probabile è altrove: conviene controllare iowait e l’output di iostat prima di incolpare il codice applicativo.

Anche perf trace può rivelare dettagli preziosi: una singola pread64 con latenza massima di 12 ms su una query verso un database è un segnale da approfondire — può indicare I/O lento sul disco, un buffer pool “freddo” dopo un riavvio, oppure indici mancanti sulla tabella interrogata.

Insidie comuni

  • Permessi (perf_event_paranoid): su molte distribuzioni derivate da Debian/Ubuntu questo parametro limita l’accesso ai contatori hardware per utenti non privilegiati. Per abilitare l’accesso temporaneamente: sudo sysctl -w kernel.perf_event_paranoid=1; per renderlo permanente si crea un file in /etc/sysctl.d/. È buona norma ripristinare il valore originale dopo la sessione di debug, non lasciarlo permanentemente permissivo su un sistema di produzione.
  • Container: il profilo seccomp predefinito di Docker blocca la syscall perf_event_open. La soluzione più semplice è profilare dall’host specificando il PID del processo containerizzato: sudo perf top -p PID.
  • Macchine virtuali e cloud: i contatori hardware possono non essere esposti al guest. Per verificarlo: perf stat -e cycles true — se l’output mostra <not supported>, bisogna ricorrere agli eventi software, che funzionano ovunque indipendentemente dalla virtualizzazione.
  • Simboli di debug mancanti: senza i simboli corretti, i report mostrano solo indirizzi esadecimali illeggibili. Servono pacchetti come php8.3-fpm-dbgsym su Ubuntu o l’equivalente ottenuto con debuginfo-install su Fedora/RHEL; le versioni più recenti di perf possono anche scaricare i simboli automaticamente da un server debuginfod. I simboli del kernel, invece, si leggono direttamente da /proc/kallsyms e non richiedono pacchetti aggiuntivi (un pacchetto di debug del kernel serve solo per annotare le righe di codice sorgente).
  • Call graph senza frame pointer: per binari compilati senza frame pointer, serve l’opzione --call-graph dwarf, che però produce file molto più grandi. Per questo motivo le registrazioni con questa opzione vanno tenute brevi.

Quick reference

perf stat COMANDO
sudo perf stat -p PID sleep 10
sudo perf top
sudo perf top -p PID
sudo perf record -g -a sleep 30
sudo perf report
sudo perf trace -p PID
sudo perf trace --summary -p PID sleep 10
perf list

Conclusione

perf è uno degli strumenti più potenti a disposizione di un sistemista Linux per capire cosa succede davvero dentro una CPU sotto stress, ma la sua potenza è anche la sua complessità: i numeri grezzi (IPC, cache miss, branch miss) hanno senso solo se interpretati nel contesto del workload specifico, e un profilo CPU da solo non racconta tutta la storia quando il collo di bottiglia è l’I/O. La combinazione vincente, nella pratica, è quasi sempre la stessa: perf stat per una prima diagnosi rapida, perf record + flame graph per individuare visivamente dove si concentra il tempo, e strumenti complementari come iostat o perf trace per coprire i casi in cui il problema non è la CPU ma l’attesa.

Fonte: linuxblog.io.

Condividi: Twitter  |  Facebook  |  LinkedIn
Unisciti alla discussione

Questo è un blog del Fediverso: puoi trovare questo articolo ovunque con @blog@insicurezzadigitale.com e ogni commento/risposta apparirà qui sotto.

Se vuoi commentare su Il comando perf su Linux: guida al profiling della CPU e ai flame graph per sistemisti, utilizza la discussione sul Forum.

>> forum community