CPU-Latenz-Durchsatz-Messung
Verfasst: 25.08.2008 13:02
Es ist sicher nicht nur für Assembler-Programmierer interessant, wie schnell denn ein bestimmter Befehl von der verfügbaren CPU abgearbeitet wird. Zur Messung von Latenz und Durchsatz dient nachfolgendes Programm, das sich beliebig erweitern lässt (weitere Kombinationen).
Der zu testende Befehl ist per Hand 2x in den Code einzutragen (mehr Aufwand lohnte nicht) und wird dann in extra reservierten Speicher kopiert, dupliziert und dann dort ausgeführt.
Die benötigte PBI-Datei:
Gruß
Helle
Edit: 26.08.2008: REG32_IMMFEST hinzugefügt
Der zu testende Befehl ist per Hand 2x in den Code einzutragen (mehr Aufwand lohnte nicht) und wird dann in extra reservierten Speicher kopiert, dupliziert und dann dort ausgeführt.
Code: Alles auswählen
;- CPU-Latenz-Durchsatz-Messung
;- "Helle" Klaus Helbing, 26.08.2008, PB 4.20
;- Latenz: Anzahl der Taktzyklen, um den Befehl komplett abzuarbeiten
;- Durchsatz: Anzahl der Taktzyklen, bis derselbe Befehl erneut eingelesen werden kann
; (nach Beginn des Einlesens des ersten Befehles)
;- Latenzmessung: Jeder nachfolgende (gleichartige) Befehl ist abhängig vom Ergebnis des vorhergehenden Befehls
;- Durchsatzmessung: Jeder nachfolgende (gleichartige) Befehl ist unabhängig vom Ergebnis des vorhergehenden Befehls
;- Die Abarbeitung der zu testenden Befehle erfolgt in speziell reserviertem Speicher
;- Ein Wert von z.B. 2.01 ist natürlich als 2.00 zu interpretieren! (auch 0.34 = 0.33 usw.)
;- Bei Speicherzugriffen wird es (wie zu erwarten) etwas unscharf, mehrere Tests machen
;- Bei einigen Befehlen macht eine Durchsatz-Messung keinen Sinn
Global Mem.l = $100000 ;Speicher reservieren, hier 1MB
Global Looping.q = 1000
Global CodeMem.l
Global CodeMemUr.l
Global CodeA.l
Global CodeL.l
Global TimeA.q
Global TimeE.q
Global TicksL.d
Global TicksD.d
Global TicksZ.d
Global Ticks.d
Global TestVar1.l = 123456789
Global TestVar2.l = 234567890
Global TestVar3.l = 345678901
Global TestVar4.l = 456789012
Global TestVar5.l = 567890123
Global TestVar6.l = 678901234
Global TestVar7.l = 789012345
Global TestVar8.l = 890123456
XIncludeFile "LD.pbi"
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)
If CodeMem
DisableDebugger
;Latenz-Messung ;keine Plausibilitäts-Überprüfung!
A1: ;hier zu testenden Befehl in den Macro-Aufruf einfügen
;ML_XMM_XMM(mulss)
;ML_REG32_REG32(imul)
;ML_REG32_MEM32(imul)
;ML_MEM32_REG32(adc)
;ML_REG32_IMM(sub)
ML_REG32_IMMFEST(rcl,3)
;ML_REG32(bswap)
;ML_JUMP ;hier sieht man sehr schön, daß Sprünge Gift sind. Also die
;ML_NOJUMP ; Verzweigungs-Art so wählen, das die Variante mit der zu
A2: ; erwartenden höheren Wahrscheinlichkeit keinen Sprung benötigt
CodeA = ?A1
CodeL = ?A2 - CodeA ;Codelänge des Macros
CodeMemUr = CodeMem ;sichern
LDTicks()
TicksL = Ticks
;Durchsatz-Messung ;keine Plausibilitäts-Überprüfung!
A3: ;hier zu testenden Befehl in den Macro-Aufruf einfügen
;MD_XMM_XMM(mulss)
;MD_REG32_REG32(imul)
;MD_REG32_MEM32(imul)
;MD_MEM32_REG32(adc)
;MD_REG32_IMM(sub)
MD_REG32_IMMFEST(rcl,3)
;MD_REG32(bswap)
A4:
CodeA = ?A3
CodeL = ?A4 - CodeA ;Codelänge des Macros
CodeMem = CodeMemUr
LDTicks()
TicksD = Ticks
;Fertig
VirtualFreeEx_(GetCurrentProcess_(), CodeMemUr, Mem, #MEM_DECOMMIT)
MessageRequester("Taktzyklen", "Latenz : " + StrD(TicksL, 2) + #LFCR$ + "Durchsatz : " + StrD(TicksD, 2))
Else
MessageRequester("Fehler !", "Der benötigte Speicher konnte nicht bereitgestellt werden !")
EndIf
End
Code: Alles auswählen
;LD.pbi
;==================================================================================================
Macro M_XMM_XMM_Z() ;XMM-Register auf 0 setzen
!pxor xmm0,xmm0
!movdqa xmm1,xmm0
!movdqa xmm2,xmm0
!movdqa xmm3,xmm0
!movdqa xmm4,xmm0
!movdqa xmm5,xmm0
!movdqa xmm6,xmm0
!movdqa xmm7,xmm0
EndMacro
;--------------------------------------------------------------------------------------------------
Macro ML_XMM_XMM(Befehl) ;Macro Latenz XMM - XMM-Register
!Befehl xmm0,xmm7 ;Einge Beispiele:
!Befehl xmm1,xmm0 ; DIVPD, DIVSD, MOVDQA, MOVDQU, MULPD, MULSD, ...
!Befehl xmm2,xmm1
!Befehl xmm3,xmm2
!Befehl xmm4,xmm3
!Befehl xmm5,xmm4
!Befehl xmm6,xmm5
!Befehl xmm7,xmm6
EndMacro
;--------------------------------------------------------------------------------------------------
Macro MD_XMM_XMM(Befehl) ;Beginn Macro Durchsatz XMM - XMM-Register
!Befehl xmm0,xmm1
!Befehl xmm2,xmm3
!Befehl xmm4,xmm5
!Befehl xmm6,xmm7
!Befehl xmm0,xmm1
!Befehl xmm2,xmm3
!Befehl xmm4,xmm5
!Befehl xmm6,xmm7
EndMacro
;--------------------------------------------------------------------------------------------------
Macro ML_REG32_REG32(Befehl) ;Macro Latenz 32-Bit-Register - 32-Bit-Register
!Befehl eax,edx ;Einige Beispiele:
!Befehl ebx,eax ; ADC, ADD, AND, BSF, BSR, CMOVcc, CMP, CMPXCHG
!Befehl ecx,ebx ; IMUL, MOV, OR, SBB, SUB, TEST, XADD, XCHG, XOR
!Befehl edx,ecx
!Befehl eax,edx
!Befehl ebx,eax
!Befehl ecx,ebx
!Befehl edx,ecx
EndMacro
;--------------------------------------------------------------------------------------------------
Macro MD_REG32_REG32(Befehl) ;Macro Durchsatz 32-Bit-Register - 32-Bit-Register
!Befehl eax,ebp
!Befehl ebx,ebp
!Befehl ecx,ebp
!Befehl edx,ebp
!Befehl eax,ebp
!Befehl ebx,ebp
!Befehl ecx,ebp
!Befehl edx,ebp
EndMacro
;--------------------------------------------------------------------------------------------------
Macro ML_REG32_MEM32(Befehl) ;Macro Latenz 32-Bit-Register - 32-Bit-Speicher
!Befehl eax,[v_TestVar1]
!Befehl eax,[v_TestVar2]
!Befehl eax,[v_TestVar3]
!Befehl eax,[v_TestVar4]
!Befehl eax,[v_TestVar5]
!Befehl eax,[v_TestVar6]
!Befehl eax,[v_TestVar7]
!Befehl eax,[v_TestVar8]
EndMacro
;--------------------------------------------------------------------------------------------------
Macro MD_REG32_MEM32(Befehl) ;Macro Durchsatz 32-Bit-Register - 32-Bit-Speicher
!Befehl eax,[v_TestVar1]
!Befehl ebx,[v_TestVar2]
!Befehl ecx,[v_TestVar3]
!Befehl edx,[v_TestVar4]
!Befehl eax,[v_TestVar5]
!Befehl ebx,[v_TestVar6]
!Befehl ecx,[v_TestVar7]
!Befehl edx,[v_TestVar8]
EndMacro
;--------------------------------------------------------------------------------------------------
Macro ML_MEM32_REG32(Befehl) ;Macro Latenz 32-Bit-Speicher - 32-Bit-Register
!Befehl [v_TestVar1],eax
!Befehl [v_TestVar2],eax
!Befehl [v_TestVar3],eax
!Befehl [v_TestVar4],eax
!Befehl [v_TestVar5],eax
!Befehl [v_TestVar6],eax
!Befehl [v_TestVar7],eax
!Befehl [v_TestVar8],eax
EndMacro
;--------------------------------------------------------------------------------------------------
Macro MD_MEM32_REG32(Befehl) ;Macro Durchsatz 32-Bit-Speicher - 32-Bit-Register
!Befehl [v_TestVar1],eax
!Befehl [v_TestVar2],ebx
!Befehl [v_TestVar3],ecx
!Befehl [v_TestVar4],edx
!Befehl [v_TestVar5],eax
!Befehl [v_TestVar6],ebx
!Befehl [v_TestVar7],ecx
!Befehl [v_TestVar8],edx
EndMacro
;--------------------------------------------------------------------------------------------------
Macro ML_REG32_IMM(Befehl) ;Macro Latenz 32-Bit-Register - Festwert
!Befehl eax,1 ;Einige Beispiele:
!Befehl eax,2 ; (RCL, RCR, ROL, ROR, SAL, SAR, SHL, SHR) dafür besser REG32_IMMFEST
!Befehl eax,3 ; ADD, ADC, CMP, IMUL, MOV, SBB, SUB
!Befehl eax,4
!Befehl eax,5
!Befehl eax,6
!Befehl eax,7
!Befehl eax,8
EndMacro
;--------------------------------------------------------------------------------------------------
Macro MD_REG32_IMM(Befehl) ;Macro Durchsatz 32-Bit-Register - Festwert
!Befehl eax,1
!Befehl ebx,2
!Befehl ecx,3
!Befehl edx,4
!Befehl eax,5
!Befehl ebx,6
!Befehl ecx,7
!Befehl edx,8
EndMacro
;--------------------------------------------------------------------------------------------------
Macro ML_REG32_IMMFEST(Befehl, Wert) ;Macro Latenz 32-Bit-Register - Festwert
!Befehl eax,Wert ;Einige Beispiele:
!Befehl eax,Wert ; RCL, RCR, ROL, ROR, SAL, SAR, SHL, SHR
!Befehl eax,Wert ; ADD, ADC, CMP, IMUL, MOV, SBB, SUB
!Befehl eax,Wert
!Befehl eax,Wert
!Befehl eax,Wert
!Befehl eax,Wert
!Befehl eax,Wert
EndMacro
;--------------------------------------------------------------------------------------------------
Macro MD_REG32_IMMFEST(Befehl, Wert) ;Macro Durchsatz 32-Bit-Register - Festwert
!Befehl eax,Wert
!Befehl ebx,Wert
!Befehl ecx,Wert
!Befehl edx,Wert
!Befehl eax,Wert
!Befehl ebx,Wert
!Befehl ecx,Wert
!Befehl edx,Wert
EndMacro
;--------------------------------------------------------------------------------------------------
Macro ML_REG32(Befehl) ;Macro Latenz 32-Bit-Register
!Befehl eax ;Einige Beispiele:
!Befehl eax ; BSWAP, DEC, IMUL, INC, MUL, NEG, NOT
!Befehl eax
!Befehl eax
!Befehl eax
!Befehl eax
!Befehl eax
!Befehl eax
EndMacro
;--------------------------------------------------------------------------------------------------
Macro MD_REG32(Befehl) ;Macro Durchsatz 32-Bit-Register
!Befehl eax
!Befehl ebx
!Befehl ecx
!Befehl edx
!Befehl edi
!Befehl esi
!Befehl ebp
!Befehl eax
EndMacro
;--------------------------------------------------------------------------------------------------
Macro ML_JUMP ;Macro Latenz JUMP, Sprung wird ausgeführt
!cmp ebp,0
!jne @f
!@@:
!cmp ebp,0
!jne @f
!@@:
!cmp ebp,0
!jne @f
!@@:
!cmp ebp,0
!jne @f
!@@:
!cmp ebp,0
!jne @f
!@@:
!cmp ebp,0
!jne @f
!@@:
!cmp ebp,0
!jne @f
!@@:
!cmp ebp,0
!jne @f
!@@:
EndMacro
;--------------------------------------------------------------------------------------------------
Macro ML_NOJUMP ;Macro Latenz NOJUMP, Sprung wird nicht ausgeführt
!cmp ebp,0
!je @f
!@@:
!cmp ebp,0
!je @f
!@@:
!cmp ebp,0
!je @f
!@@:
!cmp ebp,0
!je @f
!@@:
!cmp ebp,0
!je @f
!@@:
!cmp ebp,0
!je @f
!@@:
!cmp ebp,0
!je @f
!@@:
!cmp ebp,0
!je @f
!@@:
EndMacro
;==================================================================================================
Procedure LDTicks()
For i = 1 To Looping ;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
M_XMM_XMM_Z() ;um ungültige Werte in den XMM-Registern zu vermeiden (z.B. NaN)
!mov ebp,123456789 ;z.B. für Reg32-Reg32 definierter (Anfangs-)Wert für EBP
Ticks = 10000.0 ;irgend ein rel. hoher Wert
FlushInstructionCache_(GetCurrentProcess_(), #Null, #Null) ;(bisherigen) Befehls-Cache löschen
!cpuid ;für Serialisierung (Pipe(s) leerfegen)
For i = 0 To 25
!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
!call [v_CodeMemUr] ;Code im Speicher ausführen
!rdtsc
!mov dword[v_TimeE],eax
!mov dword[v_TimeE+4],edx
TicksZ = (TimeE - TimeA) / (Looping * 8) ;8 = Anzahl der Befehle pro Macro
If TicksZ < Ticks
Ticks = TicksZ ;der kleinste Wert wird benötigt
EndIf
Next
EndProcedure
Helle
Edit: 26.08.2008: REG32_IMMFEST hinzugefügt