Page 2 of 2

Re: Be careful with ElapsedMilliseconds() in certain cases

Posted: Wed Jul 11, 2012 3:51 pm
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.

Re: Be careful with ElapsedMilliseconds() in certain cases

Posted: Sat Aug 27, 2016 8:10 am
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. :)

Re: Be careful with ElapsedMilliseconds() in certain cases

Posted: Sat Aug 27, 2016 6:20 pm
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.

Re: Be careful with ElapsedMilliseconds() in certain cases

Posted: Sun Aug 28, 2016 1:28 am
by Dude
Thanks for confirming. So it's good for timing only, and no longer returns the system up-time, right?

Re: Be careful with ElapsedMilliseconds() in certain cases

Posted: Sun Aug 28, 2016 1:37 am
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.

Re: Be careful with ElapsedMilliseconds() in certain cases

Posted: Sun Aug 28, 2016 3:08 am
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.

Re: Be careful with ElapsedMilliseconds() in certain cases

Posted: Sun Aug 28, 2016 6:45 am
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. ;)

Re: Be careful with ElapsedMilliseconds() in certain cases

Posted: Mon Aug 29, 2016 9:06 pm
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

Re: Be careful with ElapsedMilliseconds() in certain cases

Posted: Tue Aug 30, 2016 2:55 am
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.

Re: Be careful with ElapsedMilliseconds() in certain cases

Posted: Tue Aug 30, 2016 11:02 am
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...