Verzweigungsvorhersage auf einem Funktionszeiger

Lesezeit: 4 Minuten

Benutzer-Avatar
Michael

Ich habe eine Schleife, die immer und immer wieder läuft. Die Logik innerhalb dieser Schleife hängt vom Modus ab, in dem sich das Programm befindet. Um die Leistung zu verbessern, dachte ich, dass ein Array von Funktionszeigern initialisiert werden kann, functionPtr[], das würde also nur functionPtrmode aufrufen, das die richtige Logik ausführt. Die Schleife bleibt für viele Zyklen im selben Modus (die Anzahl ist im Voraus unbekannt, aber viele Tausend). Das Programm läuft nur auf einem Intel x64-Rechner und benötigt keine Portabilität.

Ich hatte gehofft, dass die CPU die Verzweigungsvorhersage verwenden würde, aber da meine Verzweigung nicht bedingt ist (auf Assemblyebene), hängt die Position der Verzweigung jedoch von einer Variablen ab (functionPtr+mode). Wird die CPU versuchen, functionPtr+mode zu berechnen und diese Anweisungen in die Pipeline zu ziehen?

  • Es hat nichts mit Verzweigungsvorhersage zu tun, aber es sollte in Ordnung sein – selbst bei einem indirekten Funktionsaufruf sollte es keinen Pipeline-Stall geben.

    – PaulR

    7. Oktober 2014 um 15:35 Uhr

  • Wie ich sehe, verwendest du c++. Können Sie nicht zwei Klassen erstellen, die von derselben Schnittstelle erben, und dann je nach Modus die richtige instanziieren?

    – Vinzenz

    7. Oktober 2014 um 15:43 Uhr

  • Wenn es nur wenige Fälle gibt, könnten Sie die Funktion in der Schleife zu einem Vorlagenparameter machen. Wählen Sie zur Laufzeit (z. B. switch-Anweisung) eine Schablonenfunktion aus, die die Schleife enthält. Beachten Sie, dass dies die Codegröße erhöht.

    – Neil Kirk

    7. Oktober 2014 um 16:00 Uhr


  • @Vincent, ich denke, das hat das gleiche Problem, wenn Sie foo haben[mode].run() dann hast du immer noch einen Zeiger auf foo[mode] zu berechnen und eine Funktion zum Aufrufen. So oder so in meinem Fall Die im Aufruf von run() benötigten Informationen ändern Variablen, die im nächsten Aufruf von run() verwendet werden, sogar für einen anderen Modus, sodass es sinnvoll ist, sie in einer Klasse zu halten.

    – Michael

    7. Oktober 2014 um 16:02 Uhr

  • @Neil, das klingt nicht so, als würde es funktionieren, wenn der Modus unvorhersehbar während der gesamten Schleife wechselt.

    – Michael

    7. Oktober 2014 um 16:09 Uhr

Aus Die Mikroarchitektur von Intel-, AMD- und VIA-CPUs Ein Optimierungsleitfaden für Assembler-Programmierer und Compiler-Hersteller

http://www.agner.org/optimize/microarchitecture.pdf

Abschnitt 3.7 (für Sandy Bridge, andere Prozessoren befinden sich in anderen Abschnitten) Mustererkennung für indirekte Sprünge und Aufrufe Indirekte Sprünge und indirekte Aufrufe (aber keine Rückkehr) werden unter Verwendung desselben zweistufigen Prädiktors wie Verzweigungsbefehle vorhergesagt.

Ein Zeiger auf eine Funktion ist ein indirekter Aufruf.

Benutzer-Avatar
Jerry Sarg

Ja, relativ neue Prozessoren können (zumindest so etwas wie) eine Verzweigungsvorhersage für indirekte Sprünge durchführen.

Vom Pentium (Intels erstem, der Verzweigungsvorhersagen durchführte) bis zu den ersten Pentium IVs wurde für indirekte Verzweigungen nur der Verzweigungszielpuffer (BTB) verwendet. Dies bedeutete, dass sie solche Verzweigungen korrekt “vorhergesagt” haben, wenn (und nur wenn) das Ziel genau identisch mit dem vorherigen Ziel war – was für Ihren Fall angemessen klingt.

Beginnend mit dem Pentium M/Prescott (dem letzten Pentium IV) verbesserte Intel die Verzweigungsvorhersage für indirekte Sprünge, um einen zweistufigen adaptiven Prädiktor zu verwenden. Wenn ich Ihre Frage richtig verstehe (dh Ihre Schleife wird für viele aufeinanderfolgende Iterationen mit demselben Ziel ausgeführt, und das ist es, was Sie interessiert), wäre sogar nur das BTB für Ihre Zwecke ausreichend. Der zweistufige Prädiktor würde nützlicher, wenn Sie (zum Beispiel) auf dem niedrigstwertigen Bit aufeinanderfolgender Zahlen verzweigen würden, sodass Sie ein vorhersagbares Muster des Springens zu einem Ziel in einer Iteration und zum anderen in der nächsten Iteration hätten. Bei einem Muster wie diesem würde der BTB allein die Verzweigung immer falsch vorhersagen, aber der zweistufige Prädiktor in einem aktuellen Prozessor würde korrekt vorhersagen (nach den ersten paar Iterationen, damit das Muster erkannt werden könnte).

Benutzer-Avatar
Murtaza Zaidi

Die Verzweigungsvorhersage ist für tatsächliche Verzweigungen, bei denen wir bis zur Auswertung der Verzweigung nicht wissen, was angibt, welche der Anweisungen als nächstes ausgeführt werden soll. Aber da in Ihrem Code die nächste Anweisung je nach Modus bekannt ist, in dem wir uns befinden, ist keine Vorhersage erforderlich, und es wird auch kein Warten in der Pipeline geben.

Da zwischen Moduswechsel und Befehlsoptionen genügend Zeit vergeht, ruft die Pipeline jedes Mal ohne zusätzlichen Aufwand erfolgreich den richtigen Befehl ab.

  • Indirekte Verzweigungen müssen immer noch vorhergesagt werden. Es ist eine einfache Vorhersage, wenn es für einen bestimmten Zweig jedes Mal gleich ist, aber dennoch Einträge im BTB (Branch Target Buffer) verbraucht. Daten aus Speicher/Registern sind zum Zeitpunkt der Decodierung nicht verfügbar, geschweige denn zum Zeitpunkt des Abrufs vor der Decodierung, sodass eine Vorhersage auch dann noch erforderlich ist, wenn sich die Daten in letzter Zeit nicht geändert haben. Sofern Sie nicht selbstmodifizierenden Maschinencode verwenden, um relative Verzweigungsanweisungen neu zu schreiben, ist das Ziel in dem Teil der CPU, der es benötigt, nicht leicht verfügbar.

    – Peter Cordes

    3. September 2020 um 1:21 Uhr


1018880cookie-checkVerzweigungsvorhersage auf einem Funktionszeiger

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy