[Linux] ElapsedMilliseconds() startet irgendwo knapp über 0?

Für allgemeine Fragen zur Programmierung mit PureBasic.
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

[Linux] ElapsedMilliseconds() startet irgendwo knapp über 0?

Beitrag von NicTheQuick »

Kann mir das hier jemand erklären?

Code: Alles auswählen

Delay(5000)
a.i = ElapsedMilliseconds()
Delay(1000)
b.i = ElapsedMilliseconds()

Debug a
Debug b
Debug b - a
Ausgabe:
130
1130
1000
Ich weiß, dass es da Unterschiede gibt zwischen verschiedenen Betriebssystemen, aber das hier verstehe ich nicht.
Egal wie groß das erste 'Delay()' ist. Das erste 'ElapsedMilliseconds()' gibt immer irgendwas zwischen 100 und 1000 aus.

Ich hätte es ja verstanden, wenn das erste genau 0 ausgibt oder irgendwas, was mit dem Programmstart zusammenhängt, aber dieser Werte ist etwas merkwürdig. :?
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: [Linux] ElapsedMilliseconds() startet irgendwo knapp übe

Beitrag von STARGÅTE »

ich würde halt vermuten, dass der Timer erst aktiv wird, wenn das erste mal ElapsedMilliseconds() aufgerufen wird, warum es allerdings ein Offset von 130ms gibt ist nicht klar.
Vielleicht gibt das erste ElapsedMilliseconds() auch eine Art Parameter zurück.
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
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: [Linux] ElapsedMilliseconds() startet irgendwo knapp übe

Beitrag von Danilo »

STARGÅTE hat geschrieben:ich würde halt vermuten, dass der Timer erst aktiv wird, wenn das erste mal ElapsedMilliseconds() aufgerufen wird
Ja, das erste ElapsedMilliseconds() fängt bei 0 an, ist hier auf dem Mac auch so (mit und ohne Debugger).

Code: Alles auswählen

ElapsedMilliseconds()
Delay(5000)
a.i = ElapsedMilliseconds()
Delay(1000)
b.i = ElapsedMilliseconds()

Debug a
Debug b
Debug b - a
c = b-a
MessageRequester("INFO","a: "+a+" b: "+b+" b-a: "+c)
Die Ungenauigkeiten hängen wohl von der inneren Funktionsweise der Befehle ab.
Delay() muss ja auch nicht unbedingt Millisekunden-genau sein, je nach OS.

Ohne Debugger sind die Millisekunden hier jedenfalls schonmal kleiner.
Vielleicht braucht die erste Initialisierung von ElapsedMilliseconds() etwas mehr Zeit
als spätere Aufrufe. Wenn dann noch Task-Switches dazwischen funken, wird der
Wert auch mal höher ausfallen können.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
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: [Linux] ElapsedMilliseconds() startet irgendwo knapp übe

Beitrag von NicTheQuick »

Sowas ähnliches hab ich mir dann eben auch gedacht, aber ich hatte gehofft, dass es jemand genau weiß. :wink:

Ich habe auch mal spaßeshalber alle Delays von 0 bis 1000 mit ElapsedMilliseconds() gemesen. Ich hab nur 93 mal eine Abweichung von 1 ms gehabt. Und das mit Debugger! :D
Ich glaube unter Windows hatte ich ohne den HighResTimer niemals so genaue Ergebnis. :)
auser
Beiträge: 58
Registriert: 17.05.2011 10:56

Re: [Linux] ElapsedMilliseconds() startet irgendwo knapp übe

Beitrag von auser »

Vielleicht gibt das ein bisschen Aufschluss:

Code: Alles auswählen

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  Global freq_mic.d
  Global freq_mil.d
  Define freq.q

  QueryPerformanceFrequency_(@freq)
  freq_mil = freq / 1000.0
  freq_mic = freq / 1000000.0

  Procedure.q MillisecondsQ()
    Static prev_time_mil.q
    Protected cur_time.q

    QueryPerformanceCounter_(@cur_time)
    If cur_time > prev_time_mil
      prev_time_mil = cur_time
      ProcedureReturn(cur_time/freq_mil)
    Else
      ProcedureReturn(prev_time_mil/freq_mil)
    EndIf
  EndProcedure
  Procedure.q MicrosecondsQ()
    Static prev_time_mic.q
    Protected cur_time.q

    QueryPerformanceCounter_(@cur_time)
    If cur_time > prev_time_mic
      prev_time_mic = cur_time
      ProcedureReturn(cur_time/freq_mic)
    Else
      ProcedureReturn(prev_time_mic/freq_mic)
    EndIf
  EndProcedure
CompilerElse
  Structure timeval
    tv_sec.i
    tv_usec.i
  EndStructure

  Procedure.q MillisecondsQ()
    Protected time.timeval
    gettimeofday_(@time,#Null)
    ProcedureReturn((time\tv_sec*1000000 + time\tv_usec)/1000)
  EndProcedure
  Procedure.q MicrosecondsQ()
    Protected time.timeval
    gettimeofday_(@time,#Null)
    ProcedureReturn(time\tv_sec*1000000 + time\tv_usec)
  EndProcedure
CompilerEndIf


OpenConsole()

For x = 1 To 1000
  PrintN(Str(ElapsedMilliseconds()))
  PrintN(Str(MillisecondsQ()))
  PrintN(Str(MicrosecondsQ()))
Next
Ergebnis Linux (Auszug) farbig hervorgehoben:
456
1383862316456
1383862316456980
456
1383862316457
1383862316457020
457
1383862316457
1383862316457022
457
1383862316457
1383862316457024

Der kleine Wert ist der von PB. Schaut also so aus als ob hier die Sekunden und die Microsekunden fehlen. Die Sekunden wären zu groß für einen 4 Byte großen Rückgabewert und die Microsekunden wären um 3 Stellen zu genau. Ich hoffe nur daß hier PB den Umbruch richtig hinkriegt :mrgreen: . Ich bin mir übrigens ziemlich sicher daß PB gettimeofday verwendet weil in einem meiner Source-Ordner in dem auch einige C files rumliegen verdächtig viele PB-binaries gefunden werden wenn ich nach gettimeofday greppe.

Auf Windows sieht der Auszug hingegen so aus:
3695320
3695612
3695612322
3695320
3695612
3695612331
3695320
3695612
3695612345
3695320
3695612
3695612360
Da ist mir die Differenz zu groß als daß ich davon ausgehen würde daß hier QueryPerformanceCounter verwendet würde. Insbesondere wenn ich das Ergebnis mit dem nicht so genauen GetTickCount() vergleiche bin ich mir sicher daß ElapsedMilliseconds() unter Windows GetTickCount() verwendet (und das gibt halt nun mal lediglich 4 byte großen Wert zurück).

Meine Schlussfolgerung: Damit auf allen Systemen so 'n popeliger 4 byte großer Timer funzt muss man in Linux erst mal bissl rumschnippeln. Aber es dient einem guten Zweck... vermutlich... hoffentlich :wink:
Zuletzt geändert von auser am 08.11.2013 18:58, insgesamt 2-mal geändert.
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: [Linux] ElapsedMilliseconds() startet irgendwo knapp übe

Beitrag von NicTheQuick »

@auser:
Sehr cool! :allright:
Bei mir hab ich's auch mal gestartet:

Code: Alles auswählen

696
1383908625696
1383908625696146
Das heißt, dass bei Linux 'ElapsedMilliseconds()' nicht ab dem Systemstart zählt, sondern einfach die Zeit seit dem 1.1.1970 mapt.
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: [Linux] ElapsedMilliseconds() startet irgendwo knapp übe

Beitrag von Danilo »

NicTheQuick hat geschrieben:Das heißt, dass bei Linux 'ElapsedMilliseconds()' nicht ab dem Systemstart zählt, sondern einfach die Zeit seit dem 1.1.1970 mapt.
Wie kommst Du dann mit Deinem folgenden Code auf 130?

Code: Alles auswählen

Delay(5000)
a.i = ElapsedMilliseconds()

Debug a
Seit dem 1.1.1970 sind mehr als 130ms vergangen. Da waren Deine Eltern noch Kinder und Du
hast nicht mal ansatzweise gelebt.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
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: [Linux] ElapsedMilliseconds() startet irgendwo knapp übe

Beitrag von NicTheQuick »

Okay, ich hab mich nicht korrekt ausgedrückt. :D

Ich erkläre es am besten an einem Code:

Code: Alles auswählen

Structure timeval
	tv_sec.q
	tv_usec.q
EndStructure

Procedure.q MillisecondsQ()
	Protected time.timeval
	gettimeofday_(@time,#Null)
	ProcedureReturn((time\tv_sec*1000000 + time\tv_usec)/1000)
EndProcedure

Procedure.q ElapsedMillisecondsEx()
	Static first.i = #True
	Static offset.q
	If (first)
		offset = (MillisecondsQ() / 1000) * 1000 ;Nimm beim ersten Mal ein Offset
		first = #False
	EndIf
	ProcedureReturn MillisecondsQ() - offset ;Ziehe es dann immer ab
EndProcedure

OpenConsole()

Delay(1000)
PrintN(Str(ElapsedMilliseconds()))
PrintN(Str(ElapsedMillisecondsEx()))
Delay(1000)
PrintN(Str(ElapsedMilliseconds()))
PrintN(Str(ElapsedMillisecondsEx()))
Delay(1000)
PrintN(Str(ElapsedMilliseconds()))
PrintN(Str(ElapsedMillisecondsEx()))

CloseConsole()
auser
Beiträge: 58
Registriert: 17.05.2011 10:56

Re: [Linux] ElapsedMilliseconds() startet irgendwo knapp übe

Beitrag von auser »

Zur Info: Nur für den Fall daß jemand die oben geposteten MillisecondsQ() oder MicrosecondsQ() verwenden will. Ich hab die timeval Struktur nochmal korrigiert nachdem ich in C gesehen habe daß die auf 32 bit Linux "nur" 8 byte (Quad) groß ist. Wobei ich das in C eigentlich eh nicht wissen muss ...da genügt ein simpler include /:-> ...so oder so in dem Fall ist also PBs Integer für die Strukturfelder besser als Quad. Quad als Rückgabewert würd ich trotzdem lassen (wenngleich in 64bit Linux eigentlich ein 16byte Typ befüllt werden könnte...). Die Funktion gettimeofday sollte theoretisch auch auf MacOS verfügbar sein (im Gegensatz zu clock_gettime - das in neueren Versionen Nanosekunden zurückgibt... in älteren aber gettimeofday als Backend verwendet)... wie groß das Strukturfeld da ist weiß ich aber ned weil ich kein MacOS habe. Müsste man also gegebenfalls vorher testen.

Code: Alles auswählen

Structure timeval
  tv_sec.i
  tv_usec.i
EndStructure
Mfg,
auser
Antworten