Questo documento spiega come identificare e risolvere i problemi relativi ai blocchi del bus della CPU nei sistemi operativi guest Linux. Vengono trattati i sintomi dei blocchi del bus della CPU, come diagnosticare questi problemi utilizzando i messaggi di log del kernel, come individuare il codice difettoso e come applicare mitigazioni o correzioni.
Panoramica
Un blocco del bus della CPU si verifica quando un processore deve asserire un segnale hardware LOCK# per
acquisire l'accesso esclusivo al bus di memoria a livello di sistema. Questo problema si verifica in genere in una delle seguenti circostanze:
- Un'istruzione atomica opera su una memoria non allineata che attraversa un limite di riga della cache (un blocco suddiviso).
- Un'istruzione atomica opera sulla memoria designata come
uncacheable(UC), ad esempioMemory-Mapped I/O(MMIO).
Poiché la CPU asserisce un blocco del bus globale, tutti gli altri processori e dispositivi nel sistema operativo guest devono attendere il completamento dell'operazione di memoria. Un tasso elevato di blocchi del bus potrebbe ridurre notevolmente le prestazioni della CPU.
Mentre i processori più vecchi non tracciavano i blocchi del bus, i moderni processori x86
come Intel Sapphire Rapids e versioni successive o AMD Zen 5 e versioni successive, includono una
funzionalità hardware che rileva i blocchi del bus della CPU. Quando un'istruzione attiva un blocco del bus della CPU, quest'ultima genera un'eccezione di debug (#DB) immediatamente dopo il completamento dell'istruzione.
A partire dalla versione kernel 5.13 del kernel Linux su Intel e 6.13 su AMD, il kernel Linux intercetta questa eccezione #DB e applica una mitigazione, in genere limitando la velocità del processo difettoso. Forzando intenzionalmente il thread a
sospendersi, il kernel impedisce a una singola applicazione di saturare il bus di memoria,
preservando le prestazioni del sistema per il resto dell'istanza di computing a scapito
delle prestazioni dell'applicazione difettosa.
Sintomi
Se un processo nel guest Linux attiva blocchi del bus della CPU, potresti riscontrare i seguenti sintomi:
- Prestazioni delle applicazioni ridotte: i blocchi del bus della CPU potrebbero introdurre una latenza imprevista per le applicazioni.
- Picchi di carico a livello di sistema: la reattività complessiva del sistema potrebbe diminuire.
- Arresti anomali dell'applicazione: se configuri il kernel per gestire
i blocchi split o bus in modo rigoroso (
split_lock_detect=fatal), l'applicazione difettosa potrebbe arrestarsi in modo anomalo con un erroreSIGBUS.
Identificare i blocchi del bus della CPU
Per identificare se la tua istanza di computing sta riscontrando blocchi del bus della CPU, svolgi una delle seguenti operazioni:
- Se hai attivato il logging dell'output della porta seriale per l'istanza di computing, controlla l'output della porta seriale per una traccia di blocco del bus della CPU.
- Esamina i log del sistema operativo dell'istanza di calcolo (
/var/log/messages) per una traccia di blocco del bus della CPU.
Esempio di traccia del blocco del bus della CPU
x86/split lock detection: #DB: <process_name>/<pid> took a bus_lock trap at
address: 0x<address>
Per rilevare futuri blocchi del bus della CPU:
- Abilita il logging dell'output della porta seriale.
Crea un criterio di avviso basato su log per il seguente log:
resource.type="gce_instance" log_id("serialconsole.googleapis.com/serial_port_1_output") textPayload=~"took a bus_lock trap"Questa voce di log fornisce il nome del processo (
<process_name>) e l'ID processo (<pid>) responsabile del blocco del bus della CPU, nonché l'indirizzo del puntatore dell'istruzione in cui si è verificato l'errore.
Risolvi i problemi relativi ai blocchi del bus della CPU
Se stai sviluppando o compilando l'applicazione difettosa, puoi utilizzare avvisi specifici del compilatore C o C++ per identificare variabili e strutture che potrebbero causare blocchi suddivisi.
Avvisi del compilatore
Se utilizzi GCC o Clang, compila il codice con i seguenti flag per identificare
i problemi di allineamento:
-Wcast-aligno-Wcast-align=strict: questi flag ti avvisano quando un cast di puntatore aumenta l'allineamento richiesto della destinazione. Il cast di un bufferchar*generico in unuint64_t*e l'esecuzione di un'operazione atomica è una causa classica di blocchi suddivisi.-Waddress-of-packed-member: questo flag ti avvisa quando prendi l'indirizzo di un membro di una struct compattata (ad esempio, utilizzando#pragma pack(1)o__attribute__((packed))). Poiché le struct compattate non tengono conto dell'allineamento naturale della memoria, qualsiasi operazione atomica su un membro di una struct compattata ha un'alta probabilità di superare un limite di riga della cache di 64 byte.
Rilevamento dei blocchi di memoria non memorizzabili nella cache (UC)
Se le operazioni atomiche sulla memoria non memorizzabile nella cache causano il blocco del bus della CPU, gli avvisi del compilatore non lo rilevano. Questo problema si verifica in genere quando interagisci con la memoria del dispositivo:
- Controlla i mapping della memoria: esamina il codice per verificare l'utilizzo di
mmapcon flag comeO_SYNCo l'accesso diretto a/dev/memo/dev/uio. - Evita le operazioni atomiche su MMIO: non utilizzare operazioni atomiche come
__sync_fetch_and_addostd::atomicsu regioni di memoria mappate su registri del dispositivo o buffer di memoria non memorizzabili nella cache
Correzione dei blocchi del bus della CPU
Puoi risolvere i problemi di blocco del bus della CPU correggendo l'allineamento della memoria nel codice sorgente dell'applicazione.
- Evita di utilizzare
#pragma packo__attribute__((packed))su strutture che contengono variabili atomiche, mutex o spinlock. - Utilizza direttive di allineamento standard (come
alignas(64)in C++11 o__attribute__((aligned(64)))in C) per forzare l'allineamento delle variabili molto utilizzate nelle operazioni atomiche ai limiti della riga della cache. - Assicurati che non ci siano avvisi relativi all'allineamento durante la compilazione.
- Assicurati di utilizzare solo meccanismi di blocco standard (mutex, spinlock) o istruzioni atomiche su RAM standard memorizzabile nella cache, mai su memoria MMIO o UC.
Se la procedura per la risoluzione dei problemi non ha risolto il problema, allora contatta l'assistenza clienti Google Cloud e includi tutte le informazioni che hai raccolto durante la risoluzione dei problemi.