Home > Articles > Programming > C/C++

C++ Reference Guide

Hosted by

High Resolution Time Measurement and Timers, Part I

Last updated Jan 1, 2003.

Standard C++ inherited the <ctime> time and date library from C. While this library offers many useful time and date facilities, it doesn’t support a high-resolution time measurement. The POSIX standard defines extensions to this library which are capable of measuring time in microseconds (millionths of a second) and even nanoseconds (billionths of a second). Let’s see how they are used.

Measuring Time

First, let’s look at a quick reminder. In standard C and C++, you use the time() function to obtain the current timestamp. The time is represented as the number of seconds that have elapsed since The Epoch, or 1/1/1970 at midnight. In a typical 32 bit system, time_t will rollover in 2038. However, as more platforms are gradually moving to a 64 bit time_t, this time bomb so to speak will have disappeared by then.

POSIX defines a fine-grained time measuring function called gettimeofday():

#include <sys/time.h>
#include <unistd.h>
int gettimeofday(struct timeval * tv, struct timezone *tz);

If struct timeval looks familiar, it’s because I discussed awhile ago when I explained non-blocking I/O using select(). Its declaration is repeated here for convenience:

struct timeval
{
 int tv_sec; /*seconds*/
 int tv_usec; /*microseconds*/
};

struct timezone is declared as follows:

struct timezone
{
 int tz_mniuteswest; /*minutes west of Greenwich*/
 int tz_dsttime; /*dst correction type*/
};

The actual resolution of gettimeofday() depends on the hardware architecture. Intel processors as well as SPARC machines offer high resolution timers that measure microseconds. Other hardware architectures fall back to the system’s timer, which is typically set to 100 Hz. In such cases, the time resolution will be less accurate.

The following code listing displays the current timestamp in seconds and microseconds:

struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
printf("the current time of day represented as time_t is %d and %d microseconds", tv.tv_sec, tv.tv_usec);

Using Timers

A timer is a resource that enables a process or a thread to schedules an event. A program uses a timer to ask the kernel to notify it when a certain amount of time has elapsed. There are two types of timer: synchronous and asynchronous. When a process uses a timer synchronously, it waits until the timer expires, usually by means of calling sleep() or a similar syscall. Sleeping means that the process is removed from the kernel’s scheduler for a certain amount of time. POSIX defines four different functions for sleeping, each of which measures time in different units.

sleep()

sleep() causes the process to sleep at least nsec seconds or until a <a href=" http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=125">signal</a> that the process doesn’t ignore is received.

unsigned int sleep (unsigned int nsec);

If sleep() hasn’t slept nsec seconds, it returns the number of seconds left. Otherwise, it returns 0. sleep() is mostly useful for polling a certain resource in fixed intervals of time. For example, a mail client that polls its mail server every 10 minutes can use a loop that contains a sleep(600); call. This is also the most common syscall for sleeping.

usleep()

usleep() causes the process to sleep for at least usec microseconds:

void usleep (unsigned long usec);

usleep() causes the process to sleep for at least usec microseconds. No signals are used in this case. Most implementations use select() to implement this function. It’s equivalent to calling:

timeval tv;
tv.tv_sec=0;
tv.tv_usec=usec;
int select(0, NULL, NULL, NULL, &tv);

nanosleep()

nanosleep() offers a resolution of nanoseconds:

int nanosleep(struct timespec *req, struct timespec * rem);

The struct timespec is declared as follows:

struct timspec
{
 long int tv_sec; /*as in timeval*/
 long int tv_nsec; /*nanoseconds*/
};

nanosleep() causes the process to sleep at least the amount of time indicated in req or until a signal is received. If nanosleep() terminates earlier due to a signal it returns -1 and rem is filled with the remaining time. nanosleep() offers the highest resolution (theoretically, up to a billionth of a second) although it’s the least portable of these four functions. This function is mostly used in real-time environments, allowing a process to sleep a precise amount of time.

In the second part of this series I will discuss interval timers, a facility that delivers signals on a regular basis to a process.