[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::digital_unix

Title:DIGITAL UNIX(FORMERLY KNOWN AS DEC OSF/1)
Notice:Welcome to the Digital UNIX Conference
Moderator:SMURF::DENHAM
Created:Thu Mar 16 1995
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:10068
Total number of notes:35879

10007.0. "POSIX 4.0 TIMERS PROBLEM" by IB004::BERNAT () Mon Jun 02 1997 06:55


 I faced a problem working with real-time timers under POSIX 4.0
 on Digital Unix version 4.0.

My application requires a real time timer to generate a signal
 every sampling period, in order to gather data from a physical
 process. This sampling period must be constant (about 3 milliseconds).

I  built a little test program in order to work out the timing
 precision provided by POSIX 4.0 interface of Digital Unix 4.0.
 This program called "rt_test4.c" comes in the next pages.

The working is very simple. Every time the timer generates a
 SIGALRM signal, the current time is obtained through a call to
 the function "clock_gettime()". This time in microseconds 
is sent to the standard output, as well as the difference with 
regard to the value returned by "clock_gettime()" in the
 previous call.

In theory, these differences should be constant and a multiple
 of the resolution of the timer.
Nevertheless, the differences are not multiple of the resolution
, 976562 nanoseconds, but multiple of 976000 nanoseconds. 
This problem is not very important because I could choose a 
sampling period multiple of 976000 nanoseconds.
There is another problem much more important. Every time the field 
"tv_sec" of the structure returned by "clock_gettime()" 
changes of value, a change in the difference happens. Therefore,
 once per second, my system would take an incorrect sample.

In the next pages you can find the ASCII files generated by
 the program for 2 different settings of period between SIGALRM
 signals. "rt_out4.dat1" is for a period of 976 
microseconds whereas "rt_out4.dat2" is for a period of
 (60*976) microseconds. Only relevant samples of time were kept,
 the rest were substituted by horizontal ellipses.

How can I do to fix the problem with real time timers ?


Apart from the problem with timers, I faced also a problem with
 the definition of constants "MCL_CURRENT" and
 "MCL_FUTURE" to lock memory. In theory, these constants should be 
accesible, by simply including the header <sys/mman.h>.
 Nevertheless, it was also necessary to define the constant
 "_OSF_SOURCE". This behaviour, I think, is out of the standard 
and is not documented anywhere.

Defining the constant "_OSF_SOURCE" in my source files may generate
 some kind of problems working with POSIX 4.0 interface ?




Please, I hope you can answer as soon as possible.
 Thank you very much in advance.


     Jos� Mar�a Bernat (CSC Barcelona)




 /*              rt_test4.c

   This is a little program to test POSIX4.0 real time timers.

   A real time timer is installed. This timer generates a SIGGALRM
   signal every TIME_PERIOD microseconds

   After the initialization phase, the process enters into an infinite
   loop whose first instruction is wait for the SIGALRM signal. Then the
   process awakes, gets the current time of the timer and prints:
 
     - time value of the timer
     - difference of that value with regard to the value got in the
       previous cycle

   In order to avoid swapping and paging problems memory is locked.
   Besides, priority of the process is set to the maximum so as to prevent
   other process from taking over the CPU.
   Finally this program runs under superuser privileges.

   The compilation command is:

       cc -non_shared -w0 rt_test4.c -lrt -o rt_test4

   Output of the program was redirected to the file "rt_out4.dat"
             
*/


/* ??????????
   definition of _OSF_SOURCE is needed in order to deal
   with the constants MCL_CURRENT and MCL_FUTURE.
   May it produce some kind of lateral effects in my
   programs ?, because this behaviour is out of the standar. */
#define _OSF_SOURCE


#define _POSIX_C_SOURCE 199309 /* POSIX4.0 */

#include <unistd.h>
#include <sys/mman.h>
#include <signal.h>
#include <time.h>
#include <sched.h>
#include <math.h>
#include <stdio.h>

#define TIME_PERIOD  (60 * 976) /* time period in microseconds between 2 */
                                /* subsequent alarms */

#define BUFFER_SIZE (1024 * 1024)

/* buffer where output will be stored until program exits and it is
   dumped */
char               buffer[BUFFER_SIZE];



void control_c_handler(int signum)
{
  /* the program ends after a ^C, dumping the information contained
     in the buffer */
  fprintf(stderr, "\nTiming trace dumped");
  printf(buffer);
  fprintf(stderr, "\nAborting process\n\n");
  exit(0);
}


 void main()
{
  sigset_t           these_sigs;
  timer_t            created_timer;
  struct itimerspec  timer_setting;
  struct timespec    realtime_res;
  struct timespec    now;
  FILE *             file_ptr;
  int                init = 1;
  double             time_usec;
  double             prev_time_usec;
  struct sched_param scheduling_parameters;
  struct sigaction   action;
  char               *buffer_ptr;

  /* set scheduling policy to FIFO and priority to maximum */
  if ((scheduling_parameters.sched_priority = 
       sched_get_priority_max(SCHED_FIFO)) == -1)
    perror("sched_get_priority_max");
  if (sched_setscheduler(getpid(), SCHED_FIFO, &scheduling_parameters) == -1)
    perror("sched_setscheduler");

  /* lock memory */
  if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1)
    perror("mlockall");

  /* create a timer that generates a periodic SIGALRM every 976 microseconds */
  (void)timer_create(CLOCK_REALTIME, NULL, &created_timer); 
  timer_setting.it_value.tv_sec = 1;
  timer_setting.it_value.tv_nsec = 0;
  timer_setting.it_interval.tv_sec = 0;
  timer_setting.it_interval.tv_nsec = TIME_PERIOD*1000;
  (void)timer_settime(created_timer, 0, &timer_setting, NULL);

  /* set the handler for the ^C */
  action.sa_handler = control_c_handler;
  (void)sigemptyset(&action.sa_mask);
  action.sa_flags = 0;
  if (sigaction(SIGINT, &action, (struct sigaction *)NULL) == -1)
    perror("sigaction");
  (void)sigfillset(&these_sigs);
  (void)sigdelset(&these_sigs, SIGINT);
  (void)sigprocmask(SIG_BLOCK, &these_sigs, NULL);
  
  /* "sigwaitinfo" will wait for SIGALRM */
  (void)sigemptyset(&these_sigs);
  (void)sigaddset(&these_sigs, SIGALRM);
  /* initialize the buffer pointer */
  buffer_ptr = buffer;
  /* get real time clock resolution */
  (void)clock_getres(CLOCK_REALTIME, &realtime_res);
  buffer_ptr += 
    sprintf(buffer_ptr, "\nReal time clock resolution = %f useconds\n\n",
	    realtime_res.tv_sec * 1000000.0 +
	    realtime_res.tv_nsec / 1000.0);
  for (;;)
    {
      /* sleep until a SIGALRM arrives */
      (void)sigwaitinfo(&these_sigs, NULL);
      
      /* get the current time */
      (void)clock_gettime(CLOCK_REALTIME, &now);

      prev_time_usec = time_usec;

      /* calculate the current time in microseconds */
      time_usec = now.tv_sec * 1000000.0 + now.tv_nsec /1000.0;
    
      if (init == 1)
	init = 0;
      else
	if ((buffer_ptr - buffer) < (BUFFER_SIZE - 256))
	  buffer_ptr +=
	    sprintf(buffer_ptr, "%f\t%f\n", time_usec, 
		    time_usec - prev_time_usec);
    }
}
			rt_out4.dat1

Real time clock resolution = 976.562000 useconds

864927879989664.000000	976.000000
864927879990640.000000	976.000000
864927879991616.000000	976.000000
864927879992592.000000	976.000000
864927879993568.000000	976.000000
864927879994544.000000	976.000000
864927879995520.000000	976.000000
864927879996496.000000	976.000000
864927879997472.000000	976.000000
864927879998448.000000	976.000000
864927880000000.000000	1552.000000	<---------- PROBLEM !!!!
864927880000976.000000	976.000000
864927880001952.000000	976.000000
	............................

864927880995520.000000	976.000000
864927880996496.000000	976.000000
864927880997472.000000	976.000000
864927880998448.000000	976.000000
864927881000000.000000	1552.000000  <---------- PROBLEM !!!!
864927881000976.000000	976.000000
864927881001952.000000	976.000000
864927881002928.000000	976.000000
  	............................

864927881995520.000000	976.000000
864927881996496.000000	976.000000
864927881997472.000000	976.000000
864927881998448.000000	976.000000
864927882000000.000000	1552.000000  <---------- PROBLEM !!!!
864927882000976.000000	976.000000
864927882001952.000000	976.000000
864927882002928.000000	976.000000
864927882003904.000000	976.000000
864927882004880.000000	976.000000
864927882005856.000000	976.000000
864927882006832.000000	976.000000
	............................

864927882995520.000000	976.000000
864927882996496.000000	976.000000
864927882997472.000000	976.000000
864927882998448.000000	976.000000
864927883000000.000000	1552.000000  <---------- PROBLEM !!!!
864927883000976.000000	976.000000
864927883001952.000000	976.000000
	............................
 			rt_out4.dat2

Real time clock resolution = 976.562000 useconds

864928070461648.000000	58560.000000
864928070520208.000000	58560.000000
864928070578768.000000	58560.000000
864928070637328.000000	58560.000000
864928070695888.000000	58560.000000
864928070754448.000000	58560.000000
864928070813008.000000	58560.000000
864928070871568.000000	58560.000000
864928070930128.000000	58560.000000
864928070988688.000000	58560.000000
864928071048800.000000	60112.000000  <---------- PROBLEM !!!!
864928071107360.000000	58560.000000
864928071165920.000000	58560.000000
864928071224480.000000	58560.000000
864928071283040.000000	58560.000000
864928071341600.000000	58560.000000
864928071400160.000000	58560.000000
864928071458720.000000	58560.000000
864928071517280.000000	58560.000000
864928071575840.000000	58560.000000
864928071634400.000000	58560.000000
864928071692960.000000	58560.000000
864928071751520.000000	58560.000000
864928071810080.000000	58560.000000
864928071868640.000000	58560.000000
864928071927200.000000	58560.000000
864928071985760.000000	58560.000000
864928072045872.000000	60112.000000  <---------- PROBLEM !!!!
864928072104432.000000	58560.000000
864928072162992.000000	58560.000000
864928072221552.000000	58560.000000
	............................

864928072924272.000000	58560.000000
864928072982832.000000	58560.000000
864928073042944.000000	60112.000000  <---------- PROBLEM !!!!
864928073101504.000000	58560.000000
864928073160064.000000	58560.000000
	............................

864928073862784.000000	58560.000000
864928073921344.000000	58560.000000
864928073979904.000000	58560.000000
864928074040016.000000	60112.000000  <---------- PROBLEM !!!!
864928074098576.000000	58560.000000
864928074157136.000000	58560.000000
	............................

T.RTitleUserPersonal
Name
DateLines
10007.1SMURF::DENHAMDigital UNIX KernelMon Jun 02 1997 11:5918
    The _OSF_SOURCE and the mman.h header file thing is a bug. Please
    QAR it. The best workaround is to *not* define any standards
    macros when you build -- then you get everything for free.
    
    As to the behavior of the clock, you're things are they really
    are. First, the kernel keeps time with microsecond resolution,
    not nanosecond. So those extra nanoseconds you're getting back
    don't really exist as far as the kernel is concerned. But they
    do add up, as you've seen.
    
    The other effect you're seeing is that once a second the kernel
    has to make up for the fact that is clock frequency isn't a multiple
    of 10. So it adds the missing microseconds (576 on most platforms,
    400 on the 4100 series) into the system time to keep in synch.
    
    You can virtually eliminate this leap effect by turning on the
    MICRO_TIME option, which tends to smooth out the movements
    of the system time.
10007.2"core dumped" ooopsHELIX::SONTAKKEMon Jun 02 1997 18:086
    Was there any load on the system?  Because when you really want to use
    your sampling period to do "some real work", the 3 ms time period is
    going to be *very* close.  I hope the system is not connected to
    nuclear power plant or something like that :-)
    
    - Vikas
10007.3How I turn the MICRO_TIME option on ?IB004::BERNATThu Jun 05 1997 03:384
How can I turn the MICRO_TIME option on ?
I've tried, but result was not the expected. Could you help me with this ?

Thank you very again.
10007.4options MICRO_TIMERHETT::PARKERThu Jun 05 1997 10:0511
    
    Place the following in /sys/conf/SYSNAME :
    
    options	MICRO_TIME
    
    and then rebuild the kernel.  This is in the release notes.
    
    Hth, 
    
    Lee