Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

time() and gettimeofday() return different seconds

Tags:

On the two systems I've tested (a 32-bit Ubuntu 12.04 server and a 64-bit Ubuntu 13.10 VM), the seconds since the epoch given by time() may differ from gettimeofday()'s.

Specifically, though I call time() after calling gettimeofday(), the value returned by time() is sometimes less than the tv_sec value returned by gettimeofday().

This apparently occurs just after the clock rolls over to a new second.

This caused bugs in some of my code that expected time()'s and gettimeofday()'s seconds to be interchangeable.

Sample code demonstrating this problem:

#include <stdio.h> #include <time.h> #include <sys/time.h>  int main() {   time_t start = time(NULL);   int same = 0;   int different = 0;   int max_usec = 0;   while (1) {     time_t t;     struct timeval tv;     gettimeofday(&tv, NULL);     t = time(NULL);     if (t < tv.tv_sec) {       different++;       if (tv.tv_usec > max_usec) {         max_usec = tv.tv_usec;       }     } else {       same++;     }     if (t > start + 5) {       break;     }   }   printf("Same:      %i\n", same);   printf("Different: %i\n", different);   printf("Largest difference seen at %i\n", max_usec); } 

Note that I'm calling time() second and only complaining if its value is less than gettimeofday()'s.

Sample output:

Same:      33282836 Different: 177076 Largest difference seen at 5844 

I.e., the two values were the same 33 million times, they were different 177k times, and they were always different within 5844 microseconds of a new second.

Is this a known issue? What causes this?

like image 615
Josh Kelley Avatar asked Apr 07 '14 15:04

Josh Kelley


People also ask

Does gettimeofday return UTC?

The gettimeofday() function retrieves the current Coordinated Universal Time (UTC) and places it in the timeval structure pointed to by tp . If tzp is not NULL, the time zone information is returned in the time zone structure pointed to by tzp .

What does Gettimeofday return?

The gettimeofday() function returns 0 upon success and -1 on failure. The errno variable is set when the function fails.

What is tv_ sec?

long int tv_sec. This represents the number of whole seconds of elapsed time. long int tv_usec. This is the rest of the elapsed time (a fraction of a second), represented as the number of microseconds.


1 Answers

Both calls are implemented as kernel syscalls. Both functions end up reading a struct timekeeper, both refer to the very same instance. But they differ in what they do with it:

time():

uses the get_seconds() function, which is a shortcut to this:

struct timekeeper *tk = &timekeeper; return tk->xtime_sec; 

it just returns xktime_sec.

gettimeofday():

gettimeofday() on the other hand uses do_gettimeofday() (via getnstimeofday) which reads both fields xktime_sec as well as xktime_nsec (via timekeeping_get_ns). Here it might happen that xktime_nsec holds more nanoseconds than a second. This potential extra time is used to increase the tv_sec field by calling the function timespec_add_ns() which does this:

a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns); a->tv_nsec = ns; 

So, tv_sec might get bigger than the xktime_sec field was. And there you have it: a little difference in what time() gives you and what gettimeofday() gives you.

I fought against this issue in fluxbox today and until a better solution occurs I live with this:

uint64_t t_usec = gettimeofday_in_usecs(); // calcs usecs since epoch time_t t = static_cast<time_t>(t_usec / 1000000L); 
like image 123
akira Avatar answered Sep 22 '22 06:09

akira