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.
-
The header appears to be missing.
-
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). -
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. -
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. -
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