Frage

Im Folgenden ist ein Clip aus einer Aneinanderreihung von zwei Pentium Montagesequenzen. Wir haben eine äußere Schleife, die unsere Sequenzen Zeit versucht, und macht einen Callthrough-Tabelle auf diese Routinen zu bekommen. Daher wird der externe Anruf jedes Mal von der gleichen Stelle gemacht werden. Die beiden Sequenzen unterscheiden, daß die erste Anweisung eine weniger als die zweite hat.

Die Ergebnisse, die wir auf zwei Intel-Maschinen erhalten, sind sehr unterschiedlich.

Die CPUID-Anweisung sagt die Familie, Modell und Stepping.

Die Maschine 1: Familie 6, Typ 15 Stepping 11. CPUZ "Intel Core 2 Duo E6750"
berichtet Die Befehle ausführen, um statistisch die gleiche Geschwindigkeit.

Machine 2: 15 Familie, Modell 3, Stepping 3. CPUZ "Intel Pentium 4", berichtet
Die erste Sequenz dauert etwa 8% länger als die zweite Folge.

Wir können nicht einfach die Erhöhung der Zeit erklären. Es sollte nicht anders sein Flag hold-off, Vorhersage von Verzweigungen, registrieren Nutzungsprobleme usw. Zumindest nicht, dass wir sagen können.

Hat jemand eine Idee, warum die erste Sequenz länger auf der einer Maschine auszuführen nehmen würde?

Bearbeiten: Hinzufügen von "XOR PTR ereg, 0" in der ersten Folge der Zeitpunkt der zweite auf der Pentium macht übereinstimmen 4. Curious

.

Erste Sequenz:

00000040               ALUSHIFT_AND_C_V_E LABEL NEAR
00000040  0F B7 04 55       MOVZX   EAX, gwr[(SIZEOF WORD) * EDX]       ; EAX = 0000000000000000 LLLLLLLLLLLLLLLL
   00000000 E
00000048  0F B7 14 4D       MOVZX   EDX, gwr[(SIZEOF WORD) * ECX]       ; EDX = 0000000000000000 RRRRRRRRRRRRRRRR
   00000000 E
00000050  23 C2             AND     EAX, EDX                            ; AX = L&R      (result)
00000052  A3 00000000 E     MOV     dvalue, EAX                         ; Save the temporary ALU/Shifter result
00000057  C3                RET                                         ; Return

Zweite Sequenz:

00000060               ALUSHIFT_AND_C_V_NE LABEL NEAR
00000060  0F B7 04 55       MOVZX   EAX, gwr[(SIZEOF WORD) * EDX]       ; EAX = 0000000000000000 LLLLLLLLLLLLLLLL
   00000000 E
00000068  0F B7 14 4D       MOVZX   EDX, gwr[(SIZEOF WORD) * ECX]       ; EDX = 0000000000000000 RRRRRRRRRRRRRRRR
   00000000 E
00000070  23 C2             AND     EAX, EDX                            ; AX = L&R      (result)
00000072  80 35 00000000 E  XOR     BYTE PTR ereg, 1                    ; E = ~E
   01
00000079  A3 00000000 E     MOV     dvalue, EAX                         ; Save the temporary ALU/Shifter result
0000007E  C3                RET                                         ; Return
War es hilfreich?

Lösung

Nach dem Pentium I oder II, die meisten Optimierungen durch den Compiler ausgeführt, waren nicht wie notwendig. Der Chip wird diese Anweisungen in Mikro ops zersetzen und dann für Sie optimieren. t konnten die Verzweigungsvorhersage Unterschiede zwischen den Chips sein oder die Tatsache, dass die XOR + RET genauso teuer wie eine reine RET ist. Ich bin nicht so vertraut mit dem, was Modellen von Pentiums Sie oben zu sagen suchen. Eine weitere Möglichkeit besteht darin, dass es auch ein Cache-Line-Ausgabe oder Hardware-Unterschied sein könnte.

Es kann etwas in der Intel-Dokumentation sein oder es nicht können.

Egal. Erfahrene Montage Programmierer wissen, dass die einzige Wahrheit über Tests erreicht, was ist das, was Sie tun.

Andere Tipps

Es stellt sich heraus, dass es einige merkwürdige Interaktion mit dem der Code befindet, dass der Anstieg verursacht. Auch wenn alles wird, um die Zunahme der Zeit auf dem Pentium-4-Cache ausgerichtet ist, verursacht die Codeblöcke Schalt

Danke an alle, die sich die Zeit nahmen, dies zu untersuchen, oder er betrachtet wird.

Sie können hinzufügen, ein, zwei, etc nops vor diesem Code (und sonst nichts ändern) zu bewegen, wo diese Länder im Cache, um zu sehen, ob es Cache-Effekte sind (oder nur den Cache deaktivieren). Warnung aber so wenig wie ein extra nop kann eine Anweisung an andere Stelle ändern, die nicht mehr etwas mit relativ zum PC erreichen kann Adressierung, was möglicherweise mehr Befehlsbytes sowohl den im Test befindlichen Code verursacht mehr als gewünscht sowie möglicherweise eine Kettenreaktion bewegen von andere adressierten relativ Anweisungen zu ändern.

Auch wenn Sie den Cache-Spiel spielen hier die Natur des Tieres die Magie innerhalb des Chips ist, dass ein Strom von Anweisungen ausführt und teilt es unter den Ausführungseinheiten auf.

Tweak und Test ist das, was wirklich die Leistung am Ende bekommt, auch wenn Sie nicht verstehen, warum. Obwohl, sobald Sie diesen Code auf einen älteren Chip bewegen oder neuen Chip oder andere Motherboard oder gleiche Chip-Familie, aber unterschiedlicher Schritt all Performance-Verbesserungen auf Ihnen wenden können.

Vor ein paar Monaten hatte ich etwas Ähnliches zu mir kommen. Mein Projekt hat ein configure-Schalter zur Aktivierung der Verwendung von __thread für thread-lokale Variablen. Ohne sie würde es pthread_getspecific und ähnliches verwenden. Letzteres macht genauso viel wie die __thread Version plus einen Funktionsaufruf sowie einige zusätzliche Anweisungen für Argumente Einrichten, Speichern Register und so weiter. Interessanterweise war die mühsame Version konsequent schneller. Nur auf Pentium 4, though. Alle anderen Chips sanely verhalten hat.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top