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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« base/message_loop.cc ('K') | « base/time_unittest_win.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/time.h" 5 #include "base/time.h"
6 6
7 #pragma comment(lib, "winmm.lib") 7 #pragma comment(lib, "winmm.lib")
8 #include <windows.h> 8 #include <windows.h>
9 #include <mmsystem.h> 9 #include <mmsystem.h>
10
10 #include "base/basictypes.h" 11 #include "base/basictypes.h"
11 #include "base/lock.h" 12 #include "base/lock.h"
12 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/singleton.h"
13 15
14 namespace { 16 namespace {
15 17
16 // From MSDN, FILETIME "Contains a 64-bit value representing the number of 18 // From MSDN, FILETIME "Contains a 64-bit value representing the number of
17 // 100-nanosecond intervals since January 1, 1601 (UTC)." 19 // 100-nanosecond intervals since January 1, 1601 (UTC)."
18 int64 FileTimeToMicroseconds(const FILETIME& ft) { 20 int64 FileTimeToMicroseconds(const FILETIME& ft) {
19 // Need to bit_cast to fix alignment, then divide by 10 to convert 21 // Need to bit_cast to fix alignment, then divide by 10 to convert
20 // 100-nanoseconds to milliseconds. This only works on little-endian 22 // 100-nanoseconds to milliseconds. This only works on little-endian
21 // machines. 23 // machines.
22 return bit_cast<int64, FILETIME>(ft) / 10; 24 return bit_cast<int64, FILETIME>(ft) / 10;
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 exploded->month = st.wMonth; 117 exploded->month = st.wMonth;
116 exploded->day_of_week = st.wDayOfWeek; 118 exploded->day_of_week = st.wDayOfWeek;
117 exploded->day_of_month = st.wDay; 119 exploded->day_of_month = st.wDay;
118 exploded->hour = st.wHour; 120 exploded->hour = st.wHour;
119 exploded->minute = st.wMinute; 121 exploded->minute = st.wMinute;
120 exploded->second = st.wSecond; 122 exploded->second = st.wSecond;
121 exploded->millisecond = st.wMilliseconds; 123 exploded->millisecond = st.wMilliseconds;
122 } 124 }
123 125
124 // TimeTicks ------------------------------------------------------------------ 126 // TimeTicks ------------------------------------------------------------------
127 namespace {
125 128
126 TimeTicks::TickFunction TimeTicks::tick_function_= 129 DWORD (__stdcall *tick_function)(void) = &timeGetTime;
127 reinterpret_cast<TickFunction>(&timeGetTime);
128 130
129 // static 131 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic
130 TimeTicks TimeTicks::Now() { 132 // because it returns the number of milliseconds since Windows has started,
131 // Uses the multimedia timers on Windows to get a higher resolution clock. 133 // which will roll over the 32-bit value every ~49 days. We try to track
132 // timeGetTime() provides a resolution which is variable depending on 134 // rollover ourselves, which works if TimeTicks::Now() is called at least every
133 // hardware and system configuration. It can also be changed by other 135 // 49 days.
134 // apps. This class does not attempt to change the resolution of the 136 class NowSingleton {
135 // timer, because we don't want to affect other applications. 137 public:
136 138 NowSingleton()
137 // timeGetTime() should at least be accurate to ~5ms on all systems. 139 : rollover_(TimeDelta::FromMilliseconds(0)), last_seen_(0) {
138 // timeGetTime() returns a 32-bit millisecond counter which has rollovers 140 // Request a resolution of 1ms from timeGetTime(). This can have some
139 // every ~49 days. 141 // consequences on other applications (see MSDN), but we've found that it
140 static DWORD last_tick_count = 0; 142 // is very common in other applications (Flash, Media Player, etc), so it
141 static int64 tick_rollover_accum = 0; 143 // is not really a dangerous thing to do. We need this because the default
142 static Lock* tick_lock = NULL; // To protect during rollover periods. 144 // resolution of ~15ms is much too low for accurate timing and timers.
143 145 ::timeBeginPeriod(1);
144 // Lazily create the lock we use.
145 if (!tick_lock) {
146 Lock* new_lock = new Lock;
147 if (InterlockedCompareExchangePointer(
148 reinterpret_cast<PVOID*>(&tick_lock), new_lock, NULL)) {
149 delete new_lock;
150 }
151 } 146 }
152 147
153 // Atomically protect the low and high 32bit values for time. 148 ~NowSingleton() {
154 // In the future we may be able to optimize with 149 ::timeEndPeriod(1);
155 // InterlockedCompareExchange64, but that doesn't work on XP.
156 DWORD tick_count;
157 int64 rollover_count;
158 {
159 AutoLock lock(*tick_lock);
160 tick_count = tick_function_();
161 if (tick_count < last_tick_count)
162 tick_rollover_accum += GG_INT64_C(0x100000000);
163
164 last_tick_count = tick_count;
165 rollover_count = tick_rollover_accum;
166 } 150 }
167 151
168 // GetTickCount returns milliseconds, we want microseconds. 152 TimeDelta Now() {
169 return TimeTicks((tick_count + rollover_count) * 153 AutoLock locked(lock_);
170 Time::kMicrosecondsPerMillisecond); 154 // We should hold the lock while calling tick_function to make sure that
171 } 155 // we keep our last_seen_ stay correctly in sync.
156 DWORD now = tick_function();
157 if (now < last_seen_)
158 rollover_ += TimeDelta::FromMilliseconds(0x100000000I64); // ~49.7 days.
159 last_seen_ = now;
160 return TimeDelta::FromMilliseconds(now) + rollover_;
161 }
162
163 private:
164 Lock lock_; // To protected last_seen_ and rollover_.
165 TimeDelta rollover_; // Accumulation of time lost due to rollover.
166 DWORD last_seen_; // The last timeGetTime value we saw, to detect rollover.
167
168 DISALLOW_COPY_AND_ASSIGN(NowSingleton);
169 };
172 170
173 // Overview of time counters: 171 // Overview of time counters:
174 // (1) CPU cycle counter. (Retrieved via RDTSC) 172 // (1) CPU cycle counter. (Retrieved via RDTSC)
175 // The CPU counter provides the highest resolution time stamp and is the least 173 // The CPU counter provides the highest resolution time stamp and is the least
176 // expensive to retrieve. However, the CPU counter is unreliable and should not 174 // expensive to retrieve. However, the CPU counter is unreliable and should not
177 // be used in production. Its biggest issue is that it is per processor and it 175 // be used in production. Its biggest issue is that it is per processor and it
178 // is not synchronized between processors. Also, on some computers, the counters 176 // is not synchronized between processors. Also, on some computers, the counters
179 // will change frequency due to thermal and power changes, and stop in some 177 // will change frequency due to thermal and power changes, and stop in some
180 // states. 178 // states.
181 // 179 //
182 // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high- 180 // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
183 // resolution (100 nanoseconds) time stamp but is comparatively more expensive 181 // resolution (100 nanoseconds) time stamp but is comparatively more expensive
184 // to retrieve. What QueryPerformanceCounter actually does is up to the HAL. 182 // to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
185 // (with some help from ACPI). 183 // (with some help from ACPI).
186 // According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx 184 // According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
187 // in the worst case, it gets the counter from the rollover interrupt on the 185 // in the worst case, it gets the counter from the rollover interrupt on the
188 // programmable interrupt timer. In best cases, the HAL may conclude that the 186 // programmable interrupt timer. In best cases, the HAL may conclude that the
189 // RDTSC counter runs at a constant frequency, then it uses that instead. On 187 // RDTSC counter runs at a constant frequency, then it uses that instead. On
190 // multiprocessor machines, it will try to verify the values returned from 188 // multiprocessor machines, it will try to verify the values returned from
191 // RDTSC on each processor are consistent with each other, and apply a handful 189 // RDTSC on each processor are consistent with each other, and apply a handful
192 // of workarounds for known buggy hardware. In other words, QPC is supposed to 190 // of workarounds for known buggy hardware. In other words, QPC is supposed to
193 // give consistent result on a multiprocessor computer, but it is unreliable in 191 // give consistent result on a multiprocessor computer, but it is unreliable in
194 // reality due to bugs in BIOS or HAL on some, especially old computers. 192 // reality due to bugs in BIOS or HAL on some, especially old computers.
195 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but 193 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but
196 // it should be used with caution. 194 // it should be used with caution.
197 // 195 //
198 // (3) System time. The system time provides a low-resolution (typically 10ms 196 // (3) System time. The system time provides a low-resolution (typically 10ms
199 // to 55 milliseconds) time stamp but is comparatively less expensive to 197 // to 55 milliseconds) time stamp but is comparatively less expensive to
200 // retrieve and more reliable. 198 // retrieve and more reliable.
199 class UnreliableHighResNowSingleton {
200 public:
201 UnreliableHighResNowSingleton() : ticks_per_microsecond_(0) {
202 LARGE_INTEGER ticks_per_sec = {0};
203 if (!QueryPerformanceFrequency(&ticks_per_sec))
204 return; // Broken, we don't guarantee this function works.
205 ticks_per_microsecond_ =
206 ticks_per_sec.QuadPart / Time::kMicrosecondsPerSecond;
207 }
208
209 bool IsBroken() {
210 return ticks_per_microsecond_ == 0;
211 }
212
213 TimeDelta Now() {
214 LARGE_INTEGER now;
215 QueryPerformanceCounter(&now);
216 return TimeDelta::FromMicroseconds(now.QuadPart / ticks_per_microsecond_);
217 }
218
219 private:
220 // Cached clock frequency -> microseconds. This assumes that the clock
221 // frequency is faster than one microsecond (which is 1MHz, should be OK).
222 int64 ticks_per_microsecond_; // 0 indicates QPF failed and we're broken.
223
224 DISALLOW_COPY_AND_ASSIGN(UnreliableHighResNowSingleton);
225 };
226
227 } // namespace
228
229 // static
230 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
231 TickFunctionType ticker) {
232 TickFunctionType old = tick_function;
233 tick_function = ticker;
234 return old;
235 }
236
237 // static
238 TimeTicks TimeTicks::Now() {
239 return TimeTicks() + Singleton<NowSingleton>::get()->Now();
240 }
201 241
202 // static 242 // static
203 TimeTicks TimeTicks::UnreliableHighResNow() { 243 TimeTicks TimeTicks::UnreliableHighResNow() {
204 // Cached clock frequency -> microseconds. This assumes that the clock 244 UnreliableHighResNowSingleton* now =
205 // frequency is faster than one microsecond (which is 1MHz, should be OK). 245 Singleton<UnreliableHighResNowSingleton>::get();
206 static int64 ticks_per_microsecond = 0;
207 246
208 if (ticks_per_microsecond == 0) { 247 if (now->IsBroken()) {
209 LARGE_INTEGER ticks_per_sec = { 0, 0 }; 248 NOTREACHED() << "QueryPerformanceCounter is broken.";
210 if (!QueryPerformanceFrequency(&ticks_per_sec)) 249 return TimeTicks(0);
211 return TimeTicks(0); // Broken, we don't guarantee this function works.
212 ticks_per_microsecond =
213 ticks_per_sec.QuadPart / Time::kMicrosecondsPerSecond;
214 } 250 }
215 251
216 LARGE_INTEGER now; 252 return TimeTicks() + now->Now();
217 QueryPerformanceCounter(&now);
218 return TimeTicks(now.QuadPart / ticks_per_microsecond);
219 } 253 }
220
OLDNEW
« 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