2016-03-08 4 views
9

Wenn ich die Verzweigung richtig verstehe (x86), nimmt der Prozessor manchmal spekulativ einen Codepfad und führt die Anweisungen aus und "annulliert" die Ergebnisse des falschen Pfades. Was passiert, wenn die Operation im falschen Codepath sehr teuer ist, wie ein Speicher, der einen Cache-Fehler oder eine teure mathematische Operation verursacht? Wird der Prozessor versuchen, etwas teuer vor der Zeit zu tun? Wie würde ein Prozessor das normalerweise handhaben?Wird spekulative Ausführung in einen teuren Betrieb folgen?

if (likely) { 
    // do something lightweight (addition, subtraction, etc.) 
} else { 
    // do something expensive (cache-miss, division, sin/cos/tan etc.) 
} 
+0

Zumindest so weit ich weiß, führt es einen Strom von Anweisungen auf die gleiche Weise aus, ob es spekulativ ausgeführt wird oder nicht. Tatsächlich glaube ich nicht, dass die Tatsache, dass Code spekulativ ausgeführt wird, überhaupt auf die Ausführungseinheiten übertragen wird. Es ist danach (Ruhestandseinheit), dass es entscheidet, was in Rente geht und was man einfach wegwirft. –

+0

@JerryCoffin Ich verstehe nicht, was das bedeutet für eine Anweisung ausgeführt werden, aber nicht in die Ausführungseinheiten übersetzt, können Sie umformulieren? Meinst du, die spekulativen Anweisungen nehmen keine CPU-Zyklen auf? – user1043761

+2

Beachten Sie, dass Verzweigungsvorhersage und spekulative Ausführung zwei getrennte Techniken sind. Der Titel erwähnt die Verzweigungsvorhersage, und der Fragenkörper spricht dann über die spekulative Ausführung. Und die Befehle, die spekulativ ausgeführt werden, verbrauchen natürlich Ressourcen von CPU-Ausführungseinheiten. –

Antwort

7

tl: dr: die Wirkung ist nicht so schlecht, wie Sie denken, da die CPU nicht mehr für die Dinge langsam warten muss, auch wenn es nicht rückgängig gemacht. Fast alles ist stark pipelined, so dass viele Operationen gleichzeitig ausgeführt werden können. Die fehlgespekelten Operationen verhindern nicht, dass neue gestartet werden.


Aktuelles x86-Design tut nicht sofort auf beiden Seiten einer Zweigniederlassung spekulieren. Sie spekulieren nur den vorhergesagten Pfad hinunter.

Ich bin mir keiner spezifischen Mikroarchitektur bewusst, die auf beide Arten einer Verzweigung unter allen Umständen spekuliert, aber das bedeutet nicht, dass es keine gibt. Ich habe meistens nur auf Mikroarchitekturen gelesen (sehen Sie das Umbauwiki für Verbindungen zu Agner Fogs microarch gude). Ich bin sicher, dass es in akademischen Arbeiten vorgeschlagen wurde und vielleicht sogar in einem echten Design umgesetzt wurde.


Ich bin mir nicht sicher, was genau in der aktuellen Intel- und AMD-Design passiert, wenn ein Zweig Fehlvorhersage erfaßt wird, während ein Cache-Miss-Laden oder Speicher bereits anhängig ausgeführt wird, oder eine Kluft, die Kluft Einheit besetzt. Sicherlich muss die Out-of-Order-Ausführung nicht auf das Ergebnis warten, da keine zukünftigen Ups davon abhängen.

Auf anderen als P4 werden gefälschte UPs im ROB/Scheduler verworfen, wenn ein Fehler erkannt wird. Von Agner Fog microarch doc, im Gespräch über P4 im Vergleich zu anderem uarches:

die falsche Vorhersage Strafe ist ungewöhnlich aus zwei Gründen hoch ... [langer Pipeline und] ... gefälschte μops in einer falsch vorhergesagten Verzweigung nicht verworfen, bevor sie in Rente gehen. Eine Fehlvorhersage beinhaltet typischerweise 45 μops. Wenn diese μops Unterteilungen oder andere zeitaufwendige Operationen sind, kann die Fehlvorhersage extrem kostspielig sein. Andere Mikroprozessoren können μops verwerfen, sobald die Fehlvorhersage erkannt wird, sodass sie nicht unnötig Ausführungsressourcen verwenden.

Uops, die derzeit Ausführungseinheiten besetzen sind eine andere Geschichte:

Fast alle Ausführungseinheiten außer dem Teiler vollständig pipeline sind, so eine andere mehrfach, Shuffle, oder was auch immer ohne Aufheben eines im Flug FP FMA beginnen . (Haswell: 5-Zyklen-Latenzzeit, zwei Ausführungseinheiten, die jeweils einen Durchsatz pro Takt erreichen können, für einen gesamten Dauerdurchsatz von eins pro 0,5c. Dies bedeutet, dass max. Durchsatz 10 FMAs im Flug auf einmal halten muss, typischerweise mit 10 Vektorakkumulatoren). Teilen ist jedoch interessant. Integer Divide ist viele Ups, also wird ein Branch Mispredict zumindest aufhören, sie auszugeben. FP div ist nur eine einzige uop-Anweisung, aber nicht vollständig pipelined, insb. in älteren CPUs. Es wäre nützlich, ein FP-Div zu stornieren, das die Divisionseinheit gebunden hat, aber IDK, wenn dies möglich ist. Wenn das Hinzufügen der Fähigkeit zum Abbrechen den normalen Fall verlangsamt hätte oder mehr Energie kostet, würde es wahrscheinlich weggelassen werden. Es ist ein seltener Spezialfall, der es wahrscheinlich nicht wert war, Transistoren zu kaufen.

x87 fsin oder etwas ist ein gutes Beispiel für eine wirklich teure Anweisung. Das habe ich erst bemerkt, als ich zurückging, um die Frage noch einmal zu lesen. Es ist mikrocodiert, und obwohl es eine Latenz von 47-106 Zyklen (Intel Haswell) hat, sind es auch 71-100 Ups. Eine Verzweigungsfehlvorhersage würde das Frontend daran hindern, die verbleibenden Ups auszugeben, und alle, die in die Warteschlange eingereiht sind, abbrechen, wie ich für die Integer-Division gesagt habe. Beachten Sie, dass echte libm Implementierungen normalerweise fsin usw. nicht verwenden, da sie langsamer und weniger genau sind, als was in Software (auch ohne SSE) erreicht werden kann, IIRC.

Bei einem Cache-Miss kann es abgebrochen werden, wodurch möglicherweise Bandbreite im L3-Cache (und vielleicht im Hauptspeicher) gespart wird. Selbst wenn dies nicht der Fall ist, muss der Befehl nicht mehr in den Ruhestand gehen, so dass der ROB nicht mehr voll wird, wenn er darauf wartet, dass er beendet wird. Das ist normalerweise der Grund, warum Cachefehlschüsse die Ausführung von OOO so sehr schaden, aber hier ist es im schlimmsten Fall, nur einen Lade- oder Speicherpuffer zu binden. Moderne CPUs können im Flug viele herausragende Cache-Misses gleichzeitig haben. Häufig macht Code dies nicht möglich, da zukünftige Operationen von dem Ergebnis einer Last abhängen, die im Cache verpasst wurde (z. B. Zeigerverfolgung in einer verknüpften Liste oder Struktur), so dass mehrere Speicheroperationen nicht im Pipeline-Betrieb ausgeführt werden können. Selbst wenn eine Verzweigungsfehlvorhersage nicht viel von einer In-Flight-Speicheroperation aufhebt, vermeidet sie die meisten der schlimmsten Effekte.


Ich habe gehört, eine ud2 (illegale Anweisung) am Ende eines Codeblock des Setzens Befehlsvorabruf von Auslösen einer TLB-Fehl zu stoppen, wenn der Block am Ende einer Seite ist. Ich bin mir nicht sicher, wann diese Technik notwendig ist. Vielleicht, wenn es eine bedingte Verzweigung gibt, die immer genommen wird? Das macht keinen Sinn, Sie würden einfach eine unbedingte Verzweigung verwenden. Es muss etwas geben, an das ich mich nicht erinnere, wenn du das tust.

+0

Ist die Verzweigungsvorhersage nicht etwas, das normalerweise im Kompilierungsschritt durchgeführt wird (genauer gesagt, Optimierung)? Oder ist der x86-Architektur etwas inhärent, das die Verzweigungsvorhersage genau ausführen kann? – Qix

+4

@Qix Nein, Verzweigungsvorhersage ist eine Hardware-Sache. – Mysticial

+2

@Qix: Sie können den Compiler anweisen, auf welche Art eine Verzweigung normalerweise gehen wird, was sich auf seine Code-Layout-Entscheidungen auswirkt (so dass der Fast-Pfad meist nicht genommene Verzweigungen sind, die sogar bei richtiger Vorhersage etwas besser sind Codedichte im I-Cache: Um in einer Funktion herumzuspringen, werden oft mehr Cache-Zeilen Code benötigt. P4 hatte Verzweigungsvorhersagehinweise, aber alle anderen ignorieren sie. Siehe http://stackoverflow.com/a/1851445/224132 –