• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 USE(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 
highResUpTime()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 
lowResUTCTime()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 
qpcAvailable()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 
currentTime()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 
currentSystemTime()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 
currentTime()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.
currentTime()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 
currentTime()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.
currentTime()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 
currentTime()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
298