Seite 1 von 1

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

Verfasst: 07.11.2013 11:26
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. :?

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

Verfasst: 07.11.2013 12:18
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.

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

Verfasst: 07.11.2013 12:57
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.

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

Verfasst: 07.11.2013 14:34
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. :)

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

Verfasst: 08.11.2013 00:32
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:

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

Verfasst: 08.11.2013 13:11
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.

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

Verfasst: 08.11.2013 13:31
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.

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

Verfasst: 08.11.2013 14:09
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()

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

Verfasst: 08.11.2013 20:00
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