]> git.saurik.com Git - apple/javascriptcore.git/blame - wtf/CurrentTime.cpp
JavaScriptCore-554.1.tar.gz
[apple/javascriptcore.git] / wtf / CurrentTime.cpp
CommitLineData
9dae56ea
A
1/*
2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
3 * Copyright (C) 2008 Google Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "config.h"
33#include "CurrentTime.h"
34
ba379fdc
A
35#if PLATFORM(WIN_OS)
36// Windows is first since we want to use hires timers, despite PLATFORM(CF)
37// being defined.
9dae56ea
A
38// If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod.
39#undef WIN32_LEAN_AND_MEAN
40#include <windows.h>
41#include <math.h>
42#include <stdint.h>
43#include <sys/timeb.h>
44#include <sys/types.h>
45#include <time.h>
ba379fdc
A
46#elif PLATFORM(CF)
47#include <CoreFoundation/CFDate.h>
48#elif PLATFORM(GTK)
49#include <glib.h>
50#elif PLATFORM(WX)
51#include <wx/datetime.h>
9dae56ea
A
52#else // Posix systems relying on the gettimeofday()
53#include <sys/time.h>
54#endif
55
56namespace WTF {
57
58const double msPerSecond = 1000.0;
59
ba379fdc 60#if PLATFORM(WIN_OS)
9dae56ea
A
61
62static LARGE_INTEGER qpcFrequency;
63static bool syncedTime;
64
65static double highResUpTime()
66{
67 // We use QPC, but only after sanity checking its result, due to bugs:
68 // http://support.microsoft.com/kb/274323
69 // http://support.microsoft.com/kb/895980
70 // 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)."
71
72 static LARGE_INTEGER qpcLast;
73 static DWORD tickCountLast;
74 static bool inited;
75
76 LARGE_INTEGER qpc;
77 QueryPerformanceCounter(&qpc);
78 DWORD tickCount = GetTickCount();
79
80 if (inited) {
81 __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart;
82 __int64 tickCountElapsed;
83 if (tickCount >= tickCountLast)
84 tickCountElapsed = (tickCount - tickCountLast);
85 else {
86#if COMPILER(MINGW)
87 __int64 tickCountLarge = tickCount + 0x100000000ULL;
88#else
89 __int64 tickCountLarge = tickCount + 0x100000000I64;
90#endif
91 tickCountElapsed = tickCountLarge - tickCountLast;
92 }
93
94 // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms.
95 // (500ms value is from http://support.microsoft.com/kb/274323)
96 __int64 diff = tickCountElapsed - qpcElapsed;
97 if (diff > 500 || diff < -500)
98 syncedTime = false;
99 } else
100 inited = true;
101
102 qpcLast = qpc;
103 tickCountLast = tickCount;
104
105 return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart);
106}
107
108static double lowResUTCTime()
109{
ba379fdc 110#if PLATFORM(WINCE)
9dae56ea
A
111 SYSTEMTIME systemTime;
112 GetSystemTime(&systemTime);
113 struct tm tmtime;
114 tmtime.tm_year = systemTime.wYear - 1900;
115 tmtime.tm_mon = systemTime.wMonth - 1;
116 tmtime.tm_mday = systemTime.wDay;
117 tmtime.tm_wday = systemTime.wDayOfWeek;
118 tmtime.tm_hour = systemTime.wHour;
119 tmtime.tm_min = systemTime.wMinute;
120 tmtime.tm_sec = systemTime.wSecond;
121 time_t timet = mktime(&tmtime);
122 return timet * msPerSecond + systemTime.wMilliseconds;
ba379fdc 123#else
9dae56ea
A
124 struct _timeb timebuffer;
125 _ftime(&timebuffer);
126 return timebuffer.time * msPerSecond + timebuffer.millitm;
ba379fdc 127#endif
9dae56ea
A
128}
129
130static bool qpcAvailable()
131{
132 static bool available;
133 static bool checked;
134
135 if (checked)
136 return available;
137
138 available = QueryPerformanceFrequency(&qpcFrequency);
139 checked = true;
140 return available;
141}
142
143double currentTime()
144{
145 // Use a combination of ftime and QueryPerformanceCounter.
146 // ftime returns the information we want, but doesn't have sufficient resolution.
147 // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals.
148 // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter
149 // by itself, adding the delta to the saved ftime. We periodically re-sync to correct for drift.
150 static bool started;
151 static double syncLowResUTCTime;
152 static double syncHighResUpTime;
153 static double lastUTCTime;
154
155 double lowResTime = lowResUTCTime();
156
157 if (!qpcAvailable())
158 return lowResTime / 1000.0;
159
160 double highResTime = highResUpTime();
161
162 if (!syncedTime) {
163 timeBeginPeriod(1); // increase time resolution around low-res time getter
164 syncLowResUTCTime = lowResTime = lowResUTCTime();
165 timeEndPeriod(1); // restore time resolution
166 syncHighResUpTime = highResTime;
167 syncedTime = true;
168 }
169
170 double highResElapsed = highResTime - syncHighResUpTime;
171 double utc = syncLowResUTCTime + highResElapsed;
172
173 // force a clock re-sync if we've drifted
174 double lowResElapsed = lowResTime - syncLowResUTCTime;
175 const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy
176 if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec)
177 syncedTime = false;
178
179 // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur)
180 const double backwardTimeLimit = 2000.0;
181 if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit)
182 return lastUTCTime / 1000.0;
183 lastUTCTime = utc;
184 return utc / 1000.0;
185}
186
ba379fdc
A
187#elif PLATFORM(CF)
188
189double currentTime()
190{
191 return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970;
192}
193
194#elif PLATFORM(GTK)
195
196// Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides
197// better accuracy compared with Windows implementation of g_get_current_time:
198// (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time).
199// Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function.
200double currentTime()
201{
202 GTimeVal now;
203 g_get_current_time(&now);
204 return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0);
205}
206
207#elif PLATFORM(WX)
208
209double currentTime()
210{
211 wxDateTime now = wxDateTime::UNow();
212 return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0);
213}
214
9dae56ea
A
215#else // Other Posix systems rely on the gettimeofday().
216
217double currentTime()
218{
219 struct timeval now;
220 struct timezone zone;
221
222 gettimeofday(&now, &zone);
223 return static_cast<double>(now.tv_sec) + (double)(now.tv_usec / 1000000.0);
224}
225
226#endif
227
228} // namespace WTF