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