Ich habe jetzt mal alles zum testen in einen Code gebracht und etwas aufgeräumt. (siehe unten bei Interesse)
PCLMULQDQ ist der Code von Helle aber unschlagbar.
Am besten man checkt das CPU-Flag zum Programmstart, und entscheidet danach was verwendet wird.
Wilberts Code ist unterschiedlich im Vergleich je nach Prozessor - mit dem alten Atom 330 hat er (genau wie Helle)
scheinbar ein Problem.
Code: Alles auswählen
; ### Zum Test Debugger ausschalten ! ###
#Loops=10000
#ImageWidth = 64
#ImageHeight = 64
#ImageDepth = 24
#MemorySize = #ImageWidth * #ImageHeight * #ImageDepth ; ( <- Richtig wäre natürlich ... * (#ImageDepth/8) )
Global *Memory = AllocateMemory(#MemorySize + 16)
Global *MemDummy = AllocateMemory(#MemorySize + 16) ; Jeweils knapp 100K für den Test
Global tt
Procedure simpleHash(*buffer, length.i) ; by NicTheQuick
Protected *p.Integer = *buffer
Protected hash.i
CompilerIf #PB_Processor_x86 = #PB_Compiler_Processor
Protected *begin = *buffer & ~7
Protected *end = (*buffer + length) & ~7
CompilerElse
Protected *begin = *buffer & ~3
Protected *end = (*buffer + length) & ~3
CompilerEndIf
If *begin < *buffer
*begin + SizeOf(Integer)
EndIf
While *p < *begin And *p < *end
hash ! PeekA(*p)
*p + 1
Wend
While *p < *end
hash ! *p\i
*p + SizeOf(Integer)
Wend
While *p < *buffer + length
hash ! PeekA(*p)
*p + 1
Wend
CompilerIf #PB_Processor_x64 = #PB_Compiler_Processor
hash ! (hash >> 32)
CompilerEndIf
hash ! (hash >> 16)
hash ! (hash >> 8)
ProcedureReturn hash & $ff
EndProcedure
Procedure BSD_Sum(*Buffer, Size, InitialValue = 0) ; by wilbert; http://www.purebasic.fr/english/viewtopic.php?f=12&t=49250&hilit=bsd
EnableASM
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
MOV edx, *Buffer
MOV ecx, Size
MOV eax, InitialValue
!push ebx
!bsd_sum_loop:
!ror ax, 1
!movzx bx, byte [edx]
!add ax, bx
!inc edx
!dec ecx
!jnz bsd_sum_loop
!pop ebx
!movzx eax, ax
CompilerElse
MOV r8, *Buffer
MOV rcx, Size
MOV rax, InitialValue
!bsd_sum_loop:
!ror ax, 1
!movzx dx, byte [r8]
!add ax, dx
!inc r8
!dec rcx
!jnz bsd_sum_loop
!movzx rax, ax
CompilerEndIf
DisableASM
ProcedureReturn
EndProcedure
Procedure.l CRC32_CL(Mem, Laenge) ; by Helle (Version für PB32Bit)
;- "Helle" Klaus Helbing, 11.12.2015
;- CRC32 mit PCLMULQDQ ohne PB-CRC32, für 32-Bit-Windows
;- Basierend auf: http://stuff.mit.edu/afs/sipb/contrib/linux/arch/x86/crypto/crc32-pclmul_asm.S
;- Lizenz beachten!
!MOV eax,[p.v_Laenge]
!OR eax,eax ;erstmal Test, ob Länge = 0
!JNZ Laenge_OK ;nicht 0
ProcedureReturn ;Rückgabewert = 0 für Länge = 0
!Laenge_OK:
;Test auf PCLMULQDQ
!MOV eax,1
!CPUID
!MOV eax,0FFFFFFFFh ;Initialisierungswert für CRC32
!TEST ecx,2
!JNZ CL_OK ;kann losgehen! Auskommentieren für Test ohne PCLMULQDQ
!LEA ecx,[CRC_Table] ;die CPU bringts nicht, also konventionell
!MOV eax,[p.v_Mem]
!MOV edx,[p.v_Laenge]
!PUSH ebx
!MOV ebx,ecx
!PUSH esi
!MOV esi,eax
!MOV eax,0FFFFFFFFh ;Initialisierungswert für CRC32
!@@:
!MOVZX ecx,byte[esi]
!XOR cl,al
!SHR eax,8
!XOR eax,dword[ebx+ecx*4]
!INC esi
!DEC edx ;Länge
!JNZ @b
!POP esi
!POP ebx
!NOT eax ;wegen Polynomial Reversed
ProcedureReturn
!CL_OK:
!MOV eax,0FFFFFFFFh ;Initialisierungswert für CRC32
!MOV edx,[p.v_Laenge]
!AND edx,0FFFFFFC0h ;Länge < 40h?
!JZ less_64 ;ja, konventionell weiter
!MOVD xmm5,eax ;eax = 0FFFFFFFFh Initialisierungswert für CRC32
!MOV ecx,[p.v_Mem]
!MOVDQA xmm0,[ecx]
!MOVDQA xmm1,[ecx+10h]
!MOVDQA xmm2,[ecx+20h]
!MOVDQA xmm3,[ecx+30h]
!PXOR xmm0,xmm5
!SUB edx,40h
!ADD ecx,40h
!loop_64:
!PREFETCHNTA [ecx+0c0h] ;Cache "vorfüllen"
!MOVDQA xmm4,xmm0
!MOVDQA xmm5,xmm1
!MOVDQA xmm6,xmm2
!MOVDQA xmm7,xmm3
!PCLMULQDQ xmm0,[Lconstant_R2R1],00h
!PCLMULQDQ xmm1,[Lconstant_R2R1],00h
!PCLMULQDQ xmm2,[Lconstant_R2R1],00h
!PCLMULQDQ xmm3,[Lconstant_R2R1],00h
!PCLMULQDQ xmm4,[Lconstant_R2R1],11h
!PCLMULQDQ xmm5,[Lconstant_R2R1],11h
!PCLMULQDQ xmm6,[Lconstant_R2R1],11h
!PCLMULQDQ xmm7,[Lconstant_R2R1],11h
!PXOR xmm0,xmm4
!PXOR xmm1,xmm5
!PXOR xmm2,xmm6
!PXOR xmm3,xmm7
!PXOR xmm0,[ecx]
!PXOR xmm1,[ecx+10h]
!PXOR xmm2,[ecx+20h]
!PXOR xmm3,[ecx+30h]
!SUB edx,40h
!ADD ecx,40h
!CMP edx,40h
!JGE loop_64
!MOVDQA xmm6,[Lconstant_R4R3]
!PREFETCHNTA [ecx]
!MOVDQA xmm4,xmm0
!PCLMULQDQ xmm0,xmm6,00h
!PCLMULQDQ xmm4,xmm6,11h
!PXOR xmm0,xmm4
!PXOR xmm0,xmm1
!MOVDQA xmm4,xmm0
!PCLMULQDQ xmm0,xmm6,00h
!PCLMULQDQ xmm4,xmm6,11h
!PXOR xmm0,xmm4
!PXOR xmm0,xmm2
!MOVDQA xmm4,xmm0
!PCLMULQDQ xmm0,xmm6,00h
!PCLMULQDQ xmm4,xmm6,11h
!PXOR xmm0,xmm4
!PXOR xmm0,xmm3
!PCLMULQDQ xmm6,xmm0,01h
!PSRLDQ xmm0,08h
!PXOR xmm0,xmm6
!MOVDQA xmm1,xmm0
!MOVDQA xmm6,[Lconstant_R5]
!MOVDQA xmm2,[Lconstant_mask32]
!PSRLDQ xmm1,04h
!PAND xmm0,xmm2
!PCLMULQDQ xmm0,xmm6,00h
!PXOR xmm0,xmm1
!MOVDQA xmm6,[Lconstant_RUpoly]
!MOVDQA xmm1,xmm0
!PAND xmm0,xmm2
!PCLMULQDQ xmm0,xmm6,10h
!PAND xmm0,xmm2
!PCLMULQDQ xmm0,xmm6,00h
!PXOR xmm0,xmm1
!less_64: ;Rest (max.63 Bytes)
!LEA ecx,[CRC_Table] ;die restlichen Bytes mit Tabelle
!MOV eax,[p.v_Mem]
!MOV edx,[p.v_Laenge]
!PUSH ebx
!MOV ebx,ecx
!PUSH esi
!MOV esi,eax
!PEXTRD eax,xmm0,01h ;eax ist CRC32 (bis hierher)
!ADD esi,edx
!AND edx,3fh ;möglicher Rest
!JZ NoRest ;kein Rest
!SUB esi,edx
!@@:
!MOVZX ecx,byte[esi]
!XOR cl,al
!SHR eax,8
!XOR eax,dword[ebx+ecx*4]
!INC esi
!DEC edx
!JNZ @b
!NoRest:
!POP esi
!POP ebx
!NOT eax ;wegen Polynomial Reversed
ProcedureReturn
;Konstanten
!Align 16
!Lconstant_R2R1:
!dq 0000000154442BD4h, 00000001C6E41596h
!Lconstant_R4R3:
!dq 00000001751997D0h, 00000000CCAA009Eh
!Lconstant_R5:
!dq 0000000163CD6124h, 0000000000000000h
!Lconstant_mask32:
!dq 00000000FFFFFFFFh, 0000000000000000h
!Lconstant_RUpoly:
!dq 00000001DB710641h, 00000001F7011641h
!CRC_Table:
!dd 0
!dd 077073096h, 0EE0E612Ch, 0990951BAh, 0076DC419h, 0706AF48Fh
!dd 0E963A535h, 09E6495A3h, 00EDB8832h, 079DCB8A4h, 0E0D5E91Eh
!dd 097D2D988h, 009B64C2Bh, 07EB17CBDh, 0E7B82D07h, 090BF1D91h
!dd 01DB71064h, 06AB020F2h, 0F3B97148h, 084BE41DEh, 01ADAD47Dh
!dd 06DDDE4EBh, 0F4D4B551h, 083D385C7h, 0136C9856h, 0646BA8C0h
!dd 0FD62F97Ah, 08A65C9ECh, 014015C4Fh, 063066CD9h, 0FA0F3D63h
!dd 08D080DF5h, 03B6E20C8h, 04C69105Eh, 0D56041E4h, 0A2677172h
!dd 03C03E4D1h, 04B04D447h, 0D20D85FDh, 0A50AB56Bh, 035B5A8FAh
!dd 042B2986Ch, 0DBBBC9D6h, 0ACBCF940h, 032D86CE3h, 045DF5C75h
!dd 0DCD60DCFh, 0ABD13D59h, 026D930ACh, 051DE003Ah, 0C8D75180h
!dd 0BFD06116h, 021B4F4B5h, 056B3C423h, 0CFBA9599h, 0B8BDA50Fh
!dd 02802B89Eh, 05F058808h, 0C60CD9B2h, 0B10BE924h, 02F6F7C87h
!dd 058684C11h, 0C1611DABh, 0B6662D3Dh, 076DC4190h, 001DB7106h
!dd 098D220BCh, 0EFD5102Ah, 071B18589h, 006B6B51Fh, 09FBFE4A5h
!dd 0E8B8D433h, 07807C9A2h, 00F00F934h, 09609A88Eh, 0E10E9818h
!dd 07F6A0DBBh, 0086D3D2Dh, 091646C97h, 0E6635C01h, 06B6B51F4h
!dd 01C6C6162h, 0856530D8h, 0F262004Eh, 06C0695EDh, 01B01A57Bh
!dd 08208F4C1h, 0F50FC457h, 065B0D9C6h, 012B7E950h, 08BBEB8EAh
!dd 0FCB9887Ch, 062DD1DDFh, 015DA2D49h, 08CD37CF3h, 0FBD44C65h
!dd 04DB26158h, 03AB551CEh, 0A3BC0074h, 0D4BB30E2h, 04ADFA541h
!dd 03DD895D7h, 0A4D1C46Dh, 0D3D6F4FBh, 04369E96Ah, 0346ED9FCh
!dd 0AD678846h, 0DA60B8D0h, 044042D73h, 033031DE5h, 0AA0A4C5Fh
!dd 0DD0D7CC9h, 05005713Ch, 0270241AAh, 0BE0B1010h, 0C90C2086h
!dd 05768B525h, 0206F85B3h, 0B966D409h, 0CE61E49Fh, 05EDEF90Eh
!dd 029D9C998h, 0B0D09822h, 0C7D7A8B4h, 059B33D17h, 02EB40D81h
!dd 0B7BD5C3Bh, 0C0BA6CADh, 0EDB88320h, 09ABFB3B6h, 003B6E20Ch
!dd 074B1D29Ah, 0EAD54739h, 09DD277AFh, 004DB2615h, 073DC1683h
!dd 0E3630B12h, 094643B84h, 00D6D6A3Eh, 07A6A5AA8h, 0E40ECF0Bh
!dd 09309FF9Dh, 00A00AE27h, 07D079EB1h, 0F00F9344h, 08708A3D2h
!dd 01E01F268h, 06906C2FEh, 0F762575Dh, 0806567CBh, 0196C3671h
!dd 06E6B06E7h, 0FED41B76h, 089D32BE0h, 010DA7A5Ah, 067DD4ACCh
!dd 0F9B9DF6Fh, 08EBEEFF9h, 017B7BE43h, 060B08ED5h, 0D6D6A3E8h
!dd 0A1D1937Eh, 038D8C2C4h, 04FDFF252h, 0D1BB67F1h, 0A6BC5767h
!dd 03FB506DDh, 048B2364Bh, 0D80D2BDAh, 0AF0A1B4Ch, 036034AF6h
!dd 041047A60h, 0DF60EFC3h, 0A867DF55h, 0316E8EEFh, 04669BE79h
!dd 0CB61B38Ch, 0BC66831Ah, 0256FD2A0h, 05268E236h, 0CC0C7795h
!dd 0BB0B4703h, 0220216B9h, 05505262Fh, 0C5BA3BBEh, 0B2BD0B28h
!dd 02BB45A92h, 05CB36A04h, 0C2D7FFA7h, 0B5D0CF31h, 02CD99E8Bh
!dd 05BDEAE1Dh, 09B64C2B0h, 0EC63F226h, 0756AA39Ch, 0026D930Ah
!dd 09C0906A9h, 0EB0E363Fh, 072076785h, 005005713h, 095BF4A82h
!dd 0E2B87A14h, 07BB12BAEh, 00CB61B38h, 092D28E9Bh, 0E5D5BE0Dh
!dd 07CDCEFB7h, 00BDBDF21h, 086D3D2D4h, 0F1D4E242h, 068DDB3F8h
!dd 01FDA836Eh, 081BE16CDh, 0F6B9265Bh, 06FB077E1h, 018B74777h
!dd 088085AE6h, 0FF0F6A70h, 066063BCAh, 011010B5Ch, 08F659EFFh
!dd 0F862AE69h, 0616BFFD3h, 0166CCF45h, 0A00AE278h, 0D70DD2EEh
!dd 04E048354h, 03903B3C2h, 0A7672661h, 0D06016F7h, 04969474Dh
!dd 03E6E77DBh, 0AED16A4Ah, 0D9D65ADCh, 040DF0B66h, 037D83BF0h
!dd 0A9BCAE53h, 0DEBB9EC5h, 047B2CF7Fh, 030B5FFE9h, 0BDBDF21Ch
!dd 0CABAC28Ah, 053B39330h, 024B4A3A6h, 0BAD03605h, 0CDD70693h
!dd 054DE5729h, 023D967BFh, 0B3667A2Eh, 0C4614AB8h, 05D681B02h
!dd 02A6F2B94h, 0B40BBE37h, 0C30C8EA1h, 05A05DF1Bh, 02D02EF8Dh
EndProcedure
; ----------------------------------------------------------------------------------------
UseCRC32Fingerprint()
*MemoryA = *Memory ;muss Alignment 16 sein für CRC32_CL !
If *MemoryA & $0F : *MemoryA = *Memory + 16 - (*MemoryA & $0F) : EndIf
*MemDummyA = *MemDummy
If *MemDummyA & $0F : *MemDummyA = *MemDummy + 16 - (*MemDummyA & $0F) : EndIf
FillMemory(*MemoryA, #MemorySize) ; Testspeicher gleich füllen,
FillMemory(*MemDummyA, #MemorySize) ; damit CompareMemory max. lang dauert
; -------------
st=ElapsedMilliseconds()
For i=1 To #Loops
Result = Val("$"+Fingerprint(*MemoryA, #MemorySize, #PB_Cipher_CRC32))
Next
tt=ElapsedMilliseconds()-st : MessageRequester("PB CRC32:",Str(tt)+" ms")
; -------------
st=ElapsedMilliseconds()
For i=1 To #Loops
Result = BSD_Sum(*MemoryA, #MemorySize)
Next
tt=ElapsedMilliseconds()-st : MessageRequester("BSD_SUM (wilbert):",Str(tt)+" ms")
; -------------
st=ElapsedMilliseconds()
For i=1 To #Loops
Result = simpleHash(*MemoryA, #MemorySize)
Next
tt=ElapsedMilliseconds()-st : MessageRequester("SimpleHash (NicTheQuick):",Str(tt)+" ms")
; -------------
st=ElapsedMilliseconds()
For i=1 To #Loops
Result = CRC32_CL(*MemoryA, #MemorySize)
Next
tt=ElapsedMilliseconds()-st : MessageRequester("CRC32_CL (Helle):",Str(tt)+" ms")
; -------------
st=ElapsedMilliseconds()
For i=1 To #Loops
Result = CompareMemory(*MemoryA,*MemDummyA,#MemorySize) ; Dient nur zu Zeitvergleichszwecken
Next
tt=ElapsedMilliseconds()-st : MessageRequester("PB CompareMemory:",Str(tt)+" ms")