Bugreport: AMDs Dual-Core-Chips mit Zeitproblemen

(http://www.zdnet.de/magazin/39160057/bugreport-amds-dual-core-chips-mit-zeitproblemen.htm)

von Christoph H. Hochstätter, 18. Januar 2008

AMD bietet in seinen Dual-Core-CPUs Athlon 64 und Opteron mit Cool 'n' Quiet eine Energieverwaltung an. Sie führt jedoch zu Zeitproblemen und fehlerhaftem Verhalten mit bestimmter Software. ZDNet erläutert die Hintergründe.

Insbesondere in virtualisierten Umgebungen gibt es mit AMD-Dual-Core-Prozessoren erhebliche Probleme. VoIP-Telefongespräche werden zu schnell oder zu langsam wiedergegeben. Datenbanken weisen gar erhebliche Inkonsistenzen auf. Schuld daran ist Cool 'n' Quiet[1]. Im Gegensatz zum Powermanagement von Intel lässt sich bei AMDs Dual-Core-CPUs jeder Kern je nach Auslastung mit unterschiedlicher Taktfrequenz betreiben. Doch das führt dazu, dass die internen Uhren der beiden Kerne auseinanderlaufen.

Lösungsvorschläge dafür gibt es viele. Die einzige Lösung, die keine deutlichen Performanceeinbußen mit sich bringt, ist das Deaktivieren von Cool 'n' Quiet. Dies macht sich natürlich auf der nächsten Stromrechnung bemerkbar und kann im Rechenzentrum eine Anpassung der Kühlungstechnik erforderlich machen. Zudem sollte sich diese Maßnahme auch aus ökologischen Gründen verbieten. Um andere Lösungen für das eigene Szenario bewerten zu können, kommt man nicht umhin, sich mit der Materie Zeit auf einem Computer näher zu beschäftigen.

Ein Beispiel aus der Historie: 1982 präsentierte Bruce Artwick die erste Version seines Flugsimulators für den IBM-PC. Als kurze Zeit später die ersten PC-Clones mit höherer Taktfrequenz erschienen, flog die digitale Cessna unnatürlich schnell. Mit diesem Fall wird klar, wie wichtig Zeit als Faktor für viele Anwendungen ist. Während bei vielen klassischen Programmen, wie umfangreiches Numbercrunching, jede Geschwindigkeitssteigerung willkommen ist, müssen Anwendungen wie der Flugsimulator gebremst werden.

Durch die Verwendung von Timer-Bausteinen[2] wurden Probleme mit zu schnellen Anwendungen gelöst. In x86-PCs kam zunächst der Intel-8254-Timer-Bausteine zum Einsatz. Dieser Timer arbeitet mit 18,2 Hz und bietet eine Auflösung von knapp 55 Millisekunden. Mit dem IBM-PC/AT wurde eine Real-Time-Clock (RTC) eingeführt. Der RTC-Chip besitzt eine Auflösung von einer Millisekunde.

Seit der Einführung von ACPI liefert der Power-Management-Timer (PM-Timer) Zeitinformationen in einem einzigen Buszyklus. Weil der 8254- und der RTC-Chip über I/O-Ports programmiert werden müssen, werden sie heutzutage nicht mehr verwendet. Die Einrichtung eines neuen Interrupts nimmt zu viel Zeit in Anspruch.

Viele, aber nicht alle neuen Computer besitzen darüber hinaus einen High-Precision-Event-Timer (HPET)[3]. Dies ist ein eigener Timer-Baustein mit mindestens 10 MHz Takt. Damit ist eine Auflösung von mindestens 100 Nanosekunden gegeben. Höhere Taktraten und Auflösungen dürfen laut Spezifikation implementiert werden.

Der HPET bietet gegenüber dem PM-Timer den Vorteil, dass er 32 unabhängige Uhren besitzt, während der PM-Timer nur eine hat. Dies führt dazu, dass der PM-Timer periodisch, je nach Hardware alle 10 bis 15 ms, Interrupts liefern muss. Falls wartende Timerobjekte vorhanden sind, werden sie per Deferred Procedure Calls[4] (DPC) abgearbeitet. Im Falle von HPET kann jedes Timerobjekt direkt mit einer eigenen Uhr des HPET gekoppelt werden, so dass bereits die Hardware-Interrupts aperiodisch ausgelöst werden können.

Der Vollständigkeit halber sei noch der APIC-Timer (Advanced Programmable Interrupt Controller)[5] erwähnt. Er befindet sich auf dem Local APIC (LAPIC) jeder CPU seit dem Pentium Pro. Er wird jedoch traditionell von den Betriebssystemen nicht verwendet, da pro CPU ein LAPIC vorhanden ist und die Timer so gut wie nicht zu synchronisieren sind.

Viele Anwendungen benötigen heute Zeitstempel (Timestamps). Bei einem Zeitstempel kommt es meist nicht auf die Zeit in Zeiträumen an, sondern nur darauf, dass Ereignisse oder Objekte eine bestimmte Reihenfolge haben, die nicht geändert werden darf. Der häufigste Fall sind Datenbanken: Wenn in einem Hotelreservierungssystem das letzte freie Zimmer eines Hotels von zehn Reisebüros gleichzeitig gebucht wird, so darf nur ein Gast das Hotelzimmer tatsächlich bekommen.

Die Datenbank muss man hierfür mit dem höchsten Isolation-Level[6] "Serializable" konfigurieren. Aus Performancegründen werden häufig "illegale" Transaktionsschritte, wie das mehrfache Vergeben eines Hotelzimmers, zunächst zugelassen, dann aber anhand des Zeitstempels im Transaktionslog rückgängig gemacht.

Ein anderer Fall ist VoIP-Telefonie. Hier werden kurze Datenpakete per UDP-Protokoll verschickt. Bei UDP ist nicht garantiert, dass die Pakete im gleichen Zeitabstand oder in der gleichen Reihenfolge beim Empfänger ankommen, wie sie versendet wurden. Dieses Phänomen bezeichnet man als Jitter[7]. Daher verwendet der Empfänger einen Jitterbuffer, dessen Wert in der Regel zwischen 5 und 50 ms dynamisch während des Gesprächs angepasst wird. In diesem Jitterbuffer werden die Pakete sortiert. Dazu ist es erforderlich, dass die Pakete vom Absender mit einem Zeitstempel versehen werden.

Für diese Zeitstempel werden häufig die Time-Stamp-Counter[8] (TSCs) der CPUs verwendet. TSCs wurden mit dem Pentium eingeführt. Jede CPU erhält auf einer eigenen Leitung ihren Takt. Der TSC wird bei jedem Taktsignal um eins erhöht. Somit enthält der Time-Stamp-Counter die Anzahl der Takte seit dem Einschalten des Rechners. Mittels des CPU-Befehls RDTSC[9] kann der TSC in die Register EDX und EAX kopiert werden. Diese Form des Zeitstempelns bringt erhebliche Vorteile gegenüber der Verwendung eines externen Bausteins. Solange alle CPU-Kerne mit der gleichen Taktfrequenz arbeiten, liefern die TSCs aller Kerne zum gleichen Zeitpunkt auch den gleichen Wert. Eine geringe Differenz von wenigen Nanosekunden kann dabei sogar vernachlässigt werden.

Im Fall von Cool 'n' Quiet laufen die TSCs allerdings sehr schnell auseinander, weil die einzelnen CPU-Kerne des AMD-Prozessors unterschiedliche Taktraten annehmen können. Damit sind sie als Zeitstempelquelle nicht verwendbar. Sind diese Zeitstempel falsch, ist der Audio-Stream bei VoIP-Telefonaten[10] mit Fehlern behaftet. Auf einem Intel-Rechner mit Dual-Core-CPU wird der Stream korrekt ausgegeben[11]. Deutlich ist bei AMD das "Vibrato" im Rhythmus des Zeitscheibenwechsels von einem Core auf den anderen zu hören.

In diesem Beispiel macht ein Asterisk-Server[12] zunächst eine Ansage und verbindet dann zu einem weiteren Server. Sobald das Audio von einem fremden Server kommt, stammen auch die Zeitstempel von dort, und der Audio-Stream kann vom Empfänger wieder richtig interpretiert werden.

Je nach Anwendungsfall bieten der RDTSC-Befehl einen erheblichen Performance-Vorteil. Dieser Befehl ist nicht privilegiert und kommt direkt von der CPU. Das heißt, jede Anwendung kann ihn im User-Mode nutzen, ohne die Instruction-Pipeline zu verlassen und einen Cache-Miss zu riskieren. Muss die Pipeline ohnehin unterbrochen werden, zum Beispiel zur Synchronisation von Audio und Video in einem Multimedia-Stream, dann ist ein Interrupts generierender moderner externer Baustein, zum Beispiel HPET, günstiger.

Die Performancevorteile des TSC mögen beim Stempeln von UDP-Paketen, wie bei einem VoIP-Server, unerheblich sein. Bei einer Datenbankanwendung, die schon aus Gründen der Dokumentation jede Transaktion stempelt, macht sich die Verwendung der TSCs deutlich positiv bemerkbar.

Die TSCs als extrem performante Zeitquelle haben auch die Hersteller der Betriebssysteme entdeckt und machen davon Gebrauch. Bei AMD-Multiprozessor-Systemen führen sie jedoch zu Fehlern, etwa Abspielen von Sounds in falscher Geschwindigkeit oder extrem langsames Verhalten von Spielen. Um das Timer-Problem der AMD-Prozessoren zu beheben, gibt es mehrere Strategien, die aber nicht in jedem Fall helfen. Microsoft bietet für Windows XP und 2003 die BOOT.INI-Option /usepmtimer an. Windows Vista erkennt die betroffenen AMD-Systeme und benötigt diesen Parameter nicht mehr. Ferner kann Vista, anders als XP und 2003, den HPET nutzen. Im Falle von Linux können moderne Kernel mit dem Parameter notsc gebootet werden. Ist der Kernel HPET-fähig, wird ein vorhandener Baustein genutzt, ansonsten wird der PM-Timer verwendet.

Doch damit sind längst nicht alle Probleme gelöst. Nur die Programme, die das offizielle Timer-API des Betriebssystems verwenden, verhalten sich anschließend korrekt, aber dafür langsamer, was bei Datenbanksystemen deutlich spürbar ist. Probleme durch Programme, die RDTSC direkt verwenden, können mit dieser Methode nicht behoben werden.

Hier bietet AMD eine "Lösung" für Windows an. Der "Dual Core Optimizer" synchronisiert die TSCs periodisch und bei einem Taktwechsel. Multimedia-Anwendungen kommen damit sicher gut zurecht. Da die unterschiedliche Taktung der beiden Cores bei einem Datenbankserver eher eine Ausnahme darstellt, sollten auch hier relativ gute Ergebnisse erzielt werden. Eine Garantie für richtige Serialisierung des Transaktionslogs stellt diese Methode aber nicht da, so dass ein Restrisiko verbleibt.

Für Linux hat AMD keine vergleichbare Lösung. Dies hängt sicherlich mit den vielen unterschiedlichen Kernel-Versionen und vor allem auch mit den unterschiedlichen Power-Management-Daemons zusammen, die unter Linux zum Einsatz kommen.

Die Time-Stamp-Counter (TSCs) der Prozessoren bieten in vielen Fällen eine deutlich schnellere Quelle von Zeitstempeln, als dies mit Timer-Bausteinen möglich wäre. Dies gilt auch für die modernen HPET-Bausteine. Im Falle von AMDs Dual-Core-Prozessoren können die TSCs bei aktiviertem Cool 'n' Quiet jedoch nicht verwendet werden, da sie regelmäßig auseinanderlaufen.

Mögliche Lösungen führen immer zu einer Performance-Verschlechterung oder zu einem Restrisiko. Dem Betreiber einer kritischen Datenbankanwendung bleibt im Endeffekt keine andere Möglichkeit, als vom Hersteller der Software eine Garantie zu fordern, dass die Gesamtlösung auch auf einem AMD-Multiprozessorsystem ohne nennenswerten Performanceverlust betrieben werden kann.

Besonders kritisch sind virtuelle Umgebungen. Hier kann zusätzlich noch der Effekt auftreten, dass ein virtueller Prozessor in der realen Maschine nicht immer vom gleichen physikalischen Prozessor dargestellt wird. Dies bedeutet, dass Anwendungen, die in einer nicht virtualisierten Umgebung einwandfrei funktionieren, in einer virtualisierten Umgebung Probleme bereiten können.

Aktuelle Versionen von Vmware geben eine Warnung aus, wenn die virtuelle Maschine auf mehr als einem AMD-Core betrieben wird. Als mögliche Lösung wird aber nur das Abschalten von Cool'n'Quiet oder der Betrieb auf nur einem Prozessor genannt. Für zukünftige Prozessoren hat AMD versprochen, die TSCs nicht vom Prozessortakt abhängig zu machen.

URLs in diesem Artikel:
[1] = http://www.amd.com/de-de/Processors/ProductInformation/0,,30_118_9485_9487%5E10272,00.html
[2] = http://de.wikipedia.org/wiki/Programmable_Interval_Timer
[3] = http://en.wikipedia.org/wiki/HPET
[4] = http://en.wikipedia.org/wiki/Deferred_Procedure_Call
[5] = http://de.wikipedia.org/wiki/Advanced_Programmable_Interrupt_Controller
[6] = http://de.wikipedia.org/wiki/Isolation_%28Datenbank%29
[7] = http://de.wikipedia.org/wiki/Jitter
[8] = http://en.wikipedia.org/wiki/Time_Stamp_Counter
[9] = http://en.wikipedia.org/wiki/RDTSC
[10] = http://www.zdnet.de/i/et/server/2008/barcelona-ch/AMD-Dual.mp3
[11] = http://www.zdnet.de/i/et/server/2008/barcelona-ch/Intel-Dual.mp3
[12] = http://de.wikipedia.org/wiki/Asterisk_%28Telefonanlage%29