[Win] Clean up some 64-bit warnings from Visual Studio analyzer
[WebKit-https.git] / Source / WTF / wtf / CurrentTime.cpp
1 /*
2  * Copyright (C) 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Google Inc. All rights reserved.
4  * Copyright (C) 2007-2009 Torch Mobile, Inc.
5  * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following disclaimer
15  * in the documentation and/or other materials provided with the
16  * distribution.
17  *     * Neither the name of Google Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include "config.h"
35 #include "CurrentTime.h"
36
37 #if OS(DARWIN)
38 #include <mach/mach.h>
39 #include <mach/mach_time.h>
40 #include <sys/time.h>
41 #elif OS(WINDOWS)
42
43 // Windows is first since we want to use hires timers, despite USE(CF)
44 // being defined.
45 // If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod.
46 #undef WIN32_LEAN_AND_MEAN
47 #include <windows.h>
48 #include <math.h>
49 #include <stdint.h>
50 #include <time.h>
51
52 #elif PLATFORM(EFL)
53 #include <Ecore.h>
54 #else
55 #include <sys/time.h>
56 #endif
57
58 #if USE(GLIB) && !PLATFORM(EFL)
59 #include <glib.h>
60 #endif
61
62 namespace WTF {
63
64 #if OS(WINDOWS)
65
66 // Number of 100 nanosecond between January 1, 1601 and January 1, 1970.
67 static const ULONGLONG epochBias = 116444736000000000ULL;
68 static const double hundredsOfNanosecondsPerMillisecond = 10000;
69
70 static double lowResUTCTime()
71 {
72     FILETIME fileTime;
73
74 #if OS(WINCE)
75     GetCurrentFT(&fileTime);
76 #else
77     GetSystemTimeAsFileTime(&fileTime);
78 #endif
79
80     // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a
81     // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can
82     // prevent alignment faults on 64-bit Windows).
83
84     ULARGE_INTEGER dateTime;
85     memcpy(&dateTime, &fileTime, sizeof(dateTime));
86
87     // Windows file times are in 100s of nanoseconds.
88     return (dateTime.QuadPart - epochBias) / hundredsOfNanosecondsPerMillisecond;
89 }
90
91 #if USE(QUERY_PERFORMANCE_COUNTER)
92
93 static LARGE_INTEGER qpcFrequency;
94 static bool syncedTime;
95
96 static double highResUpTime()
97 {
98     // We use QPC, but only after sanity checking its result, due to bugs:
99     // http://support.microsoft.com/kb/274323
100     // http://support.microsoft.com/kb/895980
101     // 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)."
102
103     static LARGE_INTEGER qpcLast;
104     static DWORD tickCountLast;
105     static bool inited;
106
107     LARGE_INTEGER qpc;
108     QueryPerformanceCounter(&qpc);
109 #if defined(_M_IX86) || defined(__i386__)
110     DWORD tickCount = GetTickCount();
111 #else
112     ULONGLONG tickCount = GetTickCount64();
113 #endif
114
115     if (inited) {
116         __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart;
117         __int64 tickCountElapsed;
118         if (tickCount >= tickCountLast)
119             tickCountElapsed = (tickCount - tickCountLast);
120         else {
121 #if COMPILER(MINGW)
122             __int64 tickCountLarge = tickCount + 0x100000000ULL;
123 #else
124             __int64 tickCountLarge = tickCount + 0x100000000I64;
125 #endif
126             tickCountElapsed = tickCountLarge - tickCountLast;
127         }
128
129         // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms.
130         // (500ms value is from http://support.microsoft.com/kb/274323)
131         __int64 diff = tickCountElapsed - qpcElapsed;
132         if (diff > 500 || diff < -500)
133             syncedTime = false;
134     } else
135         inited = true;
136
137     qpcLast = qpc;
138     tickCountLast = tickCount;
139
140     return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart);
141 }
142
143 static bool qpcAvailable()
144 {
145     static bool available;
146     static bool checked;
147
148     if (checked)
149         return available;
150
151     available = QueryPerformanceFrequency(&qpcFrequency);
152     checked = true;
153     return available;
154 }
155
156 double currentTime()
157 {
158     // Use a combination of ftime and QueryPerformanceCounter.
159     // ftime returns the information we want, but doesn't have sufficient resolution.
160     // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals.
161     // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter
162     // by itself, adding the delta to the saved ftime.  We periodically re-sync to correct for drift.
163     static double syncLowResUTCTime;
164     static double syncHighResUpTime;
165     static double lastUTCTime;
166
167     double lowResTime = lowResUTCTime();
168
169     if (!qpcAvailable())
170         return lowResTime / 1000.0;
171
172     double highResTime = highResUpTime();
173
174     if (!syncedTime) {
175         timeBeginPeriod(1); // increase time resolution around low-res time getter
176         syncLowResUTCTime = lowResTime = lowResUTCTime();
177         timeEndPeriod(1); // restore time resolution
178         syncHighResUpTime = highResTime;
179         syncedTime = true;
180     }
181
182     double highResElapsed = highResTime - syncHighResUpTime;
183     double utc = syncLowResUTCTime + highResElapsed;
184
185     // force a clock re-sync if we've drifted
186     double lowResElapsed = lowResTime - syncLowResUTCTime;
187     const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy
188     if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec)
189         syncedTime = false;
190
191     // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur)
192     const double backwardTimeLimit = 2000.0;
193     if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit)
194         return lastUTCTime / 1000.0;
195     lastUTCTime = utc;
196     return utc / 1000.0;
197 }
198
199 #else
200
201 double currentTime()
202 {
203     static bool init = false;
204     static double lastTime;
205     static DWORD lastTickCount;
206     if (!init) {
207         lastTime = lowResUTCTime();
208         lastTickCount = GetTickCount();
209         init = true;
210         return lastTime;
211     }
212
213     DWORD tickCountNow = GetTickCount();
214     DWORD elapsed = tickCountNow - lastTickCount;
215     double timeNow = lastTime + (double)elapsed / 1000.;
216     if (elapsed >= 0x7FFFFFFF) {
217         lastTime = timeNow;
218         lastTickCount = tickCountNow;
219     }
220     return timeNow;
221 }
222
223 #endif // USE(QUERY_PERFORMANCE_COUNTER)
224
225 #elif USE(GLIB) && !PLATFORM(EFL)
226
227 // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides
228 // better accuracy compared with Windows implementation of g_get_current_time:
229 // (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time).
230 // Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function.
231 double currentTime()
232 {
233     GTimeVal now;
234     g_get_current_time(&now);
235     return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0);
236 }
237
238 #elif PLATFORM(EFL)
239
240 double currentTime()
241 {
242     return ecore_time_unix_get();
243 }
244
245 #else
246
247 double currentTime()
248 {
249     struct timeval now;
250     gettimeofday(&now, 0);
251     return now.tv_sec + now.tv_usec / 1000000.0;
252 }
253
254 #endif
255
256 #if PLATFORM(EFL)
257
258 double monotonicallyIncreasingTime()
259 {
260     return ecore_time_get();
261 }
262
263 #elif USE(GLIB)
264
265 double monotonicallyIncreasingTime()
266 {
267     return static_cast<double>(g_get_monotonic_time() / 1000000.0);
268 }
269
270 #elif OS(DARWIN)
271
272 double monotonicallyIncreasingTime()
273 {
274     // Based on listing #2 from Apple QA 1398.
275     static mach_timebase_info_data_t timebaseInfo;
276     if (!timebaseInfo.denom) {
277         kern_return_t kr = mach_timebase_info(&timebaseInfo);
278         ASSERT_UNUSED(kr, kr == KERN_SUCCESS);
279     }
280     return (mach_absolute_time() * timebaseInfo.numer) / (1.0e9 * timebaseInfo.denom);
281 }
282
283 #else
284
285 double monotonicallyIncreasingTime()
286 {
287     static double lastTime = 0;
288     double currentTimeNow = currentTime();
289     if (currentTimeNow < lastTime)
290         return lastTime;
291     lastTime = currentTimeNow;
292     return currentTimeNow;
293 }
294
295 #endif
296
297 double currentCPUTime()
298 {
299 #if OS(DARWIN)
300     mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
301     thread_basic_info_data_t info;
302
303     // Get thread information
304     mach_port_t threadPort = mach_thread_self();
305     thread_info(threadPort, THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
306     mach_port_deallocate(mach_task_self(), threadPort);
307     
308     double time = info.user_time.seconds + info.user_time.microseconds / 1000000.;
309     time += info.system_time.seconds + info.system_time.microseconds / 1000000.;
310     
311     return time;
312 #elif OS(WINDOWS)
313     union {
314         FILETIME fileTime;
315         unsigned long long fileTimeAsLong;
316     } userTime, kernelTime;
317     
318     // GetThreadTimes won't accept null arguments so we pass these even though
319     // they're not used.
320     FILETIME creationTime, exitTime;
321     
322     GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
323     
324     return userTime.fileTimeAsLong / 10000000. + kernelTime.fileTimeAsLong / 10000000.;
325 #else
326     // FIXME: We should return the time the current thread has spent executing.
327
328     // use a relative time from first call in order to avoid an overflow
329     static double firstTime = currentTime();
330     return currentTime() - firstTime;
331 #endif
332 }
333
334 double currentCPUTimeMS()
335 {
336     return currentCPUTime() * 1000;
337 }
338
339 } // namespace WTF