In diesem Dokument wird beschrieben, wie Sie CPU-Bus-Sperren in Linux-Gastbetriebssystemen erkennen und beheben. Es werden die Symptome von CPU-Bus-Sperren, die Diagnose dieser Probleme mithilfe von Kernel-Logmeldungen, die Suche nach dem fehlerhaften Code und die Anwendung von Maßnahmen oder Korrekturen behandelt.
Übersicht
Eine CPU-Bus-Sperre tritt auf, wenn ein Prozessor ein Hardware-LOCK#-Signal senden muss, um exklusiven Zugriff auf den systemweiten Speicherbus zu erhalten. Dieses Problem tritt normalerweise in einem der folgenden Fälle auf:
- Eine atomare Anweisung wird für nicht ausgerichteten Speicher ausgeführt, der eine Cachezeilengrenze überschreitet (ein Split-Lock).
- Eine atomare Anweisung wird für Speicher ausgeführt, der als
uncacheable(UC) gekennzeichnet ist, z. B.Memory-Mapped I/O(MMIO).
Da die CPU eine globale Bussperre durchsetzt, müssen alle anderen Prozessoren und Geräte im Gastbetriebssystem warten, bis der Speichervorgang abgeschlossen ist. Eine hohe Anzahl von Bus-Sperren kann die CPU-Leistung erheblich beeinträchtigen.
Bei älteren Prozessoren wurden Bus-Locks nicht erfasst. Moderne x86-Prozessoren wie Intel Sapphire Rapids und höher oder AMD Zen 5 und höher verfügen über eine Hardwarefunktion, die CPU-Bus-Locks erkennt. Wenn eine Anweisung eine CPU-Bus-Sperre auslöst, gibt die CPU unmittelbar nach Abschluss der Anweisung eine Debug-Ausnahme (#DB) aus.
Ab Linux-Kernelversion 5.13 auf Intel und 6.13 auf AMD fängt der Linux-Kernel diese #DB-Ausnahme ab und wendet eine Gegenmaßnahme an, in der Regel durch Ratenbegrenzung des fehlerhaften Prozesses. Durch das absichtliche Versetzen des Threads in den Schlafmodus verhindert der Kernel, dass eine einzelne Anwendung den Speicherbus sättigt. So wird die Systemleistung für den Rest der Compute-Instanz auf Kosten der Leistung der fehlerhaften Anwendung aufrechterhalten.
Symptome
Wenn ein Prozess in Ihrem Linux-Gast CPU-Bus-Sperren auslöst, können die folgenden Symptome auftreten:
- Beeinträchtigte Anwendungsleistung: CPU-Bus-Sperren können zu unerwarteten Latenzen bei Anwendungen führen.
- Systemweite Lastspitzen: Die Reaktionsfähigkeit des Gesamtsystems kann abnehmen.
- Unerwartete Anwendungsabstürze: Wenn Sie den Kernel so konfigurieren, dass er Split- oder Bus-Locks streng behandelt (
split_lock_detect=fatal), kann die fehlerhafte Anwendung mit einemSIGBUS-Fehler abstürzen.
CPU-Bus-Sperren identifizieren
So stellen Sie fest, ob auf Ihrer Compute-Instanz CPU-Bus-Sperren auftreten:
- Wenn Sie das Logging der Ausgabe des seriellen Ports für Ihre Compute-Instanz aktiviert haben, prüfen Sie die Ausgabe des seriellen Ports auf einen CPU-Bus-Lock-Trace.
- Sehen Sie sich die Betriebssystemlogs (
/var/log/messages) Ihrer Compute-Instanz an, um nach einem CPU-Bus-Lock-Trace zu suchen.
Beispiel für einen CPU-Bus-Lock-Trace
x86/split lock detection: #DB: <process_name>/<pid> took a bus_lock trap at
address: 0x<address>
So erkennen Sie zukünftige CPU-Bus-Sperren:
- Logging der Ausgabe des seriellen Ports aktivieren
Logbasierte Benachrichtigungsrichtlinie für das folgende Log erstellen:
resource.type="gce_instance" log_id("serialconsole.googleapis.com/serial_port_1_output") textPayload=~"took a bus_lock trap"Dieser Logeintrag enthält den Prozessnamen (
<process_name>) und die Prozess-ID (<pid>), die für die CPU-Bus-Sperre verantwortlich sind, sowie die Adresse des Befehlszeigers, an der der Fehler aufgetreten ist.
Fehlerbehebung bei CPU-Bus-Sperren
Wenn Sie die fehlerhafte Anwendung entwickeln oder kompilieren, können Sie bestimmte C- oder C++-Compilerwarnungen verwenden, um Variablen und Strukturen zu identifizieren, die möglicherweise Split Locks verursachen.
Compilerwarnungen
Wenn Sie GCC oder Clang verwenden, kompilieren Sie Ihren Code mit den folgenden Flags, um Ausrichtungsprobleme zu erkennen:
-Wcast-alignoder-Wcast-align=strict: Diese Flags warnen Sie, wenn durch eine Pointer-Umwandlung die erforderliche Ausrichtung des Ziels erhöht wird. Das Umwandeln eines generischenchar*-Puffers in einenuint64_t*-Puffer und das Ausführen eines atomaren Vorgangs darauf ist eine klassische Ursache für Split Locks.-Waddress-of-packed-member: Dieses Flag warnt Sie, wenn Sie die Adresse eines gepackten Strukturmembers abrufen (z. B. mit#pragma pack(1)oder__attribute__((packed))). Da bei gepackten Strukturen die natürliche Speicherausrichtung ignoriert wird, überschreitet jede atomare Operation für ein Member einer gepackten Struktur mit hoher Wahrscheinlichkeit eine 64‑Byte-Cachezeilengrenze.
Nicht cachefähige (UC) Speicherlocks erkennen
Wenn atomare Vorgänge für nicht im Cache speicherbaren Arbeitsspeicher die CPU-Bus-Sperre verursachen, werden sie nicht durch Compilerwarnungen erkannt. Dieses Problem tritt in der Regel auf, wenn Sie mit dem Gerätespeicher interagieren:
- Speicherzuordnungen prüfen: Sehen Sie sich Ihren Code an und suchen Sie nach Verwendungen von
mmapmit Flags wieO_SYNCoder direktem Zugriff auf/dev/memoder/dev/uio. - Vermeiden Sie atomare Operationen auf MMIO: Verwenden Sie keine atomaren Operationen wie
__sync_fetch_and_addoderstd::atomicfür Speicherbereiche, die Geräte Registern oder nicht cachefähigen Speicherpuffern zugeordnet sind.
CPU-Bus-Sperren beheben
Probleme mit CPU-Bus-Sperren können Sie beheben, indem Sie die Speicherausrichtung im Quellcode der Anwendung korrigieren.
- Vermeiden Sie die Verwendung von
#pragma packoder__attribute__((packed))für Strukturen, die atomare Variablen, Mutexe oder Spinlocks enthalten. - Verwenden Sie Standardausrichtungsanweisungen wie
alignas(64)in C++11 oder__attribute__((aligned(64)))in C, um Variablen, die häufig in atomaren Operationen verwendet werden, an Cachezeilengrenzen auszurichten. - Achten Sie darauf, dass während der Kompilierung keine Warnungen im Zusammenhang mit der Ausrichtung angezeigt werden.
- Verwenden Sie nur standardmäßige Sperrmechanismen (Mutexes, Spinlocks) oder atomare Anweisungen für standardmäßigen, cachefähigen RAM, niemals für MMIO- oder UC-Speicher.
Wenn das Problem durch die Schritte zur Fehlerbehebung nicht behoben wurde, wenden Sie sich an Cloud Customer Care und geben Sie alle Informationen an, die Sie bei der Fehlerbehebung gesammelt haben.