diff options
author | deanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-02 08:28:37 +0000 |
---|---|---|
committer | deanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-02 08:28:37 +0000 |
commit | 5f6eee53a4ba6995b68a8ec6f22d3281529060c8 (patch) | |
tree | 1464c7ca7fdaaa3b7f387da90db9667988c1f25d /base/time_win.cc | |
parent | 38f70a3e2ade7049c09831ed8f5b8ea90d9e68d6 (diff) | |
download | chromium_src-5f6eee53a4ba6995b68a8ec6f22d3281529060c8.zip chromium_src-5f6eee53a4ba6995b68a8ec6f22d3281529060c8.tar.gz chromium_src-5f6eee53a4ba6995b68a8ec6f22d3281529060c8.tar.bz2 |
Cleanup some Windows TimeTicks functions. Move TickTicks::Now and TicksTicks::UnreliableHighResNow to Singletons, which cleans up the code and removes some possible unsafe cross-thread access.
Move the Windows-specific rollover tests to time_unittests_win.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1633 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/time_win.cc')
-rw-r--r-- | base/time_win.cc | 125 |
1 files changed, 70 insertions, 55 deletions
diff --git a/base/time_win.cc b/base/time_win.cc index 9d38993..a919395 100644 --- a/base/time_win.cc +++ b/base/time_win.cc @@ -7,9 +7,11 @@ #pragma comment(lib, "winmm.lib") #include <windows.h> #include <mmsystem.h> + #include "base/basictypes.h" #include "base/lock.h" #include "base/logging.h" +#include "base/singleton.h" namespace { @@ -122,53 +124,39 @@ void Time::Explode(bool is_local, Exploded* exploded) const { } // TimeTicks ------------------------------------------------------------------ - -TimeTicks::TickFunction TimeTicks::tick_function_= +TimeTicks::TickFunction TimeTicks::tick_function_ = reinterpret_cast<TickFunction>(&timeGetTime); -// static -TimeTicks TimeTicks::Now() { - // Uses the multimedia timers on Windows to get a higher resolution clock. - // timeGetTime() provides a resolution which is variable depending on - // hardware and system configuration. It can also be changed by other - // apps. This class does not attempt to change the resolution of the - // timer, because we don't want to affect other applications. - - // timeGetTime() should at least be accurate to ~5ms on all systems. - // timeGetTime() returns a 32-bit millisecond counter which has rollovers - // every ~49 days. - static DWORD last_tick_count = 0; - static int64 tick_rollover_accum = 0; - static Lock* tick_lock = NULL; // To protect during rollover periods. - - // Lazily create the lock we use. - if (!tick_lock) { - Lock* new_lock = new Lock; - if (InterlockedCompareExchangePointer( - reinterpret_cast<PVOID*>(&tick_lock), new_lock, NULL)) { - delete new_lock; - } - } +namespace { - // Atomically protect the low and high 32bit values for time. - // In the future we may be able to optimize with - // InterlockedCompareExchange64, but that doesn't work on XP. - DWORD tick_count; - int64 rollover_count; - { - AutoLock lock(*tick_lock); - tick_count = tick_function_(); - if (tick_count < last_tick_count) - tick_rollover_accum += GG_INT64_C(0x100000000); - - last_tick_count = tick_count; - rollover_count = tick_rollover_accum; +// We use timeGetTime() to implement TimeTicks::Now(). This can be problematic +// because it returns the number of millisecond since Windows has started, which +// will roll over the 32-bit value every ~49 days. We try to track rollover +// ourselves, which works if TimeTicks::Now() is called at least every 49 days. +class NowSingleton { + public: + NowSingleton() + : rollover_(TimeDelta::FromMilliseconds(0)), + last_seen_(TimeTicks::tick_function_()) { } + + TimeDelta Now() { + AutoLock locked(lock_); + // We should hold the lock while calling tick_function_ to make sure that + // we keep our last_seen_ stay correctly in sync. + DWORD now = TimeTicks::tick_function_(); + if (now < last_seen_) + rollover_ += TimeDelta::FromMilliseconds(0x100000000I64); // ~49.7 days. + last_seen_ = now; + return TimeDelta::FromMilliseconds(now) + rollover_; } - // GetTickCount returns milliseconds, we want microseconds. - return TimeTicks((tick_count + rollover_count) * - Time::kMicrosecondsPerMillisecond); -} + private: + Lock lock_; // To protected last_seen_ and rollover_. + TimeDelta rollover_; // Accumulation of time lost do to rollover. + DWORD last_seen_; // The last timeGetTime value we saw, to detect rollover. + + DISALLOW_COPY_AND_ASSIGN(NowSingleton); +}; // Overview of time counters: // (1) CPU cycle counter. (Retrieved via RDTSC) @@ -198,23 +186,50 @@ TimeTicks TimeTicks::Now() { // (3) System time. The system time provides a low-resolution (typically 10ms // to 55 milliseconds) time stamp but is comparatively less expensive to // retrieve and more reliable. +class UnreliableHighResNowSingleton { + public: + UnreliableHighResNowSingleton() : ticks_per_microsecond_(0) { + LARGE_INTEGER ticks_per_sec = {0}; + if (!QueryPerformanceFrequency(&ticks_per_sec)) + return; // Broken, we don't guarantee this function works. + ticks_per_microsecond_ = + ticks_per_sec.QuadPart / Time::kMicrosecondsPerSecond; + } -// static -TimeTicks TimeTicks::UnreliableHighResNow() { + bool IsBroken() { + return ticks_per_microsecond_ == 0; + } + + TimeDelta Now() { + LARGE_INTEGER now; + QueryPerformanceCounter(&now); + return TimeDelta::FromMicroseconds(now.QuadPart / ticks_per_microsecond_); + } + + private: // Cached clock frequency -> microseconds. This assumes that the clock // frequency is faster than one microsecond (which is 1MHz, should be OK). - static int64 ticks_per_microsecond = 0; + int64 ticks_per_microsecond_; // 0 indicates QPF failed and we're broken. - if (ticks_per_microsecond == 0) { - LARGE_INTEGER ticks_per_sec = { 0, 0 }; - if (!QueryPerformanceFrequency(&ticks_per_sec)) - return TimeTicks(0); // Broken, we don't guarantee this function works. - ticks_per_microsecond = - ticks_per_sec.QuadPart / Time::kMicrosecondsPerSecond; - } + DISALLOW_COPY_AND_ASSIGN(UnreliableHighResNowSingleton); +}; + +} // namespace - LARGE_INTEGER now; - QueryPerformanceCounter(&now); - return TimeTicks(now.QuadPart / ticks_per_microsecond); +// static +TimeTicks TimeTicks::Now() { + return TimeTicks() + Singleton<NowSingleton>::get()->Now(); } +// static +TimeTicks TimeTicks::UnreliableHighResNow() { + UnreliableHighResNowSingleton* now = + Singleton<UnreliableHighResNowSingleton>::get(); + + if (now->IsBroken()) { + NOTREACHED() << "QueryPerformanceCounter is broken."; + return TimeTicks(0); + } + + return TimeTicks() + now->Now(); +} |