• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #elif PLATFORM(BREWMP)
63 #include <AEEStdLib.h>
64 #else // Posix systems relying on the gettimeofday()
65 #include <sys/time.h>
66 #endif
67 
68 #if PLATFORM(CHROMIUM)
69 #error Chromium uses a different timer implementation
70 #endif
71 
72 namespace WTF {
73 
74 const double msPerSecond = 1000.0;
75 
76 #if OS(WINDOWS)
77 
78 #if USE(QUERY_PERFORMANCE_COUNTER)
79 
80 static LARGE_INTEGER qpcFrequency;
81 static bool syncedTime;
82 
highResUpTime()83 static double highResUpTime()
84 {
85     // We use QPC, but only after sanity checking its result, due to bugs:
86     // http://support.microsoft.com/kb/274323
87     // http://support.microsoft.com/kb/895980
88     // 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)."
89 
90     static LARGE_INTEGER qpcLast;
91     static DWORD tickCountLast;
92     static bool inited;
93 
94     LARGE_INTEGER qpc;
95     QueryPerformanceCounter(&qpc);
96     DWORD tickCount = GetTickCount();
97 
98     if (inited) {
99         __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart;
100         __int64 tickCountElapsed;
101         if (tickCount >= tickCountLast)
102             tickCountElapsed = (tickCount - tickCountLast);
103         else {
104 #if COMPILER(MINGW)
105             __int64 tickCountLarge = tickCount + 0x100000000ULL;
106 #else
107             __int64 tickCountLarge = tickCount + 0x100000000I64;
108 #endif
109             tickCountElapsed = tickCountLarge - tickCountLast;
110         }
111 
112         // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms.
113         // (500ms value is from http://support.microsoft.com/kb/274323)
114         __int64 diff = tickCountElapsed - qpcElapsed;
115         if (diff > 500 || diff < -500)
116             syncedTime = false;
117     } else
118         inited = true;
119 
120     qpcLast = qpc;
121     tickCountLast = tickCount;
122 
123     return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart);
124 }
125 
lowResUTCTime()126 static double lowResUTCTime()
127 {
128 #if OS(WINCE)
129     SYSTEMTIME systemTime;
130     GetSystemTime(&systemTime);
131     struct tm tmtime;
132     tmtime.tm_year = systemTime.wYear - 1900;
133     tmtime.tm_mon = systemTime.wMonth - 1;
134     tmtime.tm_mday = systemTime.wDay;
135     tmtime.tm_wday = systemTime.wDayOfWeek;
136     tmtime.tm_hour = systemTime.wHour;
137     tmtime.tm_min = systemTime.wMinute;
138     tmtime.tm_sec = systemTime.wSecond;
139     time_t timet = mktime(&tmtime);
140     return timet * msPerSecond + systemTime.wMilliseconds;
141 #else
142     struct _timeb timebuffer;
143     _ftime(&timebuffer);
144     return timebuffer.time * msPerSecond + timebuffer.millitm;
145 #endif
146 }
147 
qpcAvailable()148 static bool qpcAvailable()
149 {
150     static bool available;
151     static bool checked;
152 
153     if (checked)
154         return available;
155 
156     available = QueryPerformanceFrequency(&qpcFrequency);
157     checked = true;
158     return available;
159 }
160 
currentTime()161 double currentTime()
162 {
163     // Use a combination of ftime and QueryPerformanceCounter.
164     // ftime returns the information we want, but doesn't have sufficient resolution.
165     // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals.
166     // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter
167     // by itself, adding the delta to the saved ftime.  We periodically re-sync to correct for drift.
168     static bool started;
169     static double syncLowResUTCTime;
170     static double syncHighResUpTime;
171     static double lastUTCTime;
172 
173     double lowResTime = lowResUTCTime();
174 
175     if (!qpcAvailable())
176         return lowResTime / 1000.0;
177 
178     double highResTime = highResUpTime();
179 
180     if (!syncedTime) {
181         timeBeginPeriod(1); // increase time resolution around low-res time getter
182         syncLowResUTCTime = lowResTime = lowResUTCTime();
183         timeEndPeriod(1); // restore time resolution
184         syncHighResUpTime = highResTime;
185         syncedTime = true;
186     }
187 
188     double highResElapsed = highResTime - syncHighResUpTime;
189     double utc = syncLowResUTCTime + highResElapsed;
190 
191     // force a clock re-sync if we've drifted
192     double lowResElapsed = lowResTime - syncLowResUTCTime;
193     const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy
194     if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec)
195         syncedTime = false;
196 
197     // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur)
198     const double backwardTimeLimit = 2000.0;
199     if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit)
200         return lastUTCTime / 1000.0;
201     lastUTCTime = utc;
202     return utc / 1000.0;
203 }
204 
205 #else
206 
currentSystemTime()207 static double currentSystemTime()
208 {
209     FILETIME ft;
210     GetCurrentFT(&ft);
211 
212     // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a
213     // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can
214     // prevent alignment faults on 64-bit Windows).
215 
216     ULARGE_INTEGER t;
217     memcpy(&t, &ft, sizeof(t));
218 
219     // Windows file times are in 100s of nanoseconds.
220     // To convert to seconds, we have to divide by 10,000,000, which is more quickly
221     // done by multiplying by 0.0000001.
222 
223     // Between January 1, 1601 and January 1, 1970, there were 369 complete years,
224     // of which 89 were leap years (1700, 1800, and 1900 were not leap years).
225     // That is a total of 134774 days, which is 11644473600 seconds.
226 
227     return t.QuadPart * 0.0000001 - 11644473600.0;
228 }
229 
currentTime()230 double currentTime()
231 {
232     static bool init = false;
233     static double lastTime;
234     static DWORD lastTickCount;
235     if (!init) {
236         lastTime = currentSystemTime();
237         lastTickCount = GetTickCount();
238         init = true;
239         return lastTime;
240     }
241 
242     DWORD tickCountNow = GetTickCount();
243     DWORD elapsed = tickCountNow - lastTickCount;
244     double timeNow = lastTime + (double)elapsed / 1000.;
245     if (elapsed >= 0x7FFFFFFF) {
246         lastTime = timeNow;
247         lastTickCount = tickCountNow;
248     }
249     return timeNow;
250 }
251 
252 #endif // USE(QUERY_PERFORMANCE_COUNTER)
253 
254 #elif PLATFORM(CF)
255 
currentTime()256 double currentTime()
257 {
258     return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970;
259 }
260 
261 #elif PLATFORM(GTK)
262 
263 // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides
264 // better accuracy compared with Windows implementation of g_get_current_time:
265 // (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time).
266 // Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function.
currentTime()267 double currentTime()
268 {
269     GTimeVal now;
270     g_get_current_time(&now);
271     return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0);
272 }
273 
274 #elif PLATFORM(WX)
275 
currentTime()276 double currentTime()
277 {
278     wxDateTime now = wxDateTime::UNow();
279     return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0);
280 }
281 
282 #elif PLATFORM(BREWMP)
283 
284 // GETUTCSECONDS returns the number of seconds since 1980/01/06 00:00:00 UTC,
285 // and GETTIMEMS returns the number of milliseconds that have elapsed since the last
286 // occurrence of 00:00:00 local time.
287 // We can combine GETUTCSECONDS and GETTIMEMS to calculate the number of milliseconds
288 // since 1970/01/01 00:00:00 UTC.
currentTime()289 double currentTime()
290 {
291     // diffSeconds is the number of seconds from 1970/01/01 to 1980/01/06
292     const unsigned diffSeconds = 315964800;
293     return static_cast<double>(diffSeconds + GETUTCSECONDS() + ((GETTIMEMS() % 1000) / msPerSecond));
294 }
295 
296 #else // Other Posix systems rely on the gettimeofday().
297 
currentTime()298 double currentTime()
299 {
300     struct timeval now;
301     struct timezone zone;
302 
303     gettimeofday(&now, &zone);
304     return static_cast<double>(now.tv_sec) + (double)(now.tv_usec / 1000000.0);
305 }
306 
307 #endif
308 
309 } // namespace WTF
310