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 <mutex> 41 #include <sys/time.h> 42 #elif OS(WINDOWS) 43 44 // Windows is first since we want to use hires timers, despite USE(CF) 45 // being defined. 46 // If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod. 47 #undef WIN32_LEAN_AND_MEAN 48 #include <windows.h> 49 #include <math.h> 50 #include <stdint.h> 51 #include <time.h> 52 53 #elif PLATFORM(EFL) 54 #include <Ecore.h> 55 #else 56 #include <sys/time.h> 57 #endif 58 59 #if USE(GLIB) && !PLATFORM(EFL) 60 #include <glib.h> 61 #endif 62 63 #if PLATFORM(JAVA) 64 #include <WebCore/platform/java/JavaEnv.h> 65 #endif 66 67 68 namespace WTF { 69 70 #if OS(WINDOWS) 71 72 // Number of 100 nanosecond between January 1, 1601 and January 1, 1970. 73 static const ULONGLONG epochBias = 116444736000000000ULL; 74 static const double hundredsOfNanosecondsPerMillisecond = 10000; 75 76 static double lowResUTCTime() 77 { 78 FILETIME fileTime; 79 80 GetSystemTimeAsFileTime(&fileTime); 81 82 // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a 83 // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can 84 // prevent alignment faults on 64-bit Windows). 85 86 ULARGE_INTEGER dateTime; 87 memcpy(&dateTime, &fileTime, sizeof(dateTime)); 88 89 // Windows file times are in 100s of nanoseconds. 90 return (dateTime.QuadPart - epochBias) / hundredsOfNanosecondsPerMillisecond; 91 } 92 93 #if USE(QUERY_PERFORMANCE_COUNTER) 94 95 static LARGE_INTEGER qpcFrequency; 96 static bool syncedTime; 97 98 static double highResUpTime() 99 { 100 // We use QPC, but only after sanity checking its result, due to bugs: 101 // http://support.microsoft.com/kb/274323 102 // http://support.microsoft.com/kb/895980 103 // 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)." 104 105 static LARGE_INTEGER qpcLast; 106 static DWORD tickCountLast; 107 static bool inited; 108 109 LARGE_INTEGER qpc; 110 QueryPerformanceCounter(&qpc); 111 #if defined(_M_IX86) || defined(__i386__) 112 DWORD tickCount = GetTickCount(); 113 #else 114 ULONGLONG tickCount = GetTickCount64(); 115 #endif 116 117 if (inited) { 118 __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart; 119 __int64 tickCountElapsed; 120 if (tickCount >= tickCountLast) 121 tickCountElapsed = (tickCount - tickCountLast); 122 else { 123 #if COMPILER(MINGW) 124 __int64 tickCountLarge = tickCount + 0x100000000ULL; 125 #else 126 __int64 tickCountLarge = tickCount + 0x100000000I64; 127 #endif 128 tickCountElapsed = tickCountLarge - tickCountLast; 129 } 130 131 // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms. 132 // (500ms value is from http://support.microsoft.com/kb/274323) 133 __int64 diff = tickCountElapsed - qpcElapsed; 134 if (diff > 500 || diff < -500) 135 syncedTime = false; 136 } else 137 inited = true; 138 139 qpcLast = qpc; 140 tickCountLast = tickCount; 141 142 return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart); 143 } 144 145 static bool qpcAvailable() 146 { 147 static bool available; 148 static bool checked; 149 150 if (checked) 151 return available; 152 153 available = QueryPerformanceFrequency(&qpcFrequency); 154 checked = true; 155 return available; 156 } 157 158 double currentTime() 159 { 160 // Use a combination of ftime and QueryPerformanceCounter. 161 // ftime returns the information we want, but doesn't have sufficient resolution. 162 // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals. 163 // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter 164 // by itself, adding the delta to the saved ftime. We periodically re-sync to correct for drift. 165 static double syncLowResUTCTime; 166 static double syncHighResUpTime; 167 static double lastUTCTime; 168 169 double lowResTime = lowResUTCTime(); 170 171 if (!qpcAvailable()) 172 return lowResTime / 1000.0; 173 174 double highResTime = highResUpTime(); 175 176 if (!syncedTime) { 177 timeBeginPeriod(1); // increase time resolution around low-res time getter 178 syncLowResUTCTime = lowResTime = lowResUTCTime(); 179 timeEndPeriod(1); // restore time resolution 180 syncHighResUpTime = highResTime; 181 syncedTime = true; 182 } 183 184 double highResElapsed = highResTime - syncHighResUpTime; 185 double utc = syncLowResUTCTime + highResElapsed; 186 187 // force a clock re-sync if we've drifted 188 double lowResElapsed = lowResTime - syncLowResUTCTime; 189 const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy 190 if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec) 191 syncedTime = false; 192 193 // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur) 194 const double backwardTimeLimit = 2000.0; 195 if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit) 196 return lastUTCTime / 1000.0; 197 lastUTCTime = utc; 198 return utc / 1000.0; 199 } 200 201 #else 202 203 double currentTime() 204 { 205 static bool init = false; 206 static double lastTime; 207 static DWORD lastTickCount; 208 if (!init) { 209 lastTime = lowResUTCTime(); 210 lastTickCount = GetTickCount(); 211 init = true; 212 return lastTime; 213 } 214 215 DWORD tickCountNow = GetTickCount(); 216 DWORD elapsed = tickCountNow - lastTickCount; 217 double timeNow = lastTime + (double)elapsed / 1000.; 218 if (elapsed >= 0x7FFFFFFF) { 219 lastTime = timeNow; 220 lastTickCount = tickCountNow; 221 } 222 return timeNow; 223 } 224 225 #endif // USE(QUERY_PERFORMANCE_COUNTER) 226 227 #elif USE(GLIB) && !PLATFORM(EFL) 228 229 // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides 230 // better accuracy compared with Windows implementation of g_get_current_time: 231 // (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time). 232 // Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function. 233 double currentTime() 234 { 235 GTimeVal now; 236 g_get_current_time(&now); 237 return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0); 238 } 239 240 #elif PLATFORM(EFL) 241 242 double currentTime() 243 { 244 return ecore_time_unix_get(); 245 } 246 247 #elif PLATFORM(JAVA) && 0 248 // Attention! That can be called from non-Java thread. And very often, 249 // so back to native implementation. 250 // 251 // Return the current system time in seconds, using the classic POSIX epoch of January 1, 1970. 252 // Like time(0) from <time.h>, except with a wider range of values and higher precision. 253 double currentTime() 254 { 255 JNIEnv *env = WebCore_GetJavaEnv(); 256 257 static JGClass systemCls(env->FindClass("java/lang/System")); 258 static jmethodID currentTimeMillisMID = env->GetStaticMethodID( 259 systemCls, 260 "currentTimeMillis", 261 "()J"); 262 ASSERT(currentTimeMillisMID); 263 264 jlong jvm_time = env->CallStaticLongMethod(systemCls, currentTimeMillisMID); 265 CheckAndClearException(env); 266 267 return jvm_time / 1000.0; 268 } 269 270 #else 271 272 double currentTime() 273 { 274 struct timeval now; 275 gettimeofday(&now, 0); 276 return now.tv_sec + now.tv_usec / 1000000.0; 277 } 278 279 #endif 280 281 #if PLATFORM(EFL) 282 283 double monotonicallyIncreasingTime() 284 { 285 return ecore_time_get(); 286 } 287 288 #elif USE(GLIB) 289 290 double monotonicallyIncreasingTime() 291 { 292 return static_cast<double>(g_get_monotonic_time() / 1000000.0); 293 } 294 295 #elif OS(DARWIN) 296 297 double monotonicallyIncreasingTime() 298 { 299 // Based on listing #2 from Apple QA 1398, but modified to be thread-safe. 300 static mach_timebase_info_data_t timebaseInfo; 301 static std::once_flag initializeTimerOnceFlag; 302 std::call_once(initializeTimerOnceFlag, [] { 303 kern_return_t kr = mach_timebase_info(&timebaseInfo); 304 ASSERT_UNUSED(kr, kr == KERN_SUCCESS); 305 ASSERT(timebaseInfo.denom); 306 }); 307 308 return (mach_absolute_time() * timebaseInfo.numer) / (1.0e9 * timebaseInfo.denom); 309 } 310 311 #else 312 313 double monotonicallyIncreasingTime() 314 { 315 static double lastTime = 0; 316 double currentTimeNow = currentTime(); 317 if (currentTimeNow < lastTime) 318 return lastTime; 319 lastTime = currentTimeNow; 320 return currentTimeNow; 321 } 322 323 #endif 324 325 std::chrono::microseconds currentCPUTime() 326 { 327 #if OS(DARWIN) 328 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT; 329 thread_basic_info_data_t info; 330 331 // Get thread information 332 mach_port_t threadPort = mach_thread_self(); 333 thread_info(threadPort, THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount); 334 mach_port_deallocate(mach_task_self(), threadPort); 335 336 return std::chrono::seconds(info.user_time.seconds + info.system_time.seconds) + std::chrono::microseconds(info.user_time.microseconds + info.system_time.microseconds); 337 #elif OS(WINDOWS) 338 union { 339 FILETIME fileTime; 340 unsigned long long fileTimeAsLong; 341 } userTime, kernelTime; 342 343 // GetThreadTimes won't accept null arguments so we pass these even though 344 // they're not used. 345 FILETIME creationTime, exitTime; 346 347 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime); 348 349 return std::chrono::microseconds((userTime.fileTimeAsLong + kernelTime.fileTimeAsLong) / 10); 350 #else 351 // FIXME: We should return the time the current thread has spent executing. 352 353 static auto firstTime = std::chrono::steady_clock::now(); 354 return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - firstTime); 355 #endif 356 } 357 358 } // namespace WTF