Performance: Die Basis im System

01.07.2006 von Martin Kuppinger
Die Performance eines Betriebssystems hängt von vielen Faktoren ab. Die entscheidende Basis ist aber die Architektur des Systems und die Optimierung potenzieller Engpässe. Der Artikel befasst sich mit einigen der zahlreichen Aspekte, die beim Windows Server 2003 die Performance beeinflussen.

Die Performance von Systemen wird von einer Vielzahl von Faktoren beeinflusst. Das macht die Optimierung der Performance auch zu einer „hohen Kunst“ in der IT, weil man nicht nur an einer Schraube drehen kann. Es reicht auch nicht aus, nur mehr und schnellere Prozessoren und viel Hauptspeicher zu installieren, weil diese auch optimal genutzt werden müssen.

Microsoft arbeitet schon seit den Frühzeiten von Windows NT an der Optimierung der Performance und hat im Laufe der Zeit auch manchen eingeschlagenen Weg wieder korrigiert. Zusammen mit der leistungsfähigeren Hardware ist die Performance über die Jahre auch kontinuierlich gestiegen. Dabei sind einerseits die Mindestanforderungen gewachsen, was zunächst die Vermutung nahe legt, dass die Performance des Betriebssystems selbst eigentlich schlechter geworden ist. Andererseits sind die Systeme aber auch im Vergleich mit früheren Versionen performanter geworden, wenn sie auf leistungsfähiger Hardware laufen, die heute deutlich besser genutzt werden kann.

Anders formuliert: Einfache Anforderungen lassen sich mit geringen Hardwareressourcen von einer älteren Windows-Version performanter lösen. Höhere Anforderungen lassen sich aber mit entsprechend leistungsfähiger Hardware unter den aktuellen Versionen von Windows, die mit mehr Hardware besser umgehen können, auch besser adressieren. Windows NT ist beispielsweise nicht auf die Nutzung von mehreren GByte Hauptspeicher ausgelegt, die heute in Servern Standard und nicht mehr die Ausnahme sind.

Nachfolgend werden verschiedene Änderungen, die im Betriebssystem vorgenommen wurden, im Detail und mit den erforderlichen Hintergründen zur Systemarchitektur erläutert. Der erste Teil der Serie behandelt die Änderungen im Kernel.

Synchronisation

Die Optimierungen, die die stärksten Verbesserungen bei der Performance bringen, erfolgen typischerweise entweder bei der grundlegenden Architektur oder im Kernel. Grundlegende Änderungen in der Architektur sind allerdings eher selten, in der Entwicklung seit Windows 2000 aber beispielsweise bei den Grafik- und Druckertreibern mehrfach durchgeführt worden.

Optimierungen auf der Ebene des Kernels sind dagegen bei jedem größeren Release zu finden. Der Kernel ist der Teil des Betriebssystems, der zu Beginn als Executive bezeichnet wurde und grundlegende Funktionen zur Verfügung stellt, wie unter anderem das Speichermanagement, die Interprozess-Kommunikationsmechanismen, die Treiberunterstützung, Sicherheitsfunktionen und das Scheduling, d.h. die Zuweisung von Rechenzeit zu Prozessen.

Ein weiterer wichtiger Funktionsbereich des Kernels ist die Synchronisation zwischen verschiedenen Prozessoren und, auf höherem Level, auch zwischen verschiedenen Prozessen. Dabei geht es konkret darum, den Zugriff auf kritische Daten so zu steuern, dass immer nur ein Prozessor mit diesen arbeiten kann. Bei den einzelnen Prozessoren gibt dafür den Mechanismus des IRQs (Hardware Interrupt Request). Der IRQ-Level des Prozessors wird dabei auf den höchstmöglichen Wert gesetzt, so dass dieser die Verarbeitung durchführen kann.

Wenn nun aber mehrere Prozessoren die gleichen Speicherbereiche nutzen, sind ergänzende Synchronisationsmechanismen für die Zugriffe auf kritische Informationen im globalen Speicher erforderlich. Dafür werden so genannte System Locks oder Systemsperren genutzt. Bei diesen wird ein Flag im globalen Speicher genutzt. Ist es nicht gesetzt, kann ein Prozessor die Sperre anfordern und aktivieren. Andere Prozessoren, die zugreifen möchten, müssen nun warten.

Hier kommt nun der Spinlock ins Spiel. Ein Spinlock ist eine Warteschleife, in der sich andere Prozessoren befinden, während ein Prozessor einen Lock gesetzt hat. Die wartenden Prozessoren – das können null, ein oder mehr sein – prüfen in regelmäßigen Abständen, ob die Sperre aufgehoben wurde. Dieses ständige Prüfen wird als spinning bezeichnet, woraus sich auch der Begriff des Spinlocks ergibt (Bild 1).

Bild 1: Der Ablauf bei Spinlocks.

Das bringt aber auch das Problem mit sich, dass einerseits Threads auf einem Prozessor, der den erforderlichen Lock nicht erhält, nicht weiter ausgeführt werden können. Zusätzlich muss ein Prozessor im Rahmen der Spinlocks einen Teil der verfügbaren Rechenzeit eben für das Spinning aufwenden.

Dieser auch als Lock contention bezeichnete Zustand, also der Wettbewerb oder Streit um die Sperren, ist einer der Gründe dafür, dass bei einem Zwei-Prozessor-System eben nicht 200% der Performance eines Ein-Prozessor-Systems erreichbar ist und bei einem Acht-Prozessor-System nicht annähernd die achtfache Performance zu schaffen ist. Die Problematik der Lock Contention wächst überproportional zur Anzahl der Prozessoren. Daher ist eine Optimierung in diesem Bereich unerlässlich. Dafür gibt es zwei Ansätze:

Microsoft hat beim Windows Server 2003 analysiert, in welchen Situationen es häufiger zu Locks auf Systemebene kommt. Diese Situationen hat man zu reduzieren versucht, indem man sie entweder gänzlich vermeidet, die Anzahl der Situationen für solche Locks reduziert oder zumindest den Code optimiert, für dessen Ausführung die Sperre benötigt wird.

Zusätzlich hat Microsoft auch an verschiedenen alternativen Verfahren gearbeitet. Eines sind die Queued Spinlocks, also die Kombination von Warteschlangen für Locks. Diese wurden bereits für einige wenige Locks mit Windows 2000 eingeführt. Beim Windows Server 2003 gibt es nun weitere Lock-Situationen, in denen mit solchen Warteschlangen gearbeitet wird. Der wesentliche Unterschied liegt darin, dass die Prozessoren, die auf den gesperrten Speicherbereich zugreifen müssen, nun nicht mehr ständig prüfen müssen, ob dieser wieder frei ist, sondern dass alle Anforderungen in eine Warteschlange geschrieben werden, die anschließend der Reihe nach abgearbeitet wird (Bild 2).

Bild 2: Die Arbeitsweise bei Queued Spinlocks.

Dieses Konzept hat deutliche Vorteile, da es einerseits zu weniger Prüfungen für den Status des Locks und damit einer Entlastung des Gesamtsystems führt und außerdem der Wettlauf zwischen verschiedenen wartenden Prozessoren entfällt. Falls mehrere Prozessoren warten, gibt es bei normalen Locks solche Konstellationen.

Bisher standen solche Queued Spinlocks allerdings nur für die Microsoft-Entwickler zur Verfügung, die direkt am Kernel gearbeitet haben. Ab dem Windows Server 2003 kann eine spezielle Variante davon, die In-Stack Queued Spinlocks, auch von anderen Entwicklern von Kernel-Code verwendet werden. Das ist hilfreich, wenn mehrere Threads, die auch auf unterschiedlichen Prozessoren laufen können, synchronisiert werden müssen.

Teilweise werden beim Windows Server 2003 für Intel-Prozessoren aber auch Interlocked Operations genutzt. Dabei handelt es sich um spezielle Prozessor-Instruktionen, mit denen Aktualisierungen im Speicher vorgenommen werden können. In diesem Fall übernimmt der Prozessor die Aufgabe, die sonst mit den Spinlocks vom Betriebssystem ausgeführt werden muss. Einige der Kernel-Operationen, für die bisher Spinlocks eingesetzt werden, werden nun auf diese Weise ausgeführt.

Weitere Mechanismen sind Non-Blocking Queues und Pushlocks. Im ersten Fall können Einträge in Warteschlangen im globalen Speicher ohne spezielle Sperren gesetzt werden. Im zweiten Fall können mehrere Prozessoren gemeinsam auf Datenstrukturen zugreifen. Solange sie die Informationen nur lesen, sind keine Sperren erforderlich. Diese müssen nur für den kurzen Zeitraum, in dem Änderungen vorgenommen werden, gesetzt werden. Diese Strukturen werden in einigen Fällen anstelle von Spinlocks genutzt. Auch bei den Pushlocks wird übrigens mit Warteschlangen für die exklusiven Anforderungen der Datenstruktur gearbeitet, die für den ändernden Zugriff erforderlich ist.

Die vielen Varianten, die mit dem Windows Server 2003 eingeführt wurden, machen deutlich, wie komplex die Optimierung des Systems für eine bessere Performance sein kann. Dabei muss man immer berücksichtigen, dass typische Locks nur Bruchteile von Sekunden dauern. Die Masse von Locks, die bei der Verarbeitung auftreten können, führt aber doch zu messbaren Leistungseinbußen, die es zu minimieren gilt.

Gerade bei diesem Thema wird auch klar, warum Microsoft die Anzahl der unterstützten Prozessoren nur langsam steigern kann. Theoretisch könnten zwar mehr oder minder beliebig viele Prozessoren genutzt werden – in der Praxis macht das aber nur Sinn, wenn ein weiterer Prozessor auch zu einem signifikanten Leistungszuwachs führt.

Scheduling

Das Locking-Thema spielt auch bei der Optimierung des Schedulers eine wichtige Rolle. Der Scheduler übernimmt zwei wesentliche Aufgaben:

Das Scheduling ist damit vor allem in Mehrprozessorsystemen eine komplexe Herausforderung, weil es hier eben auch noch um die Verteilung von Threads geht. Das betrifft auch Hyperthreading-Prozessoren und Dual-Core-Prozessoren. Bei Ersteren können zwei Threads quasi parallel verarbeitet werden, bei Multi Core-Prozessoren gibt es dagegen zwei oder mehr echte CPUs auf einem Prozessor. Kritisch ist das Locking bei Windows 2000 vor allem in Systemen mit mehr als acht Prozessoren gewesen, die entsprechend auch am stärksten von den Optimierungen beim Locking profitieren. Auch speziell für Hyperthreading-Prozessoren gibt es signifikante Verbesserungen.

Beim Windows Server 2003 hat man versucht, die Locking-Situationen beim Scheduling so weit wie möglich zu vermeiden oder zumindest die Häufigkeit zu reduzieren. Die wichtigste Maßnahme dabei ist, dass viele Warteschlangen und Listen mit zur Ausführung bereiten Threads nun nicht mehr systemweit und damit als globale Variable, sondern pro Prozessor geführt werden.

Im ersten Moment erscheint es zwar so, als könne es dadurch zu einer ungleichmäßigen Auslastung von Prozessoren kommen, weil Anforderungen nicht mehr gleichmäßig verteilt werden. In der Praxis werden Threads aber ohnehin nicht permanent zwischen Prozessoren hin- und hergeschoben, weil das ineffizient wäre, da auch Informationen zu den einem Thread zugeordneten Ressourcen angepasst werden müssten.

Zusätzlich hat man auch einiges an Code modifiziert, um die Phase, in der ein exklusiver Zugriff auf globale Speicherbereiche benötigt wird, zu minimieren. So ist beispielsweise der Code, mit dem die Priorität von Threads erhöht wird, nun so positioniert, dass er außerhalb der globalen Sperrphasen ausgeführt wird. Die Sperre erfolgt hier auf der Ebene des Threads.

Der Windows Server 2003 ist auch für den Einsatz auf Hyperthreading-Prozessoren optimiert. Beim Scheduling wird versucht, Situationen zu vermeiden, in denen Threads um die Ressourcen auf dem gleichen Prozessor konkurrieren. Außerdem wird erkannt, wenn sich einer der beiden logischen Prozessoren auf dem Chip in einem Spinlock befindet. In diesem Fall wird versucht, dem anderen logischen Prozessor möglichst viel Rechenzeit zuzuordnen, statt sie für die Überprüfung von Spinlocks zu vergeuden.

Daneben sind noch einige weitere interessante Verbesserungen für das Scheduling zu nennen, mit denen die Performance des Gesamtsystems erhöht werden soll:

Bild 3: In bestimmten Situationen kann es zu ineffizienten „Staus“ bei Warteschlangen kommen.

Auch hier waren also eine ganz beachtliche Liste einzelner Veränderungen erforderlich, um die Performance des Gesamtsystems zu erhöhen. Der Schwerpunkt liegt auch in diesem Fall wieder auf Mehrprozessorsystemen mit relativ vielen Prozessoren, weil hier der größte Handlungsbedarf bestand.

Speicherverwaltung

Auch bei der Speicherverwaltung hat man der Optimierung der Sperrsituationen ein hohes Gewicht gegeben. Sperren sind erforderlich, weil Informationen über die genutzten Speicherseiten im System verwaltet werden müssen. Die Informationen über die genutzten Speicherseiten werden in einer als PFN (Page Frame) bezeichneten Datenbank gehalten. Über einen Spinlock wird sichergestellt, dass nur ein Prozessor zu einem Zeitpunkt Änderungen in dieser Datenbank vornehmen kann. Das betrifft viele Operationen wie

Die wichtigste Maßnahme zur Reduktion der Spinlock-Situationen betrifft die Verringerung der Fälle, in denen überhaupt Sperren angefordert werden. So weit wie möglich werden Änderungen an der PFN auch zusammengefasst, um mehrere Operationen mit nur einer Sperre ausführen zu können. Außerdem wird in vielen Situationen mit den Interlocked Operations gearbeitet, die – wie oben beschrieben – deutlich performanter sind. Das ist beispielsweise bei den Sperren für AWE (Address Windows Extensions) der Fall. Mit diesen Maßnahmen hat es Microsoft nach eigenen Angaben erreicht, mit nur noch 5% der bisher erforderlichen Sperren auf einem 32-Prozessor-System auszukommen. Bei Systemen mit wenigen Prozessoren fällt die Reduktion natürlich deutlich niedriger aus.

Sperren für den Systemspeicher bei Ein- und Ausgabeoperationen, die bei Windows 2000 noch genutzt wurden, gibt es überhaupt nicht mehr. Die hier verwendeten Warteschlangen kommen ohne Sperren aus.

Auch in anderen Bereichen wie dem Umgang mit zugesicherten Speicherseiten und den AWE wird nun nicht mehr mit Spinlocks gearbeitet.

Der Performance ist auch das optimierte Zurücksetzen von Speicherbereichen (Zeroing) zuträglich. Sowohl beim Starten des Systems als auch beim Neustart von Anwendungen werden Speicherbereiche auf den Wert null gesetzt, um Sicherheitsrisiken zu minimieren. Bisher wurde diese Aufgabe von einem Thread für das Gesamtsystem übernommen. Beim Windows Server 2003 ist dagegen ein Thread pro Prozessor beim Boot und ein Pool von Threads beim Neustart von Anwendungen dafür verantwortlich.

Neu ist auch, dass größere Seiten auch im User Mode genutzt werden können. Die Standardseitengröße liegt bei 4 KByte. Das ist bei Systemen mit mehreren Gbyte-Hauptspeichern nicht sonderlich groß und führt zu sehr großen Seitentabellen, in denen die genutzten Seiten verwaltet werden müssen. Bei Windows 2000 können vom System bereits größere Seiten genutzt werden. Beim Windows Server 2003 gibt es für Anwendungen die User Mode Large Pages, die 4 MByte groß sind. Entsprechend ist der Verwaltungsaufwand bei Anwendungen, die sehr viel Speicher benötigen, um einiges geringer.

Auch ist die maximale Größe von kritischen Systemressourcen deutlich gestiegen. So können größere Pools für Auslagerungs- und Nichtauslagerungsseiten und ein größerer Cache für das Dateisystem verwaltet werden. Die dynamische Aufteilung dieser Ressourcen wurde ebenfalls optimiert. Allerdings fehlen weiterhin Funktionen, mit denen man die Aufteilung anpassen kann.

Neben diesen größeren Anpassungen gibt es noch mehrere kleinere Optimierungen, die in der Summe aber zu der höheren Performance vor allem bei hoch skalierbaren Systemen beitragen:

Weitere Optimierungen beim Kernel

Neben diese Anpassungen wirken sich noch einige weitere Optimierungen für den Kernel auf die Performance und die Skalierbarkeit aus:

Bei vielen weiteren Kernel-Funktionen wurden die Locking-Mechanismen optimiert, um so wenig wie möglich mit den Spinlocks arbeiten zu müssen.

Wie geht es weiter?

Zu den weiteren Veränderungen beim Windows Server 2003, die Einfluss auf die Performance des Gesamtsystems haben, zählt beispielsweise der Support für NUMA (Non-Uniform Memory Architecture), die Änderungen bei den Funktionen für die Ein- und Ausgabe auf Festplatte und im Netzwerk und Optimierungen bei verschiedenen Diensten und Anwendungen. Damit und mit verbesserten Funktionen für die Performanceanalyse befasst sich die nächste Folge dieser Artikelserie.