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