SUB vs. DEC

Fragen zu allen anderen Programmiersprachen.
Benutzeravatar
Batze
Beiträge: 1492
Registriert: 03.06.2005 21:58
Wohnort: Berlin
Kontaktdaten:

SUB vs. DEC

Beitrag von Batze »

Dachte immer DEC wäre schneller als sub ...

Code: Alles auswählen

Timer = ElapsedMilliseconds()

! MOV esi, $8FFFFFFF

! Do_X_Times:

  ! MOV ebx, $0000FFFF
  
  
  ! DEC ebx  ; Alg 1
  ! DEC ebx  ; Alg 1
  ! DEC ebx  ; Alg 1
  ! DEC ebx  ; Alg 1
  ! DEC ebx  ; Alg 1
  ! DEC ebx  ; Alg 1
  ! DEC ebx  ; Alg 1
  ! DEC ebx  ; Alg 1
  ! DEC ebx  ; Alg 1
  ! DEC ebx  ; Alg 1
  ! DEC ebx  ; Alg 1
  
;   ! SUB ebx, 1 ; Alg 2
;   ! SUB ebx, 1 ; Alg 2
;   ! SUB ebx, 1 ; Alg 2
;   ! SUB ebx, 1 ; Alg 2
;   ! SUB ebx, 1 ; Alg 2
;   ! SUB ebx, 1 ; Alg 2
;   ! SUB ebx, 1 ; Alg 2
;   ! SUB ebx, 1 ; Alg 2
;   ! SUB ebx, 1 ; Alg 2
;   ! SUB ebx, 1 ; Alg 2
;   ! SUB ebx, 1 ; Alg 2
    
  ! DEC esi
  
! JNZ Do_X_Times

MessageRequester("Time = ", Str(ElapsedMilliseconds()-Timer))
; Alg 1:  10172, 10422, 10328 
; Alg 2:   7125,  7265,  7188
Habe ich vielleicht irgendwas falsch gemacht, oder ist mein PC komisch? Oder ist Sub tatsächlich viel schneller als dec?
Hier sind meine Codes (aber die Seite geht gerade nicht):
http://www.basicpure.de.vu
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Beitrag von cxAlex »

Dec: 4484
Sub: 4485

Ziemlich gleichschnell würde ich sagen...
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Benutzeravatar
Batze
Beiträge: 1492
Registriert: 03.06.2005 21:58
Wohnort: Berlin
Kontaktdaten:

Beitrag von Batze »

Dein Ergebnis erscheint mir auch viel realistischer. Warum ist meins dann so eigenartig? Die Asm-Gurus hier vielleicht eine Antwort ?

Edit: Kann man Code eigentlich während der Laufzeit verändern? Also zb. aus einem ADD eax, 2 ein ADD eax, 100595 machen oder sowas?
Hier sind meine Codes (aber die Seite geht gerade nicht):
http://www.basicpure.de.vu
Benutzeravatar
Helle
Beiträge: 566
Registriert: 11.11.2004 16:13
Wohnort: Magdeburg

Beitrag von Helle »

Die Tests relativ kurzer Code-Stücke sind schon ´ne Sache mit vielen Unwägbarkeiten (Cache, Memory-Verwaltung) und hängen sowieso von der jeweiligem CPU ab. Für Intel gilt schon seit langem, dass SUB nicht langsamer ist als DEC. Hier ein Code, der u.a. den Cache-Einfluss eleminieren sollte:

Code: Alles auswählen

Global Mem.i = $1000000      ;Speicher reservieren, hier 16 MB
Global Loop1.i = 10000
Global Loop2.i = 10000
Global CodeMem.i
Global CodeMemUr.i
Global CodeA.i
Global CodeL.i
Global TimeA.q
Global TimeE.q
Global Ticks1.q
Global Ticks2.q
Global TicksZ.q

Macro REG32(Befehl)       ;z.B. DEC
  !Befehl ebx
  !Befehl ebx
  !Befehl ebx
  !Befehl ebx
  !Befehl ebx
  !Befehl ebx
  !Befehl ebx
  !Befehl ebx
  !Befehl ebx
  !Befehl ebx
EndMacro

Macro REG32_IMMFEST(Befehl, Wert)   ;z.B. SUB, 1
  !Befehl ebx,Wert
  !Befehl ebx,Wert
  !Befehl ebx,Wert
  !Befehl ebx,Wert
  !Befehl ebx,Wert
  !Befehl ebx,Wert
  !Befehl ebx,Wert
  !Befehl ebx,Wert
  !Befehl ebx,Wert
  !Befehl ebx,Wert
EndMacro

Macro Messung(TestBefehl)
  CodeMem = CodeMemUr
  !mov esi,[v_CodeMem]  
  !mov [v_CodeA],10          ;Länge des nachfolgenden Befehls
  !add [v_CodeA],$
  TestBefehl                 ;hier einfügen
  !mov eax,$    
  !sub eax,[v_CodeA]
  !mov [v_CodeL],eax
  LDTicks()
EndMacro

Procedure LDTicks()
  CodeMem = CodeMemUr 
  For i = 1 To Loop1          ;das Macro vom Code-Teil in den Speicher kopieren (duplizieren)
    CopyMemory(CodeA, CodeMem, CodeL)
    CodeMem + CodeL
  Next    
 
  PokeB(CodeMem, $C3)        ;zum Schluss Opcode für Return setzen
 
  FlushInstructionCache_(GetCurrentProcess_(), #Null, #Null)    ;(bisherigen) Befehls-Cache löschen
  
  !cpuid                     ;für Serialisierung (Pipe(s) leerfegen) Na ja...
 
  !rdtsc                     ;Time-Stamp auslesen
  !mov dword[v_TimeA],eax    ;EAX = Low-DWord; diese Ticks drücken wir in den Skat
  !mov dword[v_TimeA+4],edx  ;EDX = High-DWord 
  For i = 1 To Loop2
  !call [v_CodeMemUr]        ;Code im Speicher ausführen
  Next
  !rdtsc
  !mov dword[v_TimeE],eax
  !mov dword[v_TimeE+4],edx
  TicksZ = TimeE - TimeA
EndProcedure

hThread = GetCurrentThread_()
SetThreadAffinityMask_(hThread, 1)     ;Thread nur von Core0 ausführen lassen (wenn Multi-Core-CPU)
SetThreadPriority_(hThread, #THREAD_PRIORITY_TIME_CRITICAL)

CodeMem = VirtualAllocEx_(GetCurrentProcess_(), #Null, Mem, #MEM_COMMIT, #PAGE_EXECUTE_READWRITE)
CodeMem + 16 - (CodeMem % 16)     ;um sicher Alignment16 zu erreichen
CodeMemUr = CodeMem
    
Messung(REG32(DEC))
Ticks1 = TicksZ
Messung(REG32_IMMFEST(SUB, 1))
Ticks2 = TicksZ
VirtualFreeEx_(GetCurrentProcess_(), CodeMemUr, Mem, #MEM_DECOMMIT)

E1$ = "1.Test: " + Str(Ticks1) +" Taktzyklen"
E2$ = "2.Test: " + Str(Ticks2) +" Taktzyklen"
G$ = " Loops: " + Str(Loop1 * Loop2 * 10)   ;10-mal im Macro
MessageRequester("Benötigte Taktzyklen", E1$ + #LFCR$ + E2$ + #LFCR$ + G$)
Der Testcode wird ins Memory kopiert und dort als lange Code-"Kette" ausgeführt (allerdings auch mehrfach). Als Maß dienen die verbratenen Taktzyklen. Deine Werte würden mich mal interessieren.
Den Code während der Laufzeit zu verändern geht im Ring3-Modus (normaler Windows-Modus) nicht. Es gibt zwar spezielle Befehle (z.B.MOV mit Opcode $8E) dafür, aber die laufen nur im Ring0-Modus.

Gruß
Helle
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Beitrag von cxAlex »

---------------------------
Benötigte Taktzyklen
---------------------------
1.Test: 1011846915 Taktzyklen

2.Test: 1024620156 Taktzyklen

Loops: 1000000000
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Beitrag von Fluid Byte »

---------------------------
Benötigte Taktzyklen
---------------------------
1.Test: 1109235247 Taktzyklen

2.Test: 1049033918 Taktzyklen

Loops: 1000000000
---------------------------
OK
---------------------------
Windows 10 Pro, 64-Bit / Outtakes | Derek
Benutzeravatar
alter Mann
Beiträge: 201
Registriert: 29.08.2008 09:13
Wohnort: hinterm Mond

Beitrag von alter Mann »

1.Test: 1094186336 Taktzyklen

2.Test: 1075291860 Taktzyklen

Loops: 1000000000
Win11 64Bit / PB 6.0
Benutzeravatar
Batze
Beiträge: 1492
Registriert: 03.06.2005 21:58
Wohnort: Berlin
Kontaktdaten:

Beitrag von Batze »

1.Test: 1830372984 Taktzyklen
2.Test: 1167026544 Taktzyklen
Loops: 1000000000

Edit: es ist wohl nicht immer so extrem (hab noch ein par durchläufe probiert), aber immer ein merklicher Unterschied von über 50%

Naja, also ist meine CPU tatsächlich seltsam. Werde es auch nochmal auf dem Laptop testen. Aber ich kann wohl davon ausgehen dass ich da eher die Ausnahme bin.

Vielen Dank für diesen tollen Asm-Testcode, der ist sehr praktisch.
Zuletzt geändert von Batze am 07.05.2009 22:47, insgesamt 1-mal geändert.
Hier sind meine Codes (aber die Seite geht gerade nicht):
http://www.basicpure.de.vu
Benutzeravatar
X360 Andy
Beiträge: 1206
Registriert: 11.05.2008 00:22
Wohnort: Bodensee
Kontaktdaten:

Beitrag von X360 Andy »

Mal andere Zahlen :D

1. Test 2206120985
2. Test 2127548610

Und was haben diese Werte zu bedeuten ?

EDIT
Bei 2ten mal ist Test 2 um einiges Schneller als Test 1
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Beitrag von edel »

---------------------------
Benötigte Taktzyklen
---------------------------
1.Test: 1002612719 Taktzyklen

2.Test: 1002463007 Taktzyklen

Loops: 1000000000
---------------------------
OK
---------------------------
Sagt mir jetzt aber auch nichts :roll:
Antworten