Alternatives Copymemory()

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Hellhound66
Beiträge: 476
Registriert: 23.03.2005 23:19

Alternatives Copymemory()

Beitrag von Hellhound66 »

Ich hab mir mal hier ein anderes copymemory zusammengebastelt. Bei mir auf dem Athlon ist es bis zu 100% schneller. Mich würden eure Ergebnisse interessieren.

Code: Alles auswählen



Macro __cpya() ; __cpy#A1#()
    !MOVDQA [Edi+Eax]    ,xmm1
    !MOVDQA [Edi+Eax+16] ,xmm2
    !MOVDQA [Edi+Eax+32] ,xmm3
    !MOVDQA [Edi+Eax+48] ,xmm4
    !ADD Eax,64
EndMacro


Macro __cpyu()
    !MOVDQU [Edi+Eax]    ,xmm1
    !MOVDQU [Edi+Eax+16] ,xmm2
    !MOVDQU [Edi+Eax+32] ,xmm3
    !MOVDQU [Edi+Eax+48] ,xmm4
    !ADD Eax,64
EndMacro

Macro __cpys()
    !MOVNTDQ [Edi+Eax]    ,xmm1
    !MOVNTDQ [Edi+Eax+16] ,xmm2
    !MOVNTDQ [Edi+Eax+32] ,xmm3
    !MOVNTDQ [Edi+Eax+48] ,xmm4
    !ADD Eax,64
EndMacro

Macro __cpyblock(A1)
    !MOVDQ#A1# xmm1,[Esi+Eax]
    !MOVDQ#A1# xmm2,[Esi+Eax+16]
    !MOVDQ#A1# xmm3,[Esi+Eax+32]
    !MOVDQ#A1# xmm4,[Esi+Eax+48]
EndMacro

Prototype Memcpy(*Source,*Dest,Size.l)
Global MemCpy.MemCpy


Goto __JUMPOVER
__MemCpy:
!PUSH Esi
!PUSH Edi

!MOV Ecx,[Esp+20]
!MOV Esi,[Esp+12]
!MOV Edi,[Esp+16]
!XOR Eax,Eax
!MOV Ebx,Ecx
!SHR Ecx,6
!JZ @Parity

!TEST Esi,15
!JZ @okay1
!TEST Edi,15
!JZ @version01
!JMP @version00

!@okay1:
!TEST Edi,15
!JZ @Version11
!TEST Esi,15
!JZ @version10
!JMP @version00


!@Version11:
!@inner_loop11:
__cpyblock(a)
__cpys()
!DEC Ecx
!JNZ @inner_loop11
!JMP @Parity

!@version01:
!@inner_loop01:
__cpyblock(u)
__cpya()
!DEC Ecx
!JNZ @inner_loop01
!JMP @Parity

!@version10:
!@inner_loop10:
__cpyblock(a)
__cpyu()
!DEC Ecx
!JNZ @inner_loop10
!JMP @Parity

!@version00:
!@inner_loop00:
__cpyblock(u)
__cpyu()
!DEC Ecx
!JNZ @inner_loop00
; !JMP @Parity


!@Parity:
!AND Ebx,15
!JZ @retxxx
!MOV Ecx,Ebx
!REP movsb
!@retxxx:
!POP Edi
!POP Esi
!RET 12

__JUMPOVER:

MemCpy = ?__MemCpy



Delay(500)

#BufferSize = 904011
*Buffer1 = AllocateMemory(#BufferSize)
*Buffer2 = AllocateMemory(#BufferSize)
For i=1 To #BufferSize/4
    PokeL(*Buffer1+i-1,i*2)
Next
OpenConsole()
PrintN(Str(*Buffer1&15))
PrintN(Str(*Buffer2&15))
TestZeit.l  = ElapsedMilliseconds()
For i=1 To 1000
    Memcpy(*Buffer1,*Buffer2,#BufferSize)
Next
PrintN(Str(CompareMemory(*Buffer2,*Buffer1,#BufferSize)))
Zeit1 = ElapsedMilliseconds()-TestZeit


TestZeit.l  = ElapsedMilliseconds()
For i=1 To 1000
    CopyMemory(*Buffer1,*Buffer2,#BufferSize)
Next
Zeit3 = ElapsedMilliseconds()-TestZeit


Print("Es wurden je 1000 Aufrufe gestartet"+#crlf$+"Hellhound66 : "+Str(Zeit1)+" ms."+#crlf$+"PB brauchte : "+Str(Zeit3)+" ms."+#crlf$)
MessageRequester("Ende","Programm beendet",#PB_MessageRequester_Ok)
Zuletzt geändert von Hellhound66 am 07.10.2006 23:58, insgesamt 1-mal geändert.
Optimismus ist ein Mangel an Information.
Hellhound66
Beiträge: 476
Registriert: 23.03.2005 23:19

Beitrag von Hellhound66 »

/update:
Da die Prozedur bei Speicherblöcken unter ~4KB sehr langsam wurde, hab ich sie dafür nochmal optimiert:

Code: Alles auswählen



Macro __cpya() ; __cpy#A1#()
    !MOVDQA [Edi+Eax]    ,xmm1
    !MOVDQA [Edi+Eax+16] ,xmm2
    !MOVDQA [Edi+Eax+32] ,xmm3
    !MOVDQA [Edi+Eax+48] ,xmm4
    !ADD Eax,64
EndMacro


Macro __cpyu()
    !MOVDQU [Edi+Eax]    ,xmm1
    !MOVDQU [Edi+Eax+16] ,xmm2
    !MOVDQU [Edi+Eax+32] ,xmm3
    !MOVDQU [Edi+Eax+48] ,xmm4
    !ADD Eax,64
EndMacro

Macro __cpys()
    !MOVNTDQ [Edi+Eax]    ,xmm1
    !MOVNTDQ [Edi+Eax+16] ,xmm2
    !MOVNTDQ [Edi+Eax+32] ,xmm3
    !MOVNTDQ [Edi+Eax+48] ,xmm4
    !ADD Eax,64
EndMacro

Macro __cpyblock(A1)
    !MOVDQ#A1# xmm1,[Esi+Eax]
    !MOVDQ#A1# xmm2,[Esi+Eax+16]
    !MOVDQ#A1# xmm3,[Esi+Eax+32]
    !MOVDQ#A1# xmm4,[Esi+Eax+48]
EndMacro

Prototype Memcpy(*Source,*Dest,Size.l)
Global MemCpy.MemCpy


Goto __JUMPOVER
__MemCpy:
!PUSH Esi
!PUSH Edi

!MOV Ecx,[Esp+20]
!MOV Esi,[Esp+12]
!MOV Edi,[Esp+16]
!XOR Eax,Eax
!MOV Ebx,Ecx
!SHR Ecx,6
!JZ @Parity

!CMP Ecx,62
!JL @alternative

!TEST Esi,15
!JZ @okay1
!TEST Edi,15
!JZ @version01
!JMP @version00

!@okay1:
!TEST Edi,15
!JZ @Version11
!TEST Esi,15
!JZ @version10
!JMP @version00


!@Version11:
!@inner_loop11:
__cpyblock(a)
__cpys()
!DEC Ecx
!JNZ @inner_loop11
!JMP @Parity

!@version01:
!@inner_loop01:
__cpyblock(u)
__cpya()
!DEC Ecx
!JNZ @inner_loop01
!JMP @Parity

!@version10:
;CallDebugger
!@inner_loop10:
__cpyblock(a)
__cpyu()
!DEC Ecx
!JNZ @inner_loop10
!JMP @Parity

!@version00:
!@inner_loop00:
__cpyblock(u)
__cpyu()
!DEC Ecx
!JNZ @inner_loop00
; !JMP @Parity


!@Parity:
!AND Ebx,15
!JZ @retxxx
!MOV Ecx,Ebx
!SHR Ecx,1
!JNC @JUMP1
!movsb
!@JUMP1:
!SHR Ecx,1
!JNC @jump2
!movsw
!@jump2:
!JZ @retxxx
!REP movsd
!@retxxx:
!POP Edi
!POP Esi
!RET 12

!@alternative:
!MOVQ mm0,[Esi+Eax]
!MOVQ mm1,[Esi+Eax+8]
!MOVQ mm2,[Esi+Eax+16]
!MOVQ mm3,[Esi+Eax+24]
!MOVQ mm4,[Esi+Eax+32]
!MOVQ mm5,[Esi+Eax+40]
!MOVQ mm6,[Esi+Eax+48]
!MOVQ mm7,[Esi+Eax+56]

!MOVQ [Edi+Eax]     ,mm0
!MOVQ [Edi+Eax+8]   ,mm1
!MOVQ [Edi+Eax+16]  ,mm2
!MOVQ [Edi+Eax+24]  ,mm3
!MOVQ [Edi+Eax+32]  ,mm4
!MOVQ [Edi+Eax+40]  ,mm5
!MOVQ [Edi+Eax+48]  ,mm6
!MOVQ [Edi+Eax+56]  ,mm7

!ADD Eax,64
!DEC Ecx
!JNZ @alternative

!JMP @Parity

__JUMPOVER:

MemCpy = ?__MemCpy



Delay(500)

#BufferSize = 300
*Buffer1 = AllocateMemory(#BufferSize)
*Buffer2 = AllocateMemory(#BufferSize)
For i=1 To #BufferSize/4
    PokeL(*Buffer1+i-1,i*2)
Next
OpenConsole()
PrintN(Str(*Buffer1&15))
PrintN(Str(*Buffer2&15))
TestZeit.l  = ElapsedMilliseconds()
For i=1 To 10000000
    Memcpy(*Buffer1,*Buffer2,#BufferSize)
Next
PrintN(Str(CompareMemory(*Buffer2,*Buffer1,#BufferSize)))
Zeit1 = ElapsedMilliseconds()-TestZeit


TestZeit.l  = ElapsedMilliseconds()
For i=1 To 10000000
    CopyMemory(*Buffer1,*Buffer2,#BufferSize)
Next
Zeit3 = ElapsedMilliseconds()-TestZeit


Print("Es wurden je 10000000 Aufrufe gestartet"+#crlf$+"Hellhound66 : "+Str(Zeit1)+" ms."+#crlf$+"PB brauchte : "+Str(Zeit3)+" ms."+#crlf$)
MessageRequester("Ende","Programm beendet",#PB_MessageRequester_Ok)
Zuletzt geändert von Hellhound66 am 07.10.2006 23:58, insgesamt 1-mal geändert.
Optimismus ist ein Mangel an Information.
Benutzeravatar
SoS
Beiträge: 340
Registriert: 29.08.2004 09:31
Kontaktdaten:

Beitrag von SoS »

Es wurden je 10000 Aufrufe gestartet
Hellhound66 : 593 ms.
PB brauchte : 1735 ms.
P4 2.6 ghz
Benutzeravatar
Lukaso
Beiträge: 720
Registriert: 08.09.2004 18:51
Wohnort: Oberkirch
Kontaktdaten:

Beitrag von Lukaso »

Es wurden je 10000 Aufrufe gestartet
Hellhound66 : 516 ms.
PB brauchte : 718 ms.
AMD64 3000+
Nextgen Guild Wars Fanseite: Guild Wars Tactics (Pseudo-Admin + Developer)
"Das Fluchen ist die einzige Sprache, die jeder Programmierer beherrscht." - Unbekannter Autor
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Beitrag von Fluid Byte »

Es wurden je 10000000 Aufrufe gestartet
Hellhound66 : 469 ms.
PB brauchte : 1422 ms.
mknjc
Beiträge: 217
Registriert: 09.09.2006 12:59

Beitrag von mknjc »

So mal meine Messungen

Hellhound66 PB
535 1675
550 1691
566 1675
503 1675
581 1707

547 1684,6

Unten ist der Durchschnittswert.

PB4

Rennt auf nem P4 HT 3,06
Ich nutze PureBasic 4.02 unter Linux und Windows.

Momentane Projekte:
Das geheimste aller geheimen Projekte... FPBC
Benutzeravatar
Thorium
Beiträge: 1722
Registriert: 12.06.2005 11:15
Wohnort: Germany
Kontaktdaten:

Beitrag von Thorium »

Bei mir nur gering schneller:

10000000 Aufrufe
Hellhount66: 1122
PureBasic: 1302

AMD Athlon 3200+ Barton
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.

Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke! Bild
Hellhound66
Beiträge: 476
Registriert: 23.03.2005 23:19

Beitrag von Hellhound66 »

Im letzteren werden nur kleine Speicherblöcke kopiert. Mach den Speicherblock größer, dann wird der Unterschied ebenfalls größer ^^
Optimismus ist ein Mangel an Information.
Antworten