Vorhersagemechanismen in Fließbandarchitekturen
Transcription
Vorhersagemechanismen in Fließbandarchitekturen
Vorhersagemechanismen in Fließbandarchitekturen Projektarbeit im Wintersemester 2005/06 TU Darmstadt FG Rechnerarchitektur von Patrick Ediger [email protected] Betreuer: Prof. Dr. Rolf Hoffmann Darmstadt, Januar 2006 Gliederung 1. Sprungvorhersage Seite 1 1.1. Konflikte Seite 1 1.2. Kontrollflusskonflikte minimieren Seite 1 1.3. Statische Sprungvorhersage (static branch prediction) Seite 2 1.4. Dynamische Sprungvorhersage (dynamic branch prediction) Seite 2 1.5. Adaptive Sprungvorhersage (adaptive branch prediction) Seite 5 1.6. Kombinierte und hierarchisch organisierte Sprungvorhersageverfahren Seite 7 2. Sprungzielvorhersage Seite 9 3. Wertvorhersage Seite 10 3.1. Konstante Wertvorhersage (last value prediction) Seite 10 3.2. Differentielle Wertvorhersage (stride prediction) Seite 11 3.3. Kontextbasierte Wertvorhersage (context based prediction) Seite 11 3.4. Wertvorhersage als Instrument für Sprungvorhersage Seite 11 4. Literatur- und Abbildungsverzeichnis Seite 12 1. Sprungvorhersage 1.1. Konflikte Bei der Fließbandarchitektur (pipelining architecture) durchläuft ein Maschinenbefehl mehrere hintereinander geschaltete Einzeloperationen (Stufen). Dabei kann sich in jeder Stufe ein Befehl befinden, so dass sich bei einem Fließband mit n Stufen gleichzeitig n Befehle in der Verarbeitung befinden. Im Optimalfall verlässt also auch pro Takt ein Befehl das Fließband. Es gibt allerdings Konflikte, deren notwendige Beseitigung diese optimale Ausnutzung nicht mehr zulässt. Man unterscheidet drei Arten von Konflikten: Betriebsmittelkonflikte (structural hazards), Datenflusskonflikte (data hazards) und Kontrollflusskonflikte (control hazards)1. Ein Betriebsmittelkonflikt tritt auf, wenn mehrere Befehle gleichzeitig auf die gleiche Ressource (z.B. Speicher, ALU) zugreifen wollen und diese einen Mehrfachzugriff nicht unterstützt. In so einem Fall muss der konfliktverursachende Befehl und alle nachfolgenden gesperrt werden bis die Ressource frei ist (interlocking). Eine Verbesserung kann sein, solche Ressourcen, die häufig gebraucht werden, doppelt zur Verfügung zu stellen oder diese Ressourcen selbst als Fließband zu organisieren. Ein Datenflusskonflikt entsteht durch logische Abhängigkeiten zwischen Befehlen. Wenn ein Befehl A ein Ergebnis aus einem anderen Befehl B als Operand benutzt können wie beim Betriebsmittelkonflikt durch die Sperrung der nachfolgenden Befehle Wartezeiten entstehen, wenn der Befehl A schon im Fließband ist, aber das Ergebnis des Befehls B in dieser Stufe noch nicht zur Verfügung steht. Das Ergebnis eines Befehls wird normalerweise in einer der letzten Fließbandstufen in den Registerspeicher geschrieben. Die Rechenoperation, die das Ergebnis liefert, wird aber oft schon in einer früheren Stufe ausgeführt. Über einen Bypass kann dieses Ergebnis schon in einer früheren Stufe für nachfolgende Berechnungen zur Verfügung gestellt werden (bypassing, forwarding). Dadurch können Wartezeiten verkürzt werden. Ein Kontrollflusskonflikt ist dann vorhanden, wenn sich ein Befehl im Fließband befindet, der an dieser Stelle nicht ausgeführt werden soll. Ursache für diese Situation sind bedingte Sprungbefehle, bei denen in der ersten Fließbandstufe noch nicht entschieden werden kann, ob ein Sprung ausgeführt wird oder nicht. Werden die Befehle sequentiell abgearbeitet, kann es sein, dass alle dem Sprungbefehl nachfolgenden Befehle, die sich schon im Fließband befinden, annulliert werden müssen, wenn sich in einer späteren Stufe herausstellt, dass die Bedingung für einen Sprung erfüllt ist. Bei allen Konflikten entsteht also eine Strafe (penalty) von einem bis mehreren Taktzyklen, in denen der Prozessor untätig ist bzw. nicht erwünschte Befehle ausführt, die dann annulliert werden müssen. Um den Befehlsdurchsatz zu erhöhen ist es also sinnvoll, diese Konflikte zu vermeiden. Nachfolgend werden Methoden beschrieben, die gegenüber der sequentiellen Verarbeitung und anschliessender Annullierung von Befehlen bei Kontrollflusskonflikten, erhebliche Verbesserungen darstellen. 1.2. Kontrollflusskonflikte minimieren Nach [1] gibt es im wesentlichen drei Möglichkeiten, die Annullierungen bei Kontrollflusskonflikten, die in Verzögerungen resultieren, zu reduzieren. Die erste Möglichkeit besteht darin, die Sprungbefehle im Programm einfach wegzulassen. Bei den unbedingten Sprüngen ist das möglich, indem man die durch den Sprung aufgerufenen Programmteile in den aufrufenden Teil integriert. Bei bedingten Sprüngen ist das so nicht möglich, da in vielen Fällen erst zur Laufzeit entschieden werden kann, ob ein Sprung stattfindet oder nicht. Auf die Sprungbefehle kann aber verzichtet werden, wenn man jedem einzelnen Befehl eine Bedingung zuordnet, unter der er ausgeführt wird. Diese Bedingung kann auch leer sein, d.h. der Befehl wird immer ausgeführt. Diese bedingte Befehlsausführung (predication, conditional execution) hat den Nachteil, dass in jedem Befehl die Bedingung codiert sein muss. 1 In der Literatur sind für Betriebsmittelkonflikt auch die Begriffe Ressourcenkonflikt und Struktureller Konflikt gebräuchlich. Anstatt Datenflusskonflikt wird auch Datenkonflikt verwendet und Kontrollflusskonflikt wird auch Steuerungskonflikt oder Steuerflusskonflikt genannt. 1 Die zweite Möglichkeit ist die verzögerte Sprungtechnik (delayed branch). Dabei werden im Fließband alle dem Sprung nachfolgenden Befehle korrekt ausgeführt und dann nach dieser Verzögerung gesprungen. Das bedeutet für den Compiler, dass die Erzeugung des Maschinencodes deutlich komplexer wird, da man Sprungbefehle vorziehen kann. In den Verzögerungsstufen (delay slots) können nur solche Befehle platziert werden, die noch vor dem Sprung ausgeführt werden können. Sind die Abstände (Anzahl der Befehle) zwischen den Sprungbefehlen gering, so lassen sich bei Fließbändern mit vielen Stufen nicht alle Stufen sinnvoll füllen. Das Ergebnis ist dann nicht mehr optimal. Der Vorteil dieser Methode ist die einfache Realisierbarkeit, da auf Annullierung verzichtet werden kann. Die dritte Möglichkeit, die im folgenden detailliert behandelt wird, ist die Sprungvorhersage (branch prediction). Das Prinzip dabei ist, dass mit einer hohen Wahrscheinlichkeit schon in einer frühen Stufe des Fließbands vorhergesagt wird, ob ein bedingter Sprung verzweigen wird oder nicht. Nach dieser Vorhersage kann dann der nächste Befehl (entweder der sequentiell folgende oder der Befehl an der Sprungadresse) im Fließband spekulativ verarbeitet werden und muss mit hoher Wahrscheinlichkeit nicht annulliert werden. Es ist klar, dass weniger Annullierungen zu einem höheren Befehlsdurchsatz führen. Bei Fließbändern mit vielen Stufen wird dies umso wichtiger, da eine Annullierung alle einem Sprungbefehl nachfolgenden Befehle im Fließband betrifft. Zur Verdeutlichung der Dimensionen, um die es hier geht, seien einige Zahlen genannt. In [2] wird die Häufigkeit der Sprungbefehle mit 20 Prozent benannt. In [5] wird erwähnt, dass zwischen 15 und 30 Prozent aller Befehle Sprungbefehle sind. Dabei sind zwar die unbedingten Sprünge enthalten und eine Reduzierung durch verbesserte Compiler wird möglich sein, dennoch ist es ein bemerkenswerter statistischer Wert, der dafür spricht, dass die Sprungvorhersage ein wichtiges Instrument sein kann. Wie wichtig, das sollen die folgenden Zahlen zeigen. Nach [6] würde eine Verschlechterung der Rate der korrekt vorhergesagten Sprünge von 96 Prozent auf 93 Prozent bei einer Fließbandarchitektur mit 20 Stufen (z.B. Pentium 4), bei der eine Fehlannahme eine Strafe von bis zu 20 Takten verursachen kann, die Befehle pro Takt um 11 Prozent reduzieren. Eine gewaltige Verschlechterung des Befehlsdurchsatzes. Es sollen nun verschiedene Methoden zu einer solchen statistischen Vorhersage vorgestellt werden, deren Zuverlässigkeit unterschiedlich ist, aber bei einigen durchaus in den Bereich von deutlich über 90 Prozent korrekter Vorhersagen kommt. 1.3. Statische Sprungvorhersage (static branch prediction) Die Vorhersage bei einem Sprungbefehl kann zwei verschiedene Werte annehmen, der Befehl wird verzweigen bzw. der Befehl wird nicht verzweigen. Im folgenden werden diese Vorhersagen mit t (branch taken) und n (branch not taken) bezeichnet. Statisch bedeutet in diesem Fall, dass die Vorhersage bei jedem Sprungbefehl dieselbe ist, d.h. entweder wird immer angenommen, dass der Sprungbefehl verzweigt (predict taken) oder immer angenommen, dass der Sprungbefehl nicht verzweigt (predict not taken). Im letzteren Fall gibt es bei allen Befehlen, die tatsächlich nicht verzweigen, keine Verzögerung. Da aber, wie in [1] beschrieben, Sprungbefehle in nur einem Drittel aller Fälle nicht verzweigen, ist die statische Vorhersage mit der Annahme t effizienter. In etwa zwei Drittel der Fälle hätte man also eine korrekte Vorhersage. Diese Methode lässt sich dahingehend optimieren, dass man nicht alle Sprungbefehle gleich behandelt. Für die unbedingten Sprungbefehle muss die Vorhersage t gelten. Die Vorhersage t kann man auch für Sprungbefehle machen, die einen Rückwärtssprung auslösen würden, weil man dies als einen Hinweis darauf verstehen kann, dass es sich um eine Schleife handelt. Bei allen anderen Sprungbefehlen macht man die Annahme n. Ein Problem bei dieser Technik besteht darin, dass bei der Annahme t eine Adressberechnung notwendig ist. Wird diese Berechnung in der ersten Fließbandstufe durchgeführt, kann das Einfluss auf die Taktlänge haben. Wird sie aus diesem Grund in der zweiten Stufe durchgeführt, verzögert sich die Ausführung des Folgebefehls um einen Takt. 1.4. Dynamische Sprungvorhersage (dynamic branch prediction) Bei der dynamischen Sprungvorhersage wird die Tatsache ausgenutzt, dass Sprungbefehle, die 2 in einem Programm mehrfach ausgeführt werden, bestimmte Muster auftreten. So lässt sich zum Beispiel mit hoher Wahrscheinlichkeit korrekt vorraussagen, dass ein Sprungbefehl, der schon mehrere Male in Folge verzweigt hat, wieder verzweigen wird. Umgekehrt ist das ebenfalls möglich. Ein Sprungbefehl, der in vergangenen Aufrufen abwechselnd verzweigt und nicht verzweigt hat, wird mit hoher Wahrscheinlichkeit dieses Muster beibehalten. Dies geht auf eine Untersuchung von Lee und Smith zurück, die in [1] erwähnt wird. Demnach können über 90 Prozent der Sprungentscheidungen richtig vorhergesagt werden, indem man die Historie der jeweiligen Befehle betrachtet. Dafür ist es jedoch notwendig die Historie zu kennen, sie muss also gespeichert werden. Im Sprungvorhersagecache (branch prediction cache) wird zu jeder Adresse eines Sprungbefehls die jeweilige Historie gespeichert. Entsprechend des dort vorhandenen Eintrags kann nun eine Vorhersage gemacht werden. Ist für einen Sprungbefehl keine Historie gespeichert (z.B. bei der ersten Ausführung), muss zunächst eine statische Vorhersage gemacht werden. Nach der tatsächlichen Entscheidung (nicht nach der Vorhersage) muss der Sprungvorhersagecache aktualisiert werden. Die einfachste Realisierung dieser Technik ist die dynamische Sprungvorhersage mit einstufiger Historie (one bit predictor). Dabei wird die Vorhersage nach dem letzten aufgezeichneten Verhalten getroffen. Fand bei der letzten Ausführung eine Verzweigung statt, so wird die Vorhersage t getroffen und umgekehrt. Dieses Vorgehen kann als Zustandsgraph dargestellt werden (Abbildung 1), in dem die Ausgabe die Vorhersage darstellt und die Eingabe die vorher getroffenen Entscheidungen sind. Findet eine Verzweigung statt (im Unterschied zur Vorhersage sei die tatsächliche Entscheidung mit dem Großbuchstaben T bezeichnet) wird im Cache der Zustand 0 gespeichert, findet keine Verzweigung statt (N) wird 1 gespeichert. Im Zustand 0 wird die Vorhersage n getroffen, im Zustand 1 die Vorhersage t. Nach der tatsächlichen Entscheidung wird dann der Cache aktualisiert. N T 1 0 t n N T Abbildung 1: Dynamische Sprungvorhersage mit einstufiger Historie Das eben beschriebene Verfahren ist allerdings nicht sehr zuverlässig, wenn Sprungfolgen auftreten, die häufig wechseln, da bei einem stetigen Wechsel des Sprungverhaltens immer die falsche Entscheidung vorhergesagt würde. Abhilfe schafft die die dynamische Sprungvorhersage mit zweistufiger Historie (two bit predictor). Notwendig ist nun ein Cache, der zu jedem Sprungbefehl vier Zustände speichern kann, also die letzten beiden Entscheidungen über Verzweigungen. In Abbildung 2 ist der Zustandsgraph zu sehen, der diese Methode darstellt. Die Vorhersage unterscheidet sich gegenüber der der einstufigen Historie insbesondere durch den Zustand 10. Obwohl bei der letzten Ausführung nicht verzweigt wurde, wird der Sprung noch als verzweigend N T 11 10 t t N T N T 01 00 t n N T Abbildung 2: Dynamische Sprungvorhersage mit zweistufiger Historie 3 angenommen. Wurde bei den letzten beiden Sprüngen mindestens einmal verzweigt (Zustände 01, 10 und 11) so wird die Vorhersage t getroffen. Betrachtet man nun einige Beispielfolgen (Beispiel 1) für dieses Verfahren, sieht man, dass es auch hier zu Fehlvorhersagen kommen kann. Diese Art der Vorhersage ist also ebenfalls noch verbesserungswürdig. Beispiel 1: Beispiele bei der dynamischen Sprungvorhersage mit zweistufiger Historie a) TNNTNNTNN... Nach der Folge TN befindet man sich im Zustand 10, vorhergesagt wird t, tatsächlich wird aber N auftreten. Nach der Folge NN befindet man sich im Zustand 00, vorhergesagt wird n, tatsächlich wird aber T auftreten. Nach der Folge NT befindet man sich im Zustand 01, vorhergesagt wird t, tatsächlich wird aber N auftreten. Andere zweistufige Folgen treten nicht auf. Die Vorhersage ist also in 100 Prozent der Fälle falsch. b) TNTNTNTNTN... Nach der Folge TN befindet man sich im Zustand 10, vorhergesagt wird t, tatsächlich wird auch T auftreten. Nach der Folge NT befindet man sich im Zustand 01, vorhergesagt wird t, tatsächlich wird aber N auftreten. In 50 Prozent der Fälle ist die Vorhersage falsch. Gegenüber der Vorhersage mit einstufiger Historie eine Verbesserung c) NTTNTTNTT... Nach der Folge TN befindet man sich im Zustand 10, vorhergesagt wird t, tatsächlich wird auch T auftreten. Nach der Folge TT befindet man sich im Zustand 11, vorhergesagt wird t, tatsächlich wird aber N auftreten. Nach der Folge NT befindet man sich im Zustand 01, vorhergesagt wird t, tatsächlich wird auch T auftreten. In einem Drittel der Fälle ist die Vorhersage falsch. Eine solche Verbesserung findet man in der dynamischen Sprungvorhersage mit Sättigungszähler (two bit predictor with saturation counter). Dieses Verfahren ist in Abbildung 3 als Zustandsgraph dargestellt. Die vier Zustände geben an, ob ein Sprung als 1. 2. 3. 4. sicher verzweigend (st, strongly taken) sicher nicht verzweigend (sn, strongly not taken) eher verzweigend (wt, weakly taken) oder eher nicht verzweigend (wn, weakly not taken) vorausgesagt wird. Verzweigt ein Sprung mehrmals in Folge, so wird aus dem Zustand 11 die Vorhersage t gemacht. Wenn nun einmal nicht verzweigt wird, ändert sich an der Vorhersage für die nächste Ausführung noch nichts. Erst nach zwei Fehlannahmen wird die Vorhersage aus dem sicheren Zustand geändert. Allerdings ist die Vorhersage abhängig vom Startzustand. Beispielsweise würde die Sprungfolge NTNTNT aus dem Startzustand 10 zu 100 Prozent falsch vorhergesagt, aus dem Startzustand 11 nur zu 50 Prozent. N T 10 11 t (st) T t (wt) T N 00 n (sn) T N 01 n (wn) N Abbildung 3: Dynamische Sprungvorhersage mit Sättigungszähler 4 Eine weitere Modifizierung ist in Abbildung 4 dargestellt, die dynamische Sprungvorhersage mit Hysteresemethode (two bit predictor with hysteresis scheme). Die Modifizierung besteht darin, dass aus einem schwachen Zustand nach einer Fehlvorhersage nicht in den anderen schwachen Zustand gewechselt wird, sondern in den sicheren. Die Sprungfolge mit abwechselnd ausgeführter Verzweigung wird so in jedem Fall nur zu 50 Prozent falsch vorausgesagt (siehe Beispiel 2). Insgesamt lässt sich statistisch mit zweistufiger Historie nach [1] in über 90 Prozent der Fälle eine korrekte Vorhersage treffen. Dieses Verfahren ist mit dem entsprechenden Mehraufwand an Hardware auf n Bit, also n-stufige Historien, erweiterbar. N T 10 11 t (st) T N T 01 n (wn) t (wt) N 00 n (sn) N T Abbildung 4: Dynamische Sprungvorhersage mit Hysteresemethode Beispiel 2: Beispiele bei der dynamischen Sprungvorhersage mit zweistufiger Historie und Hysteresemethode a) TNNTNNTNN... Nach der Folge TN befindet sich der Automat entweder im Zustand 10 oder 00. Es wird entweder t oder n vorhergesagt. Danach wird nicht verzweigt, der Automat geht also in den Zustand 00 über und wird bei dieser Folge den Zustand nur noch zu 01 und wieder zurück wechseln, also immer n vorhersagen. Das ist in einem Drittel aller Fälle falsch. b) TNTNTNTNTN... Nach der Folge TN befindet sich der Automat entweder im Zustand 10 oder 00. Im Zustand 10 wird danach immer t vorhergesagt (Wechsel zwischen 10 und 11), was zu 50 Prozent falsch ist. Im Zustand 00 wird danach immer n vorhergesagt (Wechsel zwischen 01 und 00), was ebenfalls zu 50 Prozent falsch ist. c) NTTNTTNTT... Nach der Folge TN befindet sich der Automat entweder im Zustand 11 oder 01. Es wird entweder t oder n vorhergesagt. Danach wird verzweigt, der Automat geht also in den Zustand 11 über und wird bei dieser Folge den Zustand nur noch zu 10 und wieder zurück wechseln, also immer t vorhersagen. Das ist in einem Drittel aller Fälle falsch. 1.5. Adaptive Sprungvorhersage (adaptive branch prediction) Die Zuverlässigkeit der dynamischen Sprungvorhersage lässt sich noch steigern, indem man nicht nur die einzelnen Sprungfolgen, sondern Sprungmuster berücksichtigt. Bei der adaptiven Sprungvorhersage wird zu jedem Sprungbefehl ein solches Sprungmuster erstellt, indem die vergangenen n Sprungentscheidungen aufgezeichnet werden und in einer Sprunghistorientabelle (branch history table, BHT) gespeichert werden. Weiterhin gibt es eine Sprungmustertabelle (pattern history table, PHT), in der zu jedem Sprungmuster der Länge n eine Vorhersage gespeichert ist. Diese Vorhersage richtet sich normalerweise danach, wie in der Vergangenheit nach dem jeweiligen Muster entschieden wurde und ist abhängig vom verwendeten Verfahren für die Vorhersage (z.B. dynamische Sprungvorhersage mit Hysteresemethode). Sind sowohl die Sprungmustertabelle als auch die 5 Sprunghistorientabelle global, so werden auch miteinander korrelierende Sprungverhalten verschiedener Sprungbefehle berücksichtigt (correlation based prediction). In Abbildung 5 ist die grundsätzliche Funktionsweise der adaptiven Sprungvorhersage mit lokalen Sprungmustertabellen und lokalen Sprunghistorientabellen dargestellt. Beim Einlesen des Sprungbefehls wird in der BHT, die nach den Befehlsadressen organisiert ist, die Sprunghistorie ausgelesen, in diesem Beispiel 4 Sprünge. Die dem jeweiligen Muster zugehörige Vorhersage wird aus der lokalen PHT (in der BHT integriert) des Sprungbefehls gelesen und getroffen. Nach der tatsächlichen Entscheidung, werden die Sprunghistorientabelle und je nach Sprungvorhersageautomat die Sprungmustertabelle aktualisiert. Nach [1] lassen sich damit bis zu 97 Prozent aller Sprünge korrekt vorhersagen. Allerdings benötigt diese Methode für jeden Sprungbefehl eine eigene Sprungmustertabelle, was den Aufwand extrem hoch werden lässt. Eine weniger aufwändige Methode ist die adaptive Sprungvorhersage mit globaler Sprungmustertabelle. Das Funktionsprinzip ist identisch zu dem vorigen, nur dass zu jedem Sprungbefehl dieselbe (einzige) Sprungmustertabelle zugeordnet wird. Auf diese Weise werden immer noch häufige Muster korrekt vorhergesagt und der Aufwand ist deutlich geringer, jedoch ist diese Technik weniger zuverlässig, wenn verschiedene Sprungbefehle auch verschiedene Sprungmuster aufweisen. PHT ($0004) BHT Adresse Sprungmuster $0004 ... ... $50A4 ... NNNT + PHT($0004) TTTN + PHT($50A4) Sprungmuster NNNN NNNT ... TTNT TTTN TTTT Vorhersage 00 -> n 00 -> n 11 -> t 00 -> n 01 -> n Sprungvorhersage (z.B. dynamisch) PHT ($50A4) Sprungmuster NNNN NNNT ... TTNT TTTN TTTT Vorhersage 00 -> n 01 -> n 11 -> t 11 -> t 11 -> t ... Abbildung 5: Adaptive Sprungvorhersage mit lokalen Sprungmustertabellen und lokalen Sprunghistorientabellen Noch eine weitere Möglichkeit ist es, alle Sprungbefehle und deren Folgen zusammenzufassen. Es gibt dann nur eine globale Sprungmustertabelle und nur einen Eintrag in der Sprunghistorientabelle, weshalb sie von einer Tabelle zu einem Register schrumpft (branch history register, BHR). Die Vorgehensweise nennt sich globale adaptive Sprungvorhersage und ist ansonsten identisch mit den beiden vorangegangenen. In Abbildung 6 ist eine schematische Darstellung dieser Technik gegeben. Man spricht in dem Zusammenhang auch von (m,n)-Prädiktoren, wobei m die Anzahl der Bits im BHR ist und n die Anzahl der Bits der Vorhersageeinheit. Benötigt werden dabei 2m Tabelleneinträge in der Sprungmustertabelle oder anders gesagt, 2m Vorhersageeinheiten. Die lokale zweistufige dynamische Sprungvorhersage ist also ein (0,2)-Prädiktor. Die in der Abbildung dargestellte globale Sprungvorhersage ist ein (4,2)-Prädiktor. 6 PHT Sprungmuster NNNN NNNT ... TTNT TTTN TTTT BHR NNNT Vorhersage 00 -> n 00 -> n Sprungvorhersage (z.B. dynamisch) 11 -> t 00 -> n 01 -> n Abbildung 6: Globale adaptive Sprungvorhersage, (4,2)-Prediktor. Der Nachteil der globalen Methode ist, dass für die Vorhersage einer Sprungentscheidung oft die Historie von anderen Sprungbefehlen herangezogen wird. Es ist leicht einzusehen, dass es dann zu Fehlannahmen kommt. Von Pan, So und Rahmeh ist in [3] ein Vorschlag zur Verbesserung gemacht worden. Bei der Indexselektion (index selection, gselect) wird die Sprungmustertabelle vom globalen Modell ausgehend so erweitert, dass zu jedem Muster 2i Einträge existieren. Die ersten i Bits der Adresse des Sprungbefehls legen dabei fest, nach welchem dieser Einträge die Vorhersage getroffen werden soll (Abbildung 7a). Konflikte treten nun nur noch auf, wenn mehrere Sprungbefehle die gleichen unteren i Bits in ihrer Adresse aufweisen. Nach [4] weist die Indexselektion eine ähnlich hohe Zuverlässigkeit auf wie die lokale adaptive Sprungvorhersage (bei gleichem Ressourcenaufwand). Eine weitere Modifikation ist die Indexteilung (index sharing, gshare). Dabei werden die m Bits des BHR und die unteren m Bits der Sprungbefehlsadresse bitweise mit einem XOR (exklusives oder) verknüpft. Mit dem so entstandenen Hashwert wird auf die Sprungmustertabelle zugegriffen. Auf diese Weise werden bei gleichem Hardwareaufwand im Vergleich zur Indexselektion mehr Adressbits (weniger aliasing) und mehr Sprunghistoriebits (genauere Vorhersage) verwendet. Für die Darstellungen in Abbildung 7 heißt das, dass der Hardwareaufwand zur Speicherung der Sprungmustertabelle gleich groß ist, wenn k = i + m. Daraus folgt, dass k >= i und k >= m ist. BHR Adresse m Bits BHR i Bits Adresse k Bits k Bits XOR i+m Bits (a) gselect (b) gshare k Bits PHT Sprungmuster i+m Bits ... ... PHT Vorhersage 00 -> n ... Sprungmuster k Bits ... ... Vorhersage 00 -> n ... Abbildung 7: Indexselektion (a) und Indexteilung (b) 1.6. Kombinierte und hierarchisch organisierte Sprungvorhersageverfahren Die kombinierte Sprungvorhersage (hybrid branch prediction) bezeichnet die gleichzeitige Verwendung zweier Vorhersageverfahren (z.B. ein lokales und ein globales). Der Grund, eine Kombination als Lösung zu implementieren, ist, dass in allen Verfahren unterschiedliche Sprungmuster gut bzw. schlecht vorhergesagt werden, so werden bei der globalen Vorhersage die Korrelationen zwischen den Sprungbefehlen berücksichtigt, aber gleichzeitig das individuelle Sprungverhalten vernachlässigt. Eine situationsabhängige Verwendung könnte also die 7 Zuverlässigkeit erhöhen. Beide verwendeten Vorhersagetechniken machen dabei gleichzeitig eine Vorhersage. Ein zusätzliches Element, ein Auswahlbaustein (choice predictor), muss dann eines der beiden Ergebnisse auswählen. Dabei kann er vorgehen wie ein dynamisches Sprungvorhersageverfahren und bei Fehlannahmen das Verfahren wechseln (anstatt die Vorhersage bei Fehlannahme zu wechseln). Eine andere Art der Kombination von Vorhersageverfahren ist eine hierarchische Struktur. Dabei wird die hohe Zuverlässigkeit von komplexen Vorhersageverfahren und die kurze Verzögerung von einfacheren Verfahren kombiniert. Eine Methode ist die verfeinernde Sprungvorhersage (overriding branch prediction). In der ersten Fließbandstufe wird eine Vorhersage von einem einfachen Verfahren gemacht. Erst später, wenn aufgrund der ersten Vorhersage schon ein Folgebefehl im Fließband ist, wird die komplexe Vorhersage gemacht. Sind die Vorhersagen unterschiedlich, so werden die Folgebefehle annulliert und gemäß der komplexen Vorhersage fortgefahren. Stellt sich dann heraus, dass die komplexe Vorhersage falsch war, müssen zum zweiten mal die Folgebefehle im Fließband annulliert werden. Eine andere Methode ist die Verwendung von Caches. Ein Vorhersagezustandscache wird verwendet, um Vorhersagen zu jedem Sprungbefehl zu speichern, die dann sofort abrufbar sind. Sind in dem Cache keine Vorhersagen zu dem betreffenden Sprungbefehl vorhanden, so wird eine einfache schnelle Vorhersage gemacht. Der Cache wird später nach der tatsächlichen Sprungentscheidung durch eine komplexe Sprungvorhersageeinheit aktualisiert, so dass bei der nächsten Ausführung die Vorhersage bereits getroffen wurde. Zusammenfassend lässt sich sagen, dass jede der hier beschriebenen Vorhersageverfahren Vor- und Nachteile hat. Welches davon (auch modifiziert oder kombiniert) zum Einsatz in tatsächlichen Architekturen kommt, hängt von der Zuverlässigkeit, dem Hardwareaufwand und der Strafe bei Fehlvorhersagen ab. Diese hängt wiederum von der Realisierung des Fließbandes und den damit verbundenen Recheneinheiten und Caches ab. 8 2. Sprungzielvorhersage Bei der bisherigen Betrachtung wurde eine Tatsache völlig außer Acht gelassen. Nämlich die, dass die Sprungzieladresse bekannt sein muss, um den Befehl nach einem korrekt (oder auch nicht korrekt) vorhergesagten Sprung in das Fließband zu laden. Die Adresse lässt sich aber normalerweise erst in einer späteren Stufe berechnen. Um dieser Berechnung vorzugreifen und spekulativ (wie bei der Sprungvorhersage) einen Befehl auszuführen, wird ein Sprungzielcache (branch target buffer2, BTB) verwendet. In diesem Cache werden zu den Sprungbefehladressen die Zieladressen, auf die verzweigt wurde, gespeichert. Wird der Sprung ein weiteres mal ausgeführt, kann ohne Verzögerung das mögliche Sprungziel aus dem Cache geladen werden. Einige Sprungbefehle verzweigen allerdings nicht immer auf das gleiche Ziel, sondern sind abhängig von anderen Werten in Registern oder Speicherinhalten. Bei diesen Befehlen muss das berechnete Sprungziel mit dem spekulativen verglichen werden. Stimmt es nicht überein, müssen alle nachfolgenden Befehle wieder aus dem Fließband annulliert werden. Bei Sprungbefehlen, deren Zieladresse sich niemals ändert liefert diese Methode eine perfekte Vorhersage. Allerdings kann es Sprungbefehle geben, die einmalig ihr Sprungziel verändern und danach wieder auf das alte Sprungziel verweisen. Wegen solcher Fälle wurde von Calder, Grunwald und Lindsay, wie in [1] beschrieben, vorgeschlagen, eine Gewichtung der Eintragung im Sprungzielcache einzuführen. Wie bei der dynamischen Sprungvorhersage wird hier die Vorhersage nur verändert (durch den neuen tatsächlich berechneten Wert ersetzt), wenn ein Sättigungszähler einen bestimmten Wert erreicht hat. Dieser Zähler kann analog zum Sprungvorhersageverfahren nach richtigen und falschen Vorhersagen erhöht bzw. verringert werden. In dem eben beschriebenen Verfahren wird allerdings jeweils nur die Folge von einzelnen Sprungzielen betrachtet. Auch hier kann man Verbesserungen der Zuverlässigkeit erreichen, wenn man ein adaptives Verfahren anwendet, dass analog zum Sprungmuster beim Sprungvorhersageverfahren einen Sprungpfad betrachtet. Im Sprungpfad (path history register, PHR) sind die Zieladressen der vorher ausgeführten Sprünge gespeichert. In Abbildung 8 ist das Prinzip eines globalen Verfahrens dargestellt. Analog zur Sprungmustertabelle aus den Sprungvorhersageverfahren wird hier eine Pfadhistorientabelle verwendet, die zu jedem Muster eine Sprungzieladresse zuordnet. In der Abbildung wird aus dem PHR die Historie von Zieladressen ZA1ZA2-ZA1-ZA2 gelesen. Dieser Folge wird in der Pfadhistorientabelle die Zieladresse ZA1 zugeordnet. Nach der Berechnung des tatsächlichen Sprungziels wird das PHR aktualisiert und gegebenenfalls die Pfadhistorientabelle, wenn das Sprungziel von der Vorhersage abweicht. Pfadhistorientabelle Sprungmuster PHR ZA1 – ZA2 – ZA1 – ZA2 ZA1 – ZA2 – ZA1 – ZA2 ZA3 – ZA3 – ZA3 – ZA1 ... Vorhersage ZA1 ZA3 ... Abbildung 8: Globale Sprungzielvorhersage 2 Anstelle von branch target buffer verwendet man auch die englischen Begriffe branch target cache oder target instruction cache. 9 3. Wertvorhersage Die Wertvorhersage ist ein Instrument, das es ermöglicht Ergebnisse von Berechnungen vorherzusagen. Das ist interessant für Fälle, in denen im Fließband befindliche Befehle Operanden benutzen, die von direkt vorangehenden Befehlen als Ergebnis berechnet werden. In solchen Fällen, in denen diese Datenflusskonflikte nicht durch einen Bypass gelöst werden können (wie z.B. bei einem Ladebefehl, der einen Wert aus dem Hauptspeicher lädt), kann durch die Vorhersage der Speicheradresse schon vor dem eigentlichen Laden des Wertes der spekulative Wert an die nachfolgenden Befehle weitergegeben werden. Auch Kontrollflusskonflikte können durch die Wertvorhersage gelöst werden, nämlich indem man bei bedingten Sprüngen nicht mehr statistisch eine Sprungentscheidung vorhersagt, sondern mit vorhergesagten Werten die Bedingung für einen Sprung einfach ausrechnet. Da allerdings eine Wertvorhersage nicht an die Zuverlässigkeit von Sprungvorhersageverfahren herankommt, kann diese Technik lediglich eine Erweiterung dieser darstellen. Im den folgenden drei Abschnitten sollen Methoden zur Wertvorhersage vorgestellt werden. 3.1. Konstante Wertvorhersage (last value prediction) Hierbei wird in einer Wertvorhersagetabelle (value prediction table, VPT) zur jeweiligen Befehlsadresse ein Wert gespeichert. Bei der ersten Ausführung dieses Befehls ist also noch kein Wert gespeichert. Bei erneuter Ausführung kann jedoch schon dieser Wert ausgelesen und als spekulatives Ergebnis benutzt werden. Stellt sich in der nachträglichen Überprüfung der Vorhersage heraus, dass der Wert falsch war, müssen die nachfolgenden Befehle annulliert und erneut ausgeführt werden. Die Strafe, die dabei verursacht wird, könnte sogar gegenüber der Verarbeitung gänzlich ohne Vorhersage mehr Takte benötigen. Aus diesem Grund empfiehlt es sich auch bei dieser Technik mit einem Sättigungszähler zu arbeiten (Abbildung 9). Analog zur dynamischen Sprungvorhersage kann durch diesen Zähler festgelegt werden, ob es eine sichere Übereinstimmung gibt, eine nicht so sichere Übereinstimmung, eine nicht so sichere Nichtübereinstimmung oder eine sichere Nichtübereinstimmung. Der Unterschied besteht darin, dass hier nicht zwischen t (branch taken) und n (branch not taken) unterschieden wird, sondern darüber, ob der Wert überhaupt als Vorhersage genommen wird. Desweiteren kann der Zustand des Sättigungszählers zur Entscheidung darüber herangezogen werden, ob ein falsch vorhergesagter Wert in der VPT durch den neuen berechneten Wert ersetzt werden soll. Z.B. ist das dann sinnvoll, wenn der Zähler sich in dem Zustand einer sicheren Nichtübereinstimmung befindet. Zu erwähnen ist dabei noch die 2-Delta Methode, nach der ein neuer Wert nur in die VPT geschrieben wird, nachdem er mindestens zweimal in Folge auftrat, was wiederum die Speicherung des letzten tatsächlichen Wertes zu jedem Befehl erfordert. Eine noch etwas aufwändigere Methode ist es, zu jedem Befehl gleich mehrere Werte zu speichern und alle mit einem Zähler zu versehen. Die Vorhersage wird dann dem Wert entsprechen, der den höchsten Zählerstand hat, sofern er nach dem Sättigungsprinzip überhaupt als sichere Vorhersage gelten kann. F K 10 11 gültig K gültig F K F 00 nicht gültig K F = Falsche Vorhersage K = Korrekte Vorhersage 01 nicht gültig F Abbildung 9: Sättigungszähler für die konstante Wertvorhersage 10 3.2. Differentielle Wertvorhersage (stride prediction) Diese Art der Vorhersage eignet sich für konstant auftretende Werte, sowie für Werte, die mit jeder Ausführung schrittweise erhöht bzw. reduziert werden. Gespeichert wird dabei der letzte berechnete Wert und eine Schrittweite (die bei konstanten Werten 0 ist), aus denen sich dann die Vorhersage generieren lässt. Wie bei der konstanten Wertvorhersage, können hier ebenfalls Sättigungszähler und das 2-Delta-Verfahren angewendet werden, um Vorhersagen zuzulassen bzw. Einträge in der VPT zu ersetzen. In Abbildung 10 ist eine schematische Darstellung der VPT gegeben. Die Spalte Delta-2-Wert ist optional. Gegenüber der konstanten Wertvorhersage ist nur die Spalte Schrittweite hinzugekommen. VPT Adresse Vorhersagewert 2-Delta-Wert (jüngster Wert) $00E4 ... ... $50A4 ... $0FF4 $0FF0 $3FA7 $82BC Schrittweite $0004 ... ... $00FF ... Sättigungszähler 11 -> gültig 00 -> nicht gültig Abbildung 10: Wertvorhersagetabelle bei differentieller Vorhersage 3.3. Kontextbasierte Wertvorhersage (context based prediction) Die aufwändigste der drei hier beschriebenen Wertvorhersagemethoden ist die kontextbasierte Wertvorhersage. Sie funktioniert nach dem gleichen Prinzip wie die adaptive Sprungvorhersage. Zu jedem wertegenerierenden Befehl wird eine Wertehistorie in einer Wertehistorientabelle (value history table, VHT) gespeichert (vgl. BHT aus 1.5). In der VPT sind jeder dieser Historien ein Vorhersagewert (der sich nach den vergangenen Fortsetzungen nach der jeweiligen Wertefolge richtet) und Sättigungszähler zugeordnet (vgl. PHT aus 1.5). Nach Feststellung eines tatsächlichen Wertes werden VHT und VPT aktualisiert. Der wesentliche Unterschied zur adaptiven Sprungvorhersage liegt im Aufwand der Realisierung. Während bei der Sprungvorhersage nur zwei unterschiedliche Vorhersagen getroffen werden können, und damit eine n lange Historie höchstens 2n verschiedene Formen annehmen kann, so sind dies bei der Wertvorhersage fast unbegrenzt viele. Das ist natürlich nicht realisierbar, so dass Aliasing ein Problem darstellt (siehe Abschnitt 1.5). Der Trade-Off von Zuverlässigkeit und Hardwareaufwand ist in dem Fall so groß, dass kombinierte Lösungen wie bei der Sprungvorhersage auch bei der Wertvorhersage ein besseres Ergebnis liefern als die einzelnen Methoden für sich genommen. 3.4. Wertvorhersage als Instrument für Sprungvorhersage Wie bereits erwähnt, kann die Wertvorhersage als Ergänzung zu einem der Sprungvorhersageverfahren aus Abschnitt 1 verwendet werden. Da nach [1] die Zuverlässigkeit der Wertvorhersage bei höchstens 78 Prozent korrekter Vorhersagen liegt, kann es die anderen Sprungvorhersageverfahren nicht komplett ersetzen, ist jedoch bei bestimmten Sprungentscheidungen zuverlässiger. Deshalb scheint es am effizientesten, ein herkömmliches Verfahren mit dem Verfahren der Wertvorhersage zu kombinieren. Dabei werden beide Verfahren gleichzeitig eine Vorhersage treffen und ein weiterer Baustein wird dann eines der beiden Ergebnisse nach einem bestimmten Verfahren auswählen (vgl. choice predictor aus Abschnitt 1.6). 11 4. Literatur- und Abbildungsverzeichnis 4.1. Literatur [1] M. Menge, Moderne Prozessorarchitekturen. Springer, Berlin 2005 [2] C. Siemers, M. Eckert, A. Lauchner, tecChannel-Compact Prozessor-Technologie. IDG Interactive GmbH, München 2004 [3] S.-T. Pan, K. So, J. T. Rahmeh, Improving the Accuracy of Dynamic Branch Prediction Using Branch Correlation. S. 76-84, ASPLOS, 1992 [4] S. McFarling. Combining Branch Predictors. Technical Note TN-36, Digital Western Research Laboratory, 1993 [5] R. G. Wedig, M. A. Rose, The Reduction of Branch Instruction Execution Overhead Using Structured Control Flow. S. 119-125, ISCA, 1984 [6] D. A. Jiménez, Delay-Sensitive Branch Predictors for Future Technologies. University of Texas, Austin, 2002 4.2. Abbildungen Abbildung 1: Dynamische Sprungvorhersage mit einstufiger Historie Abbildung 2: Dynamische Sprungvorhersage mit zweistufiger Historie Abbildung 3: Dynamische Sprungvorhersage mit Sättigungszähler Abbildung 4: Dynamische Sprungvorhersage mit Hysteresemethode Abbildung 5: Adaptive Sprungvorhersage mit lokalen Sprungmustertabellen und lokalen Sprunghistorientabellen Abbildung 6: Globale adaptive Sprungvorhersage, (4,2)-Prediktor Abbildung 7: Indexselektion (a) und Indexteilung (b) Abbildung 8: Globale Sprungzielvorhersage Abbildung 9: Sättigungszähler für die konstante Wertvorhersage Abbildung 10: Wertvorhersagetabelle bei differentieller Vorhersage 4.3. Beispiele Beispiel 1: Beispiele bei der dynamischen Sprungvorhersage mit zweistufiger Historie Beispiel 2: Beispiele bei der dynamischen Sprungvorhersage mit zweistufiger Historie und Hysteresemethode 12