Schnellere Alternative zu StrD()?

Für allgemeine Fragen zur Programmierung mit PureBasic.
DePe
Beiträge: 194
Registriert: 26.11.2017 16:17

Schnellere Alternative zu StrD()?

Beitrag von DePe »

Ich speichere Messdaten als CSV-Datei, und wollte die zuständige Prozedur optimieren. Das Verarbeiten und Speichern von 1 MB dauert 15 Sekunden.
Ich verwende viermal StrD(x,14), und das kostet 12 Sekunden. Ersetze ich StrD() als Test mit Str(), dauert die Verabeitung nur 3 Sekunden.
Kann man StrD() beschleunigen, gibt es da Tricks?

Peter
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
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: Schnellere Alternative zu StrD()?

Beitrag von NicTheQuick »

Wie hast du die Zeit gemessen? Warst du dabei im Debug-Modus? Falls ja, versuch es doch mal ohne. Dann hast du oftmals schon einen gehörigen Geschwindigkeitsunterschied.
Ansonsten bin ich unsicher, ob man mit einer eigenen Implementierung von StrD() irgendwas verbessern könnte. Ich vermute ja eher nicht.
DePe
Beiträge: 194
Registriert: 26.11.2017 16:17

Re: Schnellere Alternative zu StrD()?

Beitrag von DePe »

Gemessen wurde mit der kompilierten Exe. Mich hat der große Zeitanteil von StrD() überrascht, da brauche ich nichts optimieren, ist sinnlos.

Peter
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Schnellere Alternative zu StrD()?

Beitrag von STARGÅTE »

DePe hat geschrieben:Das Verarbeiten und Speichern von 1 MB dauert 15 Sekunden.
Etwas komisch, der folgende Code speichert 1MB mit 60000 StrD() Zahlen und er dauert 55 ms!!

Code: Alles auswählen

Define Time = ElapsedMilliseconds()
CreateFile(1, GetTemporaryDirectory()+"test.csv")
Define N, M
For N = 1 To 6000
	For M = 1 To 10
		WriteString(1, StrD(Random(100000000)*0.000001, 14)+#TAB$)
	Next
	WriteStringN(1, "")
Next
CloseFile(1)
MessageRequester("1MB", Str(ElapsedMilliseconds()-Time)+" ms")
Kannst du vielleicht mal ein Beispiel zeigen?
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
sibru
Beiträge: 265
Registriert: 15.09.2004 18:11
Wohnort: hamburg

Re: Schnellere Alternative zu StrD()?

Beitrag von sibru »

was hälst Du hiervon:

Code: Alles auswählen

#NKS_Faktor=100000000000000 ;14 Nullen (zu wenig für Regierungs-Bildung, für Deinen Zweck sollte es reichen...)

a.d=12.34500000006789
Debug a
b.q=a*#NKS_Faktor ;das ist nun Str()-fähiges Format
Debug b
c.d=b/#NKS_Faktor ;Rückwandlung in Doubl-Format
Debug c
viel Erfolg bei der Millisekunden-Jagdt...
Bild Bild
DePe
Beiträge: 194
Registriert: 26.11.2017 16:17

Re: Schnellere Alternative zu StrD()?

Beitrag von DePe »

Hier ist der Code. Es fehlt jetzt einiges, das hat aber keinen Einfluss auf die Geschwindigkeit.
Es wird ein MB vom Speicher eingelesen, berechnet, der Text erstellt und gespeichert. Das Erstellen von dem Text dauert 13 Sekunden, der Rest 2 Sekunden. Ersetze ich StrD() oder entferne es, bin ich gesamt bei 3 Sekunden. Die Prozedur läuft in einem Thread, darum das PostEvent() für den Fortschritt. Gemessen habe ich nur diese For-Schleife.
r* sind Double-Variablen.

Peter

Code: Alles auswählen

For iOffset = iBlockformatLength To iCalc Step 2
  rPoint1 = PeekB(\pData + iOffset)
  rPoint2 = PeekB(\pData + iOffset + 1)
  rPoint1 = (rPoint1 * (rVerticalScale / #rCodePerDiv)) - rVerticalOffset
  rPoint2 = (rPoint2 * (rVerticalScale / #rCodePerDiv)) - rVerticalOffset

  rPointTime1 = rTimeValue + (rPointNumber * rHorizontalInterval)
  rPointTime2 = (rPointTime1 + rHorizontalInterval)
  rPointNumber + 1

  sText = Str(iCount) + sComma + RTrim(StrD(rPointTime1, #iSaveDataNbDecimal), #sChar0) + sComma + StrD(rPoint1) + EndOfLine
  iCount + 1
  sText + Str(iCount) + sComma + RTrim(StrD(rPointTime2, #iSaveDataNbDecimal), #sChar0) + sComma + StrD(rPoint2) + EndOfLine
  rPointNumber + 1

  WriteString(iFileNumber, sText)

  cProgress + 1
  If (cProgress = 1000)
    cProgress = 0
    If ((ElapsedMilliseconds() - iTimeProgress) >= #iSaveDataTimeWaitProgress)
      iTimeProgress = ElapsedMilliseconds()
      iCalc2 = (iProgressEnd - iProgressStart)
      If (iCalc2 <= 0) : iCalc2 = 100 : EndIf
      iCalc2 = (iChannelDataSize / iCalc2)
      If fLogic
        iCalc2 / 2
      EndIf
      If (iCalc2 <= 0) : iCalc2 = iChannelDataSize : EndIf
      iCalc2 = (iCount / iCalc2)
      If (iCalc2 > iProgress)
        iProgress = iCalc2
        PostEvent(#eEventCustomSaveDataThread, *uInstance\iWindowNumber,
                  iInstanceNumber, #eThreadEventProgress, (iProgress + iProgressStart))
      EndIf
    EndIf
    If (*uInstance\eSaveDataThreadStatus = #eThreadStatusCancel) Or
       (*uInstance\eSaveDataThreadStatus = #eThreadStatusEnd)
      Break
    EndIf
  EndIf
Next                                                                                                                        
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Schnellere Alternative zu StrD()?

Beitrag von ccode_new »

Hallo!

Versuche das hier mal:

Code: Alles auswählen

DisableDebugger

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  ImportC ""
    _gcvt(x.d, ndigit.l, *buf)
  EndImport
CompilerElse
  ImportC ""
    gcvt(x.d, ndigit.l, *buf)
    _gcvt(x.d, ndigit.l, *buf) As "_gcvt"
  EndImport
CompilerEndIf

StartTime.q = ElapsedMilliseconds()

Define StrDouble.s
Define StrBuffer.s{32}
Define ValDouble.d

For i = 0 To 1000000
  ValDouble = i + 0.123456789
  
  _gcvt(ValDouble, 32, @StrBuffer)
  
  ;StrD(ValDouble)
Next

MessageRequester("Test", Str( ElapsedMilliseconds() - StartTime ) + ~"\n"+ PeekS(@StrBuffer, -1, #PB_UTF8))

;MessageRequester("Test", Str( ElapsedMilliseconds() - StartTime ) + ~"\n"+ StrDouble)
Zuletzt geändert von ccode_new am 03.11.2020 23:19, insgesamt 3-mal geändert.
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
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: Schnellere Alternative zu StrD()?

Beitrag von NicTheQuick »

@sibru
Sowas geht schnell schief, weil Doubles wesentlich höhere Werte annehmen können als Quads. Und sie können so klein werden, dass die Zahl multipliziert mit 10^14 immer noch kleiner als 0 ist.

@DePe
Also schreibst du nicht 1MB raus, sondern liest 1MB an Daten ein, und aus jedem Byte wird eine Zeile in der resultierenden Datei? Dass das lange dauert, kann ich mir vorstellen. :mrgreen:
Du hast also am Ende 1 Mio. Zeilen, die so oder so ähnliche aussehen:

Code: Alles auswählen

1,63.12354,45
2,3.123332,33
...
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Schnellere Alternative zu StrD()?

Beitrag von STARGÅTE »

Das ist immer noch merkwürdig, außer #iSaveDataNbDecimal oder rPointTime1 oder rPointTime2 sind gigantisch groß.
Hast du mal den gegen Check probiert, indem du einfach die Zeile:

Code: Alles auswählen

sText = Str(iCount) + sComma + RTrim(StrD(rPointTime1, #iSaveDataNbDecimal), #sChar0) + sComma + StrD(rPoint1) + EndOfLine
zwei mal hintereinander ausführst? Dann sollte es ja von 13s auf etwa 19s springen.

Ich weiß leider nicht wie die ThreadSafe (was du ja sicher angeschaltet hast)-Variante von StrD() aussieht, aber kann mir kaum vorstellen, dass diese dann so viel langsamer sein soll.

Die Idee von sibru klapp natürlich nur bedingt, wenn die Zahl nicht zu groß wird und in eine Quad passt.

EDIT: Den code von ccode_new bekomme ich weder unter x86 noch unter x64 zum laufen, außerdem ist da n Debug drin /:->
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
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: Schnellere Alternative zu StrD()?

Beitrag von NicTheQuick »

STARGÅTE hat geschrieben:EDIT: Den code von ccode_new bekomme ich weder unter x86 noch unter x64 zum laufen, außerdem ist da n Debug drin /:->
Der Code ist auch nur für Linux, soweit ich das sehe.
Antworten