What's the best replacement for timeGetTime to avoid wrap-around?
timeGetTime seems to b开发者_运维知识库e 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?
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.
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
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.
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)"
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)
{
}
Assuming you can guarantee that this function will called at least once every 49 days, something like this will work:
// Returns current time in milliseconds
uint64_t timeGetTime64()
{
static uint32_t _prevVal = 0;
static uint64_t _wrapOffset = 0;
uint32_t newVal = (uint32_t) timeGetTime();
if (newVal < _prevVal) _wrapOffset += (((uint64_t)1)<<32);
_prevVal = newVal;
return _wrapOffset+newVal;
}
Note that due to the use of static variables, this function isn't multithread-safe, so if you plan on calling it from multiple threads you should serialize it via a critical section or mutex or similar.
I'm not sure if this fully meets your needs, but
std::chrono::system_clock
might be along the lines of what you're looking for.
http://en.cppreference.com/w/cpp/chrono/system_clock
You could use RDTSC intrinsic. To get time in milliseconds you could get transform coefficient:
double get_rdtsc_coeff() {
static double coeff = 0.0;
if ( coeff < 1.0 ) { // count it only once
unsigned __int64 t00 = __rdtsc();
Sleep(1000);
unsigned __int64 t01 = __rdtsc();
coeff = (t01-t00)/1000.0;
}
return coeff; // transformation coefficient
}
Now you could get count of milliseconds from the last reset:
__int64 get_ms_from_start() {
return static_cast<__int64>(__rdtsc()/get_rdtsc_coeff());
}
If your system uses SpeedStep or similar technologies you could use QueryPerformanceCounter/QueryPerformanceFrequency functions. Windows gives guarantees then the frequency cannot change while the system is running.
精彩评论