Finger weg vom xchg-Befehl...
-
Habe mal mit dem xchg-Befehl eine Schleife laufen lassen und zum Vergleich eine zweite Schleife mit lauter nop, um zu sehen, wieviele nop-Befehle ungefähr Pi mal Daumen genauso viele Takte brauchen. Hier sind die Funktionen, mit denen ich es getestet habe:
.intel_syntax .global _getCurrentTimeStampCounter .global _getTimeStampCounterA .global _getTimeStampCounterB .equ MAX_LOOP_CNT, 1000000 .section .text _getCurrentTimeStampCounter: rdtsc ret _getTimeStampCounterA: push ebx mov ecx, MAX_LOOP_CNT 0: .rept 36 nop .endr dec ecx jnz 0b cpuid # serialize rdtsc pop ebx ret _getTimeStampCounterB: push ebx mov ecx, MAX_LOOP_CNT 0: xchg eax, TmpVar dec ecx jnz 0b cpuid # serialize rdtsc pop ebx ret .section .data TmpVar: .long 0
Makefile und Testcode ähnlich wie hier http://www.c-plusplus.net/forum/viewtopic-var-t-is-237896.html
Das Ergebnis: 36 nop-Befehle sind in der oberen Schleife notwendig, um ungefähr genauso viele Takte zu verbraten wie die zweite Schleife mit einem einzigen xchg-Befehl. Ein Hammer, oder?
Das nenne ich Physik, ich spüre förmlich, wie die CPU Takte verbraucht...
-
^^xchg braucht drei takte oder so. mit der messung ist was faul. caching und pipelining machen dir da sowieso 'nen strich durch die rechnung.
-
+fricky schrieb:
^^xchg braucht drei takte oder so. mit der messung ist was faul. caching und pipelining machen dir da sowieso 'nen strich durch die rechnung.
Wieviele Takte weiss ich nicht und ist mir egal, ich sehe nur, was ich sehe
Wenn jemand einen Fehler in meiner Messmethode sieht, soll sich ruhig mit der folgenden Einstellung melden:
Nur kein Respekt vor dem Code !
Wenn man übrigens xchg reg, reg macht, dann benötigt die obere Schleife nur 3 nop-Befehle, um ungefähr genauso schnell zu sein:
.intel_syntax .global _getCurrentTimeStampCounter .global _getTimeStampCounterA .global _getTimeStampCounterB .equ MAX_LOOP_CNT, 1000000 .section .text _getCurrentTimeStampCounter: rdtsc ret _getTimeStampCounterA: push ebx mov ecx, MAX_LOOP_CNT 0: .rept 3 nop .endr dec ecx jnz 0b cpuid # serialize rdtsc pop ebx ret _getTimeStampCounterB: push ebx mov ecx, MAX_LOOP_CNT 0: #xchg eax, TmpVar xchg eax, ebx dec ecx jnz 0b cpuid # serialize rdtsc pop ebx ret .section .data TmpVar: .long 0
-
abc.w schrieb:
ich sehe nur, was ich sehe...
...und - lass mich raten - du testest unter einem multitasking-os, ne?
wenn ja, dann sind deine messungen ungefähr so sinnvoll, wie ein snooker-turnier auf einem schiff bei windstärke 12.abc.w schrieb:
Nur kein Respekt vor dem Code
wie meinste denn das?
-
+fricky schrieb:
...und - lass mich raten - du testest unter einem multitasking-os, ne? wenn ja, dann sind deine messungen ungefähr so sinnvoll, wie ein snooker-turnier auf einem schiff bei windstärke 12.
Ja, ich teste unter Windows XP. Aber Dein Vergleich ist übertrieben. Angemessener wäre vielleicht ein Vergleich mit einem Boxkampf mit seinen Runden und und den ganzen Pausen dazwischen...
+fricky schrieb:
abc.w schrieb:
Nur kein Respekt vor dem Code
wie meinste denn das?
Ich meine damit z.B., über den Code schauen und dabei fest daran glauben, dass mindestens ein Fehler drin ist...
-
Was erwartest du denn? Speicherzugriffe sind nunmal teuer und du kommst ja auf die 3 Takte bei xchg reg,reg wie fricky sagte. Faktor ~10 bei (gecachtem) Speicherzugriff ist absolut realistisch.
-
Helferlein, Ein schrieb:
Was erwartest du denn? Speicherzugriffe sind nunmal teuer und du kommst ja auf die 3 Takte bei xchg reg,reg wie fricky sagte. Faktor ~10 bei (gecachtem) Speicherzugriff ist absolut realistisch.
Vorsicht, ich komme nicht auf 3 Takte, sondern auf 3 nops bei xchg reg, reg und auf 36 nops bei xchg reg, mem. Wieviele Takte ein nop braucht, weiss ich nicht. Wüsste auch nicht, wie man es genau messen könnte. In diesem Sinne, wie kommst Du auf Faktor 10?
Ich glaube, ich weiss jetzt, warum ein xchg reg, mem Befehl so langsam ist. In der Intel-Doku steht, dass bei diesem Befehl bei Speicheroperanden automatisch ein LOCK Mechanismus aktiv wird, unanhängig davon, ob ein LOCK Prefix da ist oder nicht. Vermutlich blockiert er dann alles. Man kann damit Semaphore-Funktionalität implementieren.
-
Das traurige ist, dass deine künstlichen Messungen dir garnicht den wahren Wert der ganzen Operationen zeigen und die Zusammenhänge erst recht nicht.
Ein winziger loop der nur Unsinn macht nutzt so ziemlich garnichts davon aus was CPUs an Optimierungen haben.
Dein xchg der 30 Takte zieht ist entsprechend mau, in normalen Fällen sind das eher 300.
-
abc.hirn schrieb:
Das traurige ist, dass deine künstlichen Messungen dir garnicht den wahren Wert der ganzen Operationen zeigen und die Zusammenhänge erst recht nicht.
Ein winziger loop der nur Unsinn macht nutzt so ziemlich garnichts davon aus was CPUs an Optimierungen haben.
Dein xchg der 30 Takte zieht ist entsprechend mau, in normalen Fällen sind das eher 300.So winzig sind meine Schleifen nicht. Machen immerhin eine Million Wiederholungen. Sie machen natürlich Unsinn, wenn Du bessere Beispiele kennst, dann her mit dem Code.
Wie kommst Du auf 30 Takte? 300 Takte? Wie gemessen?