Seite 1 von 1

ASM: ADD/SUB vs MOV vs INC/DEC

Verfasst: 28.07.2010 17:45
von Mok
Hallo.
Aufgrund dieses Postings, frage ich mich nun, welches der schnellste und effizienteste Befehl ist, um 1 dazuzuzählen oder abzuziehen.
Praxisbeispiel:

Code: Alles auswählen

;Annahme: Eventloop einer GUI
Define.b Exit = 0 ;Exit-Variable
Repeat
Event = WaitWindowEvent(TimeOut)
Select Event
  Case #PB_Event_Gadget
    Select EventGadget()
      Case #BTN_Exit
        ;was nun hier?
        !MOV byte [v_Exit], 1  ;oder
        !ADD byte [v_Exit], 1  ;oder
        !INC byte [v_Exit]
[...]
;Nach einer Abfrage, ob das Programm ohne Speichern beendet werden soll, und auf "Nein" gedrückt wird:
 !MOV byte [v_Exit], 0  ;oder
 !SUB byte [v_Exit], 1  ;oder
 !DEC byte [v_Exit]
[...]
Until Exit
End
Grüße, Mok.

Re: ASM: ADD/SUB vs MOV vs INC/DEC

Verfasst: 28.07.2010 19:10
von NicknameFJ
Hallo Mok,

lt. meiner Taktzyklentabelle aus Oliver Müller´s Assembler Referenz

benötigt

INC r/m32: 1 bzw. 3 Zyklen ebenso wie
ADD r/m32,imm32: 1 bzw. 3 Zyklen

(1 Zyklus bei Register und 3 Zyklen bei Verwendung Speicheradresse)

Bei DEC und SUB ist es das gleiche.

Ist also gleich schnell.


MOV r/m32,imm32 benötigt 1 Zyklus

r ist ein Register, m32 eine Speicheradresse und imm32 eine 32Bit Konstante.

Die Angaben sind vom Pentium I, neuere Prozessoren sind in meiner Tabelle leider nicht enthalten. Aber nachdem hier schon mal der gleiche Speed erreicht wird hoffe ich dass es sich auf neueren Prozessoren nicht verschlechtert. Auf älteren Prozessoren waren da mal Unterschiede zwischen INC und ADD bzw. DEC und SUB

Grüße
NicknameFJ

Re: ASM: ADD/SUB vs MOV vs INC/DEC

Verfasst: 28.07.2010 19:11
von CSHW89
also ich habs mal getestet, und wie ichs mir schon dachte, machts überhaupt keinen unterschied:

Code: Alles auswählen

#anzahl = 100000000

a.i = 1

time = ElapsedMilliseconds()
For i = 0 To #anzahl-1
  ! ADD dword [v_a], 1
Next
time1 = ElapsedMilliseconds()-time


time = ElapsedMilliseconds()
For i = 0 To #anzahl-1
  ! INC dword [v_a]
Next
time2 = ElapsedMilliseconds()-time

MessageRequester("Info", Str(time1)+"/"+Str(time2))
lg kevin

Re: ASM: ADD/SUB vs MOV vs INC/DEC

Verfasst: 28.07.2010 19:31
von Mok
@NicknameFJ: Und wie siehts aus mit CMP vs AND? Zumindest habe ich in PBs generierten ASM-Code gesehen, dass eher AND statt CMP genutzt wird.

Re: ASM: ADD/SUB vs MOV vs INC/DEC

Verfasst: 28.07.2010 19:39
von Marvin
OK, bei mir auch. Hatte ich gesagt, weil ich mich zu erinnern glaube, dass add/sub auf einigen Prozessoren schneller sind (und auf anderen eben gleich schnell). :oops: / :)

Glück für mich, dass ich das „AFAIK“ so groß geschrieben hab. <)

PS: Wobei der gcc immer ein add/sub draus macht (auch wenn man ihm in C-Manier direkt eine Art inc/dec per ++/-- empfiehlt), und der im Allgemeinen so extrem optimiert, dass das eher kein Zufall ist. Aber da es wohl bei den meisten gleich schnell ist, ist das wohl nur nebenbei zu betrachten.

Re: ASM: ADD/SUB vs MOV vs INC/DEC

Verfasst: 28.07.2010 20:06
von Thorium
laut intel optimization guide sind inc und dec nicht mehr zu nutzen, da sie nicht länger von intel optimiert werden und bei neueren cpus langsamer sind.

generell beantworten kann man solche fragen nicht, da soetwas cpu model spezifisch ist. es gibt nicht nur unterschiede zwischen amd und intel cpu's sondern aich von generation zu generation.
Allerdings sind das sowieso minimale geschwindigkeitsunterschiede. Um die macht von assembler wirklich zu nutzen musst du deine denkweise an die cpu anpassen und extrem spezialisierten code schreiben. desdo generischer dein code ist, desdo geringer der geschwindigkeitsunterschied zu hochsprachencode.
Pack möglichst alle variablen in register um speicherzugriffe zu minimieren. minimiere die anzahl bedingter sprünge, nutze unrolling, berechne so viel du kannst vor und pack das in register für die eigentliche schleife, usw.

Re: ASM: ADD/SUB vs MOV vs INC/DEC

Verfasst: 29.07.2010 18:21
von NicknameFJ
@Mok:

!CMP EAX,0
und
!AND EAX,EAX

sind auf Pentium I gleich schnell. Einen Unterschied machen die beiden Befehle allerdings bei den Flags!

Beim Vergleich auf NULL ist jedoch in beiden Fällen das ZeroFlag gesetzt oder gelöscht sodass dies in diesem Fall nicht zum Tragen kommt.

Danke an Thorium für den interessanten Hinweis auf das Intel Optimization Guide

Dieser schreibt:
3.5.1.7 Compares
Use TEST when comparing a value in a register with zero. TEST essentially ANDs
operands together without writing to a destination register. TEST is preferred over
AND because AND produces an extra result register. TEST is better than CMP ..., 0
because the instruction size is smaller.
Use TEST when comparing the result of a logical AND with an immediate constant for
equality or inequality if the register is EAX for cases such as:
IF (AVAR &8) { }
The TEST instruction can also be used to detect rollover of modulo of a power of 2.
For example, the C code:
IF ( (AVAR % 16) == 0 ) { }
can be implemented using:
TEST EAX, 0x0F
JNZ AfterIf
Using the TEST instruction between the instruction that may modify part of the flag
register and the instruction that uses the flag register can also help prevent partial
flag register stall.
Assembly/Compiler Coding Rule 39. (ML impact, M generality) Use the TEST
instruction instead of AND when the result of the logical AND is not used. This saves
μops in execution. Use a TEST if a register with itself instead of a CMP of the register
to zero, this saves the need to encode the zero and saves encoding space. Avoid
comparing a constant to a memory operand. It is preferable to load the memory
operand and compare the constant to a register.
Often a produced value must be compared with zero, and then used in a branch.
Because most Intel architecture instructions set the condition codes as part of their
execution, the compare instruction may be eliminated. Thus the operation can be
tested directly by a JCC instruction. The notable exceptions are MOV and LEA. In
these cases, use TEST.

Assembly/Compiler Coding Rule 40. (ML impact, M generality) Eliminate
unnecessary compare with zero instructions by using the appropriate conditional
jump instruction when the flags are already set by a preceding arithmetic
instruction. If necessary, use a TEST instruction instead of a compare. Be certain
that any code transformations made do not introduce problems with overflow.
Demnach sollte, wenn ich das alles richtig verstehe anstatt einer der beiden CMP bzw. AND Varianten besser auf TEST ausgewichen werden

Grüße

NicknameFJ