Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2501)

Unified Diff: base/time_win.cc

Issue 1806: Time singleton and resolution changes. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« base/message_loop.cc ('K') | « base/time_unittest_win.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/time_win.cc
===================================================================
--- base/time_win.cc (revision 1835)
+++ base/time_win.cc (working copy)
@@ -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,54 +124,50 @@
}
// TimeTicks ------------------------------------------------------------------
+namespace {
-TimeTicks::TickFunction TimeTicks::tick_function_=
- reinterpret_cast<TickFunction>(&timeGetTime);
+DWORD (__stdcall *tick_function)(void) = &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.
+// We use timeGetTime() to implement TimeTicks::Now(). This can be problematic
+// because it returns the number of milliseconds 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_(0) {
+ // Request a resolution of 1ms from timeGetTime(). This can have some
+ // consequences on other applications (see MSDN), but we've found that it
+ // is very common in other applications (Flash, Media Player, etc), so it
+ // is not really a dangerous thing to do. We need this because the default
+ // resolution of ~15ms is much too low for accurate timing and timers.
+ ::timeBeginPeriod(1);
+ }
- // 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.
+ ~NowSingleton() {
+ ::timeEndPeriod(1);
+ }
- // 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;
- }
+ 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 = tick_function();
+ if (now < last_seen_)
+ rollover_ += TimeDelta::FromMilliseconds(0x100000000I64); // ~49.7 days.
+ last_seen_ = now;
+ return TimeDelta::FromMilliseconds(now) + rollover_;
}
- // 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);
+ private:
+ Lock lock_; // To protected last_seen_ and rollover_.
+ TimeDelta rollover_; // Accumulation of time lost due to rollover.
+ DWORD last_seen_; // The last timeGetTime value we saw, to detect rollover.
- last_tick_count = tick_count;
- rollover_count = tick_rollover_accum;
- }
+ DISALLOW_COPY_AND_ASSIGN(NowSingleton);
+};
- // GetTickCount returns milliseconds, we want microseconds.
- return TimeTicks((tick_count + rollover_count) *
- Time::kMicrosecondsPerMillisecond);
-}
-
// Overview of time counters:
// (1) CPU cycle counter. (Retrieved via RDTSC)
// The CPU counter provides the highest resolution time stamp and is the least
@@ -198,23 +196,58 @@
// (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
+
+// static
+TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
+ TickFunctionType ticker) {
+ TickFunctionType old = tick_function;
+ tick_function = ticker;
+ return old;
+}
+
+// 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);
}
- LARGE_INTEGER now;
- QueryPerformanceCounter(&now);
- return TimeTicks(now.QuadPart / ticks_per_microsecond);
+ return TimeTicks() + now->Now();
}
-
« base/message_loop.cc ('K') | « base/time_unittest_win.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698