Seite 2 von 3

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 13:45
von dysti
Hier nun meine Zeiten (ohne Debugger):

Mit 1000000 (Original)
Zeit 1 : 546 ms
Zeit 2 : 686 ms
Zeit 3 : 936 ms
Zeit 4 : 125 ms
Mit 10000000 (deine Einstellung)
Zeit 1 : 5975 ms
Zeit 2 : 6817 ms
Zeit 3 : 9407 ms
Zeit 4 : 1295 ms
System: Win7, i3

Werde deinen Code erstmal studieren. Die Procedure 5 jetzt nach meinem Gefühl super schnell. Toll.

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 13:53
von NicTheQuick
Komisch, dass Zeit 3 so groß bei dir ist. Hat vielleicht auch etwas mit dem OS zu tun, weil CopyMemory() ja bei Windows im Grunde nur der Aufruf einer API ist.

Ich habe das ganze jetzt mal noch mit Unicode getestet. Da kommt dann das hier raus:
Zeit 1 = 2819 ms
Zeit 2 = 2683 ms
Zeit 3 = 1140 ms
Zeit 4 = 727 ms
Wie man sieht, sind hier deine beiden Funktionen vom Anfang nochmal fast doppelt so langsam, meine beiden Versionen bleiben allerdings ziemlich gleich schnell.

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 13:57
von dysti
Ja, das wunder mich auch.
Kannst du mal die Unicodeversion reinstellen?

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 14:11
von NicTheQuick
Da gibt es keine extra Version für. Du musst nur Unicode in den Compiler Optionen aktivieren. /:->

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 14:12
von dysti
....schon wieder was dazu gelernt.

Hier nochmal das geänderte Original mit EnableExplicit und NicTheQuicks-Code:

Code: Alles auswählen

EnableExplicit

Define a.s,b.s,i
Define lmax, alt$, neu$, pos, laenge, fuell$, zeit, atext$, b$
Define len_original, l1, len_rest

Macro ErsetzeString2(String,pos,laenge,ersatz)
  Left(String,pos-1)+ersatz+Mid(String,pos+laenge)
EndMacro
Macro ErsetzeString3(String , pos , laenge , Ersatz)
  len_original = Len(PeekS(@String)) * SizeOf(Character)
  l1 = pos+laenge-1
  len_rest     = len_original - l1
  b$=PeekS(@String,pos-1) + Ersatz + PeekS(@String+l1, len_rest)
EndMacro

Procedure ErsetzeString4(*input, pos.i, length.i, replacement.s)
   Protected replaceLength.i = Len(replacement)
   Protected *c.Character, *d.Character
   
   If (replaceLength <= length)
      CopyMemory(@replacement, *input + (pos - 1) * SizeOf(Character), replaceLength * SizeOf(Character))
      If (replaceLength < length)
         ;MoveMemory(*input + (pos + replaceLength - 1) * SizeOf(Character), *input + (pos + length) * SizeOf(Character), )
         *c = *input + (pos + length - 1) * SizeOf(Character)
         *d = *input + (pos + replaceLength - 1) * SizeOf(Character)
         While (*c\c)
            *d\c = *c\c
            *c + SizeOf(Character)
            *d + SizeOf(Character)
         Wend
         While (*d\c)
            *d\c = 0
            *d + SizeOf(Character)
         Wend
      EndIf
   Else
      ;fehlt noch
   EndIf
EndProcedure

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

; Der Originalsatz

a="Das war einmal der Satz"


lmax = Len(a)
alt$ = "war einmal"
neu$ = "ist nun"
pos = FindString(a,alt$)
laenge = Len(alt$)

; Ein Füllzeichen, wenn der Str. seine Länge behalten soll.
fuell$="."

zeit=ElapsedMilliseconds()

For i=1 To 1000000
  b$=ErsetzeString2(a,pos,laenge,neu$)
Next

atext$="Zeit 2 = "+Str(ElapsedMilliseconds()-zeit)+" MilliSek."+#CRLF$

; Nun der neue Satz 2
zeit=ElapsedMilliseconds()
For i=1 To 1000000
ErsetzeString3(a,pos,laenge,neu$)
Next

atext$=atext$+"Zeit 3 = "+Str(ElapsedMilliseconds()-zeit)+" MilliSek."+#CRLF$
; Nun der neue Satz 4
zeit=ElapsedMilliseconds()
For i=1 To 1000000
ErsetzeString4(@a,pos,laenge,neu$)
Next

atext$=atext$+"Zeit 4 = "+Str(ElapsedMilliseconds()-zeit)+" MilliSek."+#CRLF$+b$

MessageRequester("Test",atext$)

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 14:48
von matbal
@NicTheQuick

Du machst bei deinem Geschwindigkeitstest einen Fehler, der mir auch schon passiert ist. Der Originalstring wird in deinen Prozeduren verändert. Das heißt, ab dem 2. Durchlauf wird nichts mehr ersetzt.

Zum Vergleichen habe ich mal in jeder Schleife noch eine Kopie aa$ = a$ vor die Ersetzfunktion eingefügt, und dann nur die Kopie verwendet. Die Meßwerte werden natürlich größer, wegen der Kopie in jeder Schleife. Bei mir sind das ca. 2000 ms.

Interessant ist, daß sich die Meßwerte 2, 3 und 4 kaum noch unterscheiden (ca. 5100), Meßwert 5 ist aber immer noch schneller als die drei (ca. 3700). Wenn ich die Kopierzeit (2000) wieder abziehe, ist deine letzte Pointer-Prozedure fast doppelt so schnell, wie die ersten drei, aber nicht so schnell, wie deine Messungen ergeben.

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 15:00
von NicTheQuick
Stimmt, das ist dann nicht ganz gerecht.
Da In-Place ersetzt wird, ist es jetzt schwierig da einen Praxistauglichen Test draus zu machen. In der Praxis wird man auch nicht 1 Mio. mal den selben String ersetzen. Man könnte für den Test 1 Million gleiche Strings erstellen und dann nacheinander von der Funktion abfrühstücken lassen. Denn das Kopieren des Ursprungsstrings macht viel Zeit aus.

///Edit:
Also eine neue Version: (Vorsicht! Das zieht bei Unicode fast 700 MB Arbeitsspeicher)

Code: Alles auswählen

Procedure ErsetzeString4(*input, pos.i, length.i, *replacement)
	Protected *c.Character, *d.Character
	
	*c = *input + (pos - 1) * SizeOf(Character)
	*d = *replacement
	While (*d\c And length >= 0)
		*c\c = *d\c
		*c + SizeOf(Character)
		*d + SizeOf(Character)
		length - 1
	Wend
	If (*d\c = 0)
		*d + *input + (pos + length - 1) * SizeOf(Character) - *replacement
		While (*d\c)
			*c\c = *d\c
			*c + SizeOf(Character)
			*d + SizeOf(Character)
		Wend
		While (*c\c)
			*c\c = 0
			*c + SizeOf(Character)
		Wend
	Else
		;length < len(*replacement)
	EndIf
EndProcedure

 Procedure ErsetzeString3(*input, pos.i, length.i, replacement.s)
   Protected replaceLength.i = Len(replacement)
   Protected *c.Character, *d.Character
   
   If (replaceLength <= length)
      CopyMemory(@replacement, *input + (pos - 1) * SizeOf(Character), replaceLength * SizeOf(Character))
      If (replaceLength < length)
         ;MoveMemory(*input + (pos + replaceLength - 1) * SizeOf(Character), *input + (pos + length) * SizeOf(Character), )
         *c = *input + (pos + length - 1) * SizeOf(Character)
         *d = *input + (pos + replaceLength - 1) * SizeOf(Character)
         While (*c\c)
            *d\c = *c\c
            *c + SizeOf(Character)
            *d + SizeOf(Character)
         Wend
         While (*d\c)
            *d\c = 0
            *d + SizeOf(Character)
         Wend
      EndIf
   Else
      ;fehlt noch
   EndIf
EndProcedure 

; a.s = "abcdefghijklmn"
; b.s = "xxx"
; ErsetzeString4(@a, 3, 3, @b)
; Debug a
; 
; End

Macro ErsetzeString1(String, pos, laenge, ersatz)
	Left(String, pos - 1) + ersatz + Mid(String, pos + laenge)
EndMacro
Macro ErsetzeString2(String , pos , laenge , Ersatz)
	len_original = Len(PeekS(@String)) * SizeOf(Character)
	l1 = pos + laenge - 1
	len_rest = len_original - l1
	b$ = PeekS(@String, pos - 1) + Ersatz + PeekS(@String + l1, len_rest)
EndMacro

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

#n = 10000000
time.s = ""

; Der Originalsatz
a$="Das war einmal der Satz"
Debug a$
Debug ""
; Das hier, weil ich zu faul zum selber Zaehlen bin
; und weil Änderungen ja später vom Prg. generiert werden könnten
lmax = Len(a$)
alt$ = "war einmal"
neu$ = "ist nun"
pos = FindString(a$,alt$)
laenge = Len(alt$)

; Ein Füllzeichen, wenn der Str. seine Länge behalten soll.
fuell$="."

; Nun der neue Satz 1, es ist laut Ausgabe der Schnellere
zeit = ElapsedMilliseconds()
For i=1 To #n
	b$=ErsetzeString1(a$,pos,laenge,neu$)
Next

time + "Zeit 1 = " + Str(ElapsedMilliseconds() - zeit) + " ms" + #CRLF$

; Nun der neue Satz 2
zeit = ElapsedMilliseconds()
For i=1 To #n
	ErsetzeString2(a$,pos,laenge,neu$)
Next
time + "Zeit 2 = " + Str(ElapsedMilliseconds() - zeit) + " ms" + #CRLF$

; Nun der neue Satz 3
Dim input_s.s(#n)
For i = 1 To #n
	input_s(i) = a$
Next
zeit = ElapsedMilliseconds()
For i=1 To #n
	ErsetzeString3(@input_s(i), pos, laenge, neu$)
Next
time + "Zeit 3 = " + Str(ElapsedMilliseconds() - zeit) + " ms" + #CRLF$

; Nun der neue Satz 4
For i = 1 To #n
	input_s(i) = a$
Next
zeit = ElapsedMilliseconds()
For i=1 To #n
	ErsetzeString4(@input_s(i), pos, laenge, @neu$)
Next
time + "Zeit 4 = " + Str(ElapsedMilliseconds() - zeit) + " ms" + #CRLF$

MessageRequester("Zeiten", time)
Mit Unicode:
Zeit 1 = 3125 ms
Zeit 2= 2675 ms
Zeit 3= 2102 ms
Zeit 4= 1472 ms
Ohne Unicode:
Zeit 1 = 1525 ms
Zeit 2 = 1557 ms
Zeit 3 = 1696 ms
Zeit 4 = 1431 ms

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 15:14
von ts-soft
Ich halte diese ganzen Tests für überflüssig.
Es genügt doch zu Wissen, warum Pointer immer schneller sind:

Bei Nutzung von Stringfunktionen müssen Register gesichert, Werte auf den Stack gelegt, die Funktion
aufgerufen, Register wieder hergestellt werden.

Bei Nutzung von Pointern wird der Wert ohne Umwege in den Speicher geschrieben.

Wichtig ist nur noch, wann ich die Pointer-Variante einsetze, da diese den Source
weniger Lesbar machen.

Hierzu muß ich feststellen, wo mein Programm hängt (die PureUnit kann hierbei helfen),
und eben nur diese Funktionen auf Pointer umstellen.

Die Frage, ob Pointer schneller sind, erübrigt sich eigentlich.

Gruß
Thomas

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 15:58
von 7x7
ts-soft hat geschrieben:Wichtig ist nur noch, wann ich die Pointer-Variante einsetze, da diese den Source
weniger Lesbar machen.
Genau meine Meinung.

btw: Wenn man schon auf der Pointer-Ebene rumdönst, kann man doch gleich in Assembler das Teilproblem lösen. Geht nochmal ein gewaltiger Fetzen schneller. Und um Geschwindigkeit gehts doch letztendlich, oder?

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Verfasst: 06.02.2013 16:03
von ts-soft
ASM wird bei diesen Beispielen wohl eher gar nichts bringen, wie auch :mrgreen:

Solange nur der Speicher manipuliert wird, und nichts berechnet, hat ASM keinerlei Einfluss.