1 /* 2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. 3 * Copyright (C) 2008 Google Inc. All rights reserved. 4 * Copyright (C) 2007-2009 Torch Mobile, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following disclaimer 14 * in the documentation and/or other materials provided with the 15 * distribution. 16 * * Neither the name of Google Inc. nor the names of its 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include "config.h" 34 #include "CurrentTime.h" 35 36 #if OS(WINDOWS) 37 38 // Windows is first since we want to use hires timers, despite PLATFORM(CF) 39 // being defined. 40 // If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod. 41 #undef WIN32_LEAN_AND_MEAN 42 #include <windows.h> 43 #include <math.h> 44 #include <stdint.h> 45 #include <time.h> 46 47 #if USE(QUERY_PERFORMANCE_COUNTER) 48 #if OS(WINCE) 49 extern "C" time_t mktime(struct tm *t); 50 #else 51 #include <sys/timeb.h> 52 #include <sys/types.h> 53 #endif 54 #endif 55 56 #elif PLATFORM(CF) 57 #include <CoreFoundation/CFDate.h> 58 #elif PLATFORM(GTK) 59 #include <glib.h> 60 #elif PLATFORM(WX) 61 #include <wx/datetime.h> 62 #elif PLATFORM(BREWMP) 63 #include <AEEStdLib.h> 64 #else // Posix systems relying on the gettimeofday() 65 #include <sys/time.h> 66 #endif 67 68 #if PLATFORM(CHROMIUM) 69 #error Chromium uses a different timer implementation 70 #endif 71 72 namespace WTF { 73 74 const double msPerSecond = 1000.0; 75 76 #if OS(WINDOWS) 77 78 #if USE(QUERY_PERFORMANCE_COUNTER) 79 80 static LARGE_INTEGER qpcFrequency; 81 static bool syncedTime; 82 83 static double highResUpTime() 84 { 85 // We use QPC, but only after sanity checking its result, due to bugs: 86 // http://support.microsoft.com/kb/274323 87 // http://support.microsoft.com/kb/895980 88 // 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)." 89 90 static LARGE_INTEGER qpcLast; 91 static DWORD tickCountLast; 92 static bool inited; 93 94 LARGE_INTEGER qpc; 95 QueryPerformanceCounter(&qpc); 96 DWORD tickCount = GetTickCount(); 97 98 if (inited) { 99 __int64 qpcElapsed = ((qpc.QuadPart - qpcLast.QuadPart) * 1000) / qpcFrequency.QuadPart; 100 __int64 tickCountElapsed; 101 if (tickCount >= tickCountLast) 102 tickCountElapsed = (tickCount - tickCountLast); 103 else { 104 #if COMPILER(MINGW) 105 __int64 tickCountLarge = tickCount + 0x100000000ULL; 106 #else 107 __int64 tickCountLarge = tickCount + 0x100000000I64; 108 #endif 109 tickCountElapsed = tickCountLarge - tickCountLast; 110 } 111 112 // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms. 113 // (500ms value is from http://support.microsoft.com/kb/274323) 114 __int64 diff = tickCountElapsed - qpcElapsed; 115 if (diff > 500 || diff < -500) 116 syncedTime = false; 117 } else 118 inited = true; 119 120 qpcLast = qpc; 121 tickCountLast = tickCount; 122 123 return (1000.0 * qpc.QuadPart) / static_cast<double>(qpcFrequency.QuadPart); 124 } 125 126 static double lowResUTCTime() 127 { 128 #if OS(WINCE) 129 SYSTEMTIME systemTime; 130 GetSystemTime(&systemTime); 131 struct tm tmtime; 132 tmtime.tm_year = systemTime.wYear - 1900; 133 tmtime.tm_mon = systemTime.wMonth - 1; 134 tmtime.tm_mday = systemTime.wDay; 135 tmtime.tm_wday = systemTime.wDayOfWeek; 136 tmtime.tm_hour = systemTime.wHour; 137 tmtime.tm_min = systemTime.wMinute; 138 tmtime.tm_sec = systemTime.wSecond; 139 time_t timet = mktime(&tmtime); 140 return timet * msPerSecond + systemTime.wMilliseconds; 141 #else 142 struct _timeb timebuffer; 143 _ftime(&timebuffer); 144 return timebuffer.time * msPerSecond + timebuffer.millitm; 145 #endif 146 } 147 148 static bool qpcAvailable() 149 { 150 static bool available; 151 static bool checked; 152 153 if (checked) 154 return available; 155 156 available = QueryPerformanceFrequency(&qpcFrequency); 157 checked = true; 158 return available; 159 } 160 161 double currentTime() 162 { 163 // Use a combination of ftime and QueryPerformanceCounter. 164 // ftime returns the information we want, but doesn't have sufficient resolution. 165 // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals. 166 // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter 167 // by itself, adding the delta to the saved ftime. We periodically re-sync to correct for drift. 168 static bool started; 169 static double syncLowResUTCTime; 170 static double syncHighResUpTime; 171 static double lastUTCTime; 172 173 double lowResTime = lowResUTCTime(); 174 175 if (!qpcAvailable()) 176 return lowResTime / 1000.0; 177 178 double highResTime = highResUpTime(); 179 180 if (!syncedTime) { 181 timeBeginPeriod(1); // increase time resolution around low-res time getter 182 syncLowResUTCTime = lowResTime = lowResUTCTime(); 183 timeEndPeriod(1); // restore time resolution 184 syncHighResUpTime = highResTime; 185 syncedTime = true; 186 } 187 188 double highResElapsed = highResTime - syncHighResUpTime; 189 double utc = syncLowResUTCTime + highResElapsed; 190 191 // force a clock re-sync if we've drifted 192 double lowResElapsed = lowResTime - syncLowResUTCTime; 193 const double maximumAllowedDriftMsec = 15.625 * 2.0; // 2x the typical low-res accuracy 194 if (fabs(highResElapsed - lowResElapsed) > maximumAllowedDriftMsec) 195 syncedTime = false; 196 197 // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur) 198 const double backwardTimeLimit = 2000.0; 199 if (utc < lastUTCTime && (lastUTCTime - utc) < backwardTimeLimit) 200 return lastUTCTime / 1000.0; 201 lastUTCTime = utc; 202 return utc / 1000.0; 203 } 204 205 #else 206 207 static double currentSystemTime() 208 { 209 FILETIME ft; 210 GetCurrentFT(&ft); 211 212 // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a 213 // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can 214 // prevent alignment faults on 64-bit Windows). 215 216 ULARGE_INTEGER t; 217 memcpy(&t, &ft, sizeof(t)); 218 219 // Windows file times are in 100s of nanoseconds. 220 // To convert to seconds, we have to divide by 10,000,000, which is more quickly 221 // done by multiplying by 0.0000001. 222 223 // Between January 1, 1601 and January 1, 1970, there were 369 complete years, 224 // of which 89 were leap years (1700, 1800, and 1900 were not leap years). 225 // That is a total of 134774 days, which is 11644473600 seconds. 226 227 return t.QuadPart * 0.0000001 - 11644473600.0; 228 } 229 230 double currentTime() 231 { 232 static bool init = false; 233 static double lastTime; 234 static DWORD lastTickCount; 235 if (!init) { 236 lastTime = currentSystemTime(); 237 lastTickCount = GetTickCount(); 238 init = true; 239 return lastTime; 240 } 241 242 DWORD tickCountNow = GetTickCount(); 243 DWORD elapsed = tickCountNow - lastTickCount; 244 double timeNow = lastTime + (double)elapsed / 1000.; 245 if (elapsed >= 0x7FFFFFFF) { 246 lastTime = timeNow; 247 lastTickCount = tickCountNow; 248 } 249 return timeNow; 250 } 251 252 #endif // USE(QUERY_PERFORMANCE_COUNTER) 253 254 #elif PLATFORM(CF) 255 256 double currentTime() 257 { 258 return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970; 259 } 260 261 #elif PLATFORM(GTK) 262 263 // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides 264 // better accuracy compared with Windows implementation of g_get_current_time: 265 // (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time). 266 // Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function. 267 double currentTime() 268 { 269 GTimeVal now; 270 g_get_current_time(&now); 271 return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0); 272 } 273 274 #elif PLATFORM(WX) 275 276 double currentTime() 277 { 278 wxDateTime now = wxDateTime::UNow(); 279 return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0); 280 } 281 282 #elif PLATFORM(BREWMP) 283 284 // GETUTCSECONDS returns the number of seconds since 1980/01/06 00:00:00 UTC, 285 // and GETTIMEMS returns the number of milliseconds that have elapsed since the last 286 // occurrence of 00:00:00 local time. 287 // We can combine GETUTCSECONDS and GETTIMEMS to calculate the number of milliseconds 288 // since 1970/01/01 00:00:00 UTC. 289 double currentTime() 290 { 291 // diffSeconds is the number of seconds from 1970/01/01 to 1980/01/06 292 const unsigned diffSeconds = 315964800; 293 return static_cast<double>(diffSeconds + GETUTCSECONDS() + ((GETTIMEMS() % 1000) / msPerSecond)); 294 } 295 296 #else // Other Posix systems rely on the gettimeofday(). 297 298 double currentTime() 299 { 300 struct timeval now; 301 struct timezone zone; 302 303 gettimeofday(&now, &zone); 304 return static_cast<double>(now.tv_sec) + (double)(now.tv_usec / 1000000.0); 305 } 306 307 #endif 308 309 } // namespace WTF 310