Meltdown- und Spectre-Benchmarks: Weniger schlimm als erwartet

Schon kurz nach Bekanntwerden der Sicherheitslücke Meltdown und der beiden Spectre-Varianten Anfang Januar spekulierten diverse Medienberichte über die möglichen Leistungseinbußen der Patches zum Beheben der Lücken. Nach dem Einspielen der Patches sollten Systeme teilweise 30 Prozent langsamer rechnen als zuvor und die CPU-Last gar um bis zu 60 Prozent steigen. Mit dem notwendigen - vor allem zeitlichen - Abstand zeigt sich jedoch, dass diese Angaben eher maßlos übertrieben sind und der tatsächliche Leistungsverlust, der durch die Patches verursacht wird, wesentlich geringer ist, als zunächst angenommen.
Das Zustandekommen der eingangs genannten Werte ist dabei außerdem teils sehr fragwürdig, da insbesondere einige Benchmarks spezielle Probleme beim Testen der Patches verursachen. Das wiederum liegt an der besonderen Natur der Sicherheitslücken und den Strategien zum Beheben dieser, so dass die synthetischen Benchmarks teils sehr wenig über realistische Anwendungsszenarien verraten.
Der Linux-Distributor Suse geht sogar so weit(öffnet im neuen Fenster) , auf die Veröffentlichung seiner Benchmark-Ergebnisse zu verzichten und verweist als Grund hierfür auf die vielen Unwägbarkeiten und betroffenen Bestandteile beim Zusammenspiel aus Hard- und Software. Auch wir bieten hier aus ähnlichen Gründen lediglich einen Überblick über den Stand der Technik und werden auch nur ungefähre Leistungsverluste in Beispielen zitieren, die wir nachvollziehen können.
Denn klar ist eigentlich nur, dass auch bisher schon leistungskritische Faktoren wie Systemaufrufe, Interrupts, Kontextwechsel oder Seitenfehler ein klein bisschen mehr an negativem Einfluss hinzugewinnen und besonders I/O-intensive Anwendungen durch die Patches an Leistung verlieren. Laut dem Magazin The Next Plattform bestätigen(öffnet im neuen Fenster) dies inzwischen auch interne Tests von Intel. Demzufolge ist inzwischen auch mit nur noch höchstens zehn Prozent Leistungsverlust zu rechnen, was auch der Linux-Distributor Red Hat bestätigt.(öffnet im neuen Fenster)
Um zu verstehen, wie diese Erkenntnisse und auch Testergebnisse zustande kommen, ist ein grundlegendes Verständnis von Meltdown und Spectre notwendig, ebenso wie von den verfügbaren Gegenmaßnahmen. Das zeigt dann außerdem die Möglichkeiten zur Optimierung. Die folgenden Ausführungen beziehen sich dabei größtenteils auf Linux.
Linux zeigt Details der Patches
Immerhin ist das freie Betriebssystem das wohl mit Abstand am meisten eingesetzte System für Server und die Änderungen sind der Open-Source-Philosophie folgend wesentlich leichter nachvollziehbar als etwa bei dem proprietären Windows. Die Erläuterungen sollten aber in den meisten Fällen auch so ähnlich für Windows gelten, da sich die Schutzmechanismen gegen die Meltdown- und Spectre-Lücken auf beiden Systemen bei einer grundlegende Betrachtung vermutlich wenig voneinander unterscheiden. Abweichungen gibt es dagegen natürlich in der konkreten Implementierung.
Gegen Meltdown setzen beide System auf eine striktere Trennung von Kernel- und Userspace und gegen Spectre v2 auf Microcode-Updates und unter Linux zudem auf die sogenannten Retpolines. Zwar enthalten diese Patches selbst schon Optimierungen, einige Linux-Entwickler verweisen aber auch noch auf weitere Möglichkeiten.
Schneller und weniger oft zum Kernel
Ziel der Maßnahme gegen Meltdown ist es, den Adressraum des Kernels möglichst weitgehend von dem einer Userspace-Anwedung zu trennen. Unter Windows wird diese Technik als Kernel Virtual Adress (KVA) Shadow bezeichnet und unter Linux als Page Table Isolation (PTI).
Bisher war der Kernel standardmäßig in den Userspace gemappt, um einen Kontextwechsel zwischen Kernelspace und Userspace schneller durchführen zu können und den Translation Lookaside Buffer ( TLB(öffnet im neuen Fenster) ) hierbei nicht leeren zu müssen. Die CPU sorgt eigentlich für die dennoch notwendige strikte Trennung zwischen Kernel- und Userspace, was bei Meltdown allerdings geschickt umgangen wird.
Der Kernel wird mit den Patches nicht mehr so gemappt wie bisher, was dazu führt, dass der TLB bei einem Wechsel des laufenden Prozesses vom User- in den Kernelspace geleert wird und auf dem Rückweg ebenfalls. Dieses neue Verhalten führt damit allerdings zwangsläufig zu einem Leistungsverlust und ist genau deshalb auch bisher vermieden worden.
Systemaufruf und Kontextwechsel sind teuer
In einem völlig synthetischen Benchmark, auf den der Linux-Entwickler Dave Hansen in seinen PTI-Patches verweist(öffnet im neuen Fenster) , fällt die Rate zum wiederholten Aufrufen des Systemaufrufs lseek von 5,2 Millionen Aufrufen je Sekunde auf 2,2 Millionen Aufrufe bei Verwendung der PTI-Patches.
In ähnlichen Tests des Netflix-Angestellten Brendan Gregg(öffnet im neuen Fenster) zeigt sich darüber hinaus, dass sich die Leistungseinbußen mit steigender Anzahl der Systemaufrufe sogar noch vergrößern könnten. Bei 10 Millionen Systemaufrufen je Sekunde und CPU liegt der Leistungsverlust demnach gar bei 400 Prozent. Ähnliche Erkenntnisse liefert Gregg auch für Kontextwechsel(öffnet im neuen Fenster) : Je mehr diese vorkommen, desto größer ist der Leistungsverlust.
Greift ein Programm außerdem häufig auf einen vergleichsweise großen Bereich des Arbeitsspeichers zu (Working Set Size) und kommt es hierbei möglicherweise gar zum Auslagern des Speicherbereiches, sind die Leistungseinbußen entsprechend noch größer. Denn schlimmstenfalls versucht ein Programm dann auf nicht im Arbeitsspeichers befindliche Speicherbereiche zuzugreifen. Solch ein Seitenfehler(öffnet im neuen Fenster) verursacht eine Programmunterbrechung und das Neuladen des notwendigen Speicherbereichs.
Für Linux-Nutzer relativ leicht nachvollziehen lassen sich diese Ergebnisse mit kleinen Werkzeugen wie stress-ng , die es ebenfalls ermöglichen, das System mit dauerhaften Systemaufrufen oder auch Kontextwechseln - wie der Name sagt - zu stressen. Damit lassen sich ebenso absurd hohe Leistungseinbußen ermitteln. Aussagekräftig oder gar relevant ist das aber nicht.
So schreibt etwa Gregg, dass die typische Rate von Systemaufrufen der Anwendungen von Netflix bei etwa 10.000 pro Sekunde und CPU liege. Der damit verbundene Leistungsverlust ist also mehr oder weniger vernachlässigbar. Eine Reduktion und eventuell auch Überprüfung der Anzahl der Systemaufrufe ist aber eigentlich immer angebracht, auch völlig unabhängig von Meltdown. Und die möglichen und tatsächlich genutzten Optimierungen spielen hierbei noch gar kein Rolle.
Verbesserungen in Kernel und Anwendungen
Damit die Leistungseinbußen bei Kontextwechseln ein wenig abgemildert werden können, nutzen sowohl Windows als auch Linux Process-Context Identifiers (PCID), sofern die Hardware diese unterstützt. Diese sind zwar seit Jahren theoretisch verfügbar, werden aber erst seit Linux 4.14 sinnvoll unterstützt. Die PCID ermöglichen es, Seitentabellen, die im TLB gecacht sind, mit entsprechenden Kennzeichnungen zu markieren.
Das Nachschlagen (Lookup) im TLB wird dann nur für den jeweiligen Kontext erlaubt, wenn der auf der CPU laufende Thread die gleiche Kennzeichnung hat. Die restlichen Einträge im TLB werden schlicht ignoriert. Das vermeidet das Leeren des TLB bei einem Kontextwechsel.
Diese Theorie wird sowohl in den Tests von Hansen als auch in jenen von Gregg wie erwartet bestätigt. Weshalb diese Technik auch standardmäßig verwendet wird. Allerdings nur, wenn auch der Befehl INVPCID (Invalidate PCID) zur Verfügung steht, was ab Intels Haswell-CPU-Generation der Fall. Die Technik ist laut Aussage der Entwickler wohl nur in Kombination der beiden Befehle(öffnet im neuen Fenster) (PCID, INVPCID) sinnvoll umsetzbar.
Globale Seitentabellen für Intel Atoms
Auf dem Linux Storage, Filesystem and Memory-Management Summit (LSFMM 2018) erläuterte Hansen laut der Zusammenfassung des Magazins LWN.net(öffnet im neuen Fenster) darüber hinaus, dass er sogenannte globale Seitentabellen für jene Systeme umsetzen will, für die die PCID-Technik nicht zur Verfügung steht.
Neben älteren Chips betrifft das aber auch moderne Atom-Chips von Intel. Die TLB-Einträge des Kernels werden mit Hilfe dieser Technik dauerhaft vorgehalten. In dem von Hansen auch hierfür genutzten synthetischen Benchmark mit lseek wird dank der globalen Seitentabellen bei aktivierter PTI eine Steigerung von bis zu fast 40 Prozent(öffnet im neuen Fenster) im Vergleich zum Verzicht auf diese Technik erreicht.
Noch macht diese Technik den Linux-Entwicklern in einigen Details aber Probleme, weshalb diese noch nicht standardmäßig aktiviert ist. Die Umsetzung erscheint allerdings vorteilhaft und sollte deshalb kommen, so dass die Kosten für einen Systemaufruf damit künftig weniger hoch sind.
Riesige Seitentabellen für alle
In seinem Vortrag nennt Hansen weitere konkrete Techniken, die das Leeren des TLB verhindern sollen und von Anwendungsentwicklern entsprechend berücksichtigt werden sollten. Darüber hinaus empfiehlt Hansen außerdem die Nutzung der sogenannten Huge Pages (riesige Seitentabellen) beziehungsweise deren Abstraktion der Transparent Huge Pages(öffnet im neuen Fenster) (THP). Diese sollten einerseits die Zahl der Seitenfehler reduzieren und andererseits die Anzahl der Systemaufrufe zum Bearbeiten der Seitentabellen verringern.
In den Benchmarks von Gregg führt die Kombination von PCID-Nutzung und der Verwendung der THP wie erwartet zu einer deutlichen Reduzierung der durch die PTI verursachten Leistungseinbußen. Für eine vergleichsweise geringe Anzahl von Systemaufrufen pro CPU und Sekunde führt die Nutzung der THP sogar zu einer leichten Leistungssteigerung im Vergleich zum Verzicht auf jegliche PTI-Optimierungen.
I/O und Spectre v2 machen Probleme
Wie erwähnt hängen die Leistungseinbußen durch PTI von einer Vielzahl von Gegebenheiten ab, die vor allem von Anwendungsentwicklern durch eine optimierte Nutzung bestimmter Kernel-Funktionen zudem in vernachlässigbarem oder zumindest geringem Umfang gehalten werden können.
Trotzdem benutzen insbesondere Datenbanken, Proxy-Server oder unter Umständen auch Storage- und Logging-Systeme tendenziell eher viele Systemaufrufe, da diese besonders oft mit vergleichsweise kleinen Dateien I/O-Operationen ausführen.
Aus Sicht der Linux-Entwickler problematisch ist hier etwa der vielfach genutzte und auch in einigen Medienberichten erwähnten Benchmark Flexible I/O (FIO), der einfach nur Daten hin- und herschiebt, ohne diese weiterzuverarbeiten, dabei unter Umständen aber unnötig viele Systemaufrufe durchführt, wie die Linux-Entwickler auf dem LSFMM 2018(öffnet im neuen Fenster) vermuten.
Kernel-Barrieren gegen Spectre v2
Interessant an den Tests mit FIO ist jedoch die Erkenntnis, dass die Anzahl der I/O-Operation pro Sekunde bei aktivierten PTI-Patches nicht abfällt, sofern dem Programm genügend Prozessorzeit(öffnet im neuen Fenster) zur Verfügung steht. Zu den mit FIO bei Intel durchgeführten Tests, von denen The Next Platform berichtet, heißt es bei dem Magazin: "Da bei diesem Speicher-Benchmark die CPUs zu 100 Prozent ausgelastet sind, gibt es nur eine Richtung, in die sich die Leistung entwickeln kann, und das ist nicht aufwärts" .
Besonders kritisch wird dieser einzig mögliche Abwärtstrend zusätzlich durch den Schutz vor der Spectre-v2-Lücke (Branch Target Injection). Über diese lässt sich die CPU dazu bewegen, das Ziel einer indirekten Codeausführung zu verfälschen, um so Zugriff auf privilegierten Speicher zu erhalten.
Um das zu verhindern, kommt neben zwei weiteren Funktionen vor allem die Indirect Branch Restricted Speculation (IBRS) zum Einsatz. Diese wird gesetzt, sobald die CPU in einen privilegierten Modus fällt. In diesem Fall sorgt der Code dafür, dass die CPU die in einem weniger privilegierten Modus erlernten Ziele für den Codezweig (Branch Targets) vergisst.
Laut dem Magazin Ars Technica(öffnet im neuen Fenster) schätzt Intel, dass Verzweigungen mit einer Genauigkeit in den oberen 90 Prozent richtig prognostiziert werden. Mit IBRS fällt diese CPU-Optimierung weg und kann dementsprechend nicht genutzt werden, was offensichtlich zu massiven Leistungseinbußen führen muss.
Retpoline als Optimierung
In den erwähnten FIO-Tests von Intel ist der Leistungsverlust durch IBRS mit 64 KByte Blockgröße bei einer typischen Arbeitslast im Rechenzentrum auf Skylake-CPUs jedoch quasi nicht vorhanden. Das wird im Prinzip auch von den Linux-Entwicklern bestätigt. Auf CPUs der Broadwell- oder Haswell-Generation liegt der Leistungsverlust hier jedoch bei rund 30 Prozent.
Diese Unterschiede sind auf Architekturverbesserungen der Skylake-Architektur zurückzuführen. Die Linux-Entwickler nutzen deshalb auch standardmäßig die per Microcode-Update umgesetzte IBRS-Funktion auf Skylake.
Für ältere CPU-Generationen ist der Leistungsverlust jedoch so groß, dass Linux gegen Spectre v2 auf die sogenannten Retpoline (Return Trampoline) setzt. Diese Lösung erlaubt es, indirekte Branches von der spekulativen Ausführung auszunehmen, was unter anderem durch Änderungen am Compiler erreicht wird.
Mit den Retpolines fällt der Leistungsverlust von den genannten 30 Prozent für Broadwell und Haswell auf lediglich 1 bis 2 Prozent. Das ist auch der Grund, weshalb im Linux-Kernel für die älteren CPU-Generationen von Intel konsequent auf Retpoline gesetzt wird.
Schadensbegrenzung erreicht
Die aufgezählten I/O-Probleme und Leistungseinbußen treten aber nicht nur bei Storage-Systemen oder Echtzeit-Transaktionsverarbeitung (OLTP) in Datenbanken auf, sondern auch bei Netzwerk-I/O-Operationen. Letztere sind häufig besonders zeitkritisch und würden damit wohl in der Außenwahrnehmung durch mögliche Leistungseinbußen der Meltdown- und Spectre-Patches schlecht abschneiden.
Das ist aber auch schon vor Bekanntwerden der Sicherheitslücken so gewesen, weshalb es inzwischen einige Techniken gibt, um den Linux-Kernel gezielt zu umgehen. Genutzt wird dies zum Beispiel von Google, etwa seinen Load-Balancern , in dem von Intel an die Linux-Foundation gespendeten DPDK(öffnet im neuen Fenster) , beim Remote Direct Memory Access ( RDMA(öffnet im neuen Fenster) ) oder auch mit den vom Linux-Kernel bereitgestellten vDSOs(öffnet im neuen Fenster) .
Entwickler, deren Anwendungen dennoch weiterhin besonders starke Leistungseinbußen durch die Meltdown- und Spectre-Patches aufweisen, sollten sich demnach nach Optimierungsmöglichkeiten außerhalb des Kernels umsehen.
Im User-Space geht's schneller
Bestätigt wird diese Annahme auch durch die Betrachtung von Anwendungen, die durch die Patches besonders wenig betroffen sind. Dazu gehören insbesondere sehr CPU-intensive Anwendungen, die relativ wenig Zeit im Kernel verbringen. Beispielhaft ist hier das sogenannte Number-Crunching des High-Performance-Computing.
Die von Intel durchgeführten Tests zeigen hier bei der Verwendung der Meltdown- und Spectre-Patches Leistungseinbußen von lediglich 1 bis 2 Prozent und damit im Bereich der üblichen Abweichungen entsprechender Benchmarks.
Bugs fast wie alle anderen
Von den noch vor wenigen Monaten berichteten massiven Leistungseinbußen bleibt bei einer näheren Betrachtung also nicht mehr viel übrig - vor allem unter Beachtung der wenigen Zeit, die bisher zur Verfügung stand. Vor allem Entwickler systemkritischer Anwendungen werden sich in den kommenden Monaten wohl noch weiter mit den Verbesserungen befassen.
Und in Bezug darauf unterscheiden sich Meltdown und Spectre eigentlich kaum noch von den üblichen Bugs und Sicherheitslücken der IT-Welt, die quasi konstant gefunden und behoben werden.



