[WTF] Move currentCPUTime and sleep(Seconds) to CPUTime.h and Seconds.h respectively
[WebKit-https.git] / Source / WTF / wtf / CurrentTime.cpp
1 /*
2  * Copyright (C) 2006-2016 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 "MonotonicTime.h"
36 #include "WallTime.h"
37
38 #if OS(DARWIN)
39 #include <mach/mach.h>
40 #include <mach/mach_time.h>
41 #include <mutex>
42 #include <sys/time.h>
43 #elif OS(WINDOWS)
44
45 // Windows is first since we want to use hires timers, despite USE(CF)
46 // being defined.
47 // If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod.
48 #undef WIN32_LEAN_AND_MEAN
49 #include <windows.h>
50 #include <math.h>
51 #include <stdint.h>
52 #include <time.h>
53 #else
54 #include <sys/time.h>
55 #endif
56
57 #if USE(GLIB)
58 #include <glib.h>
59 #endif
60
61 namespace WTF {
62
63 #if OS(WINDOWS)
64
65 // Number of 100 nanosecond between January 1, 1601 and January 1, 1970.
66 static const ULONGLONG epochBias = 116444736000000000ULL;
67 static const double hundredsOfNanosecondsPerMillisecond = 10000;
68
69 static double lowResUTCTime()
70 {
71     FILETIME fileTime;
72
73     GetSystemTimeAsFileTime(&fileTime);
74
75     // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a
76     // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can
77     // prevent alignment faults on 64-bit Windows).
78
79     ULARGE_INTEGER dateTime;
80     memcpy(&dateTime, &fileTime, sizeof(dateTime));
81
82     // Windows file times are in 100s of nanoseconds.
83     return (dateTime.QuadPart - epochBias) / hundredsOfNanosecondsPerMillisecond;
84 }
85
86 #if USE(QUERY_PERFORMANCE_COUNTER)
87
88 static LARGE_INTEGER qpcFrequency;
89 static bool syncedTime;
90
91 static 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 #if defined(_M_IX86) || defined(__i386__)
105     DWORD tickCount = GetTickCount();
106 #else
107     ULONGLONG tickCount = GetTickCount64();
108 #endif
109
110     if (inited) {
111         __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart;
112         __int64 tickCountElapsed;
113         if (tickCount >= tickCountLast)
114             tickCountElapsed = (tickCount - tickCountLast);
115         else {
116 #if COMPILER(MINGW)
117             __int64 tickCountLarge = tickCount + 0x100000000ULL;
118 #else
119             __int64 tickCountLarge = tickCount + 0x100000000I64;
120 #endif
121             tickCountElapsed = tickCountLarge - tickCountLast;
122         }
123
124         // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms.
125         // (500ms value is from http://support.microsoft.com/kb/274323)
126         __int64 diff = tickCountElapsed - qpcElapsed;
127         if (diff > 500 || diff < -500)
128             syncedTime = false;
129     } else
130         inited = true;
131
132     qpcLast = qpc;
133     tickCountLast = tickCount;
134
135     return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart);
136 }
137
138 static bool qpcAvailable()
139 {
140     static bool available;
141     static bool checked;
142
143     if (checked)
144         return available;
145
146     available = QueryPerformanceFrequency(&qpcFrequency);
147     checked = true;
148     return available;
149 }
150
151 static inline double currentTime()
152 {
153     // Use a combination of ftime and QueryPerformanceCounter.
154     // ftime returns the information we want, but doesn't have sufficient resolution.
155     // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals.
156     // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter
157     // by itself, adding the delta to the saved ftime.  We periodically re-sync to correct for drift.
158     static double syncLowResUTCTime;
159     static double syncHighResUpTime;
160     static double lastUTCTime;
161
162     double lowResTime = lowResUTCTime();
163
164     if (!qpcAvailable())
165         return lowResTime / 1000.0;
166
167     double highResTime = highResUpTime();
168
169     if (!syncedTime) {
170         timeBeginPeriod(1); // increase time resolution around low-res time getter
171         syncLowResUTCTime = lowResTime = lowResUTCTime();
172         timeEndPeriod(1); // restore time resolution
173         syncHighResUpTime = highResTime;
174         syncedTime = true;
175     }
176
177     double highResElapsed = highResTime - syncHighResUpTime;
178     double utc = syncLowResUTCTime + highResElapsed;
179
180     // force a clock re-sync if we've drifted
181     double lowResElapsed = lowResTime - syncLowResUTCTime;
182     const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy
183     if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec)
184         syncedTime = false;
185
186     // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur)
187     const double backwardTimeLimit = 2000.0;
188     if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit)
189         return lastUTCTime / 1000.0;
190     lastUTCTime = utc;
191     return utc / 1000.0;
192 }
193
194 #else
195
196 static inline double currentTime()
197 {
198     static bool init = false;
199     static double lastTime;
200     static DWORD lastTickCount;
201     if (!init) {
202         lastTime = lowResUTCTime();
203         lastTickCount = GetTickCount();
204         init = true;
205         return lastTime;
206     }
207
208     DWORD tickCountNow = GetTickCount();
209     DWORD elapsed = tickCountNow - lastTickCount;
210     double timeNow = lastTime + (double)elapsed / 1000.;
211     if (elapsed >= 0x7FFFFFFF) {
212         lastTime = timeNow;
213         lastTickCount = tickCountNow;
214     }
215     return timeNow;
216 }
217
218 #endif // USE(QUERY_PERFORMANCE_COUNTER)
219
220 #elif USE(GLIB)
221
222 // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides
223 // better accuracy compared with Windows implementation of g_get_current_time:
224 // (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time).
225 // Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function.
226 static inline double currentTime()
227 {
228     GTimeVal now;
229     g_get_current_time(&now);
230     return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0);
231 }
232
233 #else
234
235 static inline double currentTime()
236 {
237     struct timeval now;
238     gettimeofday(&now, 0);
239     return now.tv_sec + now.tv_usec / 1000000.0;
240 }
241
242 #endif
243
244 WallTime WallTime::now()
245 {
246     return fromRawSeconds(currentTime());
247 }
248
249 MonotonicTime MonotonicTime::now()
250 {
251 #if USE(GLIB)
252     return fromRawSeconds(static_cast<double>(g_get_monotonic_time() / 1000000.0));
253 #elif OS(DARWIN)
254     // Based on listing #2 from Apple QA 1398, but modified to be thread-safe.
255     static mach_timebase_info_data_t timebaseInfo;
256     static std::once_flag initializeTimerOnceFlag;
257     std::call_once(initializeTimerOnceFlag, [] {
258         kern_return_t kr = mach_timebase_info(&timebaseInfo);
259         ASSERT_UNUSED(kr, kr == KERN_SUCCESS);
260         ASSERT(timebaseInfo.denom);
261     });
262
263     return fromRawSeconds((mach_absolute_time() * timebaseInfo.numer) / (1.0e9 * timebaseInfo.denom));
264 #elif OS(LINUX) || OS(FREEBSD) || OS(OPENBSD) || OS(NETBSD)
265     struct timespec ts { };
266     clock_gettime(CLOCK_MONOTONIC, &ts);
267     return fromRawSeconds(static_cast<double>(ts.tv_sec) + ts.tv_nsec / 1.0e9);
268 #else
269     static double lastTime = 0;
270     double currentTimeNow = currentTime();
271     if (currentTimeNow < lastTime)
272         return lastTime;
273     lastTime = currentTimeNow;
274     return fromRawSeconds(currentTimeNow);
275 #endif
276 }
277
278 } // namespace WTF