]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - wtf/CurrentTime.cpp
JavaScriptCore-525.tar.gz
[apple/javascriptcore.git] / wtf / CurrentTime.cpp
... / ...
CommitLineData
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
35#if PLATFORM(MAC)
36#include <CoreFoundation/CFDate.h>
37#elif PLATFORM(GTK)
38#include <glib.h>
39#elif PLATFORM(WX)
40#include <wx/datetime.h>
41#elif PLATFORM(WIN_OS)
42// If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod.
43#undef WIN32_LEAN_AND_MEAN
44#include <windows.h>
45#include <math.h>
46#include <stdint.h>
47#include <sys/timeb.h>
48#include <sys/types.h>
49#include <time.h>
50#else // Posix systems relying on the gettimeofday()
51#include <sys/time.h>
52#endif
53
54namespace WTF {
55
56const double msPerSecond = 1000.0;
57
58#if PLATFORM(MAC)
59
60double currentTime()
61{
62 return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970;
63}
64
65#elif PLATFORM(GTK)
66
67// Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides
68// better accuracy compared with Windows implementation of g_get_current_time:
69// (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time).
70// Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function.
71double currentTime()
72{
73 GTimeVal now;
74 g_get_current_time(&now);
75 return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0);
76}
77
78#elif PLATFORM(WX)
79
80double currentTime()
81{
82 wxDateTime now = wxDateTime::UNow();
83 return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0);
84}
85
86#elif PLATFORM(WIN_OS)
87
88static LARGE_INTEGER qpcFrequency;
89static bool syncedTime;
90
91static double highResUpTime()
92{
93 // We use QPC, but only after sanity checking its result, due to bugs:
94 // http://support.microsoft.com/kb/274323
95 // http://support.microsoft.com/kb/895980
96 // 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)."
97
98 static LARGE_INTEGER qpcLast;
99 static DWORD tickCountLast;
100 static bool inited;
101
102 LARGE_INTEGER qpc;
103 QueryPerformanceCounter(&qpc);
104 DWORD tickCount = GetTickCount();
105
106 if (inited) {
107 __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart;
108 __int64 tickCountElapsed;
109 if (tickCount >= tickCountLast)
110 tickCountElapsed = (tickCount - tickCountLast);
111 else {
112#if COMPILER(MINGW)
113 __int64 tickCountLarge = tickCount + 0x100000000ULL;
114#else
115 __int64 tickCountLarge = tickCount + 0x100000000I64;
116#endif
117 tickCountElapsed = tickCountLarge - tickCountLast;
118 }
119
120 // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms.
121 // (500ms value is from http://support.microsoft.com/kb/274323)
122 __int64 diff = tickCountElapsed - qpcElapsed;
123 if (diff > 500 || diff < -500)
124 syncedTime = false;
125 } else
126 inited = true;
127
128 qpcLast = qpc;
129 tickCountLast = tickCount;
130
131 return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart);
132}
133
134static double lowResUTCTime()
135{
136#if PLATFORM(WIN_CE)
137 SYSTEMTIME systemTime;
138 GetSystemTime(&systemTime);
139 struct tm tmtime;
140 tmtime.tm_year = systemTime.wYear - 1900;
141 tmtime.tm_mon = systemTime.wMonth - 1;
142 tmtime.tm_mday = systemTime.wDay;
143 tmtime.tm_wday = systemTime.wDayOfWeek;
144 tmtime.tm_hour = systemTime.wHour;
145 tmtime.tm_min = systemTime.wMinute;
146 tmtime.tm_sec = systemTime.wSecond;
147 time_t timet = mktime(&tmtime);
148 return timet * msPerSecond + systemTime.wMilliseconds;
149#else // PLATFORM(WIN_CE)
150 struct _timeb timebuffer;
151 _ftime(&timebuffer);
152 return timebuffer.time * msPerSecond + timebuffer.millitm;
153#endif // PLATFORM(WIN_CE)
154}
155
156static bool qpcAvailable()
157{
158 static bool available;
159 static bool checked;
160
161 if (checked)
162 return available;
163
164 available = QueryPerformanceFrequency(&qpcFrequency);
165 checked = true;
166 return available;
167}
168
169double currentTime()
170{
171 // Use a combination of ftime and QueryPerformanceCounter.
172 // ftime returns the information we want, but doesn't have sufficient resolution.
173 // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals.
174 // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter
175 // by itself, adding the delta to the saved ftime. We periodically re-sync to correct for drift.
176 static bool started;
177 static double syncLowResUTCTime;
178 static double syncHighResUpTime;
179 static double lastUTCTime;
180
181 double lowResTime = lowResUTCTime();
182
183 if (!qpcAvailable())
184 return lowResTime / 1000.0;
185
186 double highResTime = highResUpTime();
187
188 if (!syncedTime) {
189 timeBeginPeriod(1); // increase time resolution around low-res time getter
190 syncLowResUTCTime = lowResTime = lowResUTCTime();
191 timeEndPeriod(1); // restore time resolution
192 syncHighResUpTime = highResTime;
193 syncedTime = true;
194 }
195
196 double highResElapsed = highResTime - syncHighResUpTime;
197 double utc = syncLowResUTCTime + highResElapsed;
198
199 // force a clock re-sync if we've drifted
200 double lowResElapsed = lowResTime - syncLowResUTCTime;
201 const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy
202 if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec)
203 syncedTime = false;
204
205 // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur)
206 const double backwardTimeLimit = 2000.0;
207 if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit)
208 return lastUTCTime / 1000.0;
209 lastUTCTime = utc;
210 return utc / 1000.0;
211}
212
213#else // Other Posix systems rely on the gettimeofday().
214
215double currentTime()
216{
217 struct timeval now;
218 struct timezone zone;
219
220 gettimeofday(&now, &zone);
221 return static_cast<double>(now.tv_sec) + (double)(now.tv_usec / 1000000.0);
222}
223
224#endif
225
226} // namespace WTF