ClearMemory(*MemoryBuffer, length)

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.
Benutzeravatar
Leonhard
Beiträge: 602
Registriert: 01.03.2006 21:25

ClearMemory(*MemoryBuffer, length)

Beitrag von Leonhard »

Eine Funktion, die den angegeben Speicherwert löscht.
Kann man das noch schneller machen? Ich hab da schon ziemlich optimert (alte Funktion: 250% langsamer).

Code: Alles auswählen

;# <description>
;#   Diese Funktion überschreibt den angegebenen Speicher mit nullen.
;# </description>
;# <param attr="(pointer)" name="MemoryBuffer" type="void">
;#   Pointer des Speicherwertes, der mit nullen überschrieben werden soll
;# </param>
;# <param name="length" type="int">
;#   Länge des Speichers.
;# </param>
;# <optimize>
;# If length <= 0
;#   ; lösche Funktion, da sinnlos
;# EndIf
;# </optimize>
Procedure ClearMemory(*MemoryBuffer, length.l)
  ;/ verwendete Register: eax, ecx, edx
  
  ;/ Variablen beschreiben:
  !MOV ecx, dword[p.v_length]        ;/ lege Länge in Register ab
  !DEC ecx                           ;/ length - 1
  !MOV edx, dword[p.p_MemoryBuffer]  ;/ lege Buffer in Register ab
  
  ;for(eax = 0; eax<=ecx; eax++)
  !MOV eax, 0                        ;/ Zählervariable für For-Schleife
!p_ClearMemory.l_for_start:
  !CMP eax, ecx                      ;/ überprüfe Bedingung:
  !JG p_ClearMemory.l_for_end        ;/ if(eax > ecx) for_break;
  
  !MOV byte[edx], 0                  ;/ schreibe 0 in Speicher
  !INC edx                           ;/ addiere den Buffer
  
  !INC eax                           ;/ addiere die Zählervariable
  !JMP p_ClearMemory.l_for_start     ;/ überprüfe For-Bedingung
!p_ClearMemory.l_for_end:
EndProcedure
Benutzeravatar
Franky
Beiträge: 1132
Registriert: 29.08.2004 16:31
Wohnort: Münsterland
Kontaktdaten:

Beitrag von Franky »

Jo, geht, hier mal ein Code von Deeem (?) aus meinem PGS.

Code: Alles auswählen

Procedure FillMemoryL(address.l,copylength.l,wert.l)
CLD 
MOV Eax,wert
MOV Edi,address
MOV Ecx,CopyLength 
SHR Ecx,2 
REP STOSD 
EndProcedure
Falsch zugeordnetes Zitat des Tages: "O'zapft is" - Edward Snowden :)
Benutzeravatar
Leonhard
Beiträge: 602
Registriert: 01.03.2006 21:25

Beitrag von Leonhard »

Kommt drauf an, wie groß der Buffer ist. Ich habs mal ausgetestet und hab festgestellt, das meine Procedure ab 150 total langsam wird. Wenn es jetzt kleine Buffers sind, so ist meine schneller.

Hier jetzt meine Funktion kombiniert mit der von Deeem (?):

Code: Alles auswählen

Procedure ClearMemory(*MemoryBuffer, length.l)
  ;/ verwendete Register: eax, ecx, edx
  
  !MOV ecx, dword[p.v_length]        ;/ lege Länge in Register ab
  
  ;/ Überprüfe, ob die länge größer als 150 ist.
  ;/ Dies ist wichtig, damit der schnellste
  ;/ Algoritmus ausgewählt werden kann.
  !CMP ecx, 96h ; 96h = 150
  !JG p_ClearMemory.l_algoritmus_hight ; if(ecx > 96h)

  ;/ Variablen beschreiben:
!p_ClearMemory.l_algoritmus_low: ;/ Algoritmus für kleine Speicherwerte (<150 lenge)
  !DEC ecx                           ;/ length - 1
  !MOV edx, dword[p.p_MemoryBuffer]  ;/ lege Buffer in Register ab
  
  ;for(eax = 0; eax<=ecx; eax++)
  !MOV eax, 0                        ;/ Zählervariable für For-Schleife
!p_ClearMemory.l_for_start:
  !CMP eax, ecx                      ;/ überprüfe Bedingung:
  !JG p_ClearMemory.l_for_end        ;/ if(eax > ecx) for_break;
  
  !MOV byte[edx], 0                  ;/ schreibe 0 in Speicher
  !INC edx                           ;/ addiere den Buffer
  
  !INC eax                           ;/ addiere die Zählervariable
  !JMP p_ClearMemory.l_for_start     ;/ überprüfe For-Bedingung
!p_ClearMemory.l_for_end:

  !JMP p_ClearMemory.l_endProcedure

!p_ClearMemory.l_algoritmus_hight: ;/ Algoritmus für große Speicherwerte (>150 lenge)
  ;// integriert von FillMemoryL(...)
  !CLD
  !MOV eax, 0
  !MOV edi, dword[p.p_MemoryBuffer]
  !REP STOSB

!p_ClearMemory.l_endProcedure:
EndProcedure
Und nocht was: die Funktion, die du mir gegeben hast geht nur auf Längen, die durch 4 teilbar sind (halt long und so).
Hier ist deine Funktion für Bytes:

Code: Alles auswählen

Procedure FillMemoryB(*MemoryBuffer, length.l, Value.b) 
  !CLD
  !MOV eax, byte[p.v_Value]
  !MOV edi, dword[p.p_MemoryBuffer]
  !MOV ecx, dword[p.v_length]
  !REP STOSB
EndProcedure
Benutzeravatar
Thorium
Beiträge: 1722
Registriert: 12.06.2005 11:15
Wohnort: Germany
Kontaktdaten:

Beitrag von Thorium »

Deine Prozedur ist so langsam, weil du in 1 Byte schritten schreibst. Es geht erheblich schneller, wenn du in 4Byte (32bit) Schritten schreibst.

Hier mal mein ASM-Code zum schnellen kopieren von Speicherblöcken. Da siehst du was ich meine.

Code: Alles auswählen

!push ecx
!shr ecx,2
!rep movsd
!pop ecx
!and ecx,3
!rep movsb
Da wird in 4 Byte Schritten kopiert und am Ende die übrigen Restbyte ermittelt und einzeln kopiert.
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.

Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke! Bild
Benutzeravatar
Thorium
Beiträge: 1722
Registriert: 12.06.2005 11:15
Wohnort: Germany
Kontaktdaten:

Beitrag von Thorium »

Ohne es getestet zu haben.
Das sollte den Job sehr schnell erledigen:

Code: Alles auswählen

Procedure ClearMemory(*MemoryBuffer, length.l)
  !xor eax,eax
  !mov edi,dword[p.p_MemoryBuffer]
  !mov ecx,dword[p.v_length]
  !mov ebx,ecx
  !shr ecx,2
  !rep stosd
  !mov ecx,ebx
  !and ecx,3
  !rep stosb
EndProcedure
Wenn du das oft hintereinander benötigst, bekommst mit nem Makro nochmal etwas Speed, da der Call weggespart wird.

Das CLD brauchst net. PureBasic sorgt dafür das das Direction-Flag sowieso glöscht ist. Das muss es auch, da viele Win-API-Funktionen ein gelöschtes Direction-Flag voraussetzen. Das heisst für dich, wenn du mal STD verwendest, nicht vergessen später wieder mit CLD zu löschen. Sonst kracht es später.

Edit: Habs nochmal geändert, zum sichern von ECX wird jetzt ein weiteres Register verwendet, anstatt der Stack.

Edit2:
Leonhard hat geschrieben:Kommt drauf an, wie groß der Buffer ist. Ich habs mal ausgetestet und hab festgestellt, das meine Procedure ab 150 total langsam wird. Wenn es jetzt kleine Buffers sind, so ist meine schneller.
Das kann ich nicht bestätigen. Habs jetzt mal bei mir getestet. Deine Prozedur ist in jedem Fall langsamer. Deeems ist die schnellste, dafür nur Längen, die durch 4 teilbar sind. Meine ist unwesentlich (desdo größer die Länge, desdo unwesentlicher) langsamer als Deems, dafür werden auf Längen die durch 1 teilbar sind korrekt abgearbeitet.
Zu mir kommen behinderte Delphine um mit mir zu schwimmen.

Wir fordern mehr Aufmerksamkeit für umfallende Reissäcke! Bild
LCD
Beiträge: 107
Registriert: 23.01.2008 13:13
Wohnort: Wien

Beitrag von LCD »

Habe ein Benchmark durchgeführt, und es gibt so gut wie keinen Unterschied zu der WinAPI Funktion ZeroMemory_(*Memory,Length), was mich etwas irritiert. Normalerweise müsste Assembler etwas schneller sein.
PB 4.61Beta1 32/64Bit. AMD FX6100, 8 GB RAM, ATI Radeon 5750, Win7 64 (64 bit ist mist weil 16-Bit Programme wie MakeTZX nicht mehr darauf funktionieren).
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Beitrag von edel »

Woher willst du wissen, wie diese Funktion aussieht und wie sehr sie optimiert
wurde ?
Andreas_S
Beiträge: 787
Registriert: 14.04.2007 16:48
Wohnort: Wien Umgebung
Kontaktdaten:

Beitrag von Andreas_S »

Die genaue Definition:

Code: Alles auswählen

void ZeroMemory(
  [in]  PVOID Destination,
  [in]  SIZE_T Length
);
Wenn ich mich nicht irre ist die ganze Win-API in C++, und das ist so stark optimiert das man das per assembler als Mensch eh nicht mehr wirklich nachschreiben kann... vor allem bei größeren Befehlen...

Zwischenfrage: Warum sollte man den Speicher löschen? Da kann man ihn doch gleich überschreiben, oder freigeben...
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Beitrag von edel »

Weil jeder Speicher erst einmal geleert werden sollte, bevor man ihn ueberhaupt benutzt.
Andreas_S
Beiträge: 787
Registriert: 14.04.2007 16:48
Wohnort: Wien Umgebung
Kontaktdaten:

Beitrag von Andreas_S »

Ok, ja stimmt... kann ja noch was drauf sein...
Antworten