Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best replacement for timeGetTime to avoid wrap-around?

Tags:

c++

time

windows

timeGetTime seems to be quite good to query for system time. However, its return value is 32-bit only, so it wraps around every 49 days approx.

It's not too hard to detect the rollover in calling code, but it adds some complexity, and (worse) requires keeping a state.

Is there some replacement for timeGetTime that would not have this wrap-around problem (probably by returning a 64-bit value), and have roughly the same precision and cost?

like image 418
Paweł Hajdan Avatar asked May 13 '10 09:05

Paweł Hajdan


5 Answers

Unless you need to time an event that is over 49 days, you can SAFELY ignore the wrap-around. Just always subtract the previous timeGetTime() from the current timeGetTime() and you will always obtain a delta measured time that is accurate, even across wrap-around -- provided that you are timing events whose total duration is under 49 days. This all works due to how unsigned modular math works inside the computer.

// this code ALWAYS works, even with wrap-around!
DWORD dwStart = timeGetTime();
// provided the event timed here has a duration of less than 49 days
DWORD dwDuration = timeGetTime()-dwStart;

TIP: look into TimeBeginPeriod(1L) to increase the accuracy of timeGetTime().

BUT... if you want a 64-bit version of timeGetTime, here it is:

__int64 timeGetTime64() {
    static __int64 time64=0;
    // warning: if multiple threads call this function, protect with a critical section!
    return (time64 += (timeGetTime()-(DWORD)time64));
    }

Please note that if this function is not called at least once every 49 days, that this function will fail to properly detect a wrap-around.

like image 114
Jerry Jongerius Avatar answered Nov 06 '22 00:11

Jerry Jongerius


What platform?

You could use GetTickCount64() if you're running on Vista or later, or synthesise your own GetTickCount64() from GetTickCount() and a timer...

I deal with the rollover issue in GetTickCount() and synthesising a GetTickCount64() on platforms that don't support it here on my blog about testing non-trivial code: http://www.lenholgate.com/blog/2008/04/practical-testing-17---a-whole-new-approach.html

like image 5
Len Holgate Avatar answered Nov 05 '22 22:11

Len Holgate


Nope, tracking roll-over requires state. It can be as simple as just incrementing your own 64-bit counter on each callback.

It is pretty unusual to want to track time periods to a resolution as low as 1 millisecond for up to 49 days. You'd have to worry that the accuracy is still there after such a long period. The next step is to use the clock, GetTickCount(64), GetSystemTimeAsFileTime have a resolution of 15.625 milliseconds and are kept accurate with a time server.

like image 2
Hans Passant Avatar answered Nov 05 '22 22:11

Hans Passant


Have a look at GetSystemTimeAsFileTime(). It fills a FILETIME struct that contains a "64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC)"

like image 1
Elrohir Avatar answered Nov 06 '22 00:11

Elrohir


How are you trying to use it? I frequently use the Win32 equivalent when checking for durations that I know will be under 49 days. For example the following code will always work.

DWORD start = timeGetTime();
DoSomthingThatTakesLessThen49Days();
DWORD duration = timeGetTime() - start;

Even if timeGetTime rolled over while calling DoSomthingThatTakesLessThen49Days duration will still be correct.

Note the following code could fail on rollover.

DWORD start = timeGetTime();
DoSomthingThatTakesLessThen49Days();
if (now + 5000 < timeGetTime())
{
}

but can easy be re-written to work as follows

DWORD start = timeGetTime();
DoSomthingThatTakesLessThen49Days();
if (timeGetTime() - start < 5000)
{
}
like image 1
Stephen Nutt Avatar answered Nov 06 '22 00:11

Stephen Nutt