CurrentTime.cpp 12 KB

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