test vs. cmp
-
Hallo,
ich habe mal ein bisschen mit IDA meinen disassemblierten Quellcode durchforstet.
Mir ist dabei folgendes aufgefallen:if(CreateDirectory(Pfad, NULL) != 0) { __asm { mov eax, 11111111h } }
Die Funktion "CreateDirectory" hat als Returnwert entweder 0 oder ungleich 0.
Ich hätte jetzt, wenn ich es direkt in Assembler umgesetzt hätte, das eax Register mit "cmp" auf 0 verglichen.Im Prinzip ist folgendes ein und das selbe:
test eax, eax
ist gleich
cmp eax, 0Nun habe ich mal in die Referenz gesehen um mal zu verstehen, wo denn da genau die Optimierung liegt.
test eax, eax (2Bytes)
cmp eax, 0 (mind. 3Bytes)Es ist also schon mal ein Größenvorteil, auch wenn es nur ein kleiner ist.
Aber gibt es da Vorteile bei der Ausführungsgeschwindigkeit?Denn beide Instruktionen haben folgende Anzahl von Takten
83 F8 00 cmp eax,0 1 74 05 je Nicht_Erstellt (401069h) 3 85 C0 test eax,eax 1 74 05 je main+4Eh (40104Eh) 3
Ganz hinten steht die Taktzahl(hab ich mal so eingefügt. Ist allerdings verrutscht).
Kann da jemand was zu sagen? Oder bleibt es bei der Größe?
-
Richtig, der einzige Unterschied auf modernen x86-CPU ist fuer Vergleiche == oder != 0 mit test/cmp zunaechst nur die Code-Groesse.
Reicht aber schon, denn darueber hast du zB. Nebeneffekte wie effizienteres Caching und guenstigeres Code Alignment mit 2 Byte.
Nicht zuletzt kannst du dabei auch davon ausgehen, dass ein test weniger Rechenaufwand als ein cmp, die Anzahl der involvierten Transistoren betreffend, brauchen wird.
Diese ganzen geschenkten Vorteile in der Situation mit dieser einfachen kleinen Optimierung nicht zu nutzen waere einfach ... schlecht.
-
Mit
test eax, eax
testest du eigentlich nur, ob irgendwo ineax
ein Bit gesetzt ist, was nicht dasselbe wie ein vergleich ist (weder logisch, noch technisch auf deinem Prozessor gesehen). Danach kannst du z.B. mitjnz
oderjnz
springen in Abhängigkeit davon, obeax
gesetzte Bits hat oder nicht. Tatsache ist aber wohl, dass es hier überhaupt keine Rolle spielt, was du verwendest, weil die Unterschiede im Grössenbereich von nicht vorhanden bis vernachlässigbar klein sindMfG
-
Im Intel Optimization Reference Manual steht genau der Fall drin. Bei Punkt 3.4.2.2 Optimizing for Macro-fusion.
Grob gesagt kann die CPU das test + bedingten Sprung zu einem einzelnen Befehl zusammenfügen und braucht dann nur einen Takt dafür. Das geht beim cmp zwar auch, aber nicht immer. Daher sollte der Compiler dafür sorgen das immer wenn es möglich ist test statt cmp benutzt wird.
-
Fragen wie diese sind sehr ausführlich und lesenswert erforscht und diskutiert
vom nimmermüden Agner Fog, der seine Manuals regelmäßig aktualisiert:Optimizing subroutines in assembly
language
An optimization guide for x86 platformsSeite:
http://www.agner.org/optimize/#manualsAber da probieren gern über studieren geht, ist es wohl nicht verkehrt,
selber ein wenig mit Profiler-Werkzeugen herumzutesten.:)(Bei einem cmp-Befehl müsste die Elektronik zuerst die Komplementärzahl erstellen?
Das geht zwar auch schnell, aber ein logisches Neg Eax wäre theoretisch einen
Schritt voraus? Aber natürlich sind Vergleiche mit Null schon stark beschleunigt worden?)