2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
3 * Copyright (C) 2008 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "CurrentTime.h"
36 // Windows is first since we want to use hires timers, despite PLATFORM(CF)
38 // If defined, WIN32_LEAN_AND_MEAN disables timeBeginPeriod/timeEndPeriod.
39 #undef WIN32_LEAN_AND_MEAN
43 #include <sys/timeb.h>
44 #include <sys/types.h>
47 #include <CoreFoundation/CFDate.h>
51 #include <wx/datetime.h>
52 #else // Posix systems relying on the gettimeofday()
58 const double msPerSecond
= 1000.0;
62 static LARGE_INTEGER qpcFrequency
;
63 static bool syncedTime
;
65 static double highResUpTime()
67 // We use QPC, but only after sanity checking its result, due to bugs:
68 // http://support.microsoft.com/kb/274323
69 // http://support.microsoft.com/kb/895980
70 // 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)."
72 static LARGE_INTEGER qpcLast
;
73 static DWORD tickCountLast
;
77 QueryPerformanceCounter(&qpc
);
78 DWORD tickCount
= GetTickCount();
81 __int64 qpcElapsed
= ((qpc
.QuadPart
- qpcLast
.QuadPart
) * 1000) / qpcFrequency
.QuadPart
;
82 __int64 tickCountElapsed
;
83 if (tickCount
>= tickCountLast
)
84 tickCountElapsed
= (tickCount
- tickCountLast
);
87 __int64 tickCountLarge
= tickCount
+ 0x100000000ULL
;
89 __int64 tickCountLarge
= tickCount
+ 0x100000000I
64;
91 tickCountElapsed
= tickCountLarge
- tickCountLast
;
94 // force a re-sync if QueryPerformanceCounter differs from GetTickCount by more than 500ms.
95 // (500ms value is from http://support.microsoft.com/kb/274323)
96 __int64 diff
= tickCountElapsed
- qpcElapsed
;
97 if (diff
> 500 || diff
< -500)
103 tickCountLast
= tickCount
;
105 return (1000.0 * qpc
.QuadPart
) / static_cast<double>(qpcFrequency
.QuadPart
);
108 static double lowResUTCTime()
111 SYSTEMTIME systemTime
;
112 GetSystemTime(&systemTime
);
114 tmtime
.tm_year
= systemTime
.wYear
- 1900;
115 tmtime
.tm_mon
= systemTime
.wMonth
- 1;
116 tmtime
.tm_mday
= systemTime
.wDay
;
117 tmtime
.tm_wday
= systemTime
.wDayOfWeek
;
118 tmtime
.tm_hour
= systemTime
.wHour
;
119 tmtime
.tm_min
= systemTime
.wMinute
;
120 tmtime
.tm_sec
= systemTime
.wSecond
;
121 time_t timet
= mktime(&tmtime
);
122 return timet
* msPerSecond
+ systemTime
.wMilliseconds
;
124 struct _timeb timebuffer
;
126 return timebuffer
.time
* msPerSecond
+ timebuffer
.millitm
;
130 static bool qpcAvailable()
132 static bool available
;
138 available
= QueryPerformanceFrequency(&qpcFrequency
);
145 // Use a combination of ftime and QueryPerformanceCounter.
146 // ftime returns the information we want, but doesn't have sufficient resolution.
147 // QueryPerformanceCounter has high resolution, but is only usable to measure time intervals.
148 // To combine them, we call ftime and QueryPerformanceCounter initially. Later calls will use QueryPerformanceCounter
149 // by itself, adding the delta to the saved ftime. We periodically re-sync to correct for drift.
151 static double syncLowResUTCTime
;
152 static double syncHighResUpTime
;
153 static double lastUTCTime
;
155 double lowResTime
= lowResUTCTime();
158 return lowResTime
/ 1000.0;
160 double highResTime
= highResUpTime();
163 timeBeginPeriod(1); // increase time resolution around low-res time getter
164 syncLowResUTCTime
= lowResTime
= lowResUTCTime();
165 timeEndPeriod(1); // restore time resolution
166 syncHighResUpTime
= highResTime
;
170 double highResElapsed
= highResTime
- syncHighResUpTime
;
171 double utc
= syncLowResUTCTime
+ highResElapsed
;
173 // force a clock re-sync if we've drifted
174 double lowResElapsed
= lowResTime
- syncLowResUTCTime
;
175 const double maximumAllowedDriftMsec
= 15.625 * 2.0; // 2x the typical low-res accuracy
176 if (fabs(highResElapsed
- lowResElapsed
) > maximumAllowedDriftMsec
)
179 // make sure time doesn't run backwards (only correct if difference is < 2 seconds, since DST or clock changes could occur)
180 const double backwardTimeLimit
= 2000.0;
181 if (utc
< lastUTCTime
&& (lastUTCTime
- utc
) < backwardTimeLimit
)
182 return lastUTCTime
/ 1000.0;
191 return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970
;
196 // Note: GTK on Windows will pick up the PLATFORM(WIN) implementation above which provides
197 // better accuracy compared with Windows implementation of g_get_current_time:
198 // (http://www.google.com/codesearch/p?hl=en#HHnNRjks1t0/glib-2.5.2/glib/gmain.c&q=g_get_current_time).
199 // Non-Windows GTK builds could use gettimeofday() directly but for the sake of consistency lets use GTK function.
203 g_get_current_time(&now
);
204 return static_cast<double>(now
.tv_sec
) + static_cast<double>(now
.tv_usec
/ 1000000.0);
211 wxDateTime now
= wxDateTime::UNow();
212 return (double)now
.GetTicks() + (double)(now
.GetMillisecond() / 1000.0);
215 #else // Other Posix systems rely on the gettimeofday().
220 struct timezone zone
;
222 gettimeofday(&now
, &zone
);
223 return static_cast<double>(now
.tv_sec
) + (double)(now
.tv_usec
/ 1000000.0);