Caches machen garnichts, ausser cachen und zu den gecachten Daten deren Gültigkeiten etc. speichern.
Die CPU besteht aus vielen Einzelteilen, eines davon ist die Arithmetische Einheit die nachdem durch den Instruction-Decoder die Befehle dekodiert wurden, die Befehle ausführt.
Moderne CPU's besitzen mehrere Instruction-Decoder sogenannte Pipelines. Jede Pipelin holt sich abwechselnd ihre Befehle aus dem
RAM. Der
RAM Zugriff wird durch den Cache Controller verwaltet.
Im Cache können verschiedene Daten aus verschiedenen physikalischen Speicherbereichen des externen RAMs zwischengespeichert werden.
Branches sind Verzweigungen innerhalb des Programmes und ändern den Programcounter der CPU.
Unbedingte Branches sind verzeigungen die die CPU immer ausführen wird.
Begingte Branches sind Verzweigungen die an zwei verschiedene Programmadressen verzeigen können. Damit sie verzweigen muß eine bestimmte Bedingung erfüllt sein. D.h. in dem Moment wo verzweigt werden soll müssen die Daten für diese Abfrage vollständig berechnet sein. Zb. die Flags oder Register ECX. Sollten diese Flags/Bedingungen in einer anderen Pipelin dekodiert worden sein so muß die aktuelle Pipeline auf diese warten, ein Stall ist eingetreten. Nachdem alle nötigen Begingung erfüllt sind muß nun die Pipeline und der eventuell der Cache mit neuen Daten gefüllt werden. Sollte dies zutreffen zu muß die Pipeline warten bis alle daten geladen wurden. Stehen die Daten im Cache so wird die Pipline nur mit den Daten aus dem Cache geladen. Stehen die daten nicht im Cache so muß zusätzlich der Cachecontroller die daten aus dem externen
RAM laden. Damit nun diese Szenario nicht zu häufig eintritt gibt es eine Branch Prediction = Springziel-Vorhersage. Diese Branchprediction arbeitet direkt mit dem Instructiondecoder der einzelnen Pipelines zusammen und ist ca. 4-5 Maschinenbefehlen im vorhinaus. Nun, nur bei bedingten Spüngen trifft all dieses zu.
Ein GOTO ist ein unbedingter Sprung und somit kann der Instructiondecoder der Pipelines den Cache schon viele Maschenzyklen im Vorhinein mitteilen WAS der Cache zu laden hat. Im allgemeinen liegen die Daten schon längst im Cache wenn der eigentliche Sprung tatsächlich ausgeführt wird.
Ein CALL involviert das Tasksheduller des
OS, also auch auf CPU Ebene. Zusätzlich schreibt ein CALL die Returnadresse auf den Stack und dieser befindet sich im externen
RAM. Es entsteht also zusätzlich zum GOTO bei einem Funktionsaufruf noch mindestens ein
RAM-Schreibzugriff.
Fazit: GOTOs = bedingte Sprünge sind die effizienteste Art und Weise auf heutigen CPU's den Programcounter zu ändern. Sie invalidieren NIEMALS den Cache sondernn sie erzwingen allerhöchsten das Nachladen von daten in den Cache. Eine Invalidation des Caches bedeutet das dieser komplett geleert wird und eventuell Daten gespeichert werden müssen und danach erneut Daten geladen werden.
@Sources die das demonstrieren: Du bist lustig, wie willst du das in Delphi Sourcen demonstrieren auf einem Protected Mode Betriebssystem mit mindestens 100 Task die parallel laufen, mit mindestens 17 Interruptroutinen die auf Ring 0 laufen, wie Timer, Mouse, DMA, Soundkarten,
IDE, PCI Bus usw. usw. All diese bedingen die Ausführung von asynchronen Interruptserviceroutinen die dann in deinem Beipielssource permanent dazwischen funken. Wie willst du in den internen CPU Cache hineinschauen ohne diesen durch eigene Assemblerbefehle zu modifizieren. Im übertragenen Sinne gilt hier Heisenbergs Vermutung, der Beobachter verändert durch seine Beobachtungen die Realität !!
Lade dir Intel's VTune, das ist ein Simulator der dir auch die Branchprediction ausrechnet.
Gruß Hagen