Vergleich der Schnelligkeit normale und Pointer-Version

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
dysti
Beiträge: 656
Registriert: 10.02.2006 18:34
Wohnort: Schlicktown

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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.
Zuletzt geändert von dysti am 06.02.2013 13:54, insgesamt 1-mal geändert.
PB5 / Spiderbasic / WB14 / Win7 / Win8.1 / Win10 / Debian 9
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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.
Benutzeravatar
dysti
Beiträge: 656
Registriert: 10.02.2006 18:34
Wohnort: Schlicktown

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag von dysti »

Ja, das wunder mich auch.
Kannst du mal die Unicodeversion reinstellen?
PB5 / Spiderbasic / WB14 / Win7 / Win8.1 / Win10 / Debian 9
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag von NicTheQuick »

Da gibt es keine extra Version für. Du musst nur Unicode in den Compiler Optionen aktivieren. /:->
Benutzeravatar
dysti
Beiträge: 656
Registriert: 10.02.2006 18:34
Wohnort: Schlicktown

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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$)
PB5 / Spiderbasic / WB14 / Win7 / Win8.1 / Win10 / Debian 9
matbal
Beiträge: 261
Registriert: 30.03.2011 20:53

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
7x7
Beiträge: 591
Registriert: 14.08.2007 15:41
Computerausstattung: ganz toll
Wohnort: Lelbach

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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?
- alles was ich hier im Forum sage/schreibe ist lediglich meine Meinung und keine Tatsachenbehauptung
- unkommentierter Quellcode = unqualifizierter Müll
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Vergleich der Schnelligkeit normale und Pointer-Version

Beitrag 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.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Antworten