Wie kann eine CPU mehr als einen Befehl pro Zyklus liefern?

Die Wikipedia- Anweisungen pro zweiter Seite besagen, dass ein i7 3630QM ~ 110.000 MIPS bei einer Frequenz von 3,2 GHz liefert; es wäre (110/3,2 Anweisungen) / 4 Kern = ~ 8,6 Anweisungen pro Zyklus pro Kern?! Wie kann ein einzelner Kern mehr als eine Anweisung pro Zyklus liefern?

Nach meinem Verständnis sollte eine Pipeline nur ein Ergebnis pro Takt liefern können.

Dies sind meine Gedanken:

  • Die interne Frequenz ist tatsächlich höher als 3,2 GHz
  • Einige Teile der CPU sind auf eine Weise asynchron, die ein bescheidener Mensch wie ich nicht verstehen kann
  • Es gibt mehrere gleichzeitige Pipelines pro Kern
  • Eine Pipeline kann mehr als ein Ergebnis pro Takt liefern, eine Anweisung kann Pipeline-Stufen überspringen und es gibt mehrere Prefetcher, die Schritt halten müssen
  • Mir fehlt etwas
Es liefert 110.000 Dhrystone MIPS, also DMIPS, nicht MIPS, sehe ich direkt - vielleicht könnte das einen Unterschied machen? Siehe en.wikipedia.org/wiki/Dhrystone

Antworten (5)

Erstens, wie Keelans Kommentar und Turbo Js Antwort darauf hinweisen, war die Messung 113.093 Dhrystone MIPS, nicht native MIPS.

Die Ivy-Bridge-Mikroarchitektur des i7 3630QM kann nur 4 fusionierte µops pro Zyklus ausführen, obwohl sie mit der Ausführung von 6 µops pro Zyklus beginnen kann. (Die Anzahl der verschmolzenen µops in einer Codespur ist ungefähr gleich der Anzahl der Befehle; einige komplexe Befehle werden in mehrere µops decodiert, die nicht verschmolzen sind, und einige Befehlspaare können zu einem einzigen µop verschmolzen werden, z. B. ein sofortiger Vergleich gefolgt von einem bedingten Sprung.)

Zwei Ihrer Spekulationen darüber, wie mehrere Befehle in einem einzigen Zyklus ausgeführt werden können, sind durchaus gültig und wurden in tatsächlichen Prozessoren verwendet. Ihre erste Spekulation, dass eine schnellere interne Uhr verwendet wird, wurde in den „Feuerball“-ALUs des ursprünglichen Pentium 4 verwendet. Diese ALUs wurden mit der doppelten Frequenz des restlichen Kerns getaktet, was bereits relativ hoch war.

(Dies wurde durch die Verwendung einer gestaffelten ALU erreicht, bei der die untere Hälfte einer Addition in einem Zyklus durchgeführt wurde, sodass eine abhängige Operation die untere Hälfte des Ergebnisses im nächsten Zyklus verwenden konnte. Für Operationen wie Addieren, xor oder Linksverschiebung die nur die untere Hälfte der Operanden benötigen, um die vollständige untere Hälfte des Ergebnisses zu erzeugen, ermöglicht eine solche Staffelung – auch bekannt als Breiten-Pipelining – eine Einzelzyklus-Ergebnislatenz sowie einen Einzelzyklus-Durchsatz.)

Eine etwas verwandte Technik, kaskadierte ALUs, wurde vom HyperSPARC verwendet. Der HyperSPARC fütterte die Ergebnisse von zwei ALUs in eine dritte ALU. Dadurch konnten zwei unabhängige und eine dritte abhängige Operation in einem einzigen Zyklus ausgeführt werden.

Ihre Spekulation, dass "es mehrere gleichzeitige Pipelines pro Kern gibt", ist die andere Technik, die verwendet wurde. Diese Art von Design wird als superskalar bezeichnet und ist bei weitem das gebräuchlichste Mittel, um die Anzahl der in einem einzigen Zyklus ausgeführten Operationen zu erhöhen.

Es gibt auch ein paar andere Besonderheiten bei der Befehlsausführung, die erwähnenswert sein könnten. Einige Operationen können effizienter außerhalb der gewöhnlichen Ausführungseinheiten durchgeführt werden. Die Technik der Verschiebungseliminierung nutzt die Verwendung von Registerumbenennung in Out-of-Order-Prozessoren aus, um Verschiebungsoperationen während der Registerumbenennung durchzuführen; Beim Verschieben wird einfach die physische Registernummer von einer Position in der Umbenennungstabelle (als Register-Alias-Tabelle bezeichnet) an eine andere kopiert. Dies erhöht nicht nur effektiv die Ausführungsbreite, sondern entfernt auch eine Abhängigkeit. Diese Technik wurde schon früh bei Stack-basierten x87-Prozessoren verwendet, findet aber jetzt breite Anwendung in Intels x86-Hochleistungsprozessoren. (Die Verwendung destruktiver Zwei-Operanden-Befehle in x86 macht die Move-Eliminierung hilfreicher als in einem typischen RISC.)

Eine Technik, die der Eliminierung von Verschiebungen ähnlich ist, ist die Behandlung von Befehlen zum Nullstellen von Registern während des Umbenennens. Durch Bereitstellen eines Registernamens, der den Nullwert liefert, kann ein Registerlöschbefehl (wie xor oder subtrahieren, wobei beide Operanden dasselbe Register sind) diesen Namen einfach in die Umbenennungstabelle (RAT) einfügen.

Eine andere Technik, die von einigen x86-Prozessoren verwendet wird, reduziert die Kosten von Push- und Pop-Operationen. Normalerweise müsste ein Befehl, der den Stapelzeiger verwendet, einen vollen Zyklus auf einen vorherigen Push oder Pop warten, um den Wert für den Stapelzeiger zu aktualisieren. Indem man erkennt, dass Push und Pop nur einen kleinen Wert zum Stapelzeiger addieren oder subtrahieren, kann man die Ergebnisse mehrerer Additionen/Subtraktionen parallel berechnen. Die Hauptverzögerung für die Addition ist die Übertragsausbreitung, aber bei kleinen Werten haben die höherwertigen Bits des Basiswerts – in diesem Fall der Stapelzeiger – nur höchstens einen Übertrag. Dadurch kann eine Optimierung ähnlich der eines Carry-Select-Addierers auf mehrfache Additionen kleiner Werte angewendet werden. Da der Stapelzeiger normalerweise nur durch Konstanten aktualisiert wird,

Es ist auch möglich, Anweisungen zu einer einzigen, komplexeren Operation zusammenzuführen. Während der umgekehrte Prozess des Aufteilens von Anweisungen in mehrere, einfachere Operationen eine alte Technik ist, kann das Zusammenführen von Anweisungen (von Intel als Makro-Op-Fusion bezeichnet) der Implementierung ermöglichen, Operationen zu unterstützen, die komplexer sind als die im Befehlssatz enthaltenen.

Auf der theoretischen Seite wurden andere Techniken vorgeschlagen. Andere kleine Konstanten als null könnten in der RAT unterstützt werden, und einige einfache Operationen, die solche kleinen Werte verwenden oder zuverlässig erzeugen, könnten früh gehandhabt werden. ("Physical Register Inlining", Mikko H. Lipasti et al., 2004, schlug vor, die RAT als Mittel zur Reduzierung der Registeranzahl zu verwenden, aber die Idee könnte erweitert werden, um das Laden kleiner Sofortwerte und einfacher Operationen mit kleinen Zahlen zu unterstützen.)

Für Trace-Caches (die Befehlssequenzen unter bestimmten Annahmen des Kontrollflusses speichern) kann es Möglichkeiten geben, durch Verzweigungen getrennte Operationen zusammenzuführen und Operationen zu entfernen, die ungenutzte Ergebnisse in der Ablaufverfolgung erzeugen. Das Zwischenspeichern der Optimierungen in einem Trace-Cache kann auch das Durchführen von Optimierungen, wie beispielsweise das Zusammenführen von Anweisungen, fördern, die sich möglicherweise nicht lohnen, wenn sie jedes Mal durchgeführt werden müssten, wenn der Anweisungsstrom abgerufen wurde.

Die Wertvorhersage kann verwendet werden, um die Anzahl der Operationen zu erhöhen, die parallel ausgeführt werden können, indem Abhängigkeiten entfernt werden. Ein schrittbasierter Wertprädiktor ähnelt der zuvor erwähnten Pop/Push-Optimierung einer spezialisierten Stack-Engine. Es kann mehrere Additionen größtenteils parallel berechnen, wodurch die Serialisierung entfernt wird. Die allgemeine Idee der Wertvorhersage ist, dass mit einem vorhergesagten Wert abhängige Operationen ohne Verzögerung fortgesetzt werden können. (Verzweigungsrichtungs- und Zielvorhersage ist praktisch nur eine sehr begrenzte Form der Wertvorhersage, die das Abrufen folgender Befehle ermöglicht, die vom "Wert" der Verzweigung - ausgeführt oder nicht - und der nächsten Befehlsadresse, einem anderen Wert, abhängen.)

fantastisch! Vielen Dank für die wertvollen Informationen. Könnten Sie mir ein Buch empfehlen, in dem ich all diese Architekturtechniken nachlesen kann?
@workless Sobald Sie über die Grundlagen des Pipelining und der superskalaren Ausführung außerhalb der Reihenfolge hinausgekommen sind (was in den meisten Lehrbüchern zur Computerarchitektur behandelt würde), sind die besten Informationsquellen wahrscheinlich Beschreibungen bestimmter Prozessormikroarchitekturen (wie der Artikel über Haswell verlinkt in der Antwort von gnasher729 ) und wissenschaftliche Arbeiten (ISCA und MICRO [Konferenzen] haben im Allgemeinen gute Arbeiten; HPCA, PACT, ASPLOS und vielleicht einige andere haben auch einen guten Ruf). Andy Glew (vielleicht am bekanntesten für seine Arbeit am Pentium Pro) ...
... arbeitete an einem CompArch-Wiki, das fortgeschrittenere Konzepte präsentieren würde, aber der Fortschritt war langsam und es wurde anscheinend vor einer Weile gehackt und gibt daher jetzt nur eine Fehlermeldung aus ( semipublic.comp-arch.net/wiki ). Er beabsichtigt, das Wiki (der Originaltext ist erhalten) mit einer anderen Wiki-Software wiederherzustellen (er hatte einige Probleme mit der von ihm verwendeten Software und nimmt dies zum Anlass, Verbesserungen vorzunehmen), aber "das wird eine Weile dauern."
Ein gutes Beispiel für den Erfolg der superskalaren Architektur war Intels HyperThreading – bei all diesen Optimierungen fanden Intels Ingenieure heraus, dass etwa 30 % der ALU die meiste Zeit ungenutzt waren, weil der Speicher nicht schnell genug einfließen konnte, oder die Pipeline kann nicht effizient genug gefüllt werden. HyperThreading ermöglicht es Ihnen, im Idealfall viel Arbeit kostenlos zu erhalten. Es ist weit weniger als ein separater neuer Kern, aber es ist auch viel billiger (und es kann auch mit Multi-Core kombiniert werden).
@PaulA.Clayton - zwei Aufnahmen dieser Seite befinden sich auf Wayback. 20. Dezember 2013 und 14. Februar 2014 . Ich weiß nicht, ob diese Aufnahmen vor den Problemen mit der Seite liegen. Als ich versuchte, diese Seiten auf Wayback zu besuchen, erhielt ich leider die Meldung „ Enttäuschung. Der Computer, der diese Datei bereitstellt, ist ausgefallen .
@KevinFegan Ich habe Kopien einiger Artikel und Links zu einigen der Wayback-Kopien auf meiner Google Sites-Website veröffentlicht . Dies ist keineswegs eine vollständige Wiedergabe des vorherigen Wikis, aber es könnte für einige von Interesse sein.

Im Inneren moderner Prozessoren passiert etwas dunkle Magie, aber Ihre Gedanken gehen definitiv in die richtige Richtung.

Der Schlüssel zum Verständnis der Effizienz moderner Prozessoren liegt in der Erkenntnis, dass sie superskalar sind . Aus Wikipedia (Hervorhebung von mir):

Eine superskalare CPU-Architektur implementiert eine Form der Parallelität, die Parallelität auf Befehlsebene genannt wird, innerhalb eines einzelnen Prozessors. Es ermöglicht daher einen schnelleren CPU-Durchsatz, als es sonst bei einer bestimmten Taktrate möglich wäre.

Diese modernen Prozessoren haben, wie Sie vermutet haben, mehrere Ausführungseinheiten pro Kern. Hyper-Threading ist interessant zu betrachten, einige Teile der Pipeline werden dupliziert, andere jedoch nicht.

Die Out-of-Order-Ausführung ist ebenfalls interessant zu lesen, beantwortet Ihre Frage jedoch nicht direkt. Es reduziert jedoch die Anzahl der "verschwendeten" CPU-Zyklen.

Die Effizienz wird auch durch viele andere Dinge beeinträchtigt, die einen Stillstand im Prozessor verursachen können, einschließlich (aber definitiv nicht beschränkt auf):

  • Die Ergebnisse früherer Anweisungen sind nicht verfügbar.
  • Cache-Fehlschläge.
  • Die Codeverzweigung, die bereits abgerufene Anweisungen ungültig machen würde (lesen Sie hier und hier über die Verzweigungsvorhersage ).

Moderne Compiler versuchen bei vielen der oben genannten Punkte zu helfen, der Prozessor übernimmt dann. Ein gutes Beispiel finden Sie in dieser Frage an anderer Stelle auf Stackexchange, die einen wichtigen Unterschied zwischen zwei Anweisungen hervorhebt, die (unter bestimmten Umständen) dasselbe tun können. Aufgrund der verwendeten Ausführungseinheit kann jedoch bei einigen Prozessoren einer "schneller" als der andere sein.

Eine für Menschen lesbare Erklärung der modernen CPU-Pipeline finden Sie unter Eine Reise durch die CPU-Pipeline . Für eine etwas technischere Erklärung siehe Agner Fogs Microarchitecture - Papier.

vielen Dank für die Erklärung und die sehr interessanten Links. Als Anmerkung, dass Cell sehr interessant aussieht, freue ich mich darauf, mehr über CPU-Architekturen zu lernen ^_^. ""Der x86 verwendet eine "Superpipeline", wie oben beschrieben. Die Cell-Familie verwendet einen "synergistischen" Ansatz mit neun Mini-CPUs. Es ist wahr, dass jede Mini-CPU einer größtenteils geordneten Pipeline folgt, die Mini-CPUs haben mehrere parallele superskalare Pipelines und nicht nur eine einzige Pipeline."""

Was ist Ihrer Meinung nach passiert: Alle Ingenieure bei Intel, AMD und IBM haben gelesen, dass eine Pipeline nur ein Ergebnis pro Zyklus liefern kann, und sie sagten: "Ach so, das war's dann, können diese Prozessoren nicht schneller machen". Oder haben sie das gelesen und gesagt: "Können nicht mehr als ein Ergebnis pro Zyklus liefern? Das werden wir sehen!".

Für eine gute Einführung in die Haswell-Architektur können Sie beispielsweise diesem Link folgen http://www.realworldtech.com/haswell-cpu/ oder Sie können einfach auf die Intel-Website gehen und dort finden Sie ein wenig Dokumentation.

Jeder Kern des Haswell-Prozessors verfügt über eine große Anzahl von Ausführungseinheiten, die Operationen unabhängig voneinander ausführen können, sodass mehrere Operationen parallel ausgeführt werden können. Als nächstes verfügt der Haswell-Prozessor über mehrere Ausführungseinheiten, die Vektoroperationen mit einer Größe von bis zu 256 Bit verarbeiten. Eine Vektoroperation könnte beispielsweise vier Gleitkommaoperationen mit doppelter Genauigkeit oder acht Gleitkommaoperationen mit einfacher Genauigkeit in einer Vektoroperation ausführen. Und schließlich unterstützt der Haswell-Prozessor "Fused Multiply-Add", was bedeutet, dass die Berechnung von a mal b plus c nur eine einzige Operation ist.

Das theoretische Maximum, da Haswell zwei Einheiten hat, die zum verschmolzenen Multiplizieren-Addieren fähig sind, sind zwei verschmolzene Multiplizieren-Addieren-Operationen pro Zyklus, wobei jede Operation acht Multiplikationen mit einfacher Genauigkeit plus Additionen oder 32 Gleitkommaoperationen mit einfacher Genauigkeit ausführt.

Der 3630-Prozessor ist nicht in Intels aktueller Preisliste, aber es gibt Modelle wie den 3740QM mit vier Kernen. Anstelle von 32 können Sie also 128 Gleitkommaoperationen pro Taktzyklus erhalten. Dies ist das theoretische Maximum. Die Hälfte davon im wirklichen Leben zu erreichen, ist eine Herausforderung, aber für geeignete Aufgaben nicht unmöglich. Es gibt andere Prozessoren mit bis zu 15 Kernen (zu Preisen, die nicht einmal die fanatischsten Gaming-Fanatiker zahlen werden).

Sie haben also eine Kombination aus mehreren Multiplikatoren:

  1. Mehrere Kerne pro Prozessor.
  2. (Das zuvor nicht erwähnte Hyperthreading ermöglicht es Ihnen, theoretischen Grenzen näher zu kommen.)
  3. Die verschmolzene Multiplikations-Additions-Operation führt zwei arithmetische Operationen aus, die nur als eine zählen.
  4. 256-Bit-Vektoren, die 8 Operationen ausführen, die nur als eine zählen.
  5. Zwei Vektorausführungseinheiten, die eine Fused-Multiply-Addition handhaben können.

8,6 Operationen pro Zyklus sind nicht allzu schwer zu erreichen. Selbst 8,6 Operationen pro Zyklus pro Kern sind nicht allzu schwierig.

Ich frage mich, ob es praktisch oder vorteilhaft wäre, eine CPU mit einigen Kernen zu entwerfen, auf denen x86 ausgeführt wird, und einigen, auf denen ein Befehlssatz ausgeführt wird, der für superskalares Verhalten optimiert ist. Ich weiß, dass Intel und AMD einige ziemlich erstaunliche Dinge tun, um Einschränkungen im x86-Befehlssatz zu umgehen, aber in einigen Fällen würde ich denken, dass es hilfreich wäre, einige Dinge zu wissen, die der aktuelle Befehlssatz nicht ausdrücken kann. Beispielsweise unterschiedliche Versionen von ADDAnweisungen, die darauf basieren, ob der Überlauf unbeeinflusst bleiben soll oder gesetzt werden soll, wenn ein Überlauf auftritt (und gesetzt gelassen wird, wenn dies nicht der Fall ist).
Ich bin traurig darüber, dass heutzutage viele Sprachen standardmäßig den Überlauf nicht überprüfen. Ich weiß, dass Java ziemlich an semantischen Anforderungen festhält, aber in Sprachen wie C#, die sowohl Trapping- als auch Non-Trapping-Arithmetikoperatoren enthalten, sehe ich den einzigen guten Grund, Überlauf nicht abzufangen, darin, dass man Wrapping-Verhalten benötigt. Gegenwärtig kann die Überlaufprüfung eine erhebliche Geschwindigkeitseinbuße mit sich bringen, aber wenn eine Maschinensprache um die Idee herum entwickelt würde, dass das Überlauf-Trapping nicht präzise sein muss, solange der Code sicherstellen kann, dass vor dem Betrieb keine Überläufe aufgetreten sind ...
... bestimmte kritische Punkte erreicht, sollte es möglich sein, den Overflow-Trapping-Overhead auf nahezu null zu reduzieren. Wenn der Code eine Berechnung durchführt und dann einen Wert an einer Stelle speichert, die verlassen wird, wenn die erste Berechnung überläuft, sollte es nicht erforderlich sein, das Speichern zu verzögern, bis der Prozessor weiß, ob die erste Berechnung erfolgreich ist, aber der Prozessor hat derzeit keine Möglichkeit das zu wissen. Wenn der Code einfach alle Operationen ausführen könnte, die sicher ausgeführt werden können, unabhängig davon, ob ein Überlauf aufgetreten ist oder nicht, und dann prüfen könnte, ob bei einem von ihnen unzulässige Überläufe aufgetreten sind ...
... das scheint, als ob es helfen sollte, Ausführungsabhängigkeiten zu reduzieren.

Der Drystone-Benchmark stammt aus dem Jahr 1984, und die entsprechende nominelle 1-MIPS-VAX-Maschine ist in modernen Begriffen nicht sehr effizient. Selbst ein Cortex M3 liefert 1,25 DMPIS/MHz.

Prozessoren mit Intel-Core-Architektur können tatsächlich mehrere Befehle parallel in einem einzigen Kern ausführen, da mehrere Recheneinheiten vorhanden sind.

Ich habe sehr viel von Jon „Hannibal“ Stokes von Ars Technica gelernt, exzellente und ausführliche Artikel zum Thema Mikroprozessorarchitektur. Die Artikel sind etwas veraltet (sie scheinen von etwa 2004 zu sein), aber immer noch sehr aktuell.

Einige der Links zum nächsten Teil eines Artikels sind defekt, aber es scheint, dass Sie sie selbst reparieren können, indem Sie die URL des ersten Teils und die defekte URL der nächsten Seite sorgfältig vergleichen (z. B. durch Hinzufügen von m-irgendwo in der URL).

(Ja, dies ist eine verherrlichte Nur-Link-Antwort, sorry; die Artikel sind zu gut, um sie nicht zu erwähnen)