Seite 1 von 3

Schnellere Alternative zu StrD()?

Verfasst: 03.11.2020 17:38
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

Re: Schnellere Alternative zu StrD()?

Verfasst: 03.11.2020 19:07
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.

Re: Schnellere Alternative zu StrD()?

Verfasst: 03.11.2020 19:28
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

Re: Schnellere Alternative zu StrD()?

Verfasst: 03.11.2020 19:42
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?

Re: Schnellere Alternative zu StrD()?

Verfasst: 03.11.2020 20:09
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...

Re: Schnellere Alternative zu StrD()?

Verfasst: 03.11.2020 20:16
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                                                                                                                        

Re: Schnellere Alternative zu StrD()?

Verfasst: 03.11.2020 20:40
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)

Re: Schnellere Alternative zu StrD()?

Verfasst: 03.11.2020 20:42
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
...

Re: Schnellere Alternative zu StrD()?

Verfasst: 03.11.2020 20:43
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 /:->

Re: Schnellere Alternative zu StrD()?

Verfasst: 03.11.2020 20:47
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.