OLD | NEW |
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 Loading... |
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 | |
OLD | NEW |