Seite 1 von 1

[DONE] Gesucht: Schnelle simple Speicherprüfsumme

Verfasst: 10.12.2015 22:43
von TheCube
Hallo! Nach einer langen Suche im deutschen und englischen Forum habe ich nichts passendes gefunden.
Bin mir aber sicher, das das hier bestimmt schonmal irgentwo ein Thema war. Vielleicht hat jemand einen Tipp.

Ich möchte von einem Speicherbereich (hält z.B. ein 64x64pix Grafik-Tile) einen Kennwert erzeugen
um Änderungen darin zu bemerken. Der Code von Helle (CRC32 mit PCLMULQDQode) geht nicht, da nur für 64Bit.
Außerdem reicht mir schon was primitives wie eine 8-Bit Chksum, Hauptsache schnell, wenigstens wie CompareMemory aus PB.

Bei mir dauert BSD_SUM 600ms, CRC32 300ms und CompareMemory 100ms. (ca.) Fand ich überraschend.

Hier ein Codeschnipsel zum Vergleichen: Anm.: Alt .... besser den Code vom 11.12 21:28 nehmen.

Code: Alles auswählen

#ImageWidth = 64
#ImageHeight = 64
#ImageDepth = 24
#MemorySize = #ImageWidth * #ImageHeight * #ImageDepth
Debug #MemorySize
Global *Memory   = AllocateMemory(#MemorySize)
Global *MemDummy = AllocateMemory(#MemorySize)    ; Jeweils knapp 100K
Global tt


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

; ----------------------------------------------------------------------------------------
UseCRC32Fingerprint()

FillMemory(*Memory,   500)   ; Testspeicher gleich füllen,
FillMemory(*MemDummy, 500)   ; damit CompareMemory max. lang dauert

st=ElapsedMilliseconds()
For i=1 To 1000
  Result = Val("$"+Fingerprint(*Memory, #MemorySize, #PB_Cipher_CRC32))
Next
tt=ElapsedMilliseconds()-st : MessageRequester("PB CRC32:",Str(tt)+" ms")

; -------------

st=ElapsedMilliseconds()
For i=1 To 1000
  Result = BSD_Sum(*Memory, #MemorySize)
Next
tt=ElapsedMilliseconds()-st : MessageRequester("BSD_SUM:",Str(tt)+" ms")

; -------------

st=ElapsedMilliseconds()
For i=1 To 1000
  Result = CompareMemory(*Memory,*MemDummy,#MemorySize)   ; Dient nur zu Zeitvergleichszwecken
Next
tt=ElapsedMilliseconds()-st : MessageRequester("CompareMemory:",Str(tt)+" ms")

Re: Gesucht: Schnelle simple Speicherprüfsumme

Verfasst: 11.12.2015 00:27
von NicTheQuick
Hier hast du eine 8-Bit-Checksum. Genauer gesagt, macht der Code einfach ein XOr über den kompletten Speicherbereich.

Code: Alles auswählen

Procedure simpleHash(*buffer, length.i)
	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

Re: Gesucht: Schnelle simple Speicherprüfsumme

Verfasst: 11.12.2015 08:54
von STARGÅTE
Deine Zeiten stimmen irgendwie garnicht.

Du hast ja 1000 Iterationen und ElapsedMilliseconds() ist in ms, somit wäre dein Testergebnis in µs.
PB CRC32: 220µs
BSD_SUM: 95µs
CompareMemory: 19µs

Im übrigen, für #ImageDepth = 24 (Bit?) brauchst du nur 3 Byte, nicht 24.

Re: Gesucht: Schnelle simple Speicherprüfsumme

Verfasst: 11.12.2015 11:56
von TheCube
@NicTheQuick: Danke! Sowas Simples meinte ich. Aber schneller als BSD_SUM ist es leider (noch?) nicht.
Aber im deinem Code müssten die CompilerIf's mit #PB_Compiler_Processor = .... ergänzt werden, sonst Fehler mit PB-32Bit.

@STARGÅTE: Du hast natürlich recht, ich gebe die Zeiten für 1000 Durchläufe aus.
#ImageDepth = 24 -> 3 Byte Stimmt :freak:
Aber hier im im Testschnipsel kam es erstmal nur auf einen mittelgrossen (ca. 100K) Speicherblock an.

Re: Gesucht: Schnelle simple Speicherprüfsumme

Verfasst: 11.12.2015 12:18
von NicTheQuick
Ich weiß ja nicht, was du für einen Rechner hast und ob du tatsächlich den Debugger ausgeschaltet hast, aber simpleHash ist bei mir mehr als doppelt so schnell wie BSD_SUM.

Code: Alles auswählen

#ImageWidth = 64
#ImageHeight = 64
#ImageDepth = 24
#MemorySize = #ImageWidth * #ImageHeight * #ImageDepth
Debug #MemorySize
Global *Memory   = AllocateMemory(#MemorySize)
Global *MemDummy = AllocateMemory(#MemorySize)    ; Jeweils knapp 100K
Global tt

Procedure simpleHash(*buffer, length.i)
	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

; ----------------------------------------------------------------------------------------
UseCRC32Fingerprint()

FillMemory(*Memory,   500)   ; Testspeicher gleich füllen,
FillMemory(*MemDummy, 500)   ; damit CompareMemory max. lang dauert

st=ElapsedMilliseconds()
For i=1 To 10000
  Result = Val("$"+Fingerprint(*Memory, #MemorySize, #PB_Cipher_CRC32))
Next
tt=ElapsedMilliseconds()-st : MessageRequester("PB CRC32:",Str(tt)+" ms")

; -------------

st=ElapsedMilliseconds()
For i=1 To 10000
  Result = BSD_Sum(*Memory, #MemorySize)
Next
tt=ElapsedMilliseconds()-st : MessageRequester("BSD_SUM:",Str(tt)+" ms")

; -------------

st=ElapsedMilliseconds()
For i=1 To 10000
  Result = simpleHash(*Memory, #MemorySize)
Next
tt=ElapsedMilliseconds()-st : MessageRequester("simpleHash:",Str(tt)+" ms")

; -------------

st=ElapsedMilliseconds()
For i=1 To 10000
  Result = CompareMemory(*Memory,*MemDummy,#MemorySize)   ; Dient nur zu Zeitvergleichszwecken
Next
tt=ElapsedMilliseconds()-st : MessageRequester("CompareMemory:",Str(tt)+" ms")
Hier meine Zeiten:

Code: Alles auswählen

Algorithmus    Zeit für 10000 Durchläufe
----------------------------------------
CRC32          2259 ms
BSD_SUM         682 ms
simpleHash      275 ms
CompareMemory   146 ms
Dein Original-Code von oben braucht bei mir übrigens 227 ms (CRC32), 74 ms (BSD_SUM) und 18 ms (CompareMemory).
TheCube hat geschrieben:Aber im deinem Code müssten die CompilerIf's mit #PB_Compiler_Processor = .... ergänzt werden, sonst Fehler mit PB-32Bit.
Danke, das habe ich einfach übersehen. Ich habe es geändert.

Re: Gesucht: Schnelle simple Speicherprüfsumme

Verfasst: 11.12.2015 12:54
von Helle
Habe für CRC32 eine 32-Bit-Version für Windows nachgereicht.
Kannst ja mal testen!
Wichtig ist, das der Speicher mind. 16-Byte-Alignment hat!
Gruß
Helle

Re: Gesucht: Schnelle simple Speicherprüfsumme

Verfasst: 11.12.2015 13:38
von TheCube
@Helle: :allright: Teste ich gerne ... heute abend frühestens. Bin gespannt.

Benutze z.T. einen Atom 2-Kern (4Gb, Win7-32), daher die schnarchigen Zeiten vom ersten Post.

Re: Gesucht: Schnelle simple Speicherprüfsumme

Verfasst: 11.12.2015 22:28
von TheCube
Ich habe jetzt mal alles zum testen in einen Code gebracht und etwas aufgeräumt. (siehe unten bei Interesse)
Folgende Ergebnisse habe ich:

Code: Alles auswählen

; Atom 330 2-Kern 2GHz W7-32 (ohne PCLMULQDQ) :    10000x
; PB CRC32:                                        3900 ms
; BSD_SUM (wilbert):                               5900 ms
; SimpleHash (NicTheQuick):                        1700 ms
; CRC32_CL (Helle):                                4850 ms (!)
; PB CompareMemory:                                1150 ms

; Core2Quad Q6700 2,7Ghz W7-32 (ohne PCLMULQDQ) :  10000x  
; PB CRC32:                                        2450 ms
; BSD_SUM (wilbert):                                830 ms
; SimpleHash (NicTheQuick):                         750 ms
; CRC32_CL (Helle):                                2270 ms
; PB CompareMemory:                                 210 ms

; i5-4430S 2,7Ghz W7-64:                           10000x  
; PB CRC32:                                        2800 ms
; BSD_SUM (wilbert):                                950 ms
; SimpleHash (NicTheQuick):                         900 ms
; CRC32_CL (Helle):                                 100 ms (!)
; PB CompareMemory:                                 350 ms
Fazit:
Der Code von NicTheQuick ist Prozessor-unabhängig immer gut, auf moderneren
Prozessoren dagegen mit 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.

Danke an alle Beteiligten !

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")

Re: Gesucht: Schnelle simple Speicherprüfsumme

Verfasst: 11.12.2015 22:58
von GPI
Jetzt kommt es halt darauf an, was du machen willst. Ich bin ja in der Beziehung etwas schmerzbefreit und würde nur noch helles code benutzen (übrigens danke dafür). Auf moderen CPUs ist er definitiv die beste Lösung. Sowohl schnell und er erkennt Änderungen wesentlich besser als die XOR-Methode (da bekommt man eine 256Bit-zahl raus. Da dürften kollisionen sehr wahrscheinlich sein. Zudem ist es nicht gegen einfaches vertauschen von zwei Bytes gefeilt).

Klar ältere Prozessoren kommen damit nicht klar und werden langsam, aber mal ehrlich, wer eine CPU von vor 2010 bzw. 2011 noch hat, der ist warten gewöhnt :)

Re: [DONE] Gesucht: Schnelle simple Speicherprüfsumme

Verfasst: 15.12.2015 20:18
von 7x7
Ist zwar schon als DONE markiert, möchte aber dennoch einen kleinen Beitrag leisten. Habe vor einiger Zeit auch mal das Problem einer schnellen Prüfsumme gehabt und mich aus Performance-Gründen für Xor entschieden. Heraus kam folgendes:

Code: Alles auswählen

EnableASM

Macro MACRO32_XORCHECK(PRUEFCODE,ADRESSE, LAENGE)
	MOV ecx,LAENGE				;übergabe als Konstante
	!SHR ecx,2					;/4, weil immer 4Bytes gelesen werden
	!MOV ebx,dword[p_#ADRESSE]
	!XOR eax,eax
	
	!@@:
	!XOR eax,dword[ebx]
	!ADD ebx,4
	!DEC ecx
	!JNZ @b
	
	!MOV dword[v_#PRUEFCODE],eax
EndMacro

Macro MACRO64_XORCHECK(PRUEFCODE,ADRESSE, LAENGE)
	MOV rcx, LAENGE
	!SHR rcx,3					; /8, weil immer 8Bytes gelesen weerden
	!MOV rbx,qword[p_#ADRESSE]
	!XOR rax,rax
	
	!@@:
	!XOR rax,qword[rbx]
	!ADD rbx,8
	!DEC rcx
	!JNZ @b
	
	!MOV qword[v_#PRUEFCODE],rax
EndMacro

;-------------------------------



Pruefcode=0

CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
	MACRO32_XORCHECK(Pruefcode, MemoryA, #MemorySize)
Else
	MACRO64_XORCHECK(Pruefcode, MemoryA, #MemorySize)	
CompilerEndIf

Debug Pruefcode
Kannst ja mal einen Performance-Test mit deinen Daten machen. Ich selbst hatte dazu im Moment keine "Zeit" (sprich: keine Lust ;-) ). Bei deinen Werten zu #MemorySize ist darauf zu achten, dass der Wert immer durch 4 (32-Bit) bzw. durch 8 (64-Bit) teilbar ist. Als Ergebnis bekommst du einen 32-Bit bzw. 64-Bit langen Prüfwert zurück.

Viel Spass!