CS 4953 Concurrency and Communication Notes: Times and Timers

1. Times in UNIX:

This material is taken from USP, Chapter 9.

Time in seconds since the Epoch:
Epoch: midnight, January 1, 1970 (Coordinated Universal Time or UTC or GMT)
The C standard defines the following functions:
Note: These return values in static objects and so they are not thread safe.

Look at programs simpletiming, timeprint, and badtiming.

The struct tm:

   int tm_sec;       /* seconds after the minute [0,60] */
   int tm_min;       /* minutes after the hour [0,59] */
   int tm_hour;      /* hours since midnight [0,23] */
   int tm_mday;      /* day of the month [1,31] */
   int tm_mon;       /* months since January [0,11] */
   int tm_year;      /* years since 1900 */
   int tm_wday;      /* days since Sunday [0,6] */
   int tm_yday;      /* days since January 1 [0,365] */
   int tm_isdst;     /* flag indicating Daylight Savings Time */

Thread safe versions:

  char *asctime_r(const struct tm *restrict timeptr, char *restrict buf);
  char *ctime_r(const time_t *clock, char *buf);
  struct tm *gmtime_r(const time_t *restrict timer,
                       struct tm *restrict result);
  struct tm *localtime_r(const time_t *restrict timer,
                       struct tm *restrict result);
Times in POSIX:XSI --- struct timeval

   time_t   tv_sec;   /* seconds since the Epoch */
   time_t   tv_usec;  /* and microseconds */

int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
The second parameter must be NULL.
Returns the time since the Epoch.

Look at gettimeofdaytiming and gettimeofdaytest.

Look at typical results of gettimeofdaytest on various platforms.

Times in POSIX:TMR --- struct timespec

    time_t  tv_sec;  /* seconds */
    long    tv_nsec; /* nanoseconds */
POSIX:TMR uses "clocks" represented by variables of type clockid_t.
Most common one is CLOCK_REALTIME

   int clock_getres(clockid_t clock_id, struct timespec *res);
   int clock_gettime(clockid_t clock_id, struct timespec *tp);
   int clock_settime(clockid_t clock_id, const struct timespec *tp);
clock_getres gives the resolution for setting the clock.
This is not necessarily time resolution for getting the time with clock_gettime.

Look at clockrealtimetiming and clockrealtimetest.

Look at typical results of clockrealtimetest on various platforms.

The times function

clock_t times(struct tms *buffer);
Returns the elapsed time in clock ticks since some arbitrary time.
The struct tms contains:
  clock_t   tms_utime;  /* user CPU time of process */
  clock_t   tms_stime;  /* system CPU time on behalf of process  */
  clock_t   tms_cutime  /* user CPU time of process and terminated children */
  clock_t   tms_cstime; /* system CPU time of process and terminated children */

Look at cpufraction and timechild.

Typical number of clock ticks per seconds is only 100, so this is not too useful.

timechild cpufraction
The number of ticks per second is 100.000000
Total CPU time for operation is 3.130000 seconds
Fraction of CPU time used is 0.695556
cpufraction used 315 clock ticks or 3.150000 seconds

High resolution time in Solaris: gethrtime

     #include <sys/time.h>
     hrtime_t gethrtime(void);
The gethrtime() function returns the current high-resolution real time.
Time is expressed as nanoseconds since some arbitrary time in the past;
It is not correlated in any way to the time of day. The hires timer is ideally suited to performance measurement tasks, where cheap, accurate interval timing is required.

Sleep Functions

You should be familiar with

     #include <unistd.h>
     unsigned sleep(unsigned seconds);

This sleeps for at least seconds seconds.
It may sleep longer.
The sleep function interacts with SIGALRM so do not use them concurrently.

It may be possible to get better resolution with the following:

     #include <time.h>
     int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
This suspends execution until either the time interval specified by rqtp has elapsed or a signal is caught.
If interrupted by a signal and rmtp is not NULL, rmtp contains the unslept time.
The resolution is determined by the system clock CLOCK_REALTIME.
Typically this is about 10 ms.

Look at the program nanotest, Program 9.6, and the results on various systems.

Interval Timer Concepts

POSIX:XSI Interval Timers

Structure used for times: struct itimerval
This contains two fileds of type struct timeval, the same type used by gettimeofday:

   struct timeval it_value;
   struct timeval it_interval;
There are 3 type of timers, corresponding to the type of clock used.
   #include <sys/time.h>
   int getitimer(int which, struct itimerval *value);
   int setitimer(int which, const struct itimerval *restrict value,
                            struct itimerval *restrict ovalue);
Look at Program 9.7, periodicasterisk that uses ITIMER_PROF.

Look at Program 9.8, xsitimer for timing a program using ITIMER_VIRTUAL.

Realtime Signals (review)
In 1993 a new signal interface was added to the POSIX standard.

The sigaction structure has been extended to include an additional field:
  #include <signal.h>
 
  struct sigaction {
     void (*sa_handler)(); /* SIG_DFL, SIG_IGN, or
                              pointer to function */
     void (*sa_sigaction)(int, siginfo_t *, void *);
     sigset_t sa_mask;     /* additional signals to be blocked
                              during execution of handler */
     int sa_flags;         /* special flags and options */
  };
This defines a new data type: siginfo_t which is a structure containing at least the following:
    int si_signo;            /* signal number */
    int si_code;             /* cause of the signal */
    union sigval si_value;   /* signal value */
where the union sigval contains at least:
    int sival_int;
    void *sival_ptr;
When the sa_flags field has the SA_SIGINFO flag set, then sa_sigaction is used for the signal handler rather than sa_handler.

The system call to send one of these signals is called sigqueue rather than kill:

  #include <signal.h>
 
  int sigqueue(pid_t pid, int signo, const union sigval value);

On some systems, only certain signals can be queued, those between SIGRTMIN and SIGRTMAX.

Program 9.9 shows a program to send a queued signal to a process. Note that there is no command line function similar to kill.

Program 9.10, gives an example program that can receive SIGUSR1 signals.

POSIX:TMR Interval Timers

Structure used for times: struct itimerspec
This contains two fileds of type struct timespec, the same type used by clock_gettime:

   struct timespec it_interval;
   struct timespec it_value;
You create a timer before you can do a set or get.
  #include <signal.h>
  #include <time.h>

  int timer_create(clockid_t clock_id, struct sigevent *restrict evp,
                   timer_t *restrict timerid);

  struct sigevent {
        int            sigev_notify   /* notification type */
        int            sigev_signo;   /* signal number */
        union sigval   sigev_value;   /* signal value */
  };

  union sigval {
        int            sival_int;     /* integer value */
        void           *sival_ptr;    /* pointer value */
  };
TMR timers are manipulated with the following:
  #include <time.h>

  int timer_getoverrun(timer_t timerid);
  int timer_gettime(timer_t timerid, struct itimerspec *value);
  int timer_settime(timer_t timerid, int flags,
       const struct itimerspec *value, struct itimerspec *ovalue);
The flags parameter indicates with relative or absolute times. We will look at absolute times in the next section. Look at Program 9.11, periodicmessage.

Look at Program 9.12, tmrtimer for timing a program using CLOCK_REALTIME.

Timer Drift, Overruns, and Absolute Time

Problem with relative times:

The problem is even worse because of the clock resolution.
expiration number 1 2 3 4 5 6 7 8 9 10
time 0306090120150180210240270300
drift 0 81624 32 40 48 56 64 72 80
desired expiration 22446688110132154176198220242
timer set for 22222222 22 22 22 22 22 22 22
rounded to resolution 30303030 30 30 30 30 30 30 30

With absolute time, you specify the absolute time the timer should expire and the system sets the timer with the appropriate relative time based on the current time.

expiration number 1 2 3 4 5 6 7 8 9 10
time 030507090110140160180200220
drift 0 864 2 0 8 6 4 2 0
desired expiration 22446688110132154176198220242
timer set for 22141618 20 22 14 16 18 20 22
rounded to resolution 30202020 20 20 30 20 20 20 30
The XSI timers do not support absolute time directly, but you can implement it yourself in the signal handler by comparing the current time to the time the next expiration should take place.

The program abstime uses TMR timers to explore 3 ways of setting up periodic timers.

abstime -a | -r | -p [inctime [numtimes [spintime]]]

Look at results of running abstime on Linux and Solaris.

Counting Signals

The program timesignals wait for a signal to come in and then times how long it takes 1000 additional signals to come in.

The Program mulitkill sends signals as fast as possible.

Look at the output from these functions.

How would you modify these two functions so that you could tell how many signals are sent before 1000 signals are received?