| /* |
| * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. |
| * Copyright (C) 2008 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "CurrentTime.h" |
| |
| #if PLATFORM(WIN_OS) |
| // Windows is first since we want to use hires timers, despite PLATFORM(CF) |
| // being defined. |
| // If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod. |
| #undef WIN32_LEAN_AND_MEAN |
| #include <windows.h> |
| #include <math.h> |
| #include <stdint.h> |
| #include <sys/timeb.h> |
| #include <sys/types.h> |
| #include <time.h> |
| #elif PLATFORM(CF) |
| #include <CoreFoundation/CFDate.h> |
| #elif PLATFORM(GTK) |
| #include <glib.h> |
| #elif PLATFORM(WX) |
| #include <wx/datetime.h> |
| #else // Posix systems relying on the gettimeofday() |
| #include <sys/time.h> |
| #endif |
| |
| namespace WTF { |
| |
| const double msPerSecond = 1000.0; |
| |
| #if PLATFORM(WIN_OS) |
| |
| static LARGE_INTEGER qpcFrequency; |
| static bool syncedTime; |
| |
| static double highResUpTime() |
| { |
| // We use QPC, but only after sanity checking its result, due to bugs: |
| // http://support.microsoft.com/kb/274323 |
| // http://support.microsoft.com/kb/895980 |
| // 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)." |
| |
| static LARGE_INTEGER qpcLast; |
| static DWORD tickCountLast; |
| static bool inited; |
| |
| LARGE_INTEGER qpc; |
| QueryPerformanceCounter(&qpc); |
| DWORD tickCount = GetTickCount(); |
| |
| if (inited) { |
| __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart; |
| __int64 tickCountElapsed; |
| if (tickCount >= tickCountLast) |
| tickCountElapsed = (tickCount - tickCountLast); |
| else { |
| #if COMPILER(MINGW) |
| __int64 tickCountLarge = tickCount + 0x100000000ULL; |
| #else |
| __int64 tickCountLarge = tickCount + 0x100000000I64; |
| #endif |
| tickCountElapsed = tickCountLarge - tickCountLast; |
| } |
| |
| // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms. |
| // (500ms value is from http://support.microsoft.com/kb/274323) |
| __int64 diff = tickCountElapsed - qpcElapsed; |
| if (diff > 500 || diff < -500) |
| syncedTime = false; |
| } else |
| inited = true; |
| |
| qpcLast = qpc; |
| tickCountLast = tickCount; |
| |
| return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart); |
| } |
| |
| static double lowResUTCTime() |
| { |
| #if PLATFORM(WINCE) |
| SYSTEMTIME systemTime; |
| GetSystemTime(&systemTime); |
| struct tm tmtime; |
| tmtime.tm_year = systemTime.wYear - 1900; |
| tmtime.tm_mon = systemTime.wMonth - 1; |
| tmtime.tm_mday = systemTime.wDay; |
| tmtime.tm_wday = systemTime.wDayOfWeek; |
| tmtime.tm_hour = systemTime.wHour; |
| tmtime.tm_min = systemTime.wMinute; |
| tmtime.tm_sec = systemTime.wSecond; |
| time_t timet = mktime(&tmtime); |
| return timet * msPerSecond + systemTime.wMilliseconds; |
| #else |
| struct _timeb timebuffer; |
| _ftime(&timebuffer); |
| return timebuffer.time * msPerSecond + timebuffer.millitm; |
| #endif |
| } |
| |
| static bool qpcAvailable() |
| { |
| static bool available; |
| static bool checked; |
| |
| if (checked) |
| return available; |
| |
| available = QueryPerformanceFrequency(&qpcFrequency); |
| checked = true; |
| return available; |
| } |
| |
| double currentTime() |
| { |
| // Use a combination of ftime and QueryPerformanceCounter. |
| // ftime returns the information we want, but doesn't have sufficient resolution. |
| // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals. |
| // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter |
| // by itself, adding the delta to the saved ftime. We periodically re-sync to correct for drift. |
| static bool started; |
| static double syncLowResUTCTime; |
| static double syncHighResUpTime; |
| static double lastUTCTime; |
| |
| double lowResTime = lowResUTCTime(); |
| |
| if (!qpcAvailable()) |
| return lowResTime / 1000.0; |
| |
| double highResTime = highResUpTime(); |
| |
| if (!syncedTime) { |
| timeBeginPeriod(1); // increase time resolution around low-res time getter |
| syncLowResUTCTime = lowResTime = lowResUTCTime(); |
| timeEndPeriod(1); // restore time resolution |
| syncHighResUpTime = highResTime; |
| syncedTime = true; |
| } |
| |
| double highResElapsed = highResTime - syncHighResUpTime; |
| double utc = syncLowResUTCTime + highResElapsed; |
| |
| // force a clock re-sync if we've drifted |
| double lowResElapsed = lowResTime - syncLowResUTCTime; |
| const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy |
| if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec) |
| syncedTime = false; |
| |
| // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur) |
| const double backwardTimeLimit = 2000.0; |
| if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit) |
| return lastUTCTime / 1000.0; |
| lastUTCTime = utc; |
| return utc / 1000.0; |
| } |
| |
| #elif PLATFORM(CF) |
| |
| double currentTime() |
| { |
| return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970; |
| } |
| |
| #elif PLATFORM(GTK) |
| |
| // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides |
| // better accuracy compared with Windows implementation of g_get_current_time: |
| // (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time). |
| // Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function. |
| double currentTime() |
| { |
| GTimeVal now; |
| g_get_current_time(&now); |
| return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0); |
| } |
| |
| #elif PLATFORM(WX) |
| |
| double currentTime() |
| { |
| wxDateTime now = wxDateTime::UNow(); |
| return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0); |
| } |
| |
| #else // Other Posix systems rely on the gettimeofday(). |
| |
| double currentTime() |
| { |
| struct timeval now; |
| struct timezone zone; |
| |
| gettimeofday(&now, &zone); |
| return static_cast<double>(now.tv_sec) + (double)(now.tv_usec / 1000000.0); |
| } |
| |
| #endif |
| |
| } // namespace WTF |