POSIX clocks and timers

Hello,

We’re currently envisaging the QNX4->Momentics migration and I’m doing
some preliminary evaluations. I’m using Momentics NC on a Pentium III
with 700Mhz.

My first goal is to reliably trigger a task every x milliseconds with
minimal jitter, with x in the range of about 2 to 5.

However… Trying to do things the POSIX way was somewhat of a failure.
The source code of my example is attached below (a simple C++ utility to
compute a histogram of the timing delays), and here are my
comments/questions.

  1. The header appears to be missing.

  2. sysconf() with _SC_REALTIME_SIGNALS reports invalid argument,
    although _SC_REALTIME_SIGNALS is defined (obviously, otherwise the
    example wouldn’t compile). Are realtime signals supported (SIGRTMIN
    through SIGRTMAX)? (They appear to work OK).

  3. What about CLOCK_MONOTONIC? It is defined by the headers if you
    define _QNX_SOURCE, but I couldn’t find any documentation about it.
    clock_getres() with CLOCK_MONOTONIC reports invalid argument, so I
    suppose it’s unsupported.

  4. This leaves us with CLOCK_REALTIME. It’s resolution, however, is
    999847 nanoseconds, which is very coarse [*]. Solaris has a CLOCK_HIGHRES
    with 5 nanoseconds, and SGI has one (can’t remember its ID) with 21
    nanoseconds.

  5. Are there any clocks with higher resolution than 999847 nanoseconds
    in QNX?

Kind regards,
-Gerhard

[*] It might just be enough for my purpose. I’ll have to do some more
measurements.

========================================================================

#define _POSIX_C_SOURCE 199506
#define _QNX_SOURCE
#include
#include
#include
// #include

#include
#include
#include // for perror


#include <time.h>
#include <unistd.h>
#include <sched.h>
#include <signal.h>



// clockid_t const MY_CLOCK = CLOCK_REALTIME ; // Std. Posix
clockid_t const MY_CLOCK = CLOCK_MONOTONIC ; // QNX
// clockid_t const MY_CLOCK = CLOCK_HIGHRES ; // Solaris
// clockid_t const MY_CLOCK = CLOCK_SGI_CYCLE ; // Solaris
// int const MY_SIGNAL = SIGUSR1 ;
int const MY_SIGNAL = SIGRTMIN ;


inline unsigned long get_nsec() {

timespec t ;
::clock_gettime( CLOCK_REALTIME , &t ) ;
return t.tv_nsec ;

}




void die( char const* msg ) {

std::perror( msg ) ;
std::exit( 1 ) ;

}


void check_rtsig() {

errno = 0 ;
long const i = ::sysconf( _SC_REALTIME_SIGNALS ) ;
if( errno ) { die( “sysconf” ) ; }

if( i <= 0 ) {
std::cerr << “realtime signals not supported\n” ;
std::exit( 1 ) ;
}

}


unsigned long interval , bins , rounds ;
std::vector< double > hist ;
double range ;

void counter() {

static unsigned long count = 0 ;
static unsigned long last = 1000000000 ;

unsigned long const cur = get_nsec() ;

if( last < 1000000000 ) {

unsigned long const delta = cur - last ;
unsigned long const j =
static_cast< unsigned long >( ( delta / range ) * bins ) ;

if( j < bins ) { ++hist[ j ] ; }

}

last = cur ;

if( ++count >= rounds ) {

for( unsigned long i = 0 ; i < hist.size() ; ++i )
{ std::cout << hist[ i ] << ‘\n’ ; }

std::exit( 0 ) ;

}


}





void set_sched() {

sched_param sp ;

sp.sched_priority = sched_get_priority_max( SCHED_RR ) ;

if( sched_setscheduler( 0 , SCHED_RR , &sp ) < 0 ) {

std::cerr << “warning: couldn’t set scheduling parameters\n” ;

}

}





int main( int argc , char const * const *argv ) {

// std::ios_base::sync_with_stdio( false ) ;

// check_rtsig() ;
set_sched() ;


if( argc != 4 ) {

std::cerr << “usage: " << argv[ 0 ] << " interval (nsec) bins rounds\n” ;
return 1 ;

}

interval = static_cast< unsigned long >( std::atof( argv[ 1 ] ) ) ;
bins = static_cast< unsigned long >( std::atof( argv[ 2 ] ) ) ;
rounds = static_cast< unsigned long >( std::atof( argv[ 3 ] ) ) ;

range = interval * 10. ;

hist.resize( bins ) ;


{
timespec res ;
if( ::clock_getres( MY_CLOCK , &res ) < 0 )
{ die( “clock_getres” ) ; }

std::cerr << “clock resolution: "
<< res.tv_sec << " seconds, "
<< res.tv_nsec << " nanoseconds\n” ;
}


#if 0
{

// Set up signal handler.
struct sigaction sa ;
::sigemptyset( &sa.sa_mask ) ;
::sigaddset( &sa.sa_mask , MY_SIGNAL ) ; // block during handler execution
sa.sa_flags = SA_SIGINFO ;
sa.sa_sigaction = ::timer_intr ;

if( ::sigaction( MY_SIGNAL , &sa , 0 ) < 0 )
{ die( “sigaction” ) ; }

}
#endif


// Block MY_SIGNAL. Will be handled by sigwaitinfo().

sigset_t sigs ;
::sigemptyset( &sigs ) ;
::sigaddset( &sigs , MY_SIGNAL ) ;
::sigprocmask( SIG_BLOCK , &sigs , 0 ) ;

{

// Set up timer

::sigevent my_event ;
my_event.sigev_notify = SIGEV_SIGNAL ;
my_event.sigev_signo = MY_SIGNAL ;
// (union: alternative is sival_ptr)
my_event.sigev_value.sival_int = 0 ;

::timer_t timer ;
if( ::timer_create( MY_CLOCK , &my_event , &timer ) < 0 )
{ die( “timer_create” ) ; }

::itimerspec its ;
its.it_value .tv_sec = 0 ;
its.it_value .tv_nsec = 1 ; // arm the timer
its.it_interval.tv_sec = 0 ;
its.it_interval.tv_nsec = interval ;

if( ::timer_settime( timer , 0 , &its , 0 ) < 0 )
{ die( “timer_settime” ) ; }

}


while( 1 ) {

siginfo_t dummy ;
if( ::sigwaitinfo( &sigs , &dummy ) < 0 )
{ die( “sigwaitinfo” ) ; }

counter() ;

}

}


\

| voice: +43 (0)676 6253725 *** web: http://www.cosy.sbg.ac.at/~gwesp/
|
| Passts auf, seid’s vuasichdig, und lossds eich nix gfoin!
| – Dr. Kurt Ostbahn

“Gerhard Wesp” <gwesp@cosy.sbg.ac.at> wrote in message
news:b191kf$h24$2@inn.qnx.com

#define _POSIX_C_SOURCE 199506
#define _QNX_SOURCE

This is a guess, but could having both defined be causing the problem?
There may be some funny mutual exclusion such that certain things are
undefined when one is set regardless of the other.

Try removing the POSIX define and see what happens.

Cheers,
Steve

  1. This leaves us with CLOCK_REALTIME. It’s resolution, however, is
    999847 nanoseconds, which is very coarse…

I’m pretty sure this is the default resolution (1 ms). You can set it
to (almost) anything you want, though. The call you want is
ClockPeriod():

http://www.qnx.com/developer/docs/momentics_nc_docs/neutrino/lib_ref/c/clockperi
od.html

David Wolfe <da5id@luvspamwolfe.name> wrote:

to (almost) anything you want, though. The call you want is
ClockPeriod():

Thanks, this did the trick.

-Gerhard

| voice: +43 (0)676 6253725 *** web: http://www.cosy.sbg.ac.at/~gwesp/
|
| Passts auf, seid’s vuasichdig, und lossds eich nix gfoin!
| – Dr. Kurt Ostbahn

Steve Cobb <steve_cobb0@yahoo.com> wrote:

Try removing the POSIX define and see what happens.

Didn’t help. Anyway, in the meantime I found some documentation about
CLOCK_MONOTONIC, it seems to be usable only with QNX-specific functions.

-Gerhard

| voice: +43 (0)676 6253725 *** web: http://www.cosy.sbg.ac.at/~gwesp/
|
| Passts auf, seid’s vuasichdig, und lossds eich nix gfoin!
| – Dr. Kurt Ostbahn

Gerhard Wesp <gwesp@cosy.sbg.ac.at> wrote:

David Wolfe <> da5id@luvspamwolfe.name> > wrote:
to (almost) anything you want, though. The call you want is
ClockPeriod():

Thanks, this did the trick.

Please note, though, that the smaller the resolution you ask for,
the greater the system overhead you are imposing. The clock period
(aka tick size, clock resolution) is driven by a hardware interrupt
from an external timer source – if you go from a 1ms to a 1/10 ms
clock period, you have asked for 10* as many interrupts (up from
1000/sec to 10000/sec).

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.