Archiv verlassen und diese Seite im Standarddesign anzeigen : Prozessorarchitektur-Fragen
Arokh
2006-09-20, 21:40:33
Hi Leute,
ich habe mich mal ein bißchen mit der Architektur moderner Prozessoren, insbesondere des AMD K7 und K8, beschäftigt, und zwar u.a. anhand dieser Grafik (K8):
http://upload.wikimedia.org/wikipedia/commons/e/eb/AMD_A64_Opteron_arch.jpg
und dieses Textes:
http://www.computerbase.de/artikel/hardware/prozessoren/2003/test_athlon_64_fx-51_athlon_64_3200/9/#abschnitt_die_kraft_der_amd64_architektur
Wenn ich das richtig verstanden habe, haben K7 und K8 3 universell einsetzbare Integer-ALUs, können also 3 beliebige Integer-Operationen parallel durchführen.
Ebenso gibt es 3 FPUs, die allerdings spezialisiert sind, eine für Addition (FADD), eine für Multiplikation (FMUL), und eine für sonstiges (FMISC). D.h. es wären zwar im Prinzip drei Fließkomma-Operationen gleichzeitig durchführbar, davon müßte aber eine Addition, eine Multiplikation, und eine eine sonstige Operation sein.
Sehe ich das richtig?
Dann habe ich eine Frage zu diesen Schedulern. Laut Grafik gibt es für jede ALU einen eigenen mit je 8 Einträgen. Wie hängen diese mit den im Text erwähnten 8 GPR-Registern zusammen?
Die 8 Register sind nicht identisch mit den 8 Scheduler-Einträgen, oder? Dazu müßte es ja für jeden Scheduler eigene 8 Register geben, und ich nehme an, dem ist nicht so? Es gibt insgesamt nur 8 von den GPR-Registern, richtig?
Die drei ALUs mit ihren Schedulern müssen sich also 8 Register teilen, korrekt?
Die 8 Registern müßten, wenn sie in der Grafik auftauchen würden, vermutlich eine Schicht zwischen den Schedulern und den ALUs bilden?
Angenommen, ich will in meinem Programm das Vorhandensein der drei parallen Integer-ALUs (Superskalarität nennt man das glaube ich?) ausnutzen, um meine Berechnungen durch Parallelisierung zu beschleunigen, müßte ich das von Hand per Assembler-Code veranlassen, oder optimieren moderne Compiler von alleine darauf?
In dem Text ist außerdem von einer ALU- und FPU-Pipeline die Rede, die 12 bzw. 17 Stages hat (beim K8). Da ich annehme, daß pro CPU-Takt nur eine Stage durchlaufen wird, braucht eine Integer- bzw. FP-Operation demnach 12 bzw. 17 Prozessortakte. Irgendwo habe ich aber mal gelesen, moderne Prozessoren könnten eine ganze Operation (oder noch mehr) innerhalb eines Taktes durchführen, was stimmt denn nun? Bezieht sich das vielleicht nur darauf, daß bei einer gut gefüllten Pipeline (wo also ständig Operanden nachgeschoben werden) die effektive Zeit pro Operation (benötigte Zeit für x Operationen, geteilt durch x) nur ein Takt ist?
Dann hätte ich noch eine Frage zum Thema MMX und SSE. Irgendwo anders habe ich gelesen, MMX bringe keine eigene Hardware mit, sondern "mißbraucht" die FPU-Hardware, indem es die FP-Register zu Integer-Registern und die drei FPUs zu ALUs umfunktioniert. Wobei die dann für drei parallele Integer-Operationen verwendbar sind, die aber zwingend gleichartig sein müssen (SIMD = Single Instruction, Multiple Data), d.h. drei Additionen, drei Multiplikationen etc. Habe ich das richtig verstanden?
Wohingegen SSE eigene Hardware-Einheiten hat (ebenfalls 3?), die aber ebenfalls nur SIMD können, dafür aber mit FP-Support. Ist das so korrekt?
Fragen über Fragen, ich hoffe ihr könnt mit weiterhelfen :smile:
enn ich das richtig verstanden habe, haben K7 und K8 3 universell einsetzbare Integer-ALUs, können also 3 beliebige Integer-Operationen parallel durchführen.
Universell sind sie nicht, nur eine kann imul durchführen, wie du siehst.
Ebenso gibt es 3 FPUs, die allerdings spezialisiert sind, eine für Addition (FADD), eine für Multiplikation (FMUL), und eine für sonstiges (FMISC). D.h. es wären zwar im Prinzip drei Fließkomma-Operationen gleichzeitig durchführbar, davon müßte aber eine Addition, eine Multiplikation, und eine eine sonstige Operation sein.
Sehe ich das richtig?
Ja. FMISC ist übrigens vor allem Load/Store.
Dann habe ich eine Frage zu diesen Schedulern. Laut Grafik gibt es für jede ALU einen eigenen mit je 8 Einträgen. Wie hängen diese mit den im Text erwähnten 8 GPR-Registern zusammen?
Die 8 Register sind nicht identisch mit den 8 Scheduler-Einträgen, oder? Dazu müßte es ja für jeden Scheduler eigene 8 Register geben, und ich nehme an, dem ist nicht so? Es gibt insgesamt nur 8 von den GPR-Registern, richtig?
Die drei ALUs mit ihren Schedulern müssen sich also 8 Register teilen, korrekt?
Die 8 Registern müßten, wenn sie in der Grafik auftauchen würden, vermutlich eine Schicht zwischen den Schedulern und den ALUs bilden?
Es sind viel mehr virtuelle Register vorhanden. Die x86-ISA hat aber nur 8 direkt ansprechbar.
Angenommen, ich will in meinem Programm das Vorhandensein der drei parallen Integer-ALUs (Superskalarität nennt man das glaube ich?) ausnutzen, um meine Berechnungen durch Parallelisierung zu beschleunigen, müßte ich das von Hand per Assembler-Code veranlassen, oder optimieren moderne Compiler von alleine darauf?
Ja natürlich optimieren die Compiler drauf, aber moderne CPUs können auch Out-Of-Order ausführen, d.h. sie führen die Instructions nicht in der Reihenfolge aus in der sie im Code vorkommen, solange das die Abhängigkeiten zulassen und verwenden dabei auch mehr Register als in der ISA eigentlich vorhanden sind. Ist ein ziemlich komplexes Thema.
In dem Text ist außerdem von einer ALU- und FPU-Pipeline die Rede, die 12 bzw. 17 Stages hat (beim K8). Da ich annehme, daß pro CPU-Takt nur eine Stage durchlaufen wird, braucht eine Integer- bzw. FP-Operation demnach 12 bzw. 17 Prozessortakte.
Irgendwo habe ich aber mal gelesen, moderne Prozessoren könnten eine ganze Operation (oder noch mehr) innerhalb eines Taktes durchführen, was stimmt denn nun? Bezieht sich das vielleicht nur darauf, daß bei einer gut gefüllten Pipeline (wo also ständig Operanden nachgeschoben werden) die effektive Zeit pro Operation (benötigte Zeit für x Operationen, geteilt durch x) nur ein Takt ist?
Es sind ja mehrere In-Flight, d.h. die ALUs führen in den Stages potentiell schon unterschiedliche Instructions aus. Das mit der Pipeline spielt nur eine Rolle wenn der Prozessor sich "verspringt" wenn er einen Branch falsch vorhergesagt hat, sonst hast du den maximalen Durchsatz.
Dann hätte ich noch eine Frage zum Thema MMX und SSE. Irgendwo anders habe ich gelesen, MMX bringe keine eigene Hardware mit, sondern "mißbraucht" die FPU-Hardware, indem es die FP-Register zu Integer-Registern und die drei FPUs zu ALUs umfunktioniert.
MMX verwendet tatsächlich die FPU-Register mit, aber welche Recheneinheiten sich dann darum kümmern ist ja CPU-Abhängig.
Wobei die dann für drei parallele Integer-Operationen verwendbar sind, die aber zwingend gleichartig sein müssen (SIMD = Single Instruction, Multiple Data), d.h. drei Additionen, drei Multiplikationen etc. Habe ich das richtig verstanden?
Wie kommst du auf drei? MMX arbeitet auf 2, 4 oder 8 Element, SSE auf 2 oder 4.
Wohingegen SSE eigene Hardware-Einheiten hat (ebenfalls 3?), die aber ebenfalls nur SIMD können, dafür aber mit FP-Support. Ist das so korrekt?
Auch hier gilt: Kommt auf die CPU an.
Der A64 hat z.B. zwei FPUs, von denen eine nur für x87 und die andere für SIMD benützt wird, d.h. eine SSE-Op die 4 Elemente bearbeitet wird in zwei Durchgängen erledigt.
Core 2 Duo hat 4 FPUs und kanns auf einmal machen.
Hi Leute,
ich habe mich mal ein bißchen mit der Architektur moderner Prozessoren, insbesondere des AMD K7 und K8, beschäftigt, und zwar u.a. anhand dieser Grafik (K8):
http://upload.wikimedia.org/wikipedia/commons/e/eb/AMD_A64_Opteron_arch.jpgSehr schöne Grafik :)
Universell sind sie nicht, nur eine kann imul durchführen, wie du siehst.Davon abgesehen sind sie es aber universell IMHO.
Dann habe ich eine Frage zu diesen Schedulern. Laut Grafik gibt es für jede ALU einen eigenen mit je 8 Einträgen. Wie hängen diese mit den im Text erwähnten 8 GPR-Registern zusammen?Nicht direkt. Dass es acht Scheduler-Einträge sind, ist Zufall. Beim K7 waren es noch sechs.
Im 64 Bit Modus sind es übrigends 16 GPRs und wie Coda schon richtig erwähnte, sind insgesamt sogar noch mehr Register auf dem Chip verfügbar, die für Register Renaming verwendet werden (AFAIK insgesamt 96).
Die 8 Register sind nicht identisch mit den 8 Scheduler-Einträgen, oder?Nein. Die Einträge der Scheduler beinhalten Instruktionen. In den Prozessorregistern stehen Daten drin, mir denen diese Instruktionen operieren.
Etwas detailierter sieht das beim K7/K8 so aus:
Bevor die Befehle in die Scheduler-Queue kommen, lesen sie das (spekulative) Register File für ihre Quelldaten. Dort markieren sie ihr Zielregister für nachfolgende Befehle, damit diese wissen, dass dieser Wert demnächst verändert wird und hinterlassen einen Tag zu Identifizierung. Nachfolgende Befehle, die dieses Register als Quellregister für ihre Operation benötigen, können also sehen, dass dieser Wert nicht aktuell ist und wissen durch den hinterlassenen Tag, auf welchen Befehl sie warten müssen, bis ihre Quelldaten bereit sind. Die Befehle lesen aus dem Registerfile also nur die Daten, die auch aktuell sind.
Mit diesen Daten bzw. den Informationen, welcher Befehl die noch fehlenden Daten produziert, kommen die Befehle in die Scheduler-Queue. Der Scheduler kann nun alle Befehle ausführen, deren Quelldaten vollständig vorhanden sind. Die ALU schickt einen Takt vor dem Ende der Operation den Tag der Instruktion, die gleich fertig wird, über den Ergebnisbus. Der Scheduler ließt diese Tags, und kann - falls dadurch ein neuer Befehl bereit wird, diesen direkt im nächsten Takt zur Ausführung in die ALU schicken. Die benötigten Daten werden per Result-Forwarding direkt vom Ausgang der ALU an den entsprechenden Eingang angelegt. Diese müssen also nicht erst in das Registerfile zurückgeschrieben und dann wieder für den nachfolgenden Befehl ausgelesen werden.
Fertige Befehle kommen erst einmal in den Reorder-Buffer, bis sichergestellt ist, dass keine Exceptions aufgetreten sind und alle anderen Befehle vor ihnen (in Programmreihenfolge), die das gleiche Zielregister beschreiben, ihre Ergebnisse geliefert haben. Dann kommen die Ergebnisse der Befehle in das spekulative Registerfile. Wenn dann weiterhin auch noch sichergestellt ist, dass die Befehle tatsächlich ausgeführt werden (also nicht falsch bei der Sprungvorhersage spekuliert wurde), werden die Daten vom spekulativen ins "echte" Registerfile geschrieben.
Die drei ALUs mit ihren Schedulern müssen sich also 8 Register teilen, korrekt?
Die 8 Registern müßten, wenn sie in der Grafik auftauchen würden, vermutlich eine Schicht zwischen den Schedulern und den ALUs bilden?Die Grafik ist ein Ablaufdiagramm, in denen das Registerfile nicht eingezeichnet ist. Das Lesen der Register findet beim Übergang der ICU zu den Schedulern statt und das Schreiben beim Verlassen des Reorder-Buffers (nicht eingezeichnet; wäre hinter den ALUs/AGUs, noch vor der L/S Queue).
Angenommen, ich will in meinem Programm das Vorhandensein der drei parallen Integer-ALUs (Superskalarität nennt man das glaube ich?) ausnutzen, um meine Berechnungen durch Parallelisierung zu beschleunigen, müßte ich das von Hand per Assembler-Code veranlassen, oder optimieren moderne Compiler von alleine darauf?Der Prozessor kann mit seinen Schedulern selbstständig Befehle aus einem seriellen Strom parallel ausführen, wenn auch nicht immer optimal.
Compiler nehmen auf die Mikroarchitektur Rücksicht, wenn sie für diese Optimieren, also auch auf die Anzahl der parallel ausführbaren Befehle uvm. Es gibt jedoch gute und weniger gute Anordnung / Wahl von Befehlen. Wenn man wirklich das Optimum an Performance rausholen will, sollte man wohl selbst in Assembler programmieren.
Trotzdem sind moderne Kompiler schon einigermaßen gut.
In dem Text ist außerdem von einer ALU- und FPU-Pipeline die Rede, die 12 bzw. 17 Stages hat (beim K8). Da ich annehme, daß pro CPU-Takt nur eine Stage durchlaufen wird, braucht eine Integer- bzw. FP-Operation demnach 12 bzw. 17 Prozessortakte. Irgendwo habe ich aber mal gelesen, moderne Prozessoren könnten eine ganze Operation (oder noch mehr) innerhalb eines Taktes durchführen, was stimmt denn nun?Also erstmal eine Klarstellung bzgl. der Zahlen. Das sind "Misprediction-Pipelines", also geben die Anzahl an Stufen/Takte an, die minimal durch einen falsch vorhergesagten Sprung gewartet werden muss, bis die neu gefetchten Befehle dekodiert, gescheduled und ausgeführt werden. Die Tatsächliche Pipeline ist noch wesentlich länger - was aber vom Befehl abhängt. Ein Sinus-Befehl braucht z.B. irgendwas zwischen 80 und 170 Takten Ausführungszeit in der FPU. Dass die Pipeline je nach Befehl unterschiedlich lang ist, kann man hier (http://www.chip-architect.com/news/Opteron_1600x1200.jpg) recht gut erkennen, wo die Stufen für den L1 und L2 Cache noch mit eingezeichnet sind. Die Ausführungsstufe in der ALU/FPU ist dort auch nur einen Takt lang. Wie erwähnt ist das nicht immer so.
Einfache Operationen (ein ADD in der ALU) braucht nur einen Takt. Das ist aber die reine Ausführungszeit in der ALU, dazu kommen wie gesagt noch die neun Takte (beim K8) für Fetch, Decode, Rename, Schedule usw.
Im Durchsatz ergibt sich aber im Schnitt ein Befehl pro Takt und ALU.
mfG, GloomY
Danke an Gloomy und Coda für die Erklärungen und an Arokh für diesen Thread. Das Thema hat mich auch sehr interessiert.
Arokh
2006-09-22, 20:28:06
Ich finde dieses Register-Renaming sehr interessant. Hier:
http://www.chip-architect.com/news/2003_09_21_Detailed_Architecture_of_AMDs_64bit_Core.html#1.9%20%20%20Register%20 Renaming%20and%20Out-Of-Order%20Processing
steht dazu:
Register renaming is used to eliminate "False Dependencies" which limit the number of Instructions Per Cycle (IPC) that a processor can execute. False Dependencies are the result of a limited number of registers. A register that holds an intermediate result needs to be re-used soon for another, maybe unrelated, calculation. Its value is then overwritten and not available anymore. The instruction that overwrites it must always wait for the instruction that needs the previous result.
This serializes the execution of the instruction and limits the IPC. This is especially true for an architecture like x86 which has a very small number of registers. The example below shows how register renaming can eliminate false data dependencies: Register rC is overwritten by the 3rd instruction, so the 3rd instruction has to wait for the 2nd instruction: a False Dependency. With register renaming we can use an "arbitrary" large register file. There is no need to re-use rC(r3) We can simple use another available register instead, register r7 in this case. The basic rule is that all of the instructions that are "in-flight" are given a different destination register. (single assignment)
Non Renamed: rC=rA+rB; rF=rC&rD; rC=rA-rB;
Renamed: r3=r1+r2; r6=r3&r4; r7=r1-r2;
Allerdings stellt sich mir die Frage, warum man dem Benutzer nicht einfach die Register r1, r2, ... zur Verfügung stellt, sondern nur die rA, rB, rC, ...? In dem Beispiel greift der Benutzer zweimal auf rC zu, nur daß beim ersten Mal rC auf r3 "renamed" wird, beim zweiten Mal auf r7. Stattdessen könnte man den Benutzer doch auch direkt auf r3 und r7 zugreifen lassen und sich damit das Renaming sparen.
Ist das damit sich der Benutzer nicht so sehr um die Vergabe der Register kümmern muß? Bzw. weil es effizienter ist, wenn die CPU die Register "just in time" selbständig verteilt?
Das wirft ja auch ein bemerkenswertes Licht darauf, wie viel Einflußmöglichkeit auf die Programmausführung man hat, wenn man in Assembler programmiert: im Assembler-Code gibt man ja immer Register an, z.B. eax, ich hatte bislang angenommen, daß man damit schon ziemlich genau festlegen würden, welches Register in der CPU-Hardware verwendet wird. Das scheint dem dann ja doch nicht so zu sein...
Dann hätte ich hier noch einen älteren Text aus Pentium1-Zeiten gefunden, wo offenbar auch von Register Renaming die Rede ist:
http://www.deinmeister.de/cyvpent.htm
Nun wurden die CPUs mit einem Programm getestet, das größtenteils aus etwas komplexeren mathematischen Berechnungen bestand. Dies tritt vor allem bei Fraktalen und Raytracern auf. Die erste, unoptimierte Version lief auf dem Cyrix166 nur unwesentlich schneller als auf dem P100. Der K6-333 war etwa doppelt so schnell. Schon hier zeigte sich das der Pentium das bessere FPU-Layout hat.
Nun wurde der Code auf den Pentium hin optimiert: Bekannt ist, daß nur eine FPU-Instruktion gleichzeitig ausgeführt werden kann. Was jedoch nicht so verbreitet ist, ist daß der Pentium aber voneinander unabhängige FPU-Berechnungen danach gleichzeitig berechnen kann, da die Berechnung selbst länger dauert als das Starten der Berechnung durch den FPU-Befehl.
Solange der eine Befehl noch rechnet, kann man schon andere starten, anstatt auf das Ergebnis des Ersten zu warten. Jedoch greifen die x86-FPU-Befehle immer auf das ST(0)-Register zu. Da auf dem Pentium aber die Register ihre Namen tauschen können, greifen unter Umständen zwei Befehle auf ein Register namens ST(0) zu, welche aber in Wirklichkeit verschieden sind!
Um die Namen zu vertauschen benützt man den Befehl FXCH, der zwei Register miteinander vertauscht. In Wirklichkeit werden die Register nur umbenannt, ein zeitaufwendiges Vertauschen ihrer Inhalte findet nicht statt!
Offenbar mußte da das Register Renaming noch manuell angestoßen werden, durch Aufruf des Befehls FXCH. Heißt das, seither (seit dem Pentium1/K6) eine Entwicklung stattgefunden hat, daß die CPU das Renaming jetzt selbständig vornimmt? Oder wie ist das zu verstehen? Ist in dem Text vielleicht von was ganz anderem die Rede?
@GloomY: daß eine Sinus-Berechnung bis zu 170 CPU-Takte benötigt, bedeutet aber doch nicht notwendigerweise, daß die Pipeline so lang ist. Die Pipeline könnte ja auch mehrfach durchlaufen werden, indem Zwischenergebnisse wieder dem Eingang zugeführt werden. Oder meintest du mit Länge der Pipeline vielleicht gar nicht die Länge der Pipeline-Hardware, also die Zahl der hardwareseitig vorhandenen Pipeline-Stages, sondern die Gesamtzahl an Stage-Durchläufen, worin eine Stage auch mehrfach vorkommen kann?
Allerdings stellt sich mir die Frage, warum man dem Benutzer nicht einfach die Register r1, r2, ... zur Verfügung stellt, sondern nur die rA, rB, rC, ...?
Weil man die vielen Register in den Befehlen ja auch enkodieren müsste und zudem die x86-ISA eben nur 8 GPRs zur Verfügung stellt (x86-64 immerhin 16).
Das wirft ja auch ein bemerkenswertes Licht darauf, wie viel Einflußmöglichkeit auf die Programmausführung man hat, wenn man in Assembler programmiert: im Assembler-Code gibt man ja immer Register an, z.B. eax, ich hatte bislang angenommen, daß man damit schon ziemlich genau festlegen würden, welches Register in der CPU-Hardware verwendet wird. Das scheint dem dann ja doch nicht so zu sein...
Macht ja nichts, es ist auf jedenfall immer schneller als die Sitation in der die CPU nur die eingeschränkte Anzahl von Registern hat die man "sieht".
Offenbar mußte da das Register Renaming noch manuell angestoßen werden, durch Aufruf des Befehls FXCH. Heißt das, seither (seit dem Pentium1/K6) eine Entwicklung stattgefunden hat, daß die CPU das Renaming jetzt selbständig vornimmt? Oder wie ist das zu verstehen? Ist in dem Text vielleicht von was ganz anderem die Rede?
Das bezieht sich auf die x87-FPU die leider keine flaches Registermodel sondern einen Register-Stack hat. Das ist kein Renaming sondern ermöglicht es einfach nur schnell zwei Register im Stack zu tauschen, weil man effektiv immer nur auf das oberste Zugreifen kann.
daß eine Sinus-Berechnung bis zu 170 CPU-Takte benötigt, bedeutet aber doch nicht notwendigerweise, daß die Pipeline so lang ist. Die Pipeline könnte ja auch mehrfach durchlaufen werden, indem Zwischenergebnisse wieder dem Eingang zugeführt werden.
Natürlich ist das der Fall. Bei Sinus wird zuerst eine Approximation aus dem ROM gelesen und dann eine Taylorreihe aus dem Microcode ausgeführt bis die gewünschte Genauigkeit erreicht ist.
Unter Vista wird das aber gar nicht mehr benützt, weil anstatt der x87-FPU skalares SSE2 zur Float-Berechnung herangezogen wird, das kein natives Sin mehr kennt. Langsamer ist es deshalb trotzdem nicht.
tatarus
2006-09-23, 00:07:35
Das Scheduling kannst du nicht mit Assembler beeinflussen und das ist auch gut so. Genausowenig wie Reorder Buffer, Tagzuweisung und die Reservation Stations. Wenn du dich näher mit Prozessorarchitekturen beschäftigen solltest, dann wirst du schnell erkennen, warum das so ist. Nehmen wir mal dein Beispiel
Non Renamed: rC=rA+rB; rF=rC&rD; rC=rA-rB; (GPR Namen)
Renamed: r3=r1+r2; r6=r3&r4; r7=r1-r2; (Tags für Register)
Tags werden beim Scheduling verwendet, um Datenabhängigkeiten zu erkennen und auflösen zu können. Es gibt keine Register r3, r1... Das sind nur Aliasnamen. Im Vorliegenden Beispiel hängt die zweite Instruktion von der Ersten ab. Die dritte ist jedoch unabhängig. Daher kommt der andere Tag. Im von dir gezeigten Blockdiagramm ist der Registersatz gar nicht eingezeichnet. Jeder Prozessor besitzt übrigens schon alleine für das Pipelining eine Vielzahl von Registern.
Bevor du aber so tief in die CPU Architektur einsteigst, solltest du dir erst mal grundlegend über Dinge wie Pipelining/Forewarding und Befehlsausführung klar werden. Nimm auch nicht gleich den Athlon 64, sondern fang mal mit einer einfacheren CPU wie einer DLX an. Die hat in der einfachen Variante nur 5 Pipeliningstufen, es gibt viel Literatur dazu und die Technik in großen CPUs basiert grundlegend auch darauf.
Arokh
2006-09-23, 13:27:30
Nehmen wir mal dein Beispiel
Non Renamed: rC=rA+rB; rF=rC&rD; rC=rA-rB; (GPR Namen)
Renamed: r3=r1+r2; r6=r3&r4; r7=r1-r2; (Tags für Register)
Tags werden beim Scheduling verwendet, um Datenabhängigkeiten zu erkennen und auflösen zu können. Es gibt keine Register r3, r1... Das sind nur Aliasnamen. Im Vorliegenden Beispiel hängt die zweite Instruktion von der Ersten ab. Die dritte ist jedoch unabhängig. jetzt verstehe ich gar nichts mehr. Ich dachte, die Register r1, r2, ... seien die "echten", also physikalisch, hardwareseitig vorhandenen Register, und die rA, rB, ... seien die 8 für den Benutzer sichtbaren Registerbezeichnungen. Und der Hintergrund der ganzen Sache sei der, daß wenn (in unserem Beispiel) das hardwareseitig vorhandene Register r3 von der ersten Instruktion belegt ist (und im Rahmen dieser Instruktion dem Benutzer als Register rC angezeigt wird), die dritte Instruktion, die ebenfalls ein für den Benutzer als rC sichtbares Register verwendet, parallel zur ersten ablaufen kann, indem sie nicht die Zuordnung rC -> r3 benutzt (wie die erste Instruktion), sondern rC -> r7, also statt dem belegten Register r3 einfach ein anderes (hardwareseitig vorhandes) Register r7 benutzt.
Wenn jetzt aber gar nicht die r1,r2,... die echten Register sind, sondern die rA,rB,..., dann verstehe ich nicht was der Sinn und Zweck der ganzen Sache sein soll? Zur Parallelisierung der ersten und dritten Instruktion wäre das dann ja nicht einsetzbar...
Gut, die CPU kann auf diese Weise die Information speichern, daß Instruktion 1 und 3 unabhängig voneinander sind, aber was bringt ihr das dann?
Edit: Zitat aus http://de.wikipedia.org/wiki/Register_renaming
Üblicherweise findet in der Dekodierstufe (ID) während der Dekodierung einer Anzahl von Befehlen (normalerweise genau so viele wie die maximale Zuordnungsbandbreite beträgt) eine Umbenennung von Registern statt. Dabei werden die in den Befehlen referenzierten Architekturregister, also die im Befehlssatz definierten, in tatsächlich physikalisch vorhandene Register (bzw. Umbenennungspufferregister) umbenannt.Dort tauchen die drei hervorgehobenen Begriffe auf. Ich nehme an, die Architekturregister sind im Beispiel die rA, rB, rC, rD und rF. Was sind dann die r1, r2, r3, r4, r6, r7, wenn nicht die physikalischen Register? Sind das diese Umbennungsregister?
Jeder Prozessor besitzt übrigens schon alleine für das Pipelining eine Vielzahl von Registern.du meinst jetzt nicht Speichereinheiten, die die Ergebnisse jeder Stage der Pipeline zwischenspeichern (Latches nennt man die glaube ich), oder? Ich dachte die seien Bestandteil der ALU/FPU und zählen nicht als Register.
Bevor du aber so tief in die CPU Architektur einsteigst, solltest du dir erst mal grundlegend über Dinge wie Pipelining/Forewarding und Befehlsausführung klar werden.mit Pipelining meine ich mich eigentlich auszukennen, Forewarding sagt mir allerdings als Begriff nicht viel.
Nimm auch nicht gleich den Athlon 64, sondern fang mal mit einer einfacheren CPU wie einer DLX an. Die hat in der einfachen Variante nur 5 Pipeliningstufen, es gibt viel Literatur dazu und die Technik in großen CPUs basiert grundlegend auch darauf.danke, werd ich mir mal anschauen.
Benedikt
2006-09-23, 22:34:29
Unter Vista wird das aber gar nicht mehr benützt, weil anstatt der x87-FPU skalares SSE2 zur Float-Berechnung herangezogen wird, das kein natives Sin mehr kennt. Langsamer ist es deshalb trotzdem nicht.
Gilt dies auch für die 32-Bit-Variante von Vista, oder nur für die x86-64-Version? Ich dachte immer, nur bei letzterer wird die FPU nicht mehr verwendet...
Ehm sorry, ich wollte natürlich x86-64-Windows sagen.
tatarus
2006-09-24, 14:29:04
Bei deinen Vorkenntnissen würde eine genaue Erklärung etwas weit führen. Am besten schaust du dir hier:
http://www.rs.e-technik.tu-darmstadt.de/Webseiten/eng_computer_systems_I.html
mal Kapitel 4 und 5 an.
Bei paralleler Befehlsverarbeitung müssen Datenabhängigkeiten erkannt werden, da abhängige Instruktionen nur nacheinander ausgeführt werden können. In deinem Beispiel müsste die zweite Instruktion auf das Beenden der Ersten warten.
Umbenennungsregister könnte man die auch nennen. Steht ja auch davor (non-renamed; renamed).
Die Register, die Zwischenergebnisse nach jeder Stage zwischenspeichern nennt man Pipeliningregister und sie dienen unter anderem auch dem Forewarding. Sie gehören nicht zu den Ausführungseinheiten, sondern zu jeder Stage.
Ein Pipelining ohne Forewarding bringt in einer CPU nichts. Daher sollte man sich auch mit Forewarding beschäftigen, wenn man ins Pipelining einsteigt.
Auf Prozessorinterne Register kannst du nicht zugreifen. Als Programmierer siehst du nur den GPR Satz. Der Rest bleibt dir verschlossen und wird hardwareseitig automatisch genutzt.
Arokh
2006-09-24, 17:26:24
Bei paralleler Befehlsverarbeitung müssen Datenabhängigkeiten erkannt werden, da abhängige Instruktionen nur nacheinander ausgeführt werden können. In deinem Beispiel müsste die zweite Instruktion auf das Beenden der Ersten warten. das war mir schon klar, meine Frage bezog sich darauf, daß für parallele Befehlsverarbeitung auch ein hardwareseitiges Vorhandensein einer größeren Registerzahl (r1,r2,...) erforderlich ist, es also nicht ausreicht, Register aus einem kleineren Satz (rA,rB,...) umzubenennen. Es ging um dein Statement Es gibt keine Register r3, r1... Das sind nur Aliasnamendas für mich so geklungen hat, als seien nur die 8 Register aus dem (rA,...) Satz physikalische vorhanden.
Die Register, die Zwischenergebnisse nach jeder Stage zwischenspeichern nennt man Pipeliningregister und sie dienen unter anderem auch dem Forewarding. Sie gehören nicht zu den Ausführungseinheiten, sondern zu jeder Stage.ich denke, ich muß meine Vorstellung von Pipelines noch einmal überarbeiten. Ich hatte bislang angenommen, die Pipeline sei eine Hardware-Einheit (bestehend aus mehreren Untereinheiten, den Stages), die Bestandteil der ALU ist, etwa so:
29010
Dies ist eine hypothetische Archtektur mit 4 Registern und 5 Pipeline-Stufen. Die Pfeile geben die Richtung des Datenflusses an. Daß jede Pipeline-Stage einen Ausgang aus der ALU heraus hat, soll berücksichtigen, daß nicht für jede Operation alle Stages durchlaufen werden müssen.
Derweil hab ich mir mal dieses DLX-Simulationsprogramm heruntergeladen und experimentiere damit ein bißchen herum. :)
Arokh
2006-09-24, 18:19:29
Am besten schaust du dir hier:
http://www.rs.e-technik.tu-darmstadt.de/Webseiten/eng_computer_systems_I.html
mal Kapitel 4 und 5 an.
hm... also nach dem was da in Kapitel 4.5 steht, ist es ja eher genau anders herum als von mir angenommen: die ALU ist nicht als Pipeline gebaut, sondern selbst nur eine Stage der Pipeline...
hat das vielleicht was damit zu tun, daß der Execute-Schritt beim DLX immer nur einen einzigen Takt benötigt? Bei einer Architektur, bei der die Ausführung eines Befehls mehrere Prozessortakte dauern kann, wäre es da so, daß die ALU mehrere Stages enthält?
Meine Kenntnisse über Pipelining gehen im wesentlichen auf eine Vorlesung zurück, in der schnelle Additions- und Multiplikationsverfahren behandelt wurden. Man stelle sich vor, man will zwei n-Bit Integer Zahlen addieren, mit Hilfe von einbittigen Addier-Einheiten. Wegen dem Übertrag, der bei der Addition zweier Einzelbits auftritt, ist es nicht so ohne weiteres möglich, die n anstehenden 1-Bit Additionen zu parallelisieren. Eine mögliche Lösung ist eine Halbaddierer-Pipeline aus n Stages: in jeder Stage wird das jeweilige Bit des Ergebnisses berechnet und der Übertrag, der zur Berechnung des nächstens Bits an die nächste Stage weitergegeben wird. Hat man nicht nur ein einziges Paar zu addierender Zahlen, sondern k Stück, ist man nach n+k Takten fertig, für k >> n bedeutet das eine effektive Dauer von einem Takt pro Addition.
Dazu muß allerdings die gesamte Pipeline Bestandteil der ALU sein. Alternativ könnte man natürlich auch eine Stage pro ALU verbauen, dann bräuchte man allerdings n ALUs.
tatarus
2006-09-24, 22:22:01
Was du meinst ist ein Ripple Carry Adder, der aus einem Halbaddierer und n-1 Volladdierern besteht. Der hat nichts mit einer Pipeline zu tun. Das Ergebnis liegt strukturbedingt allerdings mit einer sehr hohen Latenz stabil am Ausgang an. Besser wäre da übrigens der Carry Lookahead Adder. Eine CPU ALU macht zusätzlich noch logische Operationen, Vergleiche, gelegnetlich Integer Multiplikationen... Sie ist also erheblich komplexer.
Einen RCA verwendet kein Mensch beim Hardwaredesign. Bei VHDL schreibt man sich normalerweise einen schnelleren Addierer selber, damit nicht automatisch dieser Mistaddierer synthetisiert wird. Den lernt man nur am Anfang, weil er so einfach zu verstehen ist.
Die DLX ist ein einfacher Prozessor, der aus den 5 Hauptschritten besteht. Jeder dieser Schritte kann noch aufgespalten werden. Das dient vor allem dem Ermöglichen höherer Taktraten. Die Register sind vorhanden, um Zwischenergebnisse nach jeder Stufe zu speichern und die Synchronisation durch den Takt zu ermöglichen. Sie enthalten Ergebnisse, die durch das Forewarding in die entsprechende Stufe geleitet werden können, falls Datenabhängigkeiten zwischen zwei sich in der Pipeline befindlichen Befehlen entdeckt werden. Kann die Datenabhängigkeit nicht aufgelöst werden, so wird so lange kein neuer Befehl geholt, bis sie aufgelöst wurde.
Arokh
2006-09-24, 23:47:00
Was du meinst ist ein Ripple Carry Adder, der aus einem Halbaddierer und n-1 Volladdierern besteht. Der hat nichts mit einer Pipeline zu tun. das was ich meine hat sehr wohl was mit einer Pipeline zu tun. Die Funktionsweise ähnelt dem Ripple Carry Adder, mit dem Unterschied, daß nur Halbaddierer vorhanden sind, und zwar n+(n-1)+(n-2)+...1. Für n=5 sieht das z.B. so aus (für die Operation c=a+b):
29014
Die Carries der hochwertigsten Addierer habe ich jeweils weggelassen, da sie einen Überlauf darstellen und ignoriert werden. Anders als beim RCA, wo jedes Paar (a,b) erst zu Ende berechnet werden muß, bevor das nächste Paar verarbeitet werden kann, kann eine solche Halbaddierer-Pipeline bereits nach dem ersten der n Berechnungsschritte für das erste Paar mit dem ersten Schritt für das nächste Paar beginnen.
Das Ergebnis liegt strukturbedingt allerdings mit einer sehr hohen Latenz stabil am Ausgang an. Besser wäre da übrigens der Carry Lookahead Adder. mir ist schon bewußt, daß eine so einfache HA-Pipe eher nicht verwendet wird. Zum Addieren von 32-Bit Integers bräuchte man so ja 32 Stages. Schnellere Addierer wie der CLA lassen sich aber auch in Pipeline-Form bauen.
Eine CPU ALU macht zusätzlich noch logische Operationen, Vergleiche, gelegnetlich Integer Multiplikationen... Sie ist also erheblich komplexer. auch das ist klar. Das schließt aber ebenfalls keine Pipeline-Bauweise aus.
In einem Buch, das zu besagter Vorlesung empfohlen wurde, von Isreal Koren (Titel weiß ich nicht mehr genau, irgendwas mit Arithmetic Algorithms glaube ich), wurde das Pipelining verschiedener schneller Addierer (u.a. Conditional Sum) näher behandelt. Ein Addierer wurde auch erwähnt, der kein Pipelining erlaubt, ich glaube es war Carry Skip (?).
Ace of Spades
2006-10-09, 12:29:23
Gibt es solche Schemazeichnungen wie im ersten Post auch für die Rendering Pipelines von ATI und nvidia Karten?
Würde mich mal interessieren
Vielen Dank
tatarus
2006-10-09, 19:05:11
Ja gibts.
http://www.hardwaresecrets.com/article/156
http://www.beyond3d.com/previews/nvidia/g70
Ace of Spades
2006-10-09, 19:08:13
danke
vBulletin®, Copyright ©2000-2025, Jelsoft Enterprises Ltd.