[crossplatform] Nano Seconds Timer

Share your advanced PureBasic knowledge/code with the community.
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

[crossplatform] Nano Seconds Timer

Post by grabiller »

Hi,

As I'm doing some crossplatform researches for my project, I'm posting this solution to have a precision timer - or "performance counter" - working on Windows, Linux and Mac OSX:

Feel free to point me any problem you have with it, if any. I've tested it on:
- Windows 7 - 64bit
- Linux Ubuntu 12.04.1 - 64bit
- Mac OSX Lion 10.7.2 - 64bit

Code: Select all

; ============================================================================
;  IMPORT
; ============================================================================
;{
CompilerSelect #PB_Compiler_OS
    
  ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ;  WINDOWS
  ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  CompilerCase #PB_OS_Windows
    ; NOP
    
  ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ;  LINUX
  ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  CompilerCase #PB_OS_Linux
    #CLOCK_MONOTONIC = 1
    Structure timespec_t
      tv_sec.i
      tv_nsec.i
    EndStructure
    ImportC ""
      clock_getres.i ( clock_id.i, *res.timespec_t )
      clock_gettime.i( clock_id.i, *tp.timespec_t  )
    EndImport
    
  ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ;  MAC OS
  ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  CompilerCase #PB_OS_MacOS
    Structure mach_timebase_info_t
      numer.l
      denom.l
    EndStructure
    ImportC ""
      mach_timebase_info.i( *info.mach_timebase_info_t )
      mach_absolute_time.q()
    EndImport

CompilerEndSelect
;}


; ============================================================================
;  GLOBALS
; ============================================================================
;{
Global s_qpc_start.d
Global s_qpc_res  .d
;}


; ============================================================================
;  PROCEDURES
; ============================================================================
;{
; ----------------------------------------------------------------------------
;  raaQPCInitOnce
; ----------------------------------------------------------------------------
Procedure raaQPCInitOnce()
  
  CompilerSelect #PB_Compiler_OS
      
    ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  WINDOWS
    ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;{
    CompilerCase #PB_OS_Windows
      
      Protected v.q = 0
      
      If Not QueryPerformanceFrequency_( @v )
        MessageRequester( "Performance Counter", "High-Resolution Performance Counter NOT Supported!" )
        End
      EndIf
      
      If Not v
        MessageRequester( "Performance Counter", "High-Resolution Performance Counter NOT Supported!" )
        End
      EndIf
      
      s_qpc_res = 1.0/v
      
      QueryPerformanceCounter_( @v )
      
      s_qpc_start = v*s_qpc_res
    ;}
      
    ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  LINUX
    ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;{
    CompilerCase #PB_OS_Linux
      
      Protected v.timespec_t
      
      If clock_getres( #CLOCK_MONOTONIC, @v )
        MessageRequester( "Performance Counter", "High-Resolution Performance Counter NOT Supported!" )
        End
      EndIf
      
      s_qpc_res = 1.0e-9*v\tv_nsec
      
      If clock_gettime( #CLOCK_MONOTONIC, @v )
        MessageRequester( "Performance Counter", "High-Resolution Performance Counter NOT Supported!" )
        End
      EndIf
      
      s_qpc_start = v\tv_sec + v\tv_nsec*s_qpc_res
    ;}
      
      
    ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  MAC OS
    ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;{
    CompilerCase #PB_OS_MacOS
      
      Protected v.mach_timebase_info_t
      
      mach_timebase_info( @v ) ; returned error ?
      
      s_qpc_res = 1.0e-9 * v\numer / v\denom
      
      s_qpc_start =  mach_absolute_time()*s_qpc_res
    ;}
    
  CompilerEndSelect
  
EndProcedure

; ----------------------------------------------------------------------------
;  raaQPCGetAppTime
; ----------------------------------------------------------------------------
Procedure.d raaQPCGetAppTime()
  
  CompilerSelect #PB_Compiler_OS
      
    ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  WINDOWS
    ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;{
    CompilerCase #PB_OS_Windows
    
      Protected time.q = 0
      
      QueryPerformanceCounter_( @time )
      
      ProcedureReturn time*s_qpc_res - s_qpc_start
    ;}
      
    ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  LINUX
    ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;{
    CompilerCase #PB_OS_Linux
    
      Protected v.timespec_t
      
      clock_gettime( #CLOCK_MONOTONIC, @v )
      
      ProcedureReturn v\tv_sec + v\tv_nsec*s_qpc_res - s_qpc_start
    ;}
      
    ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;  MAC OS
    ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ;{
    CompilerCase #PB_OS_MacOS
    
      ProcedureReturn mach_absolute_time()*s_qpc_res - s_qpc_start
    ;}
      
  CompilerEndSelect
  
EndProcedure
;}


; ============================================================================
;  MAIN
; ============================================================================

raaQPCInitOnce()

Delay( 1000 )

MessageRequester( "Query Performance Counter", "Delay after ~1sec : "+ StrD(raaQPCGetAppTime()) )

End


; ============================================================================
;  EOF
; ============================================================================
Cheers,
Guy.
guy rabiller | radfac founder / ceo | raafal.org
User avatar
idle
Always Here
Always Here
Posts: 5915
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: [crossplatform] Nano Seconds Timer

Post by idle »

Thanks
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: [crossplatform] Nano Seconds Timer

Post by grabiller »

Here is an updated version of the real-time clock utility.

Now it's a Module, with 'milliseconds', 'microseconds' and 'milliseconds' procedures added for convenience.

This file is directly extracted from the raafal project but as there are no dependency you can use it 'as-is':

Code: Select all

; ============================================================================
;
;  Copyright (c) 2014, Guy Rabiller, RADFAC.
;  All rights reserved, worldwide.
;
;  Redistribution  and  use  in  source  and  binary  forms,  with or  without
;  modification, are permitted provided that the following conditions are met:
;
;  - Redistributions of  source code  must retain  the above copyright notice,
;    this list of conditions and the following disclaimer.
;  - Redistributions in binary form must reproduce the above copyright notice,
;    this list of conditions and the following disclaimer in the documentation
;    and/or other materials provided with the distribution.
;  - Neither the name of  RADFAC nor the names of its contributors may be used
;    to  endorse  or  promote  products  derived  from  this  software without
;    specific prior written permission.
;
;  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
;  AND ANY EXPRESS OR IMPLIED WARRANTIES,  INCLUDING,  BUT NOT LIMITED TO, THE
;  IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
;  ARE DISCLAIMED.  IN NO EVENT SHALL THE  COPYRIGHT HOLDER OR CONTRIBUTORS BE
;  LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
;  CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT  LIMITED  TO,  PROCUREMENT OF
;  SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA,  OR PROFITS; OR BUSINESS
;  INTERRUPTION) HOWEVER CAUSED  AND ON ANY  THEORY OF  LIABILITY,  WHETHER IN
;  CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING  NEGLIGENCE OR OTHERWISE)
;  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
;  POSSIBILITY OF SUCH DAMAGE.
;
;  For permission, contact copy@radfac.com.
;
; ============================================================================
;  raafal.core.rtc.pbi
; ............................................................................
;  Raafal Real Time Clock Module
; ============================================================================
;  2014/06/12 | Guy Rabiller
;  - creation
; ============================================================================


; ============================================================================
;  rtc
; ============================================================================
DeclareModule rtc
  EnableExplicit
  Declare.d apptime() ; application time in seconds with nanoseconds precision
  Declare.q milliseconds()
  Declare.q microseconds()
  Declare.q nanoseconds()
EndDeclareModule
Module rtc
  ; --------------------------------------------------------------------------
  ;  Import
  ; --------------------------------------------------------------------------
  CompilerSelect #PB_Compiler_OS
    ; ~~~[ Windows ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CompilerCase #PB_OS_Windows
      ; NOP
    ; ~~~[ Linux ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CompilerCase #PB_OS_Linux
      #CLOCK_MONOTONIC = 1
      Structure timespec_t
        tv_sec.i
        tv_nsec.i
      EndStructure
      ImportC ""
        clock_getres.i ( clock_id.i, *res.timespec_t )
        clock_gettime.i( clock_id.i, *tp.timespec_t  )
      EndImport
    ; ~~~[ MacOSX ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CompilerCase #PB_OS_MacOS
      Structure mach_timebase_info_t
        numer.l
        denom.l
      EndStructure
      ImportC ""
        mach_timebase_info.i( *info.mach_timebase_info_t )
        mach_absolute_time.q()
      EndImport
  CompilerEndSelect
  ; --------------------------------------------------------------------------
  ;  Globals
  ; --------------------------------------------------------------------------
  Global s_qpc_start.d
  Global s_qpc_res  .d
  ; --------------------------------------------------------------------------
  ;  Procedures
  ; --------------------------------------------------------------------------
  Procedure.i init()
    CompilerSelect #PB_Compiler_OS
      ; ~~~[ Windows ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      CompilerCase #PB_OS_Windows
        Protected v.q = 0
        If Not QueryPerformanceFrequency_( @v ) : ProcedureReturn #False : EndIf
        If Not v                                : ProcedureReturn #False : EndIf
        s_qpc_res = 1.0/v
        QueryPerformanceCounter_( @v )
        s_qpc_start = v*s_qpc_res
      ; ~~~[ Linux ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      CompilerCase #PB_OS_Linux
        Protected v.timespec_t
        If clock_getres( #CLOCK_MONOTONIC, @v ) : ProcedureReturn #False : EndIf
        s_qpc_res = 1.0e-9*v\tv_nsec
        If clock_gettime( #CLOCK_MONOTONIC, @v ) : ProcedureReturn #False : EndIf
        s_qpc_start = v\tv_sec + v\tv_nsec*s_qpc_res
      ; ~~~[ MacOSX ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      CompilerCase #PB_OS_MacOS
        Protected v.mach_timebase_info_t
        mach_timebase_info( @v ) ; returned error ?
        s_qpc_res = 1.0e-9 * v\numer / v\denom
        s_qpc_start =  mach_absolute_time()*s_qpc_res
    CompilerEndSelect
  EndProcedure
  Procedure.d apptime()
    CompilerSelect #PB_Compiler_OS
      ; ~~~[ Windows ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      CompilerCase #PB_OS_Windows
        Protected time.q = 0
        QueryPerformanceCounter_( @time )
        ProcedureReturn time*s_qpc_res - s_qpc_start
      ; ~~~[ Linux ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      CompilerCase #PB_OS_Linux
        Protected v.timespec_t
        clock_gettime( #CLOCK_MONOTONIC, @v )
        ProcedureReturn v\tv_sec + v\tv_nsec*s_qpc_res - s_qpc_start
      ; ~~~[ MacOSX ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      CompilerCase #PB_OS_MacOS
        ProcedureReturn mach_absolute_time()*s_qpc_res - s_qpc_start
    CompilerEndSelect
  EndProcedure
  Procedure.q milliseconds()
    ProcedureReturn Round( apptime()*1000, #PB_Round_Nearest )
  EndProcedure
  Procedure.q microseconds()
    ProcedureReturn Round( apptime()*1000000, #PB_Round_Nearest )
  EndProcedure
  Procedure.q nanoseconds()
    ProcedureReturn Round( apptime()*1000000000, #PB_Round_Nearest )
  EndProcedure
  ; --------------------------------------------------------------------------
  ;  Auto-Init
  ; --------------------------------------------------------------------------
  init()
EndModule

; ============================================================================
;  Test
; ============================================================================
CompilerIf #PB_Compiler_IsMainFile
  Debug "Application Time In : "
  Debug "Seconds : "+ StrD( rtc::apptime(), 9 )
  Debug "MicroSeconds : "+ rtc::microseconds()
  Debug "NanoSeconds : "+ rtc::nanoseconds()
  Debug "Apply Delay Of 1001 ms.."
  Delay( 1001 )
  Debug "Application Time In MilliSeconds : "+ rtc::milliseconds()
CompilerEndIf


; ============================================================================
;  EOF
; ============================================================================
guy rabiller | radfac founder / ceo | raafal.org
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: [crossplatform] Nano Seconds Timer

Post by davido »

Very interesting.

Thank you for sharing. :D
DE AA EB
User avatar
minimy
Enthusiast
Enthusiast
Posts: 630
Joined: Mon Jul 08, 2013 8:43 pm
Location: off world

Re: [crossplatform] Nano Seconds Timer

Post by minimy »

Really interesting!
Thanks grabiller, great code!
time spent to write this: 18''.98392873829 :wink:
If translation=Error: reply="Sorry, Im Spanish": Endif
coco2
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Re: [crossplatform] Nano Seconds Timer

Post by coco2 »

Nice!
Post Reply