We commonly hear complaints as to there is no way to have a portable code that takes time on all operating systems. For instance, using gettimeofday on Unix is fine, but going to Windows, there is no gettimeofday call. There, you are supposed to use a call like clock to measure time.
In fact, this is merely a confusion caused by historical reasons and a whole community of people that disdain anything related to that M company. Here, let's talk a little bit about the de facto standard way of measuring time, as ANSI C'87 has defined it.
On any system claiming to support ANSI C, it must have a < time.h >. The ANSI C standard C-library functions are:clock_t clock(void); time_t time(time_t * tp); double difftime(time_t time2, time_t time1); time_t mktime(struct tm * tp); char * ctime(const time_t *clock); struct tm * localtime(const time_t *clock); struct tm * gmtime(const time_t *clock); char * asctime(const struct tm *tm); size_t strftime(const char *s, size_t maxsize, const char *format, const struct tm *timeptr);
struct tm is used for parsing time into a human readable format.
struct tm { int tm_sec; /* seconds after the minute - [0, 61] */ /* for leap seconds */ int tm_min; /* minutes after the hour - [0, 59] */ int tm_hour; /* hour 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; /* daylight saving time tag */ }
In this standard, the return value of time is the calendar time (time_t, which is really just a large arithmetic number) is measured in number of seconds from 00:00:00, January 1, 1970 (the Universally Coordinated Time). clock returns the number of clock ticks since the start of the program, more accurately, the process.
Calls like localtime and gmtime converts the calendar time into a tm structure in either your local time zone or the Greenwich Mean time (mostly of historical significance).
To make human understand the current time, of course strings are better than a struct or a time_t. For this purposes, two function calls are designed. ctime and asctime takes a calendar time or a tm struct and converts the time to a string in the form:
Sun Jan 3 15:14:13 1998\n\0
At last, strftime is a function offering formatting time with all kinds of controls that printf offers.
Coming back to measuring time directly using gettimeofday, it is a system call on Unix. It's synopsis is:
#include < sys/time.h > int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
The structures pointed to by tp and tzp are defined in sys/time.h as:
struct timeval { time_t tv_sec; /* seconds since Jan. 1, 1970 */ suseconds_t tv_usec; /* and microseconds */ };
To date, all timing measurements we have talked about falls under the category of calendar time, or wall clock time that is the number of seconds maintained by the system since the Epoch, 00:00:00 January 1, 1970, Coordinated Universal Time (UTC). UTC is also known as Greenwich Mean Time.
After knowing all about process, let's talk about process time, which is also called CPU time. Process time is a concept that refers to how much central processor resources is used by a process. Just like calendar time, process time is also measured in clock ticks, historically with 50, 60 or 100 ticks per second.
For each process, the system maintains three values:
- clock time (wall clock time) - user CPU time - system CPU time
On Unix, process time is collected by calling
#include < sys/times.h > clock_t times (struct tms * buf);The tms structure has the following definition:
struct tms { clock_t tms_utime; /* user CPU time */ clock_t tms_stime; /* system CPU time */ clock_t tms_cutime; /* user CPU time, terminated children */ clock_t tms_cstime; /* system CPU time, terminated children */ }
Note, the return value of times is the wall clock time, measured from a arbitrary point in the past. One does not use that absolute value, but rather use the relative. That is, taking the difference between two return values obtained at two points in the program to get the wall clock execution time of that segment of the code. The ANSI C standard time.h can be used to measure wall clock time as well, but not the CPU time.
The u/stime measures the CPU time that the current process spent in user space or system calls, respectively. cu/stime measures the same quantities for all children processes of the current processes that have been wait'ed for.
To find out how many ticks there are in each second, use
#include < unistd.h > long clktck = 0; clktck = sysconf(_SC_CLK_TCK);
/* timetest.c */ #include < stdio.h > #include < stdlib.h > #include < time.h > #include < sys/time.h > #include < sys/times.h > #include < unistd.h > typedef struct { clock_t clock_val; time_t time_val; struct timeval gettime_val; struct tms times_val; } all_times; void get_time(all_times * t) { t->clock_val = clock(); t->time_val = time(NULL); gettimeofday(&(t->gettime_val), NULL); times(&(t->times_val)); } void print_duration(all_times * t1, all_times * t2) { float elapsed; long clktck, nticks; nticks = t2->clock_val - t1->clock_val; elapsed = (float)nticks/CLOCKS_PER_SEC; fprintf(stderr,"clock: %f sec\n", elapsed); nticks = t2->time_val - t1->time_val; fprintf(stderr,"time: %d sec\n", nticks); elapsed = t2->gettime_val.tv_sec - t1->gettime_val.tv_sec; elapsed += (t2->gettime_val.tv_usec - t1->gettime_val.tv_usec)/1e6; fprintf(stderr,"gettimeofday: %f sec\n", elapsed); clktck = sysconf(_SC_CLK_TCK); nticks = t2->times_val.tms_utime - t1->times_val.tms_utime; elapsed = (float)nticks/clktck; fprintf(stderr,"times: %f sec user time\n", elapsed); nticks = t2->times_val.tms_stime - t1->times_val.tms_stime; elapsed = (float)nticks/clktck; fprintf(stderr,"times: %f sec system time\n", elapsed); } long simplecat() { char c; int i; long cnt = 0; i = fread(&c, 1, 1, stdin); while(i > 0) { fwrite(&c, 1, 1, stdout); i = fread(&c, 1, 1, stdin); cnt ++; } return cnt; } int main(void) { int totalbytes; all_times a1, a2; get_time(&a1); totalbytes = simplecat(); get_time(&a2); print_duration(&a1, &a2); fprintf(stderr, "total of %f MiB\n", totalbytes/1e6); return 0; }
UNIX> timetest < gigantic.jpeg > /dev/null clock: 2.140000 sec time: 2 sec gettimeofday: 2.193709 sec times: 2.120000 sec user time times: 0.020000 sec system time total of 59.134079 MiB UNIX> timetest 1 1 2 2 3 3 4 4 5 5 6 6 clock: 0.000000 sec time: 8 sec gettimeofday: 7.487184 sec times: 0.000000 sec user time times: 0.000000 sec system time total of 0.000012 MiB