Seite 1 von 3
Schneller Len(String$) Befehl
Verfasst: 06.10.2006 22:57
von Hellhound66
Code: Alles auswählen
;#PB 4.0
Prototype HellLen(UserString.s)
Global HellLen.HellLen
Goto __JUMPOVER
__HellLen:
!PUSH Edi
!PUSH Ecx
!MOV Edi,[Esp+12]
!XOR Ecx,Ecx
!XOR Ebx,Ebx
!__OUTERLOOP:
!MOV Eax,dword[Edi]
!TEST Eax,255
!JZ __FINISHED
!INC Ecx
!TEST Eax,65280
!JZ __FINISHED
!INC Ecx
!SHR Eax,16
!TEST Eax,255
!JZ __FINISHED
!INC Ecx
!TEST Eax,65280
!JZ __FINISHED
!INC Ecx
!ADD Edi,4
!JMP __OUTERLOOP
!__FINISHED:
!MOV Eax,Ecx
!POP Ecx
!POP Edi
!RET 4
__JUMPOVER:
HellLen = ?__HellLen
Delay(100)
string.s = "Ich bin ein fieser Teststring"
TestZeit.l = ElapsedMilliseconds()
For i=1 To 10000000
HellLen(string)
Next
Zeit1 = ElapsedMilliseconds()-TestZeit
TestZeit.l = ElapsedMilliseconds()
For i=1 To 10000000
lstrlen_(string)
Next
Zeit2 = ElapsedMilliseconds()-TestZeit
TestZeit.l = ElapsedMilliseconds()
For i=1 To 10000000
Len(string)
Next
Zeit3 = ElapsedMilliseconds()-TestZeit
MessageRequester("Ergebnis","Es wurden je 10000000 Aufrufe gestartet"+#crlf$+"Hellhound66 : "+Str(Zeit1)+" ms."+#crlf$+"WinAPI brauchte : "+Str(Zeit2)+" ms."+#crlf$+"PB brauchte : "+Str(Zeit3)+" ms."+#crlf$,#PB_MessageRequester_Ok)
Keine Garantie, dass der unter PB<4.0 läuft.
/edit:
Auf P4 HT kanns langsamer sein, aber auf nem Athlon isses eher schnell.
Verfasst: 07.10.2006 02:38
von ts-soft
Bei Unicode ergibts immer 1
Das machen die langsameren besser

Verfasst: 07.10.2006 03:08
von edel
Code: Alles auswählen
CompilerIf #PB_Compiler_Unicode
CompilerElse
Macro Len(string)
HellLen(string)
EndMacro
CompilerEndIf
Wer braucht schon unicode ...

Verfasst: 07.10.2006 13:53
von remi_meier
Hells Code für Unicode:
Code: Alles auswählen
Prototype FakeRemi(UserString.s)
Global FakeRemi.FakeRemi
Goto __JUMPOVER2
__fakeremi:
!MOV Edx,[Esp+4]
!XOR Eax, Eax
!__OUTERLOOP2: ;>
!MOV Ecx, dword[Edx]
CompilerIf #pb_compiler_unicode
!TEST Ecx, 0xFFFF
!JZ __FINISHED2
!INC Eax
!TEST Ecx, 0xFFFF0000
!JZ __FINISHED2
!INC Eax
CompilerElse
!TEST Ecx, 0xFF
!JZ __FINISHED2
!INC Eax
!TEST Ecx, 0xFF00
!JZ __FINISHED2
!INC Eax
!TEST Ecx, 0xFF0000
!JZ __FINISHED2
!INC Eax
!TEST Ecx, 0xFF000000
!JZ __FINISHED2
!INC Eax
CompilerEndIf
!ADD Edx, 4
!JMP __OUTERLOOP2 ;<
!__FINISHED2:
!RET 4
__JUMPOVER2:
FakeRemi = ?__fakeremi
Verfasst: 07.10.2006 14:26
von nco2k
ouch, ein speedvergleich anhand ElapsedMilliseconds(). verwende lieber timeGetTime_() und benütze timeBeginPeriod_(1) am anfang deines programms und timeEndPeriod_(1) am ende deines programms.
auf meinem p4 ist deine variante etwa ~5ms schneller.
c ya,
nco2k
Verfasst: 07.10.2006 14:27
von remi_meier
Nimm einfach mehr Durchläufe. Die Zeiten sollten grösser als 1 Sek. sein.
Verfasst: 07.10.2006 21:52
von Helle
Zur allgemeinen Ergötzung hier ein Beispiel mit MMX/SSE (ohne Unicode).
So richtig Spass machts mit längeren Strings.
Code: Alles auswählen
;- Zeigt Einsatz von MMX und SSE zur Ermittlung von Len(String)
;- Auf Feinheiten wie Überprüfung auf Verfügbarkeit und Sicherungen der Umgebung wurde verzichtet
Global X.l
Global Y.l
Global Len.l
Global String.s = "Ich bin ein fieser Teststring"
TestZeit.l = ElapsedMilliseconds()
X = @String ;Zeiger auf den String
For i = 1 To 10000000
!mov ebx,[v_X]
W0:
!movq mm0,[ebx] ;8 Byte des Strings einlesen
!add ebx,8
!pxor mm1,mm1 ;mm1 auf Null setzen
!pcmpeqb mm0,mm1 ;jedes der 8 Byte von mm0 mit Null (mm1) vergleichen
!cvtpi2pd xmm0,mm0 ;Konvertierung von Integer in Double für nachfolgenden Vergleich
!pxor xmm2,xmm2 ;xmm2 auf Null setzen
!ucomisd xmm0,xmm2 ;vergleicht die 2 Doubles in den unteren Quad-Words
!jz l_w0
!sub ebx,8 ;Zeiger in String 8 Byte zurück und Ende suchen
!mov edx,[v_X]
!sub edx,ebx
!jnc l_w1
!sub ebx,4
W1:
!mov eax,[ebx]
!test eax,0ffh
!jz l_w2
!inc ebx
!test eax,0ff00h
!jz l_w2
!inc ebx
!test eax,0ff0000h
!jz l_w2
!inc ebx
!test eax,0ff000000h
!jz l_w2
!inc ebx
!jmp l_w1
W2:
Next
!mov [v_Y],ebx ;"nur" für Anzeige der Stringlänge
Zeit = ElapsedMilliseconds() - TestZeit
!mov edx,[v_Y]
!sub edx,[v_X]
!mov [v_Len],edx
MessageRequester("Len(String) mit SSE und MMX","Stringlänge = " + Str(Len) + Chr(13) + "Testzeit = " + Str(Zeit) + " ms")
End
Gruss
Helle
/Edit: Mindestlänge String aufgehoben und optimiert, FAsm-Data-Section eingespart
Verfasst: 08.10.2006 10:04
von Helle
Hier noch eine Version ohne MMX, nur mit SSE2. Greift gut bei längeren Strings, deshalb wurde als Teststring ein aktuelles Beispiel aus der PureBasic-Lounge genommen. Werte bei mir: "Denise": 1.030ms, SSE2: 610ms.
Code: Alles auswählen
;- Helle 08.10.2006 PB4.00
;- Zeigt Einsatz von SSE2 zur Ermittlung von Len(String)
;- Auf Feinheiten wie Überprüfung auf Verfügbarkeit und Sicherungen der Umgebung wurde verzichtet
Global X.l
Global Y.l
Global Len.l
Global String.s = "Ich bin ein fieser Teststaksjdfasdfkajslödfjaslkdjflöalöaksjdflkasjdlkfjasölkdfjlaksdjfing"
TestZeit.l = ElapsedMilliseconds()
X = @String ;Zeiger auf den String
For i = 1 To 20000000
!mov ebx,[v_X]
W0:
!movdqu xmm0,[ebx] ;16 Byte des Strings einlesen
!add ebx,16
!pxor xmm1,xmm1 ;xmm1 auf Null setzen
!pcmpeqb xmm0,xmm1 ;jedes der 16 Byte von xmm0 mit Null (xmm1) vergleichen
!cvtdq2ps xmm2,xmm0 ;Konvertierung von Integer in 4 Singles für nachfolgenden Vergleich
!ucomiss xmm2,xmm1 ;vergleicht die 4 Singles mit Null
!jz l_w0 ;Null-Byte (String-Ende) noch nicht gefunden
!sub ebx,16 ;Zeiger in String 16 Byte zurück und Ende suchen
!mov edx,[v_X]
!sub edx,ebx
!jnc l_w1
!sub ebx,12
W1:
!mov eax,[ebx]
!test eax,0ffh
!jz l_w2
!inc ebx
!test eax,0ff00h
!jz l_w2
!inc ebx
!test eax,0ff0000h
!jz l_w2
!inc ebx
!test eax,0ff000000h
!jz l_w2
!inc ebx
!jmp l_w1
W2:
Next
!mov [v_Y],ebx ;"nur" für Anzeige der Stringlänge
Zeit = ElapsedMilliseconds() - TestZeit
!mov edx,[v_Y]
!sub edx,[v_X]
!mov [v_Len],edx
MessageRequester("Len(String) mit SSE2","Stringlänge = " + Str(Len) + Chr(13) + "Testzeit = " + Str(Zeit) + " ms")
End
Gruss
Helle
Verfasst: 08.10.2006 22:16
von Helle
Nachdem meine obigen Beispiele schamlos den Speicher-Verwaltungsmodus für Strings von PB ausgenutzt haben und mein SSE-Buch auch etwas unklar war, hier eine "saubere" Variante, die sogar noch etwas schneller ist.
Code: Alles auswählen
;- Helle 08.10.2006 PB4.00
;- Zeigt Einsatz von SSE zur Ermittlung von Len(String)
;- Auf Feinheiten wie Überprüfung auf Verfügbarkeit und Sicherungen der Umgebung wurde verzichtet
Global X.l
Global Y.l
Global Len.l
Global String.s = "Ich bin ein fieser Teststaksjdfasdfkajslödfjaslkdjflöalöaksjdflkasjdlkfjasölkdfjlaksdjfing"
TestZeit.l = ElapsedMilliseconds()
X = @String ;Zeiger auf den String
For i = 1 To 20000000
!mov ebx,[v_X]
W0:
!movdqu xmm0,[ebx] ;16 Byte des Strings einlesen
!add ebx,16
!pxor xmm1,xmm1 ;xmm1 auf Null setzen
!pcmpeqb xmm0,xmm1 ;jedes der 16 Byte von xmm0 mit Null (xmm1) vergleichen und auf 0 oder 255 (bei Gleichheit) setzen
!pmovmskb eax,xmm0 ;die Vorzeichen-Bits nach eax kopieren
!or ax,ax ;auf Null testen. Waren in xmm1 Null-Bytes, ist ax nicht mehr Null
!jz l_w0 ;weiter einlesen, wenn Null-Byte (String-Ende) noch nicht gefunden
!sub ebx,16 ;Zeiger in String 16 Byte zurück und Ende suchen
W1:
!mov eax,[ebx] ;ab hier muss Byte-weise gesucht werden
!test eax,0ffh
!jz l_w2
!inc ebx
!test eax,0ff00h
!jz l_w2
!inc ebx
!test eax,0ff0000h
!jz l_w2
!inc ebx
!test eax,0ff000000h
!jz l_w2
!inc ebx
!jmp l_w1
W2:
Next
!mov [v_Y],ebx ;"nur" für Anzeige der Stringlänge
Zeit = ElapsedMilliseconds() - TestZeit
!mov edx,[v_Y]
!sub edx,[v_X]
!mov [v_Len],edx
MessageRequester("Len(String) mit SSE2","Stringlänge = " + Str(Len) + Chr(13) + "Testzeit = " + Str(Zeit) + " ms")
End
Gruss
Helle
Verfasst: 08.10.2006 22:31
von Hellhound66
Warum checkst du nicht die einzelnen Bits im EAX Register, dass ja schon das Ergebnis beinhaltet. Vielleicht so: