The Clocks
To measure time, every machine has clocks and timers. At a system level, there are various ways to keep track of time. In the machine, one basic clock is just like our real world clock, which keeps ticking and tells the machine the current time. This clock runs on a battery and even keeps running when our system is turned off. However, when the system boots up, it initialises other Linux clocks which now have their separate axis of reference, though still ticking with the frequency of the underlying hardware.
There is another clock in Linux, which just keep ticking to let you know how many ticks have occurred since the system has booted up. Howsoever, unless and until our program is to show/work on the current local time, the developers mostly work on the time intervals i.e. how much time elapsed by a particular function or a sleep for a particular interval of time, etc.
From a developer’s point of view, there are various functions available for fetching timing information from Linux system. It might sometimes get confusing as to why we have so many methods, structs and how do they differ with each other. Lets understand each function one by one.
1. The time(), ctime() and asctime() functions
The time() function is used to fetch the local time in seconds.
NAME
time – get time in secondsSYNOPSIS
#include <time.h>
time_t time(time_t *t);DESCRIPTION
time() returns the time as the number of seconds since the Epoch, 1970-01-01 00:00:00
+0000 (UTC). If t is non-NULL, the return value is also stored in the memory pointed to
by t.RETURN VALUE
On success, the value of time in seconds since the Epoch is returned. On error,
((time_t) -1) is returned, and errno is set appropriately.
This function accepts a pointer to ‘time_t’ as an argument, through which it returns the time along with a return value. hence, it works fine even passing a NULL, where it will just return the time value. Note, ‘time_t’ internally is of ‘long int’ type.
So how does this ‘long int’ value stores time? Well, it just stores the number of seconds passed since a reference point which is taken as January 1, 1970 (termed as Epoch).
There are some methods and C structures offered by Linux to convert these number of seconds to compute the date/time in human readable form. Here is a summary of these functions from respective man pages :
#include <time.h> char *asctime(const struct tm *tm); char *ctime(const time_t *timep);
To know more on how these methods and structures work and their variations, please refer the man page.
So, now lets see how these methods work and how to use them.
Here is an example :
#include <stdio.h> #include <time.h> int main() { time_t currTime; struct tm *localTime; currTime = time(NULL); printf("For Linux, curr time is %ld\n", currTime); printf("For humans, curr time is %s\n", ctime(&currTime)); localTime = localtime (&currTime); printf("For Linux, Local time = %d:%d:%d %d:%d:%d\n", localTime->tm_hour, localTime->tm_min, localTime->tm_sec, localTime->tm_mon, localTime->tm_mday, localTime->tm_year); printf("For Humans, Local time is %s\n", asctime(localTime)); return 0; }
Here is the output:
For Linux, curr time is 1349805572 For humans, curr time is Tue Oct 9 13:59:32 2012 For Linux, Local time = 13:59:32 9:9:112 For Humans, Local time is Tue Oct 9 13:59:32 2012
This method can also be used to determine the time elapsed by a program in seconds. It uses the system clock or sometimes which is termed as the kernel clock. However, keep in mind, the precision would be in seconds.
2. The gettimeofday() function
Here is an excerpt of the details from it’s man page :
NAME
gettimeofday – get / set timeSYNOPSIS
#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
Comparatively, this one gives time with a precision better than the above mentioned method. This uses the system clock for the time computation. All the time values are updated in ‘timeval’ struct and supposedly ‘timezone’ struct as well. However, struct ‘timezone’ is obsolete now and is rarely used. The return value is success/failure.
Lets see a simple implementation using ‘gettimeofday’
#include <stdio.h> #include <sys/time.h> int main() { struct timeval localTime; gettimeofday(&localTime, NULL); //Time zone struct is obsolete, hence NULL printf("The curr time in seconds %ld\n", localTime.tv_sec); printf("The curr time in microseconds %ld\n", localTime.tv_usec); return 0; }
Here is the output:
The curr time in seconds 1349810620 The curr time in microseconds 708991
This method can be used to determine the time interval with the precision of micro-seconds. To know more about this method, you can go through it’s man page.
3. The clock_gettime() function
Here are some details about this function from man page :
#include <time.h>
int clock_gettime(clockid_t clk_id, struct timespec *tp);The tp argument is a timespec structure, as specified in <time.h>:
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
This method gives time with precision on nanoseconds. This method uses a different struct for time values, “struct timespec” which its members as secs and nanosecs. This method also offers for the developer to use various available clocks to determine time. How these available clocks vary is, how they run. Like, the system clock just sends an interrupt at every tick, and increments the time. There are some clocks, which measure the time for a process, some for a thread which is very useful to determine precise time taken by a control flow.
These different clocks are specified by the parameter of the method,
clockid_t clk_id
Here is a list of all available clocks generally in Linux as of today.
- CLOCK_REALTIME : As the name says, it is the real time clock, which matches the system wide time. Hence, this needs special privileges to set. Interestingly, this clock can be adjusted by the Network Time Protocol (NTP) to be in sync with the external sources.
- CLOCK_MONOTONIC :This one keep on running at its pace, and cannot be set or modified.
- CLOCK_MONOTONIC_RAW : This one is similar to CLOCK_MONOTONIC, however it gives the hardware based time.
- CLOCK_PROCESS_CPUTIME_ID : This one is a clock specific to a process with times as per the process. They use CPU timers and different than the above mentioned clocks.
- CLOCK_THREAD_CPUTIME_ID : This one is a clock specific to a thread with times as per the thread. It is similar to CLOCK_PROCESS_CPUTIME_ID and use CPU timers.
Prior to we start playing with this method, important to note that, this method is provided by an external library.
librt.so
Hence, we need to link our code using ‘clock_gettime’ with this library. It is part of the gcc libs and hence available. Therefore, you would not need to install it explicitly.
Here is an example of this function
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #define MAX 500000 int main() { int array[MAX]; int i; struct timespec starttime, endtime, ttime; double timeinterval; //initialise whole array with 0 memset ((int*)array, 0, (MAX * sizeof(int))); clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &starttime); for (i = 0; i < MAX; i++) array[i] = i; sleep(1); clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &endtime); ttime.tv_sec = endtime.tv_sec - starttime.tv_sec; ttime.tv_nsec = endtime.tv_nsec - starttime.tv_nsec; timeinterval = ttime.tv_sec * 1000000000 + ttime.tv_nsec; printf("Time in milliseconds %lf ms \n", (double) timeinterval/1000000); printf("Time in nanoseconds %lf ns \n", (double) timeinterval); return 0; }
Here is how the code is compiled :
$ gcc mytime.c -Wall -o mytime -lrt
Here is the output :
Time in milliseconds 2.163321 ms Time in nanoseconds 2163321.000000 ns
4. The clock() function
Here is some information from the man page :
NAME clock - Determine processor time SYNOPSIS #include <time.h> clock_t clock(void); DESCRIPTION The clock() function returns an approximation of processor time used by the program. RETURN VALUE The value returned is the CPU time used so far as a clock_t; to get the number of seconds used, divide by CLOCKS_PER_SEC. If the processor time used is not available or its value cannot be represented, the function returns the value (clock_t) -1.
The way it can be used is to note the start time, by calling this function before the code block starts. Then determine by end time after the code block and compute the time elapsed.
Here is a pseudo code :
startClock = clock(); //........control flow stopClock = clock();
However, it does not give accurate discuss and not even to much precision.
Here is a working example :
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> #define MAX 500000 int main() { int array[MAX]; int i; clock_t startClock, stopClock; startClock = clock(); for (i = 0; i < MAX; i++) array[i] = i; sleep(5); stopClock = clock(); printf("The CPU Time = %lf\n", (double)((stopClock - startClock)/(double)CLOCKS_PER_SEC)); return 0; }
Here is the output :
The CPU Time = 0.040000
Conclusion
In this article we learned about various time and date functions in Linux through working examples. You will also be able to have a good judgement where to use which method as per one’s requirement. However, there are still certain things which may affect the accuracy of times in certain conditions like SMP machines, context switches etc.
For many circumstances, profilers could be a better option to use instead of time functions. Basically, it all depends on your precision requirements, machine specifications and software requirements.
http://mylinuxbook.com/linux-time-and-date-functions/