|
1 /* |
|
2 * Copyright (C) 2006, 2010 Apple Inc. All rights reserved. |
|
3 * Copyright (C) 2008 Google Inc. All rights reserved. |
|
4 * Copyright (C) 2007-2009 Torch Mobile, Inc. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are |
|
8 * met: |
|
9 * |
|
10 * * Redistributions of source code must retain the above copyright |
|
11 * notice, this list of conditions and the following disclaimer. |
|
12 * * Redistributions in binary form must reproduce the above |
|
13 * copyright notice, this list of conditions and the following disclaimer |
|
14 * in the documentation and/or other materials provided with the |
|
15 * distribution. |
|
16 * * Neither the name of Google Inc. nor the names of its |
|
17 * contributors may be used to endorse or promote products derived from |
|
18 * this software without specific prior written permission. |
|
19 * |
|
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
31 */ |
|
32 |
|
33 #include "config.h" |
|
34 #include "CurrentTime.h" |
|
35 |
|
36 #if OS(WINDOWS) |
|
37 |
|
38 // Windows is first since we want to use hires timers, despite PLATFORM(CF) |
|
39 // being defined. |
|
40 // If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod. |
|
41 #undef WIN32_LEAN_AND_MEAN |
|
42 #include <windows.h> |
|
43 #include <math.h> |
|
44 #include <stdint.h> |
|
45 #include <time.h> |
|
46 |
|
47 #if USE(QUERY_PERFORMANCE_COUNTER) |
|
48 #if OS(WINCE) |
|
49 extern "C" time_t mktime(struct tm *t); |
|
50 #else |
|
51 #include <sys/timeb.h> |
|
52 #include <sys/types.h> |
|
53 #endif |
|
54 #endif |
|
55 |
|
56 #elif PLATFORM(GTK) |
|
57 #include <glib.h> |
|
58 #elif PLATFORM(WX) |
|
59 #include <wx/datetime.h> |
|
60 #elif PLATFORM(BREWMP) |
|
61 #include <AEEStdLib.h> |
|
62 #else |
|
63 #include <sys/time.h> |
|
64 #endif |
|
65 |
|
66 #if PLATFORM(CHROMIUM) |
|
67 #error Chromium uses a different timer implementation |
|
68 #endif |
|
69 |
|
70 namespace WTF { |
|
71 |
|
72 const double msPerSecond = 1000.0; |
|
73 |
|
74 #if OS(WINDOWS) |
|
75 |
|
76 #if USE(QUERY_PERFORMANCE_COUNTER) |
|
77 |
|
78 static LARGE_INTEGER qpcFrequency; |
|
79 static bool syncedTime; |
|
80 |
|
81 static double highResUpTime() |
|
82 { |
|
83 // We use QPC, but only after sanity checking its result, due to bugs: |
|
84 // http://support.microsoft.com/kb/274323 |
|
85 // http://support.microsoft.com/kb/895980 |
|
86 // http://msdn.microsoft.com/en-us/library/ms644904.aspx ("...you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL)." |
|
87 |
|
88 static LARGE_INTEGER qpcLast; |
|
89 static DWORD tickCountLast; |
|
90 static bool inited; |
|
91 |
|
92 LARGE_INTEGER qpc; |
|
93 QueryPerformanceCounter(&qpc); |
|
94 DWORD tickCount = GetTickCount(); |
|
95 |
|
96 if (inited) { |
|
97 __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart; |
|
98 __int64 tickCountElapsed; |
|
99 if (tickCount >= tickCountLast) |
|
100 tickCountElapsed = (tickCount - tickCountLast); |
|
101 else { |
|
102 #if COMPILER(MINGW) |
|
103 __int64 tickCountLarge = tickCount + 0x100000000ULL; |
|
104 #else |
|
105 __int64 tickCountLarge = tickCount + 0x100000000I64; |
|
106 #endif |
|
107 tickCountElapsed = tickCountLarge - tickCountLast; |
|
108 } |
|
109 |
|
110 // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms. |
|
111 // (500ms value is from http://support.microsoft.com/kb/274323) |
|
112 __int64 diff = tickCountElapsed - qpcElapsed; |
|
113 if (diff > 500 || diff < -500) |
|
114 syncedTime = false; |
|
115 } else |
|
116 inited = true; |
|
117 |
|
118 qpcLast = qpc; |
|
119 tickCountLast = tickCount; |
|
120 |
|
121 return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart); |
|
122 } |
|
123 |
|
124 static double lowResUTCTime() |
|
125 { |
|
126 #if OS(WINCE) |
|
127 SYSTEMTIME systemTime; |
|
128 GetSystemTime(&systemTime); |
|
129 struct tm tmtime; |
|
130 tmtime.tm_year = systemTime.wYear - 1900; |
|
131 tmtime.tm_mon = systemTime.wMonth - 1; |
|
132 tmtime.tm_mday = systemTime.wDay; |
|
133 tmtime.tm_wday = systemTime.wDayOfWeek; |
|
134 tmtime.tm_hour = systemTime.wHour; |
|
135 tmtime.tm_min = systemTime.wMinute; |
|
136 tmtime.tm_sec = systemTime.wSecond; |
|
137 time_t timet = mktime(&tmtime); |
|
138 return timet * msPerSecond + systemTime.wMilliseconds; |
|
139 #else |
|
140 struct _timeb timebuffer; |
|
141 _ftime(&timebuffer); |
|
142 return timebuffer.time * msPerSecond + timebuffer.millitm; |
|
143 #endif |
|
144 } |
|
145 |
|
146 static bool qpcAvailable() |
|
147 { |
|
148 static bool available; |
|
149 static bool checked; |
|
150 |
|
151 if (checked) |
|
152 return available; |
|
153 |
|
154 available = QueryPerformanceFrequency(&qpcFrequency); |
|
155 checked = true; |
|
156 return available; |
|
157 } |
|
158 |
|
159 double currentTime() |
|
160 { |
|
161 // Use a combination of ftime and QueryPerformanceCounter. |
|
162 // ftime returns the information we want, but doesn't have sufficient resolution. |
|
163 // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals. |
|
164 // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter |
|
165 // by itself, adding the delta to the saved ftime. We periodically re-sync to correct for drift. |
|
166 static double syncLowResUTCTime; |
|
167 static double syncHighResUpTime; |
|
168 static double lastUTCTime; |
|
169 |
|
170 double lowResTime = lowResUTCTime(); |
|
171 |
|
172 if (!qpcAvailable()) |
|
173 return lowResTime / 1000.0; |
|
174 |
|
175 double highResTime = highResUpTime(); |
|
176 |
|
177 if (!syncedTime) { |
|
178 timeBeginPeriod(1); // increase time resolution around low-res time getter |
|
179 syncLowResUTCTime = lowResTime = lowResUTCTime(); |
|
180 timeEndPeriod(1); // restore time resolution |
|
181 syncHighResUpTime = highResTime; |
|
182 syncedTime = true; |
|
183 } |
|
184 |
|
185 double highResElapsed = highResTime - syncHighResUpTime; |
|
186 double utc = syncLowResUTCTime + highResElapsed; |
|
187 |
|
188 // force a clock re-sync if we've drifted |
|
189 double lowResElapsed = lowResTime - syncLowResUTCTime; |
|
190 const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy |
|
191 if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec) |
|
192 syncedTime = false; |
|
193 |
|
194 // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur) |
|
195 const double backwardTimeLimit = 2000.0; |
|
196 if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit) |
|
197 return lastUTCTime / 1000.0; |
|
198 lastUTCTime = utc; |
|
199 return utc / 1000.0; |
|
200 } |
|
201 |
|
202 #else |
|
203 |
|
204 static double currentSystemTime() |
|
205 { |
|
206 FILETIME ft; |
|
207 GetCurrentFT(&ft); |
|
208 |
|
209 // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a |
|
210 // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can |
|
211 // prevent alignment faults on 64-bit Windows). |
|
212 |
|
213 ULARGE_INTEGER t; |
|
214 memcpy(&t, &ft, sizeof(t)); |
|
215 |
|
216 // Windows file times are in 100s of nanoseconds. |
|
217 // To convert to seconds, we have to divide by 10,000,000, which is more quickly |
|
218 // done by multiplying by 0.0000001. |
|
219 |
|
220 // Between January 1, 1601 and January 1, 1970, there were 369 complete years, |
|
221 // of which 89 were leap years (1700, 1800, and 1900 were not leap years). |
|
222 // That is a total of 134774 days, which is 11644473600 seconds. |
|
223 |
|
224 return t.QuadPart * 0.0000001 - 11644473600.0; |
|
225 } |
|
226 |
|
227 double currentTime() |
|
228 { |
|
229 static bool init = false; |
|
230 static double lastTime; |
|
231 static DWORD lastTickCount; |
|
232 if (!init) { |
|
233 lastTime = currentSystemTime(); |
|
234 lastTickCount = GetTickCount(); |
|
235 init = true; |
|
236 return lastTime; |
|
237 } |
|
238 |
|
239 DWORD tickCountNow = GetTickCount(); |
|
240 DWORD elapsed = tickCountNow - lastTickCount; |
|
241 double timeNow = lastTime + (double)elapsed / 1000.; |
|
242 if (elapsed >= 0x7FFFFFFF) { |
|
243 lastTime = timeNow; |
|
244 lastTickCount = tickCountNow; |
|
245 } |
|
246 return timeNow; |
|
247 } |
|
248 |
|
249 #endif // USE(QUERY_PERFORMANCE_COUNTER) |
|
250 |
|
251 #elif PLATFORM(GTK) |
|
252 |
|
253 // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides |
|
254 // better accuracy compared with Windows implementation of g_get_current_time: |
|
255 // (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time). |
|
256 // Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function. |
|
257 double currentTime() |
|
258 { |
|
259 GTimeVal now; |
|
260 g_get_current_time(&now); |
|
261 return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0); |
|
262 } |
|
263 |
|
264 #elif PLATFORM(WX) |
|
265 |
|
266 double currentTime() |
|
267 { |
|
268 wxDateTime now = wxDateTime::UNow(); |
|
269 return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0); |
|
270 } |
|
271 |
|
272 #elif PLATFORM(BREWMP) |
|
273 |
|
274 // GETUTCSECONDS returns the number of seconds since 1980/01/06 00:00:00 UTC, |
|
275 // and GETTIMEMS returns the number of milliseconds that have elapsed since the last |
|
276 // occurrence of 00:00:00 local time. |
|
277 // We can combine GETUTCSECONDS and GETTIMEMS to calculate the number of milliseconds |
|
278 // since 1970/01/01 00:00:00 UTC. |
|
279 double currentTime() |
|
280 { |
|
281 // diffSeconds is the number of seconds from 1970/01/01 to 1980/01/06 |
|
282 const unsigned diffSeconds = 315964800; |
|
283 return static_cast<double>(diffSeconds + GETUTCSECONDS() + ((GETTIMEMS() % 1000) / msPerSecond)); |
|
284 } |
|
285 |
|
286 #else |
|
287 |
|
288 double currentTime() |
|
289 { |
|
290 struct timeval now; |
|
291 gettimeofday(&now, 0); |
|
292 return now.tv_sec + now.tv_usec / 1000000.0; |
|
293 } |
|
294 |
|
295 #endif |
|
296 |
|
297 } // namespace WTF |