Be careful with ElapsedMilliseconds() in certain cases

Everything else that doesn't fall into one of the other PB categories.
auser
Enthusiast
Enthusiast
Posts: 195
Joined: Wed Sep 06, 2006 6:59 am

Re: Be careful with ElapsedMilliseconds() in certain cases

Post by auser »

MachineCode wrote:What? A real-world solution is posted in the other thread and uses quads for the difference
The solution you mean is no "how to use ElapsedMilliseconds" but different function and not multi-platform (as I wrote you could use gettimeofday() on linux). Using quads was suggested here as well. But there is nothing wrong with ElapsedMilliseconds (GetTickCount) as it is if you just know how to use it.
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Be careful with ElapsedMilliseconds() in certain cases

Post by Dude »

So am I right in assuming that ElapsedMilliseconds() is now a Quad in PureBasic 5.50, and that it's more accurate than GetTickCount_() and should be used instead of GetTickCount_() for timing references? It will not return a negative after 49.7 days like GetTickCount_(), correct? If this is all correct, then I can go ahead and search/replace all my sources to use it. :)
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Be careful with ElapsedMilliseconds() in certain cases

Post by netmaestro »

It returns a quad and uses QueryPerformanceCounter_(). Wrapping issues from before the change are no longer of concern.
MSDN wrote:QPC is typically the best method to use to time-stamp events and measure small time intervals that occur on the same system or virtual machine.
BERESHEIT
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Be careful with ElapsedMilliseconds() in certain cases

Post by Dude »

Thanks for confirming. So it's good for timing only, and no longer returns the system up-time, right?
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Be careful with ElapsedMilliseconds() in certain cases

Post by netmaestro »

It's still system uptime but in a much higher-res api than GetTickCount. Be aware though, it is going to roll over on you as well - if you leave your system up for 290 years.
BERESHEIT
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

Re: Be careful with ElapsedMilliseconds() in certain cases

Post by Thunder93 »

LOL!!!!!!!!! :lol: :lol:
netmaestro wrote:* Be aware though, it is going to roll over on you as well - if you leave your system up for 290 years.
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Be careful with ElapsedMilliseconds() in certain cases

Post by Dude »

netmaestro wrote:it is going to roll over on you as well - if you leave your system up for 290 years.
Ah crap... I better code a different method instead, that is 290-year-proof. ;)
Helle
Enthusiast
Enthusiast
Posts: 178
Joined: Wed Apr 12, 2006 7:59 pm
Location: Germany
Contact:

Re: Be careful with ElapsedMilliseconds() in certain cases

Post by Helle »

For fun: This code check the time-base for the QueryPerformanceCounter, the base for ElapsedMilliseconds since years.
Need the inpout32.dll/inpoutx64.dll (for download see google)
Result on my PC:
Image

Code: Select all

;Test with Windows7/64, PureBasic 5.43 LTS (x64) / PureBasic 5.50 (x64), Windows XP (32-Bit) and PureBasic 5.50 (x86) 
;Power Management Timer = PMT = 3.579545 MHz, color burst frequency used by NTSC
;Programmable Interval Timer = PIT = 1.193182 MHz, one third of the color burst frequency used by NTSC
;Need inpout32.dll/inpoutx64.dll (for download see google) in this directory
;x86 and x64, Ascii and Unicode
;"Helle" Klaus Helbing, Aug. 30, 2016

Freq.q
Start.q
Ende.q
RDTSC1.q
RDTSC2.q
Base_ClockI.q
TA.q
TE.q

HPET_Freq.d
Base_Clock.d

ITSC.l
MaxIDExt.l
HPET_Resolution.l
Value1.l
Value2.l

#PROCESSOR_ARCHITECTURE_AMD64 = $9
#HPET_Address = $FED00000         ;most, or check your Windows-Device-Manager

Prototype GetNativeSystemInfo(*lpSystemInfo.SYSTEM_INFO)
Procedure Is64bitOS() 
  Protected Kernel32, GetNativeSystemInfo.GetNativeSystemInfo 
  Protected Info.SYSTEM_INFO 
  Protected Result = #False 
  
  Kernel32 = OpenLibrary(#PB_Any, "Kernel32.dll") 
  If Kernel32 
    GetNativeSystemInfo = GetFunction(Kernel32, "GetNativeSystemInfo") 
    If GetNativeSystemInfo 
      GetNativeSystemInfo(@Info) 
      If Info\wProcessorArchitecture = #PROCESSOR_ARCHITECTURE_AMD64 ;x64 
        Result = #True 
      EndIf      
    EndIf 
    CloseLibrary(Kernel32) 
  EndIf  

  ProcedureReturn Result 
EndProcedure 

CPU$ = Space(48)                  ;96 Bytes in Unicode
S1.l                              ;for CPU-String x86/x64 and ASCI/Unicode
S2.l
S3.l
S4.l
Z.l
;CPU-String
While Z < 3
  !mov eax,80000002h
  !add eax,[v_Z]
  !cpuid        
  !mov [v_S1],eax
  !mov [v_S2],ebx  
  !mov [v_S3],ecx
  !mov [v_S4],edx
  PokeL(@CPU$ + (Z << 4), S1)
  PokeL(@CPU$ + (Z << 4) + 4, S2)
  PokeL(@CPU$ + (Z << 4) + 8, S3)
  PokeL(@CPU$ + (Z << 4) + 12, S4)
  Z + 1
Wend
Result$ = "CPU:     " + PeekS(@CPU$, #PB_Any, #PB_Ascii) + #LFCR$

;Check CPU for Invariant TSC
ITSC$ = " Available" 
!mov eax,80000000h                ;check for max. Extended Level, Intel and AMD
!cpuid
!mov [v_MaxIDExt],eax             ;max. ExtID, 8000000xh
If (MaxIDExt & $FFFFFFFF) < $80000007
  ITSC$ = "Not available"      
 Else                      
  !mov eax,80000007h   
  !cpuid
  !and edx,100000000b             ;Flag Invariant TSC
  !mov [v_ITSC],edx
 !jnz @f 
  ITSC$ = "Not available"
!@@:
EndIf

QueryPerformanceFrequency_(@Freq) ;const., determined during windows-system initialization and doesn't change while the windows-system is running.
Result$ + "QueryPerformanceFrequency (Hz):             " + Str(Freq) + #LFCR$
Result$ + "Invariant Time Stamp Counter (ITSC):          " + ITSC$ + #LFCR$

If Freq = 0
  Result$ + "QueryPerformanceCounter:                 Not available. End."
 Else
  ;Check for HPET (High Precision Event Timers)
  ;Check for 32- or 64-Bit-OS 
  If Is64bitOS()
    If #PB_Compiler_Processor = #PB_Processor_x86
      MessageRequester("Error!", "64-Bit-OS and 32-Bit-PB --> No Way! End.")
      End
    EndIf
    DLLOK = OpenLibrary(0, "inpoutx64.dll") ;64-Bit-Version, for download see google
   Else
    DLLOK = OpenLibrary(0, "inpout32.dll")  ;32-Bit-Version, for download see google
  EndIf
  If DLLOK
    Prototype.i ProtoIO_0()
      IO_IsOpen.ProtoIO_0 = GetFunction(0, "IsInpOutDriverOpen")
    Prototype.i ProtoIO_2(physAddr.l, physVal.l)
      IO_GetPhysLong.ProtoIO_2 = GetFunction(0, "GetPhysLong")

    If IO_IsOpen()
      IO_GetPhysLong(#HPET_Address + 4, @HPET_Resolution)  ;read the Resolution in Femtoseconds (10^-15 Seconds), see HPET-Documentation
      If HPET_Resolution
        Result$ + "High Precision Event Timers (HPET):               Available" + #LFCR$
        Result$ + "Resolution HPET (ns):                                             " + StrD(HPET_Resolution / 1e6, 6) + #LFCR$
        HPET_Freq = 1e15 / HPET_Resolution
        Result$ + "This gives the HPET-Frequency (Hz):         " + Str(HPET_Freq) + #LFCR$

        If ITSC
          ;for tests. SetThreadAffinityMask: MS says: No!
          ;hThread = GetCurrentThread_()
          ;Core = 4                 ;CPU_2
          ;SetThreadAffinityMask_(hThread, Core)
          ;;hProcess = GetCurrentProcess_()
          ;;SetPriorityClass_(hProcess, #REALTIME_PRIORITY_CLASS)     ;for hard!
          ;SetThreadPriority_(hThread, #THREAD_PRIORITY_TIME_CRITICAL)

          While Value2 <= Value1
            IO_GetPhysLong(#HPET_Address + $F0, @Value1)   ;read only Low
            !rdtsc
            !mov dword[v_RDTSC1],eax
            !mov dword[v_RDTSC1+4],edx
            ;Simple Time-Loop for Calibration
            !mov ecx,0FFFFFFFFh        ;any value for this test
          !@@:
            !dec ecx
           !jnz @b
            IO_GetPhysLong(#HPET_Address + $F0, @Value2)   ;read only Low
            !rdtsc
            !mov dword[v_RDTSC2],eax
            !mov dword[v_RDTSC2+4],edx
          Wend

          Base_Clock = (RDTSC2 - RDTSC1) / ((Value2 - Value1) / HPET_Freq)
          Result$ + "This gives the CPU-Base-Clock (Hz):      " + StrD(Base_Clock, 0) + #LFCR$
          Base_ClockI = Base_Clock
          Result$ + "CPU-Base-Clock >> 10:                               " + Str(Base_ClockI >> 10) + #LFCR$
          Result$ + "QueryPerformanceFrequency << 10:   " + Str(Freq << 10) + #LFCR$
          Result$ + "Info Resolution QPC (ns):                                    " + StrD(1e9 / Freq, 6) + #LFCR$
          Result$ + "QueryPerformance Base:       " + "Invariant Time Stamp Counter (ITSC)" + #LFCR$     

          Result$ + "Test with QPC and ITSC:" + #LFCR$ 

          TA = ElapsedMilliseconds()
          QueryPerformanceCounter_(@Start)
          !rdtsc
          !mov dword[v_RDTSC1],eax
          !mov dword[v_RDTSC1+4],edx

          Delay(1234)                  ;or any code

          TE = ElapsedMilliseconds()
          QueryPerformanceCounter_(@Ende) 
          !rdtsc
          !mov dword[v_RDTSC2],eax
          !mov dword[v_RDTSC2+4],edx

          Result$ + "QueryPerformanceCounter_Start:       " + Str(Start) + #LFCR$
          Result$ + "RDTSC_Start:                                 " + Str(RDTSC1) + #LFCR$
          Result$ + "RDTSC_Start >> 10:                            " + Str(RDTSC1 >> 10) + #LFCR$
          Result$ + "After Delay(any value) or any code:" + #LFCR$
          Result$ + "QueryPerformanceCounter_End:         " + Str(Ende) + #LFCR$
          Result$ + "RDTSC_End:                                    " + Str(RDTSC2) + #LFCR$
          Result$ + "RDTSC_End >> 10:                               " + Str(RDTSC2 >> 10) + #LFCR$
          Result$ + "QPC_End - QPC_Start:                                  " + Str(Ende - Start) + #LFCR$
          Result$ + "RDTSC_End - RDTSC_Start:                    " + Str(RDTSC2 - RDTSC1) + #LFCR$
          Result$ + "(RDTSC_End - RDTSC_Start) >> 10:            " + Str((RDTSC2 - RDTSC1) >> 10) + #LFCR$
          Result$ + "Elapsed Time QPC (ms):                                       " + StrD((((Ende - Start) / Freq) * 1000), 6) + #LFCR$
          Result$ + "Elapsed Time RDTSC (ms):                                   " + StrD((((RDTSC2 - RDTSC1) / Base_Clock) * 1000), 6) + #LFCR$
          Result$ + "ElapsedMilliseconds PB (ms):                                " + Str(TE - TA) + #LFCR$
          Result$ + "Overflow signed QPC (PB-Quad) on this PC in:       " + Str((9223372036854775807 / Base_ClockI) / (60*60*24*365)) + " Years"     ;Start ignored, or calculate precise... :-)

         Else
          Result$ + "QueryPerformance Base:       " + "High Precision Event Timers (HPET)" + #LFCR$
        EndIf

       Else
        Result$ + "High Precision Event Timers (HPET):              Not available" + #LFCR$
        If Freq > 3579540 And Freq < 3579550          ;3579545 Hz
          QP$ = "Power Management Timer (PMT)" 
         ElseIf Freq > 1193180 And Freq < 1193185     ;1193182 Hz
          QP$ = "Programmable Interval Timer (PIT)"
         Else
          QP$ = "Not detected"
        EndIf
        Result$ + "QueryPerformance Base:       " + QP$ + #LFCR$

      EndIf

     Else 
      MessageRequester("Error!", "Can not open inpoutxx.dll! End.")
      End
    EndIf

   Else
    MessageRequester("Error!", "Can not open inpoutxx.dll! End.")
    End
  EndIf 

EndIf

If IsLibrary(0)
  CloseLibrary(0)
EndIf
MessageRequester("QueryPerformanceCounter-Test", Result$)
Edit: Change GetSystemInfo to GetNativeSystemInfo and then check for 64-Bit-OS with 32-Bit-PB



__________________________________________________
IMG tags repaired
29.08.2016
RSBasic
Last edited by Helle on Tue Aug 30, 2016 10:58 am, edited 1 time in total.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Be careful with ElapsedMilliseconds() in certain cases

Post by netmaestro »

Looks very good but I'm getting an IMA on line 91: If IO_IsOpen(). Win 7 x64, PB 5.50 x86. I have both versions of the inpout.dll in System32 along with the .sys driver file.
BERESHEIT
Helle
Enthusiast
Enthusiast
Posts: 178
Joined: Wed Apr 12, 2006 7:59 pm
Location: Germany
Contact:

Re: Be careful with ElapsedMilliseconds() in certain cases

Post by Helle »

See changed code above. 64-Bit-OS and (with) 32-Bit-PB --> No Way! For hardware-accesses is this not a good idea...
Post Reply