High Resolution Timer Research

Linux specific forum
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: High Resolution Timer Research

Post by wilbert »

nanosleep does exist on both Linux and OS X if I'm correct
On OS X

Code: Select all

Structure timespec
  tv_sec.i
  tv_nsec.l
EndStructure
    
ImportC ""
  nanosleep(*req.timespec, *rem.timespec = #Null)
EndImport

pause.timespec\tv_nsec = 300000
nanosleep(@pause)
On Linux you probably need to specify a library for ImportC and it's not very accurate.
There's also clock_delay_until(deadline.q)
User avatar
Guimauve
Enthusiast
Enthusiast
Posts: 742
Joined: Wed Oct 22, 2003 2:51 am
Location: Canada

Re: High Resolution Timer Research

Post by Guimauve »

It's better and more safe to implement it this way :

Code: Select all

Procedure NanoDelay(Nanoseconds.l)
  
  If Nanoseconds > 0 And Nanoseconds <= 999999999
    req.timespec\tv_nsec = Nanoseconds
    ProcedureReturn nanosleep(@req, #Null)
  Else
    ProcedureReturn -1
  EndIf
  
EndProcedure
But the Sleep will always be a little bit longer than expected. Maybe this is due to PureBasic Procedure calling time or the CPU load or both.

Best regards
Guimauve
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: High Resolution Timer Research

Post by infratec »

An old thread, I know, but ...

I just tested this code on Win XP and ...
it failed.

A short debugging session found that

Code: Select all

QueryPerformanceCounter_(@GetHighResTimerStartCount(*HighResTimerA))
failed with
LastError 998, which means No Access.

I tried it with

Code: Select all

Define TimerQ.q

If QueryPerformanceFrequency_(@TimerQ) = 0
  Debug GetLastError_()
EndIf

Debug TimerQ
And it worked.

But with the structure it worked not.
I checked the address of \Frequency and it was Ok.

I need to use

Code: Select all

Structure HighResTimer Align #PB_Structure_AlignC 
Than it worked.

I have no explanation for that, since the single quad variable is also not aligned, or is it ?

Bernd
User avatar
StarBootics
Addict
Addict
Posts: 984
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: High Resolution Timer Research

Post by StarBootics »

Hello everyone,

Sorry to re-open a very old thread but it's fully related even after so many years. Since I'm a Module Addict I have converted Guimauve's HighResTimer into a Module.

Code: Select all

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

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Programming notes :
; 
; Based on Guimauve's original code.
; https://www.purebasic.fr/english/viewtopic.php?f=15&t=49365
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

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
        Second.i
        NanoSecond.l
      EndStructure
      
      ImportC "-lrt"
        clock_gettime(ClockID.l, *TimeSpecA.TimeSpec)
      EndImport
      
    CompilerCase #PB_OS_MacOS
      
      Structure TimeBase
        Numerator.l
        Denominator.l
      EndStructure
      
      ImportC ""
        mach_absolute_time.q()
        mach_timebase_info(*TimeBaseA.TimeBase)
      EndImport
      
  CompilerEndSelect
  
  Structure Instance
    
    IsRunning.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\IsRunning = #False
    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\IsRunning = 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\IsRunning = #True
    
    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\IsRunning = #False
    
    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 ElapsedMicroSec <<<<<
  
  Procedure.q Consult()
    
    CompilerSelect #PB_Compiler_OS
        
      CompilerCase #PB_OS_Windows 
        
        If Instance\IsRunning = #True
          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\IsRunning = #True
          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\IsRunning = #True
          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()
  
  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 <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<
Best regards.
StarBootics
The Stone Age did not end due to a shortage of stones !
Post Reply