1 26/10/2026 10 min

perf_event è il sottosistema del kernel Linux che espone contatori di performance e campionamento eventi a strumenti come perf, e in parte a eBPF, profiler e monitoraggi low-level. Se vuoi capire dove finisce il tempo CPU, perché un servizio scala male o dove si concentrano i cache miss, è uno dei primi punti da conoscere.

Il concetto chiave è semplice: il kernel conta eventi hardware e software, li rende accessibili tramite file descriptor e consente di campionarli a intervalli controllati. In pratica puoi osservare quanto una CPU sta lavorando, su cosa sta lavorando e con quali costi, senza dover strumentare l’applicazione in modo invasivo.

Che cosa fa davvero perf_event

Il framework perf_event non è un singolo comando, ma una API kernel. Espone eventi come cicli CPU, istruzioni, cache references, cache misses, branch misses, page faults, context switch, CPU migrations, fault di sistema e molto altro. Da lì gli strumenti utente possono fare due cose principali:

  • Contare eventi in modo continuativo, per esempio il numero di cache miss di un processo.
  • Campionare eventi a frequenza o soglia, costruendo profili di dove il sistema spende tempo.

La differenza tra un contatore e un campionamento è importante. Un contatore ti dice il totale; il campionamento ti dice anche dove si verifica il costo, grazie a stack trace, simboli e call graph. È il motivo per cui perf top e perf record sono così utili quando un host è lento ma non sai se il collo di bottiglia è CPU, lock, memoria o scheduler.

Quando usarlo e quando no

Usa perf_event quando hai bisogno di capire il comportamento reale del sistema sotto carico. È particolarmente utile in questi casi:

  • servizi web con latenza alta e CPU non ovviamente satura;
  • processi che fanno molto lavoro kernel-side, ad esempio networking o storage;
  • analisi di regressioni dopo deploy o upgrade del kernel;
  • confronto tra due build, due configurazioni o due strategie di allocazione.

Non è lo strumento giusto per ogni problema. Se il servizio è giù per DNS, disco pieno, certificato scaduto o database non raggiungibile, partire da perf è tempo perso. Prima si verifica il layer corretto; poi si entra nel dettaglio CPU/memoria/kernel. Su un incidente di produzione, perf_event è una lente, non un sostituto del triage.

Architettura: eventi, PMU e file descriptor

Sotto il cofano, il kernel collega gli eventi a una PMU (Performance Monitoring Unit), cioè il blocco hardware che supporta contatori e interrupt di campionamento. Quando usi perf stat o perf record, in realtà stai aprendo uno o più file descriptor verso /proc e il sottosistema perf_event, configurando tipo di evento, periodo, PID o CPU target, e modalità di raccolta.

Gli eventi possono essere:

  • hardware: cicli, istruzioni, branch, cache miss, bus cycles;
  • software: page fault, context switch, CPU migrations, task clock;
  • tracepoint: punti di tracing esposti dal kernel;
  • raw: eventi specifici della microarchitettura o della PMU.

La parte interessante è che non sei limitato ai soli contatori hardware. Puoi combinare eventi software e tracepoint per capire, ad esempio, se un aumento di latenza è legato a troppi context switch, a fault di pagina o a lock contention nel kernel.

Prerequisiti e controlli rapidi sul sistema

Prima di raccogliere dati, conviene verificare che il kernel esponga la funzionalità e che i permessi siano adeguati. Su molte distribuzioni moderne perf è già disponibile come pacchetto, ma alcuni parametri di sicurezza possono limitarne l’uso da parte di utenti non privilegiati.

Controlli utili:

uname -r
which perf
perf --version
cat /proc/sys/kernel/perf_event_paranoid
cat /proc/sys/kernel/kptr_restrict

Interpretazione pratica:

  • perf --version deve restituire una versione coerente con il kernel installato o comunque compatibile.
  • /proc/sys/kernel/perf_event_paranoid più alto significa meno accesso per utenti non root.
  • /proc/sys/kernel/kptr_restrict può limitare la visibilità dei simboli kernel.

Se non hai i privilegi necessari, il comportamento atteso è un errore chiaro, non un output vuoto. In quel caso la chiusura del gap è amministrativa: eseguire i test con un account autorizzato o adeguare i parametri in modo controllato, tenendo conto del rischio di esposizione di informazioni sensibili.

Misurare: perf stat per i contatori

perf stat è il punto di partenza più pulito. Ti restituisce contatori aggregati sull’intervallo di esecuzione di un comando, di un PID o dell’intero sistema. È utile quando vuoi una fotografia numerica prima di entrare nel profiling dettagliato.

perf stat -d -- sleep 10

Con -d ottieni metriche più ricche, come IPC, cache references e miss. Se stai confrontando due build o due configurazioni, esegui sempre più run e guarda trend e varianza, non un solo valore. Un singolo campione può essere fuorviante per effetto di rumore di sistema, turbo, scheduler o I/O concorrente.

Un uso molto comune è misurare un processo specifico:

perf stat -p 1234 -d -- sleep 30

Qui il PID 1234 va sostituito con il processo di interesse. Il risultato atteso è una tabella con eventi e conteggi; se il processo termina prima, l’output può essere incompleto. In quel caso conviene agganciare il comando di avvio oppure usare un workload ripetibile.

Profilare: perf record e perf report

Quando vuoi sapere dove si accumula il tempo CPU, il flusso tipico è perf record seguito da perf report. Il primo campiona; il secondo analizza il file di dati generato.

perf record -F 99 -g -- ./applicazione
perf report

Con -F 99 imposti una frequenza di campionamento ragionevole per molti casi d’uso. Con -g chiedi il call graph, cioè la catena di chiamate che ha portato al campione. Il risultato utile non è solo il simbolo più costoso, ma la sequenza che lo ha attivato.

Se vedi molti campioni in funzioni generiche come allocator, memcpy, lock o scheduler, il problema può non essere nell’algoritmo principale ma nel modo in cui l’applicazione gestisce memoria, concorrenza o accessi condivisi. Questa è una delle ragioni per cui perf è così efficace nel debugging di regressioni “non ovvie”.

Flame graph e lettura dei call stack

Un flame graph non è parte stretta di perf_event, ma è uno degli sbocchi più utili dei dati raccolti con perf. L’idea è visualizzare i call stack in modo che la larghezza rappresenti il tempo campionato. Più un ramo è largo, più spesso compare nei campioni.

Nel mondo reale, il vantaggio è immediato: invece di leggere una tabella lunga e poco intuitiva, vedi subito i percorsi dominanti. È molto utile per servizi web, runtime gestiti e applicazioni con molte librerie condivise. Se il sistema è CPU-bound ma il grafico non mostra il tuo codice applicativo in alto, la colpa spesso sta nella libreria, nel runtime o in una serializzazione troppo costosa.

Eventi software che aiutano davvero

Non fermarti agli eventi hardware. In molti incidenti, i segnali più interessanti sono software. Alcuni esempi pratici:

  • context-switches per capire se il processo viene rimbalzato troppo spesso;
  • cpu-migrations per verificare se il task si sposta tra CPU più del previsto;
  • page-faults per indagare accessi memoria costosi;
  • task-clock per confrontare il tempo CPU effettivo con il wall clock.

Se un processo ha tanti context switch ma poca CPU utile, spesso il collo di bottiglia è nella sincronizzazione o nell’I/O. Se invece i page fault crescono durante un picco di traffico, conviene guardare l’allocazione memoria, il working set e l’eventuale swapping.

Tracepoint e analisi del kernel

I tracepoint consentono di osservare eventi interni del kernel con un dettaglio molto più specifico dei contatori generici. Sono utili per storage, networking, scheduler e memoria. Per esempio puoi indagare un problema di latenza I/O guardando eventi legati a blocchi, oppure verificare se il kernel sta spendendo tempo in una certa classe di wakeup o scheduling.

Questa analisi è preziosa quando il problema non è nel processo utente ma nel percorso kernel. Un server che sembra “lento” può in realtà essere penalizzato da interrupt storm, driver, filesystem o pressione su memoria. perf aiuta a distinguere la CPU dell’app dalla CPU del sistema.

Permessi, sicurezza e impatto operativo

Dal punto di vista operativo, perf_event è potente e quindi va usato con criterio. In ambienti multi-tenant o condivisi, i profiler possono rivelare dettagli sensibili sui carichi in esecuzione, sui simboli e persino sul comportamento del kernel. Per questo i sistemi moderni limitano spesso l’accesso ai contatori a utenti privilegiati o a policy più restrittive.

Se devi abilitare diagnostica per un team applicativo, definisci prima il perimetro: chi può leggere i dati, su quali host, per quanto tempo e con quale retention dei file di profiling. È una scelta di sicurezza oltre che di osservabilità.

Problemi tipici e come interpretarli

Ci sono alcuni errori ricorrenti nell’uso di perf. Il primo è prendere un dato singolo come verità assoluta. Il secondo è profilare senza carico rappresentativo. Il terzo è cercare il colpevole nel punto sbagliato della stack.

  • Campionamento troppo basso: perdi i picchi brevi e sottostimi alcuni percorsi.
  • Campionamento troppo alto: introduci overhead e distorci il risultato.
  • Simboli mancanti: il report mostra indirizzi o nomi poco leggibili invece delle funzioni.
  • Kernel o libreria senza debug symbols: l’analisi si ferma prima di arrivare al dettaglio utile.

La soluzione non è “alzare tutto” ma trovare il compromesso giusto: frequenza ragionevole, workload realistico, simboli disponibili e più run per confermare il pattern.

Workflow pratico per una diagnosi seria

Se vuoi usare perf_event in modo ordinato, il flusso più robusto è questo:

  1. Conferma il problema con metriche di alto livello: CPU, latenza, error rate, load, I/O, memoria.
  2. Isola il processo o il nodo interessato e raccogli un baseline con perf stat.
  3. Se il problema sembra CPU-bound, passa a perf record con call graph.
  4. Se sospetti kernel, usa eventi software o tracepoint mirati.
  5. Correla sempre il profilo con log applicativi, metriche di sistema e cambi recenti.

Questo approccio evita il classico errore di partire dal dettaglio prima di aver capito il contesto. perf è ottimo per la seconda metà dell’analisi, non per sostituire il triage iniziale.

Un esempio concreto: capire dove va il tempo

Immagina un servizio HTTP che risponde lentamente, ma senza saturazione evidente di CPU o RAM. Con perf stat scopri che il processo fa molti context switch e poche istruzioni per ciclo. Con perf record -g vedi che una parte consistente del tempo finisce in lock di libreria e in routine di serializzazione. Il problema non era il kernel, ma la concorrenza interna dell’applicazione.

In un altro caso, un job batch sembra lento perché la CPU è moderata, ma perf mostra un numero elevato di cache miss e branch miss. Qui il punto non è “più CPU”, bensì un access pattern inefficiente, magari una struttura dati poco cache-friendly o un algoritmo che fa salti continui in memoria.

Limiti da tenere presenti

perf_event è potentissimo, ma non è magico. Su alcune piattaforme o con alcuni eventi puoi avere contatori non disponibili, precisione limitata o overhead non trascurabile. Inoltre il profiling di sistemi con workload molto variabile richiede disciplina: stesso input, stessa finestra temporale, stesso tipo di carico, altrimenti i confronti diventano fragili.

Il limite più comune, però, resta umano: interpretare male i numeri. Un alto valore di cache miss non significa automaticamente che il codice sia “scritto male”; può essere la conseguenza di dati grandi, accessi random o una scelta progettuale consapevole. Il dato va letto insieme al contesto.

In sintesi operativa

perf_event è la base del profiling moderno su Linux: contatori, campionamento, call graph, eventi hardware e software, tracepoint. Se vuoi capire il comportamento reale del sistema sotto carico, è uno strumento da tenere pronto. Parti da perf stat per la fotografia generale, poi passa a perf record e perf report quando devi trovare il punto esatto in cui il tempo si disperde.

La regola pratica è semplice: osserva prima, modifica dopo. Con dati buoni, perf ti fa risparmiare ore di tentativi ciechi e ti porta più vicino alla causa reale del problema.