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