Ja, nach der kurzen Übersicht über Grundlagen der Assembler-Programmierung werde ich jetzt in diesem Kapitel 14,
was jetzt Rechnerarchitektur 2 heißt, noch mal einiges an Begriffen vorstellen,
womit eigentlich jetzt charakterisiert wird,
wie aktuelle Prozessoren seien das jetzt Server oder Desktop-Geräte,
seien das aber auch die Prozessoren,
die wir jetzt also in Smartphones,
in irgendwelchen Home-Appliances verbaut haben oder eben auch teilweise deutlich kleinere Rechner,
die dann also typischerweise als Steuerungs- oder Kontrollrechner in eingebetteten System eingesetzt werden.
Jedenfalls wie diese Rechner intern dann eben auch realisiert sind.
Bislang folgte die Vorlesungen eigentlich immer diesem Paradigma des von Neumann-Rechners,
wo man halt jetzt eben sagt,
ich habe eine zeitsequenzielle Abarbeitung von Befehlen,
wo eben ein einzelner Befehl geholt wird, dekodiert wird,
abgearbeitet wird,
wenn das fertig ist,
wird eben entsprechend der nächste Befehl geholt
Nicht, das ist dann eine Abarbeitung, wie sie dann eben
auch beispielsweise jetzt in dem kleinen mikroprogrammierten Dekor in dem RSB-Praktikum vorgekommen ist.
Das, was wir heutzutage eigentlich finden, sind aber typischerweise eben Architekturen,
die jetzt noch davon abweichende Grundprinzipien, quasi Verfeinerung dieses Prinzips,
mit berücksichtigen.
Deswegen sollen jetzt in diesem Kapitel eben nochmal diese Begriffe Pipelining
als eben ein zentraler Begriff Parallelität und eben auch Speicherierarchie
nochmal weiter erläutert werden
Ja. Pipelining, was ist das? Da ist im Prinzip die Grundidee,
dass man eine Funktion oder Funktionalität, Großelf hier in mehrere Teilschritte zerlegen kann.
Wenn man das jetzt macht und dabei für jeden Teilschritt,
das was hier jetzt also quasi als Stage bezeichnet ist,
diese Teilfunktion, F1 bis FK, dann eben so wählt,
dass jeder dieser Teilschritte eben ähnlich viele Schritte oder ähnlich viel Zeit braucht,
dass man dann Aufeinanderfolgende Berechnung dieser Gesamtfunktion F,
dann eben in so einer Pipeline realisieren kann,
wo ich dann eben immer eine Talberechnung mache,
das Ergebnis in einem Register-Speicher, das ist also das,
was dann eben hier in diesem Kasten drin ist.
Man spricht dann auch immer von einer Pipeline Stage und ich
dann dementsprechend mehrere dieser Pipeline Stages hintereinander geschaltet habe,
sodass ich insgesamt natürlich auch meine Gesamtfunktion Groß-F erreiche,
diese dann aber eben teilweise in mehreren dieser Schritte erfolgt.
Und der Trick dabei eben mit dieser zusätzlichen Speicherung der Zwischenergebnisse in den Registern führt jetzt eben dazu,
dass sich jetzt diese einzelnen Teilschritte da noch parallel zueinander ausführen kann.
Das heißt, wir stellen uns jetzt vor,
Großelf wäre jetzt also irgendwie eine Funktion,
sprich ein Schaltnetz, wie wir das ja kennengelernt haben,
wo jetzt also eine relativ komplexe Funktion ist.
Also beispielsweise, wir berechnen jetzt irgendwie eine Multiplikation von zwei Zahlen,
dann lässt sich das mit entsprechend viel Aufwand natürlich auch als reines Schaltnetz daraus beschreiben,
was dann also quasi als A Eingänge die beiden multiplikant und Multiplikatorwerte hat.
Und wenn entsprechend viel Zeit vergeht,
war ich dann natürlich dann doch relativ viel an arathmetischen Berechnungen dort,
also sprich Addition, das,
was an diesem Schieben entspricht und so weiter, mitmachen müsste,
würde ich dann eben im Ausgang mal ein Ergebnis bekommen.
Der Trick bei den Pipelines ist jetzt eben,
dass wenn ich jetzt mehrere dieser Multiplikation hätteeinander machen müsste,
dass ich dann eben sagen kann, ich habe hier entsprechende Hardware,
die dann eben in solche Partel-Stages aufgebaut ist oder unterteilt ist.
Und ich schiebe jetzt eben eine Reihe nach, meine verschiedenen Multiplikationen hier durch.
Und er halte so dann natürlich auch immer noch die Gesamtberechnung,
bekomme dann aber, das finden wir gleich auf einer
nächsten Folie dann eben sehen, ein deutlich höheren Durchsatz.
Das heißt, Anzahl der Berechnung pro Zeit steigt dann eben die gemacht werden.
Was dann dann auch noch mit wichtig ist, ist natürlich,
Diese Talfunktion F-I-N natürlich nicht beliebig klein oder trivial werden sollten.
Das heißt also jetzt nicht ein Pipeline-Register nach jedem Inverter in der Logik,
sondern das vom Verhältnis her, also das,
was hier an Zeitbedarf drin ist,
natürlich doch nochmal um einiges größer ist,
als dass ich was, oder das,
was man dann also als Zugriffszeit auf die Register hat.
Das heißt also, die Taktfrequenz dieser Register, die er dann also durch Eigenschaften wie Setup und holt irgendwie,
zum einen mit vorgegeben ist und dann eben die Komplexität dieser Funktion hier sollte dann eben so eingestellt sein,
dass ich hier über die Register natürlich schon mit der Zugriffszeit eine zusätzliche Verzögerung zeitlich bekomme,
diese aber im Vergleich, also mit der Verzögerungszeit dieser Funktion hier, entsprechend klein ist. So,
dieses Grundprinzip, ein Prozess oder eine Berechnung in unabhängige Abschnitte aufzuteilen,
ist dann eben etwas,
was wir so aus dem täglichen Leben natürlich also auch kennen,
also sprich Fließbänder sind so umgesehen, nichts anderes als Pipelines,
dass man eben die gesamte Bearbeitung eines Werkstücks in mehrere Tagschritte zerlegt,
die dann der Rainer abgearbeitet werden und man dann aber eben,
sagen wir jetzt nicht, einen Arbeiter hat er jetzt erst,
also sequenziell vom Anfang bis zum Ende der Arbeit oder der Bearbeitung arbeitet,
sondern eben nur ein kleine Teilaufgabe macht und entsprechend mehrere Leute dann also parallel mitbearbeitet,
Auto war schon lagen,
ist dann natürlich dann auch immer noch das klassische andere Beispiel dazu.
Das heißt, was man da dann immer macht,
ist eben solche Talschritte parallel zueinander abzulaufen,
dass man dann eben sagt,
zu jedem Zeitpunkt habe ich dann dementsprechend mehrere Objekte in unterschiedlichen Stadien,
Detailbearbeitung und was man natürlich dann auch immer hat,
gerade bei Fiesbändern ist es natürlich klar,
dass ich dann also zu sieben Zeitpunkten dann,
also wenn die Pipeline läuft,
dann eben auch alle Arbeitsstationen ausgelastet habe
So, wo wird sowas jetzt in der Computertechnik eingesetzt? Zum einen,
ich hatte ja eben schon das Beispiel Multiplikation genannt,
kann ich eben solche arrathmetischen Pipelines bei komplizierteren arrathmetischen Operationen machen,
die also sonst entsprechend sehr lange dauern würden,
weil ich dann eben ein sehr großes Schaltennetz für die Multiplikation habe,
wenn ich das dann eben unterteile in mehrere Teilschritte,
gewinne ich dabei entsprechend was,
wo dann eben dieser Durchsatz entsprechend erhöht werden kann, vorausgesetzt,
ich habe dann eben mehrere von diesen Funktionen da noch immer jeweils hintereinander.
Deswegen lohnen solche Grundprinzipien natürlich dann auch immer nur,
wenn die Pipeline überhaupt erstmal einigermaßen gut ausgelastet ist. Das ist etwas,
was heute dann also später bei oder dem Stichwort Bewertung von Pipelines
dann also auch noch sehen werden, was sich dann dahinter verbirgt,
wann so war es entsprechend zu machen ist. Das,
was sich jetzt hier eigentlich als Beispiel eher noch vorstellen werde,
ist dann eben das, was man in einem Prozess,
da dann bei der Befehlsabverwaltung macht,
was sich dann also jetzt hier Befehlsparkplan genannt habe,
dass man nämlich diese einzelnen Teilschritte so einer Befehlsabarbeitung,
wie sie in einem Forneumann-Rechner stattfindet, dann eben als Pipelining durchlaufen lasse,
wo dann eben diese Teilschritte Befehl holen, Befehl dekodieren,
entsprechend durchlaufen.
Nicht das folgt dann später nochmal ein bisschen genauer,
wo ich dann diese Schritte nochmal vorstelle. Vorher nochmal reinige Grundüberlegungen,
die jetzt noch mal so ein bisschen dieses Pipelining-Prinzip veranschaulichen und eben auch noch zeigen,
welche Probleme es gibt, wo die Grenzen von Pipelining sind.
Und ja, wie man dann eigentlich so damit umgehen kann.
Dazu erst mal noch mal eine Veranschaulichung in diesem Fall aus
dem Buch von Brandt und The Hallerun, wie jetzt das Park Running-Prinzip funktioniert.
Also angenommen, wir haben jetzt also hier irgendeine logische Funktion,
die braucht eine bestimmte Zeit, in diesem Fall also 300 Pico-Sekunden.
Und anschließend kommt dann eben ein Register, wo dann also
der Wert Bei aller Tagflanke dann eben entsprechend gespeichert wird.
Das heißt, man kann jetzt eben sagen,
für diese Funktion oder Funktionalität, der Eingang ändert sich,
es dauert hier eine bestimmte Zeit, der Tag kommt.
Das heißt, nach 320 Pico-Sekunden hätte ich dann also hier
jeweils mein Ergebnis und könnte dann einen Tag blau kommen lassen.
Hier ändert sich wieder was und das Ganze läuft dann eben
entsprechend hier wieder durch. Demzufolge kann man eben sagen,
ich habe sowas wie eine Gesamtverzögerungszeit dann eben von 320 Pico-Sekunden.
Und ich habe eben einen Durchsatz, Durchsatz wäre dann ja also nichts anderes,
als wie schnell kann ich das System takten.
Also der Kehr wird von 320 Pico-Sekunden sind 3,12 Giga-Herz.
Nach dem zufolge hätte ich dann eben 3,12 Giga-Operationen pro Sekunde.
Das ist dann also diese Abkürzung von Giga-Ops. So,
das wäre jetzt das Schaltnetz ohne die Pipeline. Wenn ich jetzt das das Ganze nehme und beispielsweise eine dreistufige Parkplan realisiere. Das heißt,
in diesem Fall dann die Logik, die jetzt also die 300 Piko-Sekunden braucht,
in drei Blöcke, A100 Piko-Sekunden oder Teile,
dann jetzt hier noch zwei zusätzliche Register mit einbaue,
ergibt sich, dass ich natürlich jetzt die Taktfrequenz so erhöhen kann,
dass ich eben alle 120 Piko-Sekunden einen neuen Takt geben kann,
der dann dazu führt,
dass das Ergebnis oder eine Berechnung dann eben hierüber ein bisschen dieses Register stattfindet,
dann mit dem nächsten Tag dann eben ein bisschen dieses Register und dann eben hier Pipelining-mäßig dann so durchwandert.
Ich nehme zufolge alle 120 Pipelsekunden, eine neue Operation.
Für die gesamte Bearbeitung einer einzelnen Rechnung ist es natürlich so,
dass die Latenz durch diese zusätzlichen Parkplan-Register minimal zunimmt.
Das heißt, vorher hatte ich ja 300 Pico-Sekunden Plus 20,
also 320, hiermit noch die beiden zusätzlichen Parkplan-Register,
habe ich dem zuvor jetzt für die Gesamtzeit,
die jetzt eine spezielle Berechnung braucht, dann eben 360 Pigo-Sekunden.
Aber da jetzt die Taktfrequenz jetzt eben entsprechend mit 120 Pigo-Sekunden eingestellt werden kann,
erhöht sich dann also hier der Durchsatz von vorher 3,12 auf 8,33 Giga-Operationen pro Sekunde.
Das heißt also, hier sieht man also sehr schön,
wie jetzt durch so einen entsprechenden Unterteilung die Gesamtlatenz zwar minimal singt,
man aber, sofern ich diese Parkplan eben immer gefüllt bekomme,
doch einen deutlich höheren Durchsatz mit erreichen kann.
Hier ist das Ganze dann eben auch nochmal grafisch dargestellt,
in der Art und Weise,
wie jetzt über die Zeit gesehen die Operationen ausgeführt werden,
nicht ohne Parkplaning, das war eben ja auch das,
was wir sonst ja auch immer beinahe,
Befehlsabarbeitung im Vornamen am Rechner gehabt haben,
nicht ich hole mir einen Befehl, der wird entsprechend Angefangen hier,
abzuarbeiten, wenn der fertig ist,
kommt der nächste Befehl.
Und die Sachen laufen an ihm hier streng, sequenziell hintereinander. So,
weil im Pipelining habe ich jetzt eben genau diese Überlappung,
dass ich sagen kann, ich mache eben einen ersten Teilschritt von dem ersten Befehl.
Und dann kommt jetzt eben Takt und die nächste Pipeline-Stufe.
Dieser Befehl wird dann eben entsprechend weiterbearbeitet. Aber es kann
dann eben schon ein neuer Befehl mit angefangen werden, sodass während ich,
also hier von dem ersten Buffet dann in diesem Tal lebe,
ich dann eben schon Teil A, von den zweiten Befehlen mit abarbeiten kann und man dadurch dann dementsprechend diese Überlappung hinbekommt.
Ja, das ist also im Prinzip eigentlich erst mal das,
was Pipelining ist, hier auf den jetzt folgenden Folien sieht man das Ganze,
also auch noch mal so ein bisschen zeitlichen Ablauf,
also ich habe jetzt hier also irgendwie irgendwelche Register,
sind alle jeweils mit der Taktvorderflanke hier irgendwie immer getaktet und ich habe hier meine Befehle in der Abarbeitung,
nicht also Befehl 1, Befehl 2,
Befehl 3 oder Operation 1 Operation 2,
da war es schon 3.
Und das Ganze ist jetzt einfach nur, damit man sieht,
wo sich das jetzt in der Pipeline befindet,
dann eben entweder mit Dunkelgrau, hellblau oder hellgrau entsprechend gekennzeichnet.
So, zu diesem Zeitpunkt, es war nach 939,
also kurz vor dem Takt,
habe ich am Eingang jetzt also die Eingangswerte von der Operation 2 anliegen.
Das Ganze ist jetzt hier auch schon durch diese Verzögerung oder durch
die Logik A durchgelaufen und das fertige Teilergebnis wäre dann eben schon mal am Eingang dieses Registers.
Noch ist der Tag nicht gekommen, in dem Register selber,
ist jetzt eben noch dieses Teilergebnis B gespeichert,
dessen Wert ist dann eben auch schon hier durch diese Logik
der Teilberechnung B an den Eingang dieses Registers hier gelangt und demzufolge befinde ich mich jetzt also hier an dieser Stelle,
wo ich dann also hier für diese beiden Befehle die entsprechend hier in der Parklines sind.
So, jetzt kommt der Pipeline-Takt. Was passiert? Das
Register übernimmt den Wert am Eingang. Dieses Register desgleichen.
Und man stelle sich dann eben immer vor der Eingang der Schaltung.
Hier ist dann im Prinzip auch erstmal nichts anderes als der Ausgang eines Registers.
Das heißt, der kann sich dann eben hier auch schon ändern. Und ich habe dann eben hier jetzt also den Befehl oder die Operation 3 dann eben in der Abarbeitung. So,
wenn jetzt weiter Zeit vergeht, Quasi zwischen diesem Takt und diesem Takt,
dann wird jetzt also durch die Werdewechsel hier in den Eingängen jeweils in der Logik irgendwie eine Teilberechnung erfolgen,
was hiermit so ein bisschen mit dieser Linie,
also dieser verwaschenen Linie angedeutet ist,
ist das natürlich dann also abhängig von den Daten,
also wir bleiben jetzt hier wieder, dann steht,
gehen wir jetzt wieder in die Schaltnetze zurück,
Stichwort Hasatz und so weiter, fangen jetzt also an,
sich diese Daten irgendwie zu ändern,
nicht und einige Bits haben dann vielleicht schon irgendwie ein richtiges Ergebnis,
andere noch nicht,
weil also diese Änderung hier noch irgendwo in der Logik sich erst durcharbeiten muss,
weil ich jetzt natürlich dann also immer die jeweiligen Gatta-Verzögerungen der Beteiligten nennt,
oder Ripple Carry, Adira,
oder was auch immer man dort drin dann also verbaut hat,
habe, die dann dazu führen,
dass ich dann also sukzessive hier durch die Logik sich,
also irgendwo der richtige Wert entwickelt und berechnet wird.
Gut, wenn wir jetzt weiter in der Zeit geht,
jetzt quasi wieder kurz vor dem nächsten Tag,
habe ich im Prinzip was Analoges zu der Ausgangssituation von dem Ganzen,
dass sie nämlich an den Eingängen dieser Register dann den
wirklich jetzt komplett gültigen Wert liegen habe.
Und das Ganze dann eben mit der nächsten Taktflanke wieder übernommen
werden kann und ich dann eben nach der Taktflanke dann eben wieder diese Ausgangssituation habe,
wo sich das dann entsprechend weiter fortarbeitet.
Ja, das ist also so dieses Parkplaning-Prinzip.
Hört sich jetzt natürlich also erstmal sehr gut an.
Es gibt allerdings dann doch noch einiges an Randbedingungen, die man reinhalten muss,
beziehungsweise die zu berücksichtigen sind, damit das entsprechend funktioniert. Zum einen,
was also natürlich klar ist oder offensichtlich sein sollte,
ist, dass das Ganze eigentlich nur dann richtig gut geht,
wenn diese Aufteilung der Gesamtfunktion, das was also ganz am Anfang,
diese Große F war, in die einzelne Teilschritte,
dass die Teilschritte natürlich alle irgendwo gleich oder ähnlich lang dauern sollten,
weil sich nachher natürlich die Taktfrequenz von dem Gesamtsystem an der längsten Verzögerung in einem dieser Pipeline-Blöcke ausrichtet.
Das heißt, wenn ich jetzt also meine Funktionen mit den 300 Pico-Sekunden nehme und die jetzt,
also ich ihren Talblöcke nicht A100 zerlege,
sondern war das vielleicht schadungstechnisch, also irgendwie nicht so richtig sinnvoll ist,
hier also irgendwie eine Praditionierung habe,
wo ich also hier 50 Pico-Sekunden in dieser Pipeline Stage A 150 Pico-Sekunden hier unter 100 Pico-Sekunden hier habe,
dass ich dann natürlich Die Gesamtdurchsatz, sich also wirklich jetzt danach richtet, wie schnell kann ich mein System takten?
In diesem Fall würde sich dann also die Taktfrequenz natürlich jetzt zu den 170 Pico-Sekunden heraus ergeben,
was dann aber eben auch heißt,
dass Hier beispielsweise jetzt bei der ersten Partline Stage,
wo ich es also ja eigentlich sehr schnell bin und schneller takten könnte,
ich natürlich nach 50 Pico-Sekunden hier schon das richtige Ergebnis anliegen habe, es aber entsprechend lange dauert, bis dann der Takt kommt.
Das heißt, hier verschenkt man dementsprechend viel Zeit hier genauso.
Nicht demzufolge ergibt sich dann auch eine Gesamtverzögerung des Systems,
die dann eben nicht mehr aus der Summe der einzelnen Verzögerung herausgebildet wird,
sondern wo ich dann hier natürlich genauso 150 Pico-Sekunden plus 20.
Das heißt also 170 Pico-Sekunden mal drei. Demzufolge 510 Pico-Sekunden
Verzögerung habe. Und der Durchsatz,
dann zwar immer noch höher ist als bei dem System,
ohne Parklining, aber die Latenz größer geworden ist.
Und wenn ich das eben vergleiche mit dieser Lösung hier,
man da natürlich dann also auch einiges verschenkt hat.
Also hier sieht man das dann eben auch nochmal im zeitlichen
Also das nützt mir jetzt eben nichts,
dass also A und C hier schneller sind als B,
weil also eben diese Taktfrequenz natürlich dann also durch diesen längsten Block
bestimmt wird und ich dann eben hier einfach irgendwo Zeit verschenke,
was dann also sich dann also deutlich an dieser Latenz dann eben auszeichnet.
Deswegen Quintessenz funktioniert eben nur wirklich gut, wenn man das also schafft,
sein System in möglichst gleich schnelle Stufen aufzupeilen. Dann eine andere Sache,
wenn man jetzt sagt, ich nehme jetzt also Diese Aufgabe mit den 300 Pico-Sekunden und mache jetzt also noch eine größere Pipeline-Tiefe. In diesem Fall würde ich jetzt,
als ich hier sechs Pipeline Stages machen,
die dann jeweils 50 Pico-Sekunden brauchen und dann dementsprechend,
die wir als die Pipeline-Register dazwischen,
dann sieht man natürlich dadurch,
dass ich dann also hier doch einiges mehr jetzt an zusätzlichen Pipeline-Registern einbaue,
der die Gesamtverzögerung dann eben doch schon etwas deutlicher anwächst,
weil jetzt natürlich dieses Verhältnis von der Zeit,
die also jetzt hier in der Logik verbraucht wird und der Zeit,
die ich jetzt also zusätzlich mit diesem Partner-Registern hin super hingehe,
da natürlich also immer deutlich ungünstiger wird,
als das also in dem ersten Beispiel dann mit dem Dreier Carpeline Stages der Fall war.
Der Durchsatz, dadurch, dass ich jetzt hier natürlich jetzt sechs Teilberechnungen Arbeit habe,
steigt bei diesem Schema allerdings dann trotzdem immer noch.
Trotzdem, wir sollen uns also merken, es gibt eben entsprechender Pipeline-Länge wachsenden Overhead durch die Register.
Und wenn man sich jetzt also ansieht,
wie das Verhältnis ist, von dem Overhead,
der jetzt also durch das Register in Bezug auf die Taktperiode mit hinzukommt,
dann sieht man, dass mit wachsender Registeranzahl,
also jetzt hier bei diesen Zahlen 20 Begrüßekunden pro Register und 300
für die Gesamtfunktionalität dann bei dieser Lösung jetzt hier mit den sechs Registern dann eben schon über ein Viertel zusätzlicher Verzögerung Kanalsa als Overhead durch die Register hier mit reingekommen ist.
Also das ist etwas, was man dann auch immer noch im Hinterkopf haben sollte,
um dann zu sagen, naja, bis wann,
beziehungsweise bis zu welcher Pipeline-Tiefe lohnt sich das überhaupt,
das hier entsprechend zu unterteilen.
Andere Gründe jetzt also in Bezug auf Prozessor-Pipelines,
weswegen man da jetzt also die Pipelines nicht beliebig tief machen kann,
wen wir da noch kennenlernen,
weil da gibt es dann eben bei der Abarbeitung von Befehlen jetzt in solchen Befehls-Pipelines
Zum Beispiel Sachen, die Datenabhängigkeiten, die dann eben auch dazu führen,
dass das Ganze daran auch nicht beliebig gut funktioniert. Ja,
ansonsten ergeben sich Datenabhängigkeiten generell natürlich erstmal durch etwas,
wo man sagt, ich kann das nicht für beliebige Berechnungen machen,
sondern wenn ich jetzt sowas wie solche Rückkopplungseffekte habe,
also beispielsweise die Combinational Logic wäre jetzt,
also hier sowas wie ein Schaltnetz,
was irgendwie anwehrt zu einer Zahl hinzuaddiert
Und nehmen wir jetzt einfach ein Inkrement da und es war
einfach immer nur plus eins gerechnet werden.
Ich habe hier meinen Wert und das wird jetzt also hier irgendwie durchgeschoben.
Dann habe ich logischerweise die Datenabhängigkeit, dass Operation 2 erst starten kann,
wenn Operation 1 komplett fertig ist. Das heißt also,
in solchen Fällen mit solchen Rückkopplungen kann ich oder eben generell gesprochen mit Datenabhängigkeiten,
kann ich eben kein Pipelining verwenden, weil ich eben warten muss,
bis die Operation komplett abgeschlossen ist,
wegen dieser Datenabhängigkeit und dann erst wieder neue anfangen könnte
Deswegen ist es klar, wenn man das jetzt hier nicht. Ja,
hier ist dann eben auch, wie das Ganze jetzt eben aussehen würde,
wenn man das jetzt also quasi naiv in irgendwie so ein Parkplaning bringt.
Nicht, dass man dann eben sagt,
wenn ich hier entsprechend mit diesen Rückkopplungen jetzt,
also Datenabhängigkeiten habe und das Ergebnis dieser Operation, Gesamtoperation,
Großf, hier eben dann nächsten Schritt wieder weiter bearbeitet werden sollen.
Dann sieht man eben hier schon, ich bin erst nach drei Takten
in diesem Fall hier fertig und könnte damit dann weiterarbeiten.
So und alles, was ich hier vorher schon als Operation
2 und Operation 3 hier in die Pipeline getan habe,
ist eigentlich auch solid, weil ich dann,
dass ich hier noch gar nicht das gultige Ergebnis habe.
Nicht, weil also das Ergebnis dann also entsprechend zu spät ist. So,
dadurch sieht man dann eben eigentlich auch etwas,
was sich jetzt,
also zumindest also auf die saueren Hardware-Ebene auch auszeichnet,
dass ich eben durch das Pipelining dann eben auch das Gesamtverhalten oder das zeitliche Verhalten des Systems dann,
also auch deutlich ändert und ich eben solche Pipelining-Techniken auch nicht für beliebige Anwendungsfälle einsetzen kann.
Nicht ansonsten muss man immer sagen, diese Idee,
Pipelining ist für uns als Programmierbar,
wenn ich das jetzt also in Bezug auf solche Prozessor-Pipelines sehe,
als Informatiker natürlich transparent, sondern da schreibe ich mein Programm.
Das wird, wie wir im letzten Kapitel gesehen haben,
dann irgendwie übersetzt
Mehr stufe ich jetzt, also irgendwie in nachher Assembler-Anweisungen,
die dann also irgendwo auf einer Hardware ausgeführt werden.
Und also ob diese Hardware jetzt nach dem bislang immer propagierten
ganz einfachen Zeitsequenzellen von Norman Schema ablaufen oder ob Gott,
also irgendwelches Pipelining verwendet wird, das sehen macht für den Programmcode auf Assembler-Ebene,
so rum gesehen, eigentlich erstmal keinen Unterschied.
Gut, jetzt hat er ja schon immer gesagt,
das, was ich jetzt hier als Beispiel nehme,
für das Parklining ist halt eben der Teil,
wo man also jetzt so eine klassische Befehlsabarbeitung hat,
wie wir das also bislang immer ja bei dem von Neumann-Schema gesehen haben,
wo ich jetzt also in einer Stufe eben sage,
ich hole die Instruktion aus dem Speicher,
lade sie in das Befehlsregister.
Dort, wo diese Instruktion dekodiert,
anschließend wird jetzt eben festgestellt,
woher sollen die Operanten kommen
Aus dem Speicher, aus irgendwelchen Registern, dann wird diese Operation ausgeführt,
beispielsweise jetzt also irgendeine Art medische und logische Operation,
die dann also durch die Adu gemacht wird und dann wird
gegebenenfalls dann eben dieses Ergebnis auch wieder eine Speicher zurückgeschrieben,
beziehungsweise wenn ich jetzt also einen Befehle habe,
die jetzt also Daten laden,
hole ich dann eben was aus dem Speicher.
So und dieses Schreiben entweder auf Speicher oder auf Register,
das sind dann eben hier
diese letzten Schritte hier
So,
hier ist das Ganze jetzt auch schon so ein bisschen eigentlich erweitert in die Art und Weise,
wie so eine Befehlsabarbeitung als Pipelining überhaupt noch funktioniert oder funktionieren kann,
wo man jetzt nämlich in Bezug auf den Befehlssatz,
wenn ihr es wieder in Rechnerarchitektur 1 zurückgehen,
sagt,
der Befehlssatz wird typischerweise dann eben so aufgebaut,
dass ich jetzt nicht mit allen Befehlen auf den Speicher oder also auf den Hauptspeicher drauf zugreifen kann,
sondern dass die ganzen Arathmetisch und logischen Befehle eben immer nur auf internen Registern arbeiten und der einzige oder die einzige Möglichkeit auf den Hauptspeicher zuzugreifen,
dann eben über Load and Store ist,
wo ich dann eben einen Datentrantransfer entweder vom Hauptspeicher in diese internen Register habe oder eben zurück aus diesen Registern in den Hauptspeicher.
Das heißt, also dieses hier funktioniert dann eben auch nur für solche Load and Store Architekturen.
Also wenn ich dieses jetzt aber hier habe,
kann man eben Hier auch entsprechend diese Schritte der Befehlsabarbeitung,
was dann also Hierarchie diese horizontalen Linien angedeutet ist,
dann nehme ich auch sehr gut in eine Pipeline umsetzen.
Und das war also,
sag man, dann auch dieses grundlegende erste Prinzip,
wie das also in der Mips-Architektur dann eben von den Herren Hannessey und Patterson,
die das also entwickelt haben, dann eben auch umgesetzt wurde,
wie man Pipelining realisieren kann.
So, hier ist das jetzt also nochmal,
ich also vorher generell auf den Folien hatte,
also jetzt nochmal für diese Befehlsabarbeitung gezeigt.
Und zwar einmal eine serielle Bearbeitung ohne Pipelining. Ja,
beziehungsweise bevor ich hier nochmal anfange, Entschuldigung, nochmal kurz zurück.
Also bei diesen Schritten, die dir jetzt vorgestellt worden sind,
bei solchen Load-Store-Architekturen, muss man auch immer sagen,
wenn ich da jetzt sowas wie eine Pipeline einbaue und sage,
ich weiß jetzt,
also diesen Schritten dann eben hier
auch irgendwelche Pipeline-Stages zu
Es ist natürlich befehlsabhängig, welche von diesen Stufen jetzt hier,
also auch für die Abarbeitung eines Befehls genutzt werden.
Das heißt, es kann eben sein,
dass Teile dieser Pipeline-Stages für bestimmte Befehle eben nicht benutzt werden,
beziehungsweise dann der Befehl einfach nur von einer Stage direkt zu anderen durchwandert.
Das heißt also, was wie ein Speicherzugriff habe ich jetzt
eben bei einem Load und Store natürlich auch nur bei diesen beiden Befehlen,
während wenn ich jetzt also einen Alu-Befehl habe,
wo jetzt also mit Registerinhalten, gerechnet wird.
Das Ergebnis landet wieder in einem Register. Nicht,
dann muss ich hier dieses Execute haben, ich muss das
Rideback haben, also unser Ganze in den Register zurückzuschreiben.
Ich habe aber hier keinen Speicherzugriff. Also da ist eben nur zu der Art und Weise,
dass also teilweise dann für viele Sachen, also Art Operationen,
ohne Speicherzugriff, ich bei irgendwelchen Sprüngen,
hat man dann also keinen Speicherzugriff, vielleicht auch keinen Registerzugriff,
das ist dann davon abhängig,
was für Sprünge das jetzt sind
Gegebenenfalls kann also eine Sprungadresse natürlich auch am Register sein.
Häufig sprengt man aber irgendwie jetzt zum Beispiel jetzt bei kleinen Schleifen
einfach nur relativ zum Programmzähler. Hätte dann diesen relativen Wert
dann einfach als kleinen Emiliat-Wert im SM-Lacode direkt mit drin stehen.
Da kommen wir jetzt also wieder so ein bisschen,
also auf dieses Kapitel 13 zurück.
Was man jetzt bei einem empfehlen setzt und bei der Befehlskodierung
dann hat, wie man da Sachen eingeben kann.
Und gut, dann gibt es noch
so einige Sachen
Wie jetzt zum Beispiel so einen Befehl namens Nope,
No Operation, wo eigentlich nichts weitergetan wird.
Warum ist sowas jetzt überhaupt sinnvoll? Werden wir später dann
gleich noch sehen, wenn ich jetzt nämlich Probleme in dem
Zweite Probleme in den Pipelining bekomme.
Ich hatte eben schon gesagt, es gibt sowas wie Datenabhängigkeiten.
Ein Teil dieser Datenabhängigkeiten könnte man zum Beispiel durch bestimmte Nope,
oder durch das Einfügen von Nope-Befehlen dann also wieder entschärfen,
indem ich dann eben beispielsweise einfach jetzt diese Dummy-Befehle in
die Pipeline schiebe und dafür sorge das dann also
bestimmte Sachen
aufgelöst werden
Gut, dann hier auch noch mal als Ergänzung,
Partelines können also auch teilweise noch deutlich feiner unterteilt werden. Also wie gesagt,
hier stelle ich jetzt dieses ursprüngliche Schema jetzt von MIPS-Architektur vor,
wenn man sich jetzt also irgendwie so aktuelle Prozessoren ansieht,
wie dort bei denen Parkplaning realisiert wird,
hat man also deutlich tiefere Parteline-Stufen.
Beispiele folgen dann also auch gleich noch am Ende dieses Teilabschnitts
zu dem Pipelining. Gut, aber jetzt nochmal also wieder
also auf das Beispiel zurück, serielle Bearbeitung ohne Pipeline.
Ich habe hier also diese Teile Estruction Fetch, Registerzugriff,
Alu, Speicherzugriff und gegebenenfalls das Speichern eines Ergebnisses dann wieder in das Register zurück.
Dauert dann eben hier eine bestimmte Zeit,
in diesem Fall jetzt also irgendwie hier 800 Pico-Sekunden und das
wäre dann eben das Ganze in so einer strengen Zeitsequenz herren Abarbeitung ohne irgendwelches Pipelining.
Hier, keine Angst, müssen sie nicht wissen,
sieht man dann also den Programm, in diesem Fall ist das jetzt hier MIPS-Assembler-Code,
also LW steht dann für Load Word.
Dieses hier ist dann also quasi das, hergeladen wird,
also sprechende Speicheradresse und dieses ist dann die Zieladresse.
Also es wird also auch auf einem den Hauptspeicher zugegriffen und in Register Null,
die dort stehende Adresse,
auf die wird ein Offset von 100 hinzuaddiert und das Ergebnis ist
dann in die Adresse unter der auf dem Hautspeicher zugegriffen wird,
dort ein Datum gelesen wird und dessen Wert wird dann eben in Register 1 gespeichert.
So, hier sieht man dann ja auch,
dass sich also quasi hier so für solche Adressberechnungen beispielsweise dann
eben Inhalte von Registern habe und dann eben noch Offsets hinzuaddiere.
Nicht sowas ist dann Teilweise war das dann ja also auch beim X86er,
Sambler schon so bei einigen Befehlen, sowohl sowas mal kurz vorgestellt wurde.
Teilweise ist so was dann eben sinnvoll,
um jetzt beispielsweise bei Race oder bei Datenstrukturen auch aufeinanderfolgende Elemente zu verweisen,
die dann eben entsprechend mit diesen Off-Sets dann über Indizes indiziert werden können,
was man dort also an der Stelle machen kann.
Hiermit erklärt sich dann auch, weswegen ich jetzt,
also hier, in diesen Parkplans hier nicht sage,
Warum mache ich jetzt nicht, weil entweder ich habe Load and Store,
da greife ich auch einen Speicher zu oder ich habe eben Alu-Befehle,
wo ich jetzt mit der Alu rechne.
Warum sind das jetzt hier zwei aufeinanderfolgende Pipeline-Stages und nicht Sachen,
die ihr quasi parallel sind und bei dem einen Befehl benutze ich dieses,
bei dem anderen Buffet benutze ich dieses hier.
Und die Idee ist natürlich, dass man sagt,
für irgendwelche Adressberechnungen, so wie sie hier stattfinden,
also sprich den Inhalt von Register 0 plus 200,
benutze ich natürlich dann also auch nicht jetzt irgendwie eine spezielle Adressberechnungsalue,
sondern ich benutze jetzt eben Erstmal die eine einzige Alu,
die mein System jetzt hier haben sollte.
In dem späteren Abschnitt zur Rechnerarchitekturen, also 14.2,
wo es dann also in Parallelität geht,
werden wir dann also als Begriff auch nur etwas kennenlernen, was dann Superskalarität heißt.
Das ist das, was also inzwischen auch eigentlich alle Prozessoren haben,
die handels eben nicht nur eine einzige Alu,
mit der ich rechnen kann, sondern mehrere,
also sprich meinetwegen vier Alus für Indiger-Berechnung,
ein oder zwei für Fließkomma-Berechnung und dann vielleicht nochmal irgendwie zwei zusätzlich, um jetzt also nur solche Adressberechnungen zu machen.
Nicht, das ist also etwas, was dann zusätzlich nochmal hinzukommt,
wie gesagt, hier geht es jetzt erstmal nur darum,
dass wir sagen, ganz einfache primitive Architektur,
wie wir sie also beim Deko kennengelernt haben, eine einzige Alu,
aber jetzt soll das Ganze eben in ein Parkline-Exchema gepackt werden.
Gut, also das ist jetzt die serielle Bearbeitung ohne Pipelining,
wenn man das jetzt also hier mit dem Pipelining macht,
sieht man natürlich die Taktfrequenz richtet sich dann nach den längsten Operationen.
In diesem Beispiel waren das also in 200 Pico-Sekunden,
die dann also wohl für Alu Speicherzugriff beziehungsweise Instruction Fetch,
was ja dann auch ein Speicherzugriff ist, verwendet werden.
So, und dadurch sieht man dann eben,
dass dann eben diese Talberechnung hier eben in entsprechend fünf solcher Takte unterteilt werden kann,
von Befehl holen bis zu der kompletten Abarbeitung,
die dann also hier in diesem Fall dann,
also hier mit dem Ride Back beziehungsweise schreiben und das Register stattfindet
Und ich dann aber, natürlich entsprechend dieser höheren Taktrate dann nachher
bis zu fünf Operationen dann auch gleichzeitig in der Bearbeitung in dieser Pipeline habe.
Inzwischen diesen einzelnen Schritten, das, was ja ganz am Anfang vorgestellt worden ist,
hat man dann dementsprechend diese Pipeline-Register. So,
das ist jetzt also hier auf dieser Folie einmal so skizziert, Instruction Fatch,
Instruction Decode und Operanten holen aus dem Register, Execute,
Memory und Wrightback, dazwischen sind dann eben immer diese paar Weitweinregistern.
Und ja, je nachdem, was jetzt also hier nicht gezeichnet ist,
um welche Befehle es sich handelt,
hat man hier natürlich noch beliebig viel an zusätzlicher Logik und Multiplexer dazwischen.
Sprich, wenn ich jetzt also zum Beispiel kein Spari jetzt
sogar farbe und ich nach einem metrischen Befehl habe,
dann wird also hier irgendwie was in einem Execute berechnet und das Ergebnis,
das soll jetzt das hier rüber angedeutet werden,
wird dann natürlich dann im übernächsten Tag einfach in den Register zurückgeschrieben.
So, das ist also diese Grundidee von dem,
was man dann, also Risk-Architekturen hat. Wie gesagt,
einer der oder der erste Vertreter davon war dann eben
im Prinzip dieser Mips aus dem Buch von Peterson Pennecy.
Ja, das, was sie hiervon jetzt eigentlich mitbekommen sollen,
wissen müssen, ist eben dieses Koron-Prinzip-Pipelining.
Was ist das? Wie funktioniert das? Was jetzt nicht wissen müssen,
ist, wenn ich jetzt,
dass ich hier gleich nochmal so ein paar Grafiken dazu zeige,
wie die jetzt genau aussehen.
Da wird also jetzt niemand verlangen, dass da also
irgendwie sowas kommt
Komplett aufgezeichnet wird, also auch, weil auch da,
muss ich sagen, in den Grafiken sind ja teilweise,
wenn man das jetzt selber so realisieren und umsetzen würde, sind dann teilweise auch noch super Kinken mit drin.
Nicht deswegen nur das, was man eigentlich wissen muss, eben diese Grundidee. So,
was dann hier jetzt natürlich sieht,
wenn man das jetzt also für so einen relativ einfachen Befehlssatz,
den man sich da jetzt also ausdenken kann,
also für so einen beispielsweise, also irgendwie drei Adress-Loadstore-Rechner,
wenn man das jetzt eben vergleicht mit einer Abarbeitung ohne Pipelining,
dass man da also je nachdem, wie die Befehle aussehen,
wie sie die Pipeline Stages nutzen, wie das Ganze zeitlich aufgeteilt ist,
aber eben so um bis zu fünfmal besser sind als die Seriele Ausführung. Ich aber eben verglichen mit einer seriellen Lösung,
also hierdoch nur ein relativ gering, zusätzlichen Hardwareaufwand habe,
nämlich durch,
also hier entsprechend viele Pipeline-Register.
So, wie sieht das Ganze nochmal jetzt ein bisschen im Detail aus,
wenn wir uns das jetzt da Sie nochmal ansehen?
Also ich habe Jetzt hier diese Rechenarchitektur jetzt,
also als serielle Realisierung ohne Pipeline.
Ist jetzt also hier in dieser Grafik angedeutet. Wie gesagt,
die muss man jetzt also nicht irgendwie zwingend auswendig kennen.
Hier einfach nur angedeutet, Programmzähler. Da habe ich jetzt eine Adresse,
mit dieser Adresse greife ich dann eben auf das Instruction-Memory,
also den Spalter darauf zu, wo ich jetzt also meine Befehle hole.
Anschließend, wenn die Befehle da sind,
kann ich die jetzt eben über Schadennetze
entsprechend dekodieren
Könnte jetzt eben sagen, beispielsweise bei Alu-Befehlen,
die Operanten sollen jetzt eben aus Register 1 und Register 5 geholt werden.
Demzufolge wird dann also hier auch über einen Multiplexer dann eben gesagt,
okay, hier, diese Werte kommen,
gehen dann eben an den Eingang der Alu,
wo dann die eigentliche atmetische Operation,
also beispielsweise die Addition stattfindet und das Ergebnis in diesem Fall
würde dann eben hier über diesen Multiplexer und hier dann eben
wieder in einem Zielregister hineingehen
Und gut, dadurch, dass ich jetzt sage, load on store,
passiert jetzt also an der Stelle natürlich jetzt keinen Zugriff auf irgendwie den Datenspeicher,
wo ich jetzt also entweder Sachen rauslese,
um sie dann quasi hier rausgelesen,
in ein Register zu transferieren beim Load oder beim Dorf,
wenn der Inhalt eines Registers dann eben hier in den Spalter reingeschrieben wird.
So, wenn man sich so hier oben, das,
was hier angedeutet ist,
ist dann also im Prinzip die Adressberechnung von dem Ganzen,
also auch dazu, Ich habe im Befehlszähler,
also mein Befehlswort, was ja gelesen worden ist,
das Ganze setzt dann auch voraus,
dass hier sowas wie ein Wortbefehle habe.
Das heißt, es wird immer nur ein einziges Speicherwort gelesen.
Da steht dann eben auch der komplette Befehl drin.
Und nach der Abarbeitung wird im nächsten Schritt dann eben es sein,
es handelt sich um irgendwelche Sprungbefehle, der nächste Befehl geholt.
So, der nächste Befehl holen passiert hier jetzt durch dieses Plus 4.
So, jetzt konnte ich natürlich wieder die allgemein beliebte Prüfungsfrage
stellen,
warum plus 4
Sollten sie jetzt eigentlich wissen. Und zwar, wenn man
jetzt als Speicheradressierung sowas voraussetzt, wie die Speicherworte werden waldweise adressiert.
Und wenn man jetzt eben weiß, ich habe eine 32-Bit-Architektur,
dann sind natürlich jetzt quasi zwei aufeinanderfolgende Befehle adressmäßig jeweils vier voneinander unterschiedlich.
Das heißt also, der erste Befehl wäre dann also quasi Hier beispielsweise an Adresse Null,
der nächste dann eben demzufolge dann hier an Adresse 4,
8, 12, 16 und so weiter.
Das heißt, ich lese dann hier immer jeweils ein ganzes 32-Bit-Wort aus.
Bei 64-Bit-Architekturen müsste man dann eben hier jetzt plus 8 rechnen,
um dann hier also ein 64-Bit-Wort rauszulesen und da müsste er arbeiten.
Also da sind wir zu diesen Offsets. Diejenigen,
die das jetzt also nochmal irgendwie so ein bisschen rekapitulieren, jetzt in den Decore
Das rechnet Struktur im Praktikum wieder zurück, denken nicht,
da haben wir 16 Bild, da wurde dann eben plus 2 gerechnet.
Auch da muss man sagen, das ist natürlich jetzt immer so ein bisschen davon abhängig,
wieder die Randbedingungen sind, sprich rechne ich hier bei itweise oder rechne ich jetzt A frakieren und direkt in Adressen, dann würde natürlich plus 1 gerechnet werden. Gut,
also wie gesagt, hier oben dann,
also sowas wie nächsten Befehl machen und das,
was also hier über diesen Multiplexer und diesen Adira dann gegebenenfalls noch passiert,
sind halt Sachen, wenn ich jetzt sowas wie Sprünge habe oder wie bediente Sprünge,
dass ich dem zufolge dann natürlich Das Sprungziel,
also sprich den nächsten Wert dieses Befehlszählers,
dann jetzt nicht mehr als alter Wert plus 4 habe,
sondern dass das dann eben entweder als Emediate-Wert,
als Teil in einem Buffet drinsteht oder eben irgendwie entsprechend durch eine Berechnung passiert worden ist,
wo ich dann relativ zu irgendwelchen Registerinhalten mein neuen Programmzählerinhalt,
also sprich das Sprungziel dann eben passend berechnet habe,
wenn ich sowas habe,
wie bedingte Sprünge wurde das dann eben gegebenenfalls Hier sowas wie diesen Multiplexer mit ansteuern,
wo ich dann eben sagen kann, wenn der Sprung stattfindet,
habe ich hier das neue Sprungziel,
wenn der Sprung nicht stattfindet,
dann nehme ich eben den nächsten sequenziellen Formen empfehlen.
Das ist also das, was sich hier dahinter verbirgt. Letztendlich ist natürlich der Aufbau,
welche Einheiten hier irgendwie drin sind, wie die verwendet werden,
immer von der Instruction Set Architecture, also sprich von dem Befehlssatz abhängig.
Und bei den MIPS-Befehlssatz würde es dann eben so,
beziehungsweise ähnlich aussehen, wenn ich einen anderen Befehlssatz habe,
Kann sich das natürlich entsprechend stark davon unterscheiden. So,
was wir jetzt hier bei dieser Serienrealisierung ohne irgendwelches Pipelining mit hat,
ist, wenn ich jetzt also mir das Ganze hier immer ansehe,
ich kriege hier sowas wie einen längsten Fahrt,
der dann die Taktfrequenz des Systems vorgibt.
Also dies ist ein Register, das kriegt einen Takt,
der Takt ist gekommen, ich habe hier meinen neuen Wert,
aufgrund dieses Werts adressiere ich jetzt natürlich den Restruktionsspeicher,
der ist für mich nichts anderes als ein Scheitnetz,
das heißt, es dauert eine gewisse Zeit, dann habe ich die Instruktion gelesen
Anschließend wird diese Instruktion aus dem Instruction Memory dekodiert.
Wenn das sowas wie ein Alu-Befehl ist,
aus dem Registern an eben der entsprechende Operant irgendwie geholt.
Nicht, dann läuft das hier gegebenenfalls natürlich auch wirklich ein Multiplexer,
dann durch die Alu. Wenn jetzt beispielsweise sowas stattfindet wie ein Read,
oder nee, ein Load von einer Adresse, die hier berechnet wird,
habe ich an der Stelle dann eben auch noch einen Zugriff auf den Datenspeicher.
Auch das ist dann hier nichts anderes als ein Schaltnetz oder
Alpha der Entspannung eine große Verzögerung.
Das Ergebnis läuft dann hier durch den Multiplexer hier rein.
Und mit der nächsten Taktflanke kam es dann eben in das entsprechende Zierregister geschrieben werden,
beziehungsweise der Program Counter wird dann neu geladen.
Das ist dann das hier hinten. So,
und alles hier dazwischen ist dann eben nichts anderes als jede Menge Schaltnetze,
die dann dementsprechend Zeit kosten.
Aufgrund dieser Zeit oder Verzögerungszeit berechnet sich dann eben die maximale Taktfrequenz,
die ich dort ansetzen kann
So, und diese Idee,
die Herren Hennessin und Patterson da jetzt hatten,
für diesen Befehlssatz und für diese Architektur ist,
dass man da eben sagt, diese einzelnen Teilschritte nach diesem Partlining-Schema,
das ja schon vorgestellt hatte,
passe ich dann eben entsprechend an,
nehmen hier im Prinzip jetzt nichts anderes als diese Architektur auf der Folie vorher,
füge jetzt aber eben noch entsprechende Parkplan-Register hier in den entsprechenden Teilstufen mit ein,
das heißt also alles,
was hier grün ist,
ist eben getaktet und Register mit einem zentralen Takt
Und ich habe dann eben genau diese Unterteilung in Instruction Fetch,
Astruction Lecode, Execute oder bei Speicherzugriff eben Berechnung der Adresse.
Speicherzugriff und Ride Back, also das Ergebnis,
was ich gegebenenfalls aus dem Mautspeicher gelesen habe oder das Ergebnis aus
der atmetischen Operation wird dann eben hier in die Registerbank wieder zurückgeschrieben.
Ich dachte also, dies klassische Schema der Mips-Architektur als fünfstufige Pipeline.
Aber alles, was hier ihm dazwischen an, Logik ist,
entsprecht ja eigentlich mehr oder minder. Dem, beziehungsweise gut,
hier die Adressberechnung ist hier ein bisschen anders gezeichnet, aber...
Ja, also das ist eben im Prinzip da diese Idee. So,
und damit kann dann eben,
wenn ich jetzt also hier diese Pipeline habe, dann auch sagen,
wenn ich jetzt also aufeinander folgende Befehle habe und die abarbeite,
dass ich das dann eben in mehreren Talschritten mache,
also sprich beispielsweise ein Load Word,
wo ich jetzt also quasi ein Wort aus dem Speicher lese in ein Register schreibe,
dann sollte ich jetzt eine Subtraktion, also ein arathymetischer Befehl stattfinden,
wo es also Register 11, den Inhalt von Register 2,
minus Register 3 bekommt.
In diesem Fall wird es hier so arathymetisch Operationen stattfinden.
Ich habe aber jetzt hier keinen Speicherzugriff,
dass es hier dann auch immer so ein bisschen so kennzeichnet,
alles, was hier so leicht grau hinterlegt ist,
da wird die Stufe dann jeweils benutzt,
in diesem Fall bei diesen artometischen Operationen
habe ich dann also hier keinen Zugriff auf das Data Memory
Dann hätte ich jetzt, also hier, Lot,
Subfraktion, Addition, dann wieder irgendwie so ein Ladebefehl,
wieder eine Addition und könnte dann aber eben immer entsprechend bis der erste Befehl hier fertig abgearbeitet ist,
habe ich dann eben hier auch entsprechend schon den fünften Befehl in
der Pipeline angefangen und man hat dann eben entsprechend jetzt also bei diesem Schema dann eben immer genau fünf Befehle in der Pipeline komplett arbeiten mit drin.
Nicht, dass also die klassische fünfstufige Prozessor-Pipeline, wie sie
dann eben bei einfachen Risk-Architekturen so gemacht und umgesetzt werden kann.
Ja, wie gesagt, dieses Schema wurde im Prinzip dann
an von der 80er Jahre entwickelt. Da wurden dann eben auch die Befehlssätze auf solche Pipelining-Schema dahin optimiert. Beispiele waren also im Prinzip,
also eine Rechnergeneration von IBM, eine 800er-Serie,
nicht Mips als Prozessoren, die dann,
also die halt von Patterson und Pennecy dann also entsprechende Entwicklung dann also auch lizenziert worden sind oder dann eben die Spark-Rechner,
die ist dann also auch, sagen wir mal,
bis die Firma dann irgendwann von Oregle mit übernommen wurde und dann zumindest dann die Hardware spart,
dann irgendwann auch verschwunden ist,
die dann aber doch sehr erfolgreiche Workstations das auch gebaut hat.
So, im Gegensatz dazu haben wir ja also in dem Kapitel 12 ja schon kennengelernt,
bei im Gegenkomplex Instruction Set Architekturen, also sprich das,
was eigentlich der X86-Befehlsatz ist,
wo man jetzt eben auch mit einem Befehl sowohl Speicher als auch Prägisteradressen, adressieren kann.
Und da wird dann also eben auch solchen Mischbetrieb auch bei arrangiertischen Operationen mitmachen kann. Da war es dann eben so,
dass die Entwicklung eigentlich war, dass die Prozessoren sukzessive,
war man dann also gesehen, hat bei einem Prozessor Herstellern,
wie erfolgreich eigentlich diese Grundidee,
gerade eben in Bezug auf höhere Taktfrequenzen und Vervielfachung des Durchsatzes ist,
dass man dort dann eben angefangen hat in ursprünglich vom Befehlsatz her rein, eine Ciska-Architektur und dann eben auch Pipelines mit reinzubauen.
Also Intel hat dann also auch irgendwann mit einem 4686,
also Ende der 80er Jahre angefangen, also Pipelining mit einzubauen,
Pennsum-Architekturen, so und inzwischen sind eben eigentlich auch alle Prozessoren intern sowas wie Pipelining.
So, was hier dann passiert ist, ist,
dass eben diese ursprünglichen Befehle, also beispielsweise 6686-Buffetsatzes,
in Folgen von solchen Risk-ähnlichen Anweisungen umgesetzt worden.
Das heißt also, nach der Dekodierung habe ich dann eben
auf einmal eine ganze Liste von Mikrobefehlen, die dann eben,
oder Mikroanweisungen, die dann eben abgearbeitet werden.
Und die folgen dann eben sehr streng, eigentlich solchen Pipeline-Prinzipien.
Und bei allen X-86-Architekturen, die sie jetzt also irgendwo haben und verwenden
, passiert sowas genauso. Einziger Unterschied,
der jetzt also heutzutage dann immer noch mit hinzugekommen ist,
da inzwischen eigentlich auch niemand meldet,
mit Assembler programmiert und das intern sowieso ähnlich umgesetzt wird,
dass die Compiler das, was im Befehlsatz theoretisch möglich ist.
Also sprich, mit artometischen Operationen dann eben auch direkt,
also die Operanten aus dem Hauptschweiger zu holen ist,
gar nicht mehr als Assembler-Code erzeugen, sondern der Assembler-Quote dann eigentlich auch schon so im Blow-Store-Schema folgend aufgebaut ist.
So, aber mit dieser Übersetzung eben von solchen Anweisungen in diese Teilschritte haben es die Firmen,
also allen voran Ente dann eben geschafft, dass die Software,
die jetzt also eigentlich dieser Cis-Ideologie folgt,
obwohl er die Hardware intern dann eben auch Parkplanics verwendet, nach wie vor lauffähig bleibt.
Das heißt, der Kunde, der sich jetzt also vielleicht irgendwie für teuer Geld,
also jetzt irgendwie seine Software, hat schreiben lassen oder eben irgendwo gekauft hat,
kann auf die neuere, schnellere Hardware aufrüsten,
muss ich jetzt aber nicht, also auf einmal komplett neue Programme überall kaufen, sondern das läuft entsprechend weiter.
Das ist also Eigentlich einer der Gründe gewesen, weswegen sich also vieles,
also war es jetzt also auch so an neueren Befehlsätzen,
ist, also außer im Embedded-Bereich eigentlich nicht größer durchgesetzt hat und wer auch eben im Desktop-Bereich,
ja, bis auf die Tatsache, wo sich das jetzt gerade ändert,
nach wie vor eben sowas wie X86-Architektur ist,
grundsätzlich Cis-Befehlsatz wird ja bei ihm intern dann eigentlich anders genommen.
Ich habe jetzt gerade gesagt, Ändert sich,
Beispiel wäre jetzt also gerade von My Apple, mit dem aktuellen M1-Prozessor.
Das ist eben dann von Armarchitektur, das ist eben eine reine Riskrechner. Nicht,
aber inzwischen muss man sagen, alles,
was es also auch sonst noch an Prozessoren gab oder einen anderen Architekturen gab,
ist im Laufe der Zeit einfach verschwunden,
weil da also wirklich die Marktdominanz von X86,
also dann so groß war,
weil man einfach seine Software immer komplett abwärtskompatibel ist,
dann eben auch immer noch mit den nächsten neueren Maschinen laufen lassen kann.
Nicht, wenn ich jetzt sage,
X86 meine ich dann eben nicht nur Intel,
sondern also auch AMD oder es gibt also auch noch,
es gab früher zumindest noch Leute eben mehr Hersteller,
die jetzt also mit dem Befehlssatz arbeiten konnten.
Heute weiß ich es nicht, es gibt vielleicht also auch noch
ein paar kleinere Richtungen eingebettet, die dann also auch noch damit arbeiten. Gut,
also das eigentlich, dass man sagen kann, okay,
wie hat sich die Pipeline heutzutage durchgesetzt und wie ist das Verhältnis zwischen Der im Hardware-Aufbau oder der Hardware-Architektur,
die jetzt mit Pipelining ist, zusammen zu sehen,
jetzt mit dem Befehlssatz, also der Instruction-Set Architecture,
beziehungsweise dort dann auch grob mit dieser Unterteilung, Risk versus Sisk.
Ja, das, also jetzt hier erstmal zu der Pipeline.
Und wie gesagt, hier hatte ich ja schon gesagt,
als ich die Grafik vorgestellt hatte, also Hardware-Blöcke selber sind unverändert.
Es gibt dann eben nur zusätzliche Parkplan-Register. Und wenn ich das jetzt
eben nochmal vergleiche mit der einen ersten Folie ohne Pipelining,
nicht der längste Fahrt zwischen den Registern,
ist jetzt eben natürlich nicht mehr hier einmal irgendwie durch bis hier rein.
Das, was Demir entspricht,
sondern die längste Fahrt ist dann also hier eben jeweils nur
noch von einem Register bis zum Eingang des nächsten Registers.
Und je nachdem, wie jetzt also hier diese zeitlichen Abhängigkeiten sind,
erhält man damit dann natürlich dann alles schon mal entsprechend andere.
Taggeschwindigkeiten, die dann gefahren werden können
Das war so auch einer der Gründe, wenn wir dann,
da habe ich dann nachher nochmal eine Folie,
wo dann also das Ganze mal so ein bisschen zeitlich zu Prozess zu Architekturen zugeordnet ist,
wo man dann sieht, wo also wirklich so doch relativ deutlich,
also die Taktfrequenzen von einigen zig oder eben 100 Mega-Ärztinnen,
also auf einmal sehr stark aufgegangen sind,
als dann eben diese Pipeline-Techniken aufgekommen sind.
Ja, ich hatte ja eben schon gesagt,
wie wirkt sich das jetzt auf die Software aus,
beziehungsweise auf die Abarbeitung
War ich ja eben schon meinte,
also im Prinzip bis auf die Sachen mit den Datenabhängigkeiten sehen wir als Programmierer von den Pipelining erstmal nichts,
beziehungsweise wenn ich ein Programm schreibe,
dann gucke ich mir jetzt natürlich bei Hochsprachen jetzt also nicht an,
also auf welchen Prozessor das nachher läuft,
um da jetzt also vielleicht noch irgendwelche speziellen Eigenheiten der Prozessorarchitektur jetzt noch mit rein zu berücksichtigen,
sondern da sage ich, gut,
da verlasse ich mich dann eben auf den Compiler,
der dann eben weiß,
das soll jetzt eben für Arm oder für Mips oder für Apple M1 oder soll es eben für irgendeinen X,
86 von Firma Intel oder von Firma AMD realisiert umgesetzt werden und der dann eben entsprechend bei der Umsetzung von Hochsprachencode in den Assemblercode,
dann eben die jeweiligen passenden Assembler-Anweisungen auswählt und gegebenenfalls dann eben auch noch entsprechende Anpassungen dort hat.
Das heißt also,
seitens der Softwareentwicklung kümmert man sich erstmal nicht direkt darum,
wie sieht das jetzt mit Partnerinnen
und wie sieht das mit der Hardwarearchitektur aus
Wobei, wo das etwas anders zu sehen ist,
ist jetzt nicht bei den, ich sag mal,
großen Systemen oder bei dem,
was also irgendwie jetzt die Masse von dem aus macht,
dass wir jetzt programmieren, beziehungsweise, womit wir,
oder andersrum, also womit sie jetzt eigentlich arbeiten,
so rum, muss ich das sagen,
sondern wo man also dann schon ein bisschen darauf achten muss,
sind eigentlich einmal diese kleinen Systeme,
nämlich also bei Argebett im System
Und da habe ich teilweise ganz spezielle Anforderungen in Bezug auf Energieverbrauch,
Energieeffizienz, wo ich dann eben auch sage, gut,
da habe ich jetzt keine großen Fließkomma-Einheiten, da habe ich jetzt also nicht ein Netzteil oder irgendeinen Akku,
der mir also so und so viele Wattstunden da so irgendwie bereitstellt,
sondern da soll das Ding also irgendwie aus einer möglichst kleinen Knopfzelle entsprechend jetzt mehrere Monate lang vernünftig laufen und irgendwas machen.
Und bei solchen Architekturen,
wo ich dann also sehr reingeschränkt bin in Bezug auf die Rechenleistungskapazität,
die dann da ist, aber dann eben auch in Bezug auf Energieverbrauch oder andere spezielle Anforderungen,
Größe, Cotternan, zum Beispiel mit rein und so weiter,
dass man bei solchen Systemen dann natürlich schon wieder ein bisschen spezieller gucken muss,
auf welcher Hardware, welchem Prozessor das läuft,
um dort dann also wirklich noch den letzten Teil herauszuoptimieren,
weil da ist es natürlich dann schon, sagen wir jetzt,
also irgendwo so ein Verkaufsargument, wo man sagen kann,
ja gut,
aber das System von dem und dem Hersteller
Da hält die Bandbatterie nur halb so lange.
Und bei uns war öfter läuft das, also mit Leiterbatterieleistung,
also doppelt so lange. Das sind dann natürlich da dann
schon wieder entsprechende Argumente jetzt für bestimmte Systeme.
Auf der anderen Seite der Skala beim High-Performance-Computing, Supercomputing.
Auch da wird dann natürlich dann schon nochmal wieder deutlich mehr jetzt,
also auf irgendwelche Hardware-Abhängigkeiten geguckt,
weil also auch da will man natürlich die vorhandene Hardware möglichst gut,
möglichst effizient ausnutzen, um also jetzt wirklich noch die letzten paar Prozent Rechenleistung herauszuholen.
Auch da würde man dann also nochmal entsprechend mehr Aufwand betreiben. Alles,
was sie jetzt aber im Prinzip kennengelernt haben in Bezug auf Programmierung,
auf Rechner und was die meisten Sachen,
die sie ja meistens während des Studiums hier begleiten wird,
da guckt man jetzt eben nicht weiter danach, wie sie dann die zugrunde liegende Hardware aus.
Das heißt also,
Auswirkungen auf die Software sehen wir dann eigentlich nur in dem Begriff oder in der Art und Weise,
wie sich jetzt also irgendwie solche Hardwarearchitekturen dann in Bezug auf die Effizienz,
sprich auf die Geschwindigkeit, wie jetzt also Programme,
Algorithmen abgearbeitet werden,
wie sich das auswirkt
Gut, bevor wir dazu kommen, hier jetzt noch erst mal einige Begriffe.
Also, Parkline Stage hatte ich ja schon gesagt,
dass da so eine einzelne Stufe in der Pipeline,
Parkline Machine Cycle heißt jetzt eben, mit einem Tag,
mit einem Schritt, läuft diese Teilabarbeitung dann eben genau einen Schritt weiter.
Als Durchsatz wird dann eben immer bezeichnet,
das hat er in dem Beispiel ganz am Anfang,
die Hans Saal der Instruktion,
die in jedem Tag abgeschlossen werden und mit Latenz bezeichnet man dann eben die Zeit,
die vergeht vom Staat einer Instruktion bis zu deren kompletten Abarbeitung.
Das heißt also, die Zeit, die benötigt wird,
um dann eben alle Partline-Stufen zu durchlaufen.
Ja, Pipelining, Vor- und Nachteile, hier jetzt erstmal
allgemein beschrieben. Was ihr eingangs schon gesagt hatte,
mit der Unterteilung der großen Schaltennetz eine kleinere Blöcke und die entsprechenden dementsprechenden Einfügen der Parkplanregister,
kann man eben einen sehr viel höheren Takt erreichen.
Im Idealfall, das heißt,
diese Pipeline wird jetzt eben immer gefüllt mit Gut,
bei der Buffetsabarbeitung ist das eigentlich klar,
dass ich da immer aufeinander folgende Sachen habe,
bei rhythmetischen Parkplans, das ist eben schon die Sache nicht.
Wenn ich jetzt also sprich für Multiplikation jetzt eben eine entsprechende Parkplane aufbaue,
die mir das also realisiert,
dann gewinne ich damit natürlich ganz gut was,
wenn ich jetzt immer Multiplikation hintereinander ausführe.
Das ist dann aber wieder von der Art und Weise abhängig,
wie jetzt also in dem Programm der Algorithmus arbeitet bzw.
was dort gemacht oder gerechnet
werden soll
Wo man dann ja auch sagen muss, im Idealfall,
wenn die Pipeline ausgenutzt wird, habe ich eben einen höheren Durchsatz,
sondern eben einen entsprechend deutlich bessere Performance,
wenn die Pipeline nicht ausgenutzt wird, dann lohnt das nicht nicht.
Deswegen eben immer diese Grundüberlegung, das, was man,
wenn man jetzt irgendwo Optimierung macht, auch später,
wenn sie das jetzt in Programmen bei der Programmierung machen,
immer an den Stellen den Code zu optimieren,
wo entsprechend viel gearbeitet wird, nicht, also beispielsweise bei Schleifen,
wo ich jetzt eben andauernd durchiteriere und nicht bei irgendwelchen Co-Teilen,
die also nur ein einziges Mal irgendwo beispielsweise zur Initialisierung von irgendwelchen Sachen durchlaufen werden.
Da ist dann natürlich eine Verbesserung von irgendwie ein paar Prozent marginal im Vergleich zu irgendeiner Verbesserung,
die jetzt also in der Schleife stattfindet,
die dann also mehrere Millionen Mal durchlaufen wird,
weil sich dann natürlich entsprechend dann diese Performancesteigerung stärker auswirkt.
Gut, aber eben bei Befehls-Pipelines ist es natürlich klar,
da habe ich die entsprechenden Vorteile, weil ich dann natürlich,
wenn ich jetzt Programme abarbeite, auch erstmal davon ausgehe,
dass ich jetzt mit jedem Takt dann auch entsprechend neuen Befehlen habe.
Ja, was wir ja schon gesehen haben,
der Zusatzaufwand an Hardware ist vergleichsweise gering, nämlich einfach nur an entsprechenden Stellen Parkplan-Register einzufügen.
Und das ist es dann. Und ich hatte ja schon gesagt,
von der Idee her ist eben Parkplaning für den Programmierer nicht direktsichtbar.
Was wir später noch kennenlernen werden, ist,
dass es eben Daten- und Kontrollabhängigkeiten gibt. Das heißt also,
ich kann jetzt nicht Jede beliebige Folge von Befehlen,
so erstmal in Parkplaning schieben, weil ich da dann also gegebenenfalls Probleme bekommen könnte.
Ja, die Latenz,
also sprich vom Staat eines Befehls bis zu deren komplette Aberweiterung,
wirklich das Pipeline natürlich nicht verbessert, sondern dadurch,
dass ihr einfach nur diese zusätzlichen Parkplan-Register habe,
wächst sie erstmal und wenn die Pipeline jetzt nicht gleichmäßig dimensioniert ist,
wird es dann also sowieso nochmal deutlich schlechter.
Nicht, das heißt, also die Lautenz Hier bleibt im
Idealfahrt, also ähnlich oder in einer vergleichbaren Größenordnung.
Und was ja eingangs also auch schon in diesem Beispiel gezeigt hat,
also der Pipeline-Takt wird eben richtig langsamste Pipeline-Stufe limitiert,
demzufolge sollte man dann also eine möglichst gleichmäßige Unterteilung dort haben.
So etwas, was dann also noch mit hinzukommt,
wenn man jetzt also gerade so an nachher Kontrollabhängigkeiten denkt,
ist, dass sich bei Pipelining natürlich dann also auch jetzt
nicht mehr eine 1-zu-1-Zuordnung von Takt zu,
jetzt ist der Beth Eal
abgearbeitet habe
Sondern da wird es dann eben so aussehen,
dass wenn ich jetzt das System starte, es also erstmal mehrere Takte dauert,
bevor dann der erste Befehl quasi aus der Pipeline fertig abgearbeitet.
Beendet ist. Und ich am Ende des Programms natürlich dann auch dafür sorgen muss,
dass ich beispielsweise bei einer fünfstufigen Paracline ich jetzt nicht nach dem letzten Befehl sagen kann,
wunderbar, halt Programme ist zu Ende, Betriebssystem übernimm mal wieder,
sondern dieser Befehl ist ja dann erst gerade Durch das Instruction Fatch gelaufen,
aber noch nicht dekodiert und noch nicht ausgeführt worden.
Das heißt, ich muss dann eben nochmal entsprechend mehrere Takte nachschieben,
die dafür sorgen, dass dieser Befehl dann eben auch noch durch die Partner hindurchläuft.
Das heißt, man hat da dann eben zusätzliche Zeiten oder zusätzliche Tagtücher eben benötigt werden,
um die Pipeline zu füllen oder die Pipeline entsprechend zu lehren. Gut,
dann kommen wir jetzt zu der Analyse in Bezug auf Programme oder Programmabarbeitung,
was passiert, wenn ich jetzt eben eine ernsthafte Instruktion und eine Anzahl von Part-Line-Stufen habe,
was gewinne ich mit Parklining, beziehungsweise wie sieht das aus,
wenn ich das System habe, ohne Pira-Plining und wie sieht das aus,
wenn ich das System habe, mit Pipelining.
So, an dieser Stelle werde ich jetzt wieder zu dem Lecture to Go überleiten,
weil ab dem Teil wurde das dann,
also wieder jetzt mit Lecture to Go aufgezeichnet, alles,
was ich vorher jetzt heute erzählt hatte,
da fehlte der Kollege entsprechend leider,
beziehungsweise war zu spät.
Deswegen das jetzt hier nochmal als extra Aufzeichnung zwischendurch.
Ab dieser Folie wird das dann also erstmal wieder mit Lecture to Go weitergehen.
Und ja, ich werde mich jetzt also hier an
dieser Stelle erstmal verabschieden. Und ja,
dann geht es jetzt hier wieder mit der Bewertung der Prozessor
Partelin entsprechend mit dem nächsten Video aus Lecture to Go