]> git.saurik.com Git - apple/javascriptcore.git/blob - wtf/CurrentTime.cpp
b2728747bbb51559f10b74a128e44065459d23c0
[apple/javascriptcore.git] / wtf / CurrentTime.cpp
1 /*
2 * Copyright (C) 2006 Apple Computer, 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(CF)
57 #include <CoreFoundation/CFDate.h>
58 #elif PLATFORM(GTK)
59 #include <glib.h>
60 #elif PLATFORM(WX)
61 #include <wx/datetime.h>
62 #else // Posix systems relying on the gettimeofday()
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 bool started;
167 static double syncLowResUTCTime;
168 static double syncHighResUpTime;
169 static double lastUTCTime;
170
171 double lowResTime = lowResUTCTime();
172
173 if (!qpcAvailable())
174 return lowResTime / 1000.0;
175
176 double highResTime = highResUpTime();
177
178 if (!syncedTime) {
179 timeBeginPeriod(1); // increase time resolution around low-res time getter
180 syncLowResUTCTime = lowResTime = lowResUTCTime();
181 timeEndPeriod(1); // restore time resolution
182 syncHighResUpTime = highResTime;
183 syncedTime = true;
184 }
185
186 double highResElapsed = highResTime - syncHighResUpTime;
187 double utc = syncLowResUTCTime + highResElapsed;
188
189 // force a clock re-sync if we've drifted
190 double lowResElapsed = lowResTime - syncLowResUTCTime;
191 const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy
192 if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec)
193 syncedTime = false;
194
195 // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur)
196 const double backwardTimeLimit = 2000.0;
197 if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit)
198 return lastUTCTime / 1000.0;
199 lastUTCTime = utc;
200 return utc / 1000.0;
201 }
202
203 #else
204
205 static double currentSystemTime()
206 {
207 FILETIME ft;
208 GetCurrentFT(&ft);
209
210 // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a
211 // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can
212 // prevent alignment faults on 64-bit Windows).
213
214 ULARGE_INTEGER t;
215 memcpy(&t, &ft, sizeof(t));
216
217 // Windows file times are in 100s of nanoseconds.
218 // To convert to seconds, we have to divide by 10,000,000, which is more quickly
219 // done by multiplying by 0.0000001.
220
221 // Between January 1, 1601 and January 1, 1970, there were 369 complete years,
222 // of which 89 were leap years (1700, 1800, and 1900 were not leap years).
223 // That is a total of 134774 days, which is 11644473600 seconds.
224
225 return t.QuadPart * 0.0000001 - 11644473600.0;
226 }
227
228 double currentTime()
229 {
230 static bool init = false;
231 static double lastTime;
232 static DWORD lastTickCount;
233 if (!init) {
234 lastTime = currentSystemTime();
235 lastTickCount = GetTickCount();
236 init = true;
237 return lastTime;
238 }
239
240 DWORD tickCountNow = GetTickCount();
241 DWORD elapsed = tickCountNow - lastTickCount;
242 double timeNow = lastTime + (double)elapsed / 1000.;
243 if (elapsed >= 0x7FFFFFFF) {
244 lastTime = timeNow;
245 lastTickCount = tickCountNow;
246 }
247 return timeNow;
248 }
249
250 #endif // USE(QUERY_PERFORMANCE_COUNTER)
251
252 #elif PLATFORM(CF)
253
254 double currentTime()
255 {
256 return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970;
257 }
258
259 #elif PLATFORM(GTK)
260
261 // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides
262 // better accuracy compared with Windows implementation of g_get_current_time:
263 // (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time).
264 // Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function.
265 double currentTime()
266 {
267 GTimeVal now;
268 g_get_current_time(&now);
269 return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0);
270 }
271
272 #elif PLATFORM(WX)
273
274 double currentTime()
275 {
276 wxDateTime now = wxDateTime::UNow();
277 return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0);
278 }
279
280 #else // Other Posix systems rely on the gettimeofday().
281
282 double currentTime()
283 {
284 struct timeval now;
285 struct timezone zone;
286
287 gettimeofday(&now, &zone);
288 return static_cast<double>(now.tv_sec) + (double)(now.tv_usec / 1000000.0);
289 }
290
291 #endif
292
293 } // namespace WTF