HighResTimer - Module

Share your advanced PureBasic knowledge/code with the community.
User avatar
StarBootics
Addict
Addict
Posts: 984
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

HighResTimer - Module

Post by StarBootics »

Hello everyone,

Another Module conversion, this time a HighResTimer.

Best regards
StarBootics

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Project name : HighResTimer - Module
; File Name : HighResTimer - Module.pb
; File version: 1.0.0
; Programming : OK
; Programmed by : StarBootics
; Date : 06-08-2016
; Last Update : 06-08-2016
; PureBasic code : V5.50
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; This code was originally created by Guimauve to have a High Resolution 
; Timer. See : http://www.purebasic.fr/english/viewtopic.php?f=15&t=49365
;
; I deserve credit only to convert the original code into a Module.
;
; This code is free to be use where ever you like but you use it at your 
; own risk.
;
; The author can in no way be held responsible for data loss, damage or 
; other annoying situations that may occur.
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule HighResTimer
  
  Declare Initialize()
  Declare Reset()
  Declare Start()
  Declare Stop()
  Declare.q Consult()
  
EndDeclareModule

Module HighResTimer
  
  CompilerSelect #PB_Compiler_OS
      
    CompilerCase #PB_OS_Linux
      
      #CLOCK_MONOTONIC = 1
      
      Structure TimeSpec Align #PB_Structure_AlignC 
        Second.i
        NanoSecond.l
      EndStructure
      
      ImportC "-lrt"
        clock_gettime(ClockID.l, *TimeSpecA.TimeSpec)
      EndImport
      
    CompilerCase #PB_OS_MacOS
      
      Structure TimeBase Align #PB_Structure_AlignC 
        Numerator.l
        Denominator.l
      EndStructure
      
      ImportC ""
        mach_absolute_time.q()
        mach_timebase_info(*TimeBaseA.TimeBase)
      EndImport
      
  CompilerEndSelect
  
  Structure Instance Align #PB_Structure_AlignC 
    
    Stopped.b
    StartMicroSec.q
    StopMicroSec.q
    
    CompilerSelect #PB_Compiler_OS
        
      CompilerCase #PB_OS_Windows 
        Frequency.q
        StartCount.q
        EndCount.q
        
      CompilerCase #PB_OS_Linux
        StartCount.TimeSpec
        EndCount.TimeSpec
        
      CompilerCase #PB_OS_MacOS
        MicroSecConversion.d
        TimeBase.TimeBase
        StartCount.q
        EndCount.q
        
    CompilerEndSelect
    
  EndStructure
  
  Global Instance.Instance
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The New Operator <<<<<
  
  Procedure Initialize()
    
    Instance\Stopped = #True
    Instance\StartMicroSec = 0
    Instance\StopMicroSec = 0 
    
    CompilerSelect #PB_Compiler_OS
        
      CompilerCase #PB_OS_Windows 
        QueryPerformanceFrequency_(@Instance\Frequency)
        Instance\StartCount = 0
        Instance\EndCount = 0
        
      CompilerCase #PB_OS_Linux
        Instance\StartCount\Second = 0
        Instance\StartCount\NanoSecond = 0
        Instance\EndCount\Second = 0
        Instance\EndCount\NanoSecond = 0
        
      CompilerCase #PB_OS_MacOS
        mach_timebase_info(@Instance\TimeBase)
        Instance\MicroSecConversion = 1e-3 * Instance\TimeBase\Numerator / Instance\TimeBase\Denominator
        Instance\StartCount = 0
        Instance\EndCount = 0
        
    CompilerEndSelect
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Reset Operator <<<<<
  
  Procedure Reset()
    
    Instance\Stopped = 0
    Instance\StartMicroSec = 0
    Instance\StopMicroSec = 0 
    
    CompilerSelect #PB_Compiler_OS
        
      CompilerCase #PB_OS_Windows 
        Instance\Frequency = 0
        Instance\StartCount = 0
        Instance\EndCount = 0
        
      CompilerCase #PB_OS_Linux
        Instance\StartCount\Second = 0
        Instance\StartCount\NanoSecond = 0
        Instance\EndCount\Second = 0
        Instance\EndCount\NanoSecond = 0
        
      CompilerCase #PB_OS_MacOS
        Instance\MicroSecConversion = 0.0
        Instance\TimeBase\Numerator = 0
        Instance\TimeBase\Denominator = 0
        Instance\StartCount = 0
        Instance\EndCount = 0
        
    CompilerEndSelect
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Start operator <<<<<
  
  Procedure Start()
    
    Instance\Stopped = #False
    
    CompilerSelect #PB_Compiler_OS
        
      CompilerCase #PB_OS_Windows 
        QueryPerformanceCounter_(@Instance\StartCount)
        
      CompilerCase #PB_OS_Linux
        clock_gettime(#CLOCK_MONOTONIC, @Instance\StartCount)
        
      CompilerCase #PB_OS_MacOS
        Instance\StartCount = mach_absolute_time() * Instance\MicroSecConversion
        
    CompilerEndSelect
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Stop operator <<<<<
  
  Procedure Stop()
    
    Instance\Stopped = #True
    
    CompilerSelect #PB_Compiler_OS
        
      CompilerCase #PB_OS_Windows 
        QueryPerformanceCounter_(@Instance\EndCount)
        
      CompilerCase #PB_OS_Linux
        clock_gettime(#CLOCK_MONOTONIC, @Instance\EndCount)
        
      CompilerCase #PB_OS_MacOS
        Instance\EndCount = mach_absolute_time() * Instance\MicroSecConversion
        
    CompilerEndSelect
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Consult Operator <<<<<
  
  Procedure.q Consult()
    
    CompilerSelect #PB_Compiler_OS
        
      CompilerCase #PB_OS_Windows 
        
        If Instance\Stopped = #False
          QueryPerformanceCounter_(@Instance\EndCount)
        EndIf
        
        Instance\StartMicroSec = Instance\StartCount * (1000000.0 / Instance\Frequency)
        Instance\StopMicroSec = Instance\EndCount * (1000000.0 / Instance\Frequency) 
        
      CompilerCase #PB_OS_Linux
        
        If Instance\Stopped = #False
          clock_gettime(#CLOCK_MONOTONIC, @Instance\EndCount)
        EndIf
        
        Instance\StartMicroSec = Instance\StartCount\Second * 1000000 + Instance\StartCount\NanoSecond / 1000
        Instance\StopMicroSec = Instance\EndCount\Second * 1000000 + Instance\EndCount\NanoSecond / 1000
        
      CompilerCase #PB_OS_MacOS
        
        If Instance\Stopped = #False
          Instance\EndCount = mach_absolute_time() * Instance\MicroSecConversion
        EndIf
        
        Instance\StartMicroSec = Instance\StartCount
        Instance\StopMicroSec = Instance\EndCount
        
    CompilerEndSelect
    
    ProcedureReturn Instance\StopMicroSec - Instance\StartMicroSec
  EndProcedure
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  HighResTimer::Initialize() ; <-- Mandatory to Initialize the timer before using it
  HighResTimer::Start()
  
  Delay(1)
  Debug HighResTimer::Consult()
  
  Delay(5)
  Debug HighResTimer::Consult()
  
  Delay(499)
  Debug HighResTimer::Consult()
  
  Delay(500)
  Debug HighResTimer::Consult()
  
  Delay(1499)
  Debug HighResTimer::Consult()
  
  Delay(1501)
  Debug HighResTimer::Consult()
  
  HighResTimer::Stop()
  HighResTimer::Reset()
  
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<
Last edited by StarBootics on Sun Aug 07, 2016 11:16 pm, edited 2 times in total.
The Stone Age did not end due to a shortage of stones !
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: HighResTimer - Module

Post by Joris »

StarBootics I get six times a zero ?
Debug HighResTimer::Consult() ;all 0
Shouldn't it give the delta-timings ?
(XP SP3)

Thanks
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
User avatar
Demivec
Addict
Addict
Posts: 4086
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: HighResTimer - Module

Post by Demivec »

Joris wrote: StarBootics I get six times a zero ?
Debug HighResTimer::Consult() ;all 0
Shouldn't it give the delta-timings ?
(XP SP3)
The fractional parts of the calculation are being rounded to zero before multiplying to find the results. It can be corrected by making the following modification in the Consult() procedure to shift the calculation into using floats throughout the entire calculation:

Change this part:

Code: Select all

CompilerSelect #PB_Compiler_OS
        
      CompilerCase #PB_OS_Windows 
        
        If Instance\Stopped = #False
          QueryPerformanceCounter_(@Instance\EndCount)
        EndIf
        
        Instance\StartMicroSec = Instance\StartCount * (1000000 / Instance\Frequency)
        Instance\StopMicroSec = Instance\EndCount * (1000000 / Instance\Frequency) 
to this:

Code: Select all

CompilerSelect #PB_Compiler_OS
        
      CompilerCase #PB_OS_Windows 
        
        If Instance\Stopped = #False
          QueryPerformanceCounter_(@Instance\EndCount)
        EndIf
        
        Instance\StartMicroSec = 0.0 + Instance\StartCount * (1000000 / Instance\Frequency) ; ***
        Instance\StopMicroSec = 0.0 + Instance\EndCount * (1000000 / Instance\Frequency) ; *** 
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: HighResTimer - Module

Post by Joris »

That helped.

But then, with what you said, I thought why wouldn't this work then :

Code: Select all

   Instance\StartMicroSec =  Instance\StartCount * 1000000 / Instance\Frequency
   Instance\StopMicroSec =  Instance\EndCount * 1000000 / Instance\Frequency
And it does too.

Thanks.
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: HighResTimer - Module

Post by Joris »

In my search on accurate timings, I also found this site. They talk about a setting in the bios that can change QueryPerformanceFrequency upto 5 times faster.
http://www.neowin.net/forum/topic/10757 ... e-and-fps/
By hardbag :
TSC+LAPICs Low performance (slow timers + syncing) = 2.76MHz
LAPICs low performance (slow timer - no syncing) = 3.5Mhz
TSC+HPET medium performance (slow and fast timer + syncing) = 3.8Mhz
HPET high performance (fast timer - no syncing) = 14.3MHz
Run the WinTimerTester 1.1 to see your QueryPerformanceFrequency
Then try with HPET, you'll be amazed.
Reading more comments I'm not going into that (for now). But maybe others can get inspired.
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
Post Reply