C Tutorial: Get and measure elapsed process time
times: get current process times
The times system call gets the user time and system time used by the current process and its children. User time is the time that the processor spent executing instructions in the process. System time is the time that the processor spent in the operating system executing instructions on behalf of the process. The times system call has the following usage:
Prior to calling times, you'll need to declare a variable of struct tms
that
the system call will fill in. The struct is defined in sys/times.h
as:
Note that all values are in clock_t
units. The actual definition of clock_t
is system-dependent. It is typically a long
but might be a long long
on
some systems. All the time values are expressed in "clock ticks." This is an ever-incrementing count
of the operating system's "ticks". We can obtain the frequency of these ticks via the sysconf
function, which allows us to test and get various system configuration values at runtime. To find
the clock frequency, we use:
The call to sysconf(_SC_CLK_TCK) returns a long
that indicates the number of ticks per second. Both
my Ubuntu Linux and OS X report a value of 100, which means that each tick represents a count of
1/100 second (0.01 s).
Example: reading current process times
This is a small program that does some busy work to use up a bit of CPU time and kernel
resources (in the kill_time function) and then prints the time value in clock ticks.
Note that we cast the time values into type uintmax_t
and call printf
with a format of %j
. This type represents tha largest available integer. You
can usually get away with using long
or long long
.
Save this file by control-clicking or right clicking the download link and then saving it as times.c.
Compile this program via:
If you don't have gcc, You may need to substitute the gcc command with cc or another name of your compiler.
Run the program:
Measure elapsed time between two points in your code
The times system call returns the current tick count.
This is an ever-incrementing number from some arbitrary point in the past.
While this on its own is not useful, we can use it to mark a starting and ending time. The difference between
these two times is the elapsed time. To do this, we don't care about the data placed in the tms
struct.
Linux does reasonable error checking and allows us to call times with a null pointer as a parameter.
OS X, however, tries to write time values into a structure, which causes the program to die due to an
attempt to dereference a null pointer. It is safer to pass a struct tms
pointer that
we will simply ignore.
Example: measuring elapsed time
In the last example, we ignored the return value from a call to times.
In this program, we ignore the struct tms
parameter to times but record
a start time and a stop time. Between these two times, it calls sleep(2) to sleep for two
seconds. It then prints the result in ticks and in seconds. To convert ticks to seconds, you simply
divide the elapsed tick count by the frequency obtained from sysconf(_SC_CLK_TCK).
Note that we ignore the case of the clock overflowing and wrapping back through 0 during our test.
Good programming would dictate that we take this into account.
In practice, the value of clock_t
on my 64-bit processors (my Linux and Mac systems) is
an unsigned 64-bit integer with a clock frequency of 100 ticks per seconds. That corresponds to
a clock wraparound period of 1.8×1017 seconds or 5.8×109 years.
I'll take my chances that this will not happen. With 32 bit machines, you need to be more careful
since the wrap-around time with a 100 Hz clock will be under two years and far less with a higher
frequency clock. If you want to write portable code, you'll need to be aware that wrap-around
can be a very real possibility on some architectures.
Save this file by control-clicking or right clicking the download link and then saving it as elapsed.c.
Compile this program via:
If you don't have gcc, You may need to substitute the gcc command with cc or another name of your compiler.
Run the program:
The clock function
The clock library function (not system call) provides an analogous approach to the return value of times to mark start and end times. Clock takes no parameter and returns an estimate of the processor time used by the running process. The starting time value is undefined so you need to resort to reading the start and end times and then computing the difference, just as we did with times.
The big difference between measuring with clock and times is that clock measures approximate process time used while times returns overall elapsed time. If you try the above program that sleeps for two seconds with clock, you will get a value of 0 elapsed seconds. Basically, the call to sleep put the process to sleep and there was no CPU time used on behalf of the process during that time.
While clock returns its result in the same clock_t
data type as times,
the scale is different. The POSIX requires that the result be scaled by a value CLOCKS_PER_SEC, which
is always defined as one million (1000000), regardless of the actual clock resolution. Note that the
finer scale does not mean that clock will always produce more accurate results.
The accuracy depends on the implementation.
Also note that the high value of CLOCKS_PER_SEC will cause the clock to wrap around to 0 approximately
every 72 minutes on a 32-bit processor.
Save this file by control-clicking or right clicking the download link and then saving it as clock.c.
Compile this program via:
If you don't have gcc, You may need to substitute the gcc command with cc or another name of your compiler.
Run the program:
The gettimeofday system call
As if we didn't have enough mechanisms to compute time intervals, we can also use the gettimeofday system call. It has the following usage:
This function, as its name implies, measures the time of day. It returns its value as the number of seconds and microseconds since the Epoch, which is defined as midnight (0:00) January 1, 1970 UTC (Greenwich Mean Time). This value is returned in the first parameter, which is a pointer to a structure that contains two fields: seconds and microseconds. The second parameter identifies the time zone but this is obsolete and should not be used. Keeping track of elapsed seconds avoids the problems of time jumps due to daylight saving time or timezone changes. Those can be added in if a printable calendar time is ever required (see the ctime function).
As with clock, note that the precision is limited by the kernel's timekeeping granularity. Just because the data structure reads microseconds does not imply that you will get microsecond accuracy.
Here's an example of using gettimeofday. You'll note that we measure the overall delay. Expect the delay to be greater than 2 seconds (2,000,000 microseconds) since we show a greater resolution than we do with times.Save this file by control-clicking or right clicking the download link and then saving it as gettimeofday.c.
Compile this program via:
If you don't have gcc, You may need to substitute the gcc command with cc or another name of your compiler.
Run the program:
Beware!
The problem with using a time-of-day report such as the gettimeodday system call is that the time-of-day clock may be spontaneously adjusted to keep the system's time of day synchronized with UTC time (for example, via the Network Time Protocol, NTP). Whenever the time is adjusted, your measurement of the interval between start and stop times becomes invalid and, unless you notice something bizarre such as an end time that is less than the start time, you will not even know that an adjustment took place.
The gettimeofday system call is considered obsolete but is still supported on most POSIX systems. The replacement is clock_gettime but it is not broadly supported yet (OS X, does not have it as of February 2014, for example).
For high-resolution benchmarking, the recommended approach, if available, is to use clock_gettime.