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.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
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
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.
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.
34 #include "CurrentTime.h"
38 // Windows is first since we want to use hires timers, despite PLATFORM(CF)
40 // If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod.
41 #undef WIN32_LEAN_AND_MEAN
47 #if USE(QUERY_PERFORMANCE_COUNTER)
49 extern "C" time_t mktime(struct tm
*t
);
51 #include <sys/timeb.h>
52 #include <sys/types.h>
59 #include <wx/datetime.h>
60 #elif PLATFORM(BREWMP)
61 #include <AEEStdLib.h>
66 #if PLATFORM(CHROMIUM)
67 #error Chromium uses a different timer implementation
72 const double msPerSecond
= 1000.0;
76 #if USE(QUERY_PERFORMANCE_COUNTER)
78 static LARGE_INTEGER qpcFrequency
;
79 static bool syncedTime
;
81 static double highResUpTime()
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)."
88 static LARGE_INTEGER qpcLast
;
89 static DWORD tickCountLast
;
93 QueryPerformanceCounter(&qpc
);
94 DWORD tickCount
= GetTickCount();
97 __int64 qpcElapsed
= ((qpc
.QuadPart
- qpcLast
.QuadPart
) * 1000) / qpcFrequency
.QuadPart
;
98 __int64 tickCountElapsed
;
99 if (tickCount
>= tickCountLast
)
100 tickCountElapsed
= (tickCount
- tickCountLast
);
103 __int64 tickCountLarge
= tickCount
+ 0x100000000ULL
;
105 __int64 tickCountLarge
= tickCount
+ 0x100000000I
64;
107 tickCountElapsed
= tickCountLarge
- tickCountLast
;
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)
119 tickCountLast
= tickCount
;
121 return (1000.0 * qpc
.QuadPart
) / static_cast<double>(qpcFrequency
.QuadPart
);
124 static double lowResUTCTime()
127 SYSTEMTIME systemTime
;
128 GetSystemTime(&systemTime
);
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
;
140 struct _timeb timebuffer
;
142 return timebuffer
.time
* msPerSecond
+ timebuffer
.millitm
;
146 static bool qpcAvailable()
148 static bool available
;
154 available
= QueryPerformanceFrequency(&qpcFrequency
);
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.
167 static double syncLowResUTCTime
;
168 static double syncHighResUpTime
;
169 static double lastUTCTime
;
171 double lowResTime
= lowResUTCTime();
174 return lowResTime
/ 1000.0;
176 double highResTime
= highResUpTime();
179 timeBeginPeriod(1); // increase time resolution around low-res time getter
180 syncLowResUTCTime
= lowResTime
= lowResUTCTime();
181 timeEndPeriod(1); // restore time resolution
182 syncHighResUpTime
= highResTime
;
186 double highResElapsed
= highResTime
- syncHighResUpTime
;
187 double utc
= syncLowResUTCTime
+ highResElapsed
;
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
)
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;
205 static double currentSystemTime()
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).
215 memcpy(&t
, &ft
, sizeof(t
));
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.
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.
225 return t
.QuadPart
* 0.0000001 - 11644473600.0;
230 static bool init
= false;
231 static double lastTime
;
232 static DWORD lastTickCount
;
234 lastTime
= currentSystemTime();
235 lastTickCount
= GetTickCount();
240 DWORD tickCountNow
= GetTickCount();
241 DWORD elapsed
= tickCountNow
- lastTickCount
;
242 double timeNow
= lastTime
+ (double)elapsed
/ 1000.;
243 if (elapsed
>= 0x7FFFFFFF) {
245 lastTickCount
= tickCountNow
;
250 #endif // USE(QUERY_PERFORMANCE_COUNTER)
254 // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides
255 // better accuracy compared with Windows implementation of g_get_current_time:
256 // (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time).
257 // Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function.
261 g_get_current_time(&now
);
262 return static_cast<double>(now
.tv_sec
) + static_cast<double>(now
.tv_usec
/ 1000000.0);
269 wxDateTime now
= wxDateTime::UNow();
270 return (double)now
.GetTicks() + (double)(now
.GetMillisecond() / 1000.0);
273 #elif PLATFORM(BREWMP)
275 // GETUTCSECONDS returns the number of seconds since 1980/01/06 00:00:00 UTC,
276 // and GETTIMEMS returns the number of milliseconds that have elapsed since the last
277 // occurrence of 00:00:00 local time.
278 // We can combine GETUTCSECONDS and GETTIMEMS to calculate the number of milliseconds
279 // since 1970/01/01 00:00:00 UTC.
282 // diffSeconds is the number of seconds from 1970/01/01 to 1980/01/06
283 const unsigned diffSeconds
= 315964800;
284 return static_cast<double>(diffSeconds
+ GETUTCSECONDS() + ((GETTIMEMS() % 1000) / msPerSecond
));
292 gettimeofday(&now
, 0);
293 return now
.tv_sec
+ now
.tv_usec
/ 1000000.0;