blob: 019c80036b6ec229f5f290d6cedb9bac35b0f353 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
wu@webrtc.org6e6ea042012-03-12 19:42:22 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11// System independant wrapper for polling elapsed time in ms and us.
12// The implementation works in the tick domain which can be mapped over to the
13// time domain.
14#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TICK_UTIL_H_
15#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TICK_UTIL_H_
16
17#if _WIN32
18#include <windows.h>
19#include <mmsystem.h>
20#elif WEBRTC_LINUX
21#include <ctime>
wu@webrtc.org6e6ea042012-03-12 19:42:22 +000022#elif WEBRTC_MAC
23#include <mach/mach_time.h>
24#include <string.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000025#else
26#include <sys/time.h>
27#include <time.h>
28#endif
29
30#include "typedefs.h"
31
32namespace webrtc {
33class TickInterval;
34
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +000035// Class representing the current time. This class is immutable.
niklase@google.com470e71d2011-07-07 08:21:25 +000036class TickTime
37{
38public:
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +000039 TickTime();
40 explicit TickTime(WebRtc_Word64 ticks);
41
niklase@google.com470e71d2011-07-07 08:21:25 +000042 // Current time in the tick domain.
43 static TickTime Now();
44
45 // Now in the time domain in ms.
46 static WebRtc_Word64 MillisecondTimestamp();
47
48 // Now in the time domain in us.
49 static WebRtc_Word64 MicrosecondTimestamp();
50
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +000051 // Returns the number of ticks in the tick domain.
niklase@google.com470e71d2011-07-07 08:21:25 +000052 WebRtc_Word64 Ticks() const;
53
54 static WebRtc_Word64 MillisecondsToTicks(const WebRtc_Word64 ms);
55
56 static WebRtc_Word64 TicksToMilliseconds(const WebRtc_Word64 ticks);
57
58 // Returns a TickTime that is ticks later than the passed TickTime
59 friend TickTime operator+(const TickTime lhs, const WebRtc_Word64 ticks);
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +000060 TickTime& operator+=(const WebRtc_Word64& ticks);
niklase@google.com470e71d2011-07-07 08:21:25 +000061
62 // Returns a TickInterval that is the difference in ticks beween rhs and lhs
63 friend TickInterval operator-(const TickTime& lhs, const TickTime& rhs);
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +000064
65 // Call to engage the fake clock. This is useful for tests since relying on
66 // a real clock often makes the test flaky.
67 static void UseFakeClock(WebRtc_Word64 start_millisecond);
68
69 // Advance the fake clock. Must be called after UseFakeClock.
70 static void AdvanceFakeClock(WebRtc_Word64 milliseconds);
71
niklase@google.com470e71d2011-07-07 08:21:25 +000072private:
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +000073 static WebRtc_Word64 QueryOsForTicks();
74
75 static bool _use_fake_clock;
76 static WebRtc_Word64 _fake_ticks;
77
niklase@google.com470e71d2011-07-07 08:21:25 +000078 WebRtc_Word64 _ticks;
79};
80
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +000081// Reperesents a time delta in ticks. This class is immutable.
niklase@google.com470e71d2011-07-07 08:21:25 +000082class TickInterval
83{
84public:
85 TickInterval();
86
87 WebRtc_Word64 Milliseconds() const;
88 WebRtc_Word64 Microseconds() const;
89
90 // Returns the sum of two TickIntervals as a TickInterval
91 friend TickInterval operator+(const TickInterval& lhs,
92 const TickInterval& rhs);
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +000093 TickInterval& operator+=(const TickInterval& rhs);
niklase@google.com470e71d2011-07-07 08:21:25 +000094
95 // Returns a TickInterval corresponding to rhs - lhs
96 friend TickInterval operator-(const TickInterval& lhs,
97 const TickInterval& rhs);
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +000098 TickInterval& operator-=(const TickInterval& rhs);
niklase@google.com470e71d2011-07-07 08:21:25 +000099
kjellander@webrtc.org9e7774f2011-09-23 11:33:31 +0000100 friend bool operator>(const TickInterval& lhs, const TickInterval& rhs);
101 friend bool operator<=(const TickInterval& lhs, const TickInterval& rhs);
102 friend bool operator<(const TickInterval& lhs, const TickInterval& rhs);
103 friend bool operator>=(const TickInterval& lhs, const TickInterval& rhs);
104
niklase@google.com470e71d2011-07-07 08:21:25 +0000105private:
106 TickInterval(WebRtc_Word64 interval);
107
108 friend class TickTime;
109 friend TickInterval operator-(const TickTime& lhs, const TickTime& rhs);
110
111private:
112 WebRtc_Word64 _interval;
113};
114
115inline TickInterval operator+(const TickInterval& lhs, const TickInterval& rhs)
116{
117 return TickInterval(lhs._interval + rhs._interval);
118}
119
120inline TickInterval operator-(const TickInterval& lhs, const TickInterval& rhs)
121{
122 return TickInterval(lhs._interval - rhs._interval);
123}
124
125inline TickInterval operator-(const TickTime& lhs,const TickTime& rhs)
126{
127 return TickInterval(lhs._ticks - rhs._ticks);
128}
129
130inline TickTime operator+(const TickTime lhs, const WebRtc_Word64 ticks)
131{
132 TickTime time = lhs;
133 time._ticks += ticks;
134 return time;
135}
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000136
kjellander@webrtc.org9e7774f2011-09-23 11:33:31 +0000137inline bool operator>(const TickInterval& lhs, const TickInterval& rhs)
138{
139 return lhs._interval > rhs._interval;
140}
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000141
kjellander@webrtc.org9e7774f2011-09-23 11:33:31 +0000142inline bool operator<=(const TickInterval& lhs, const TickInterval& rhs)
143{
144 return lhs._interval <= rhs._interval;
145}
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000146
kjellander@webrtc.org9e7774f2011-09-23 11:33:31 +0000147inline bool operator<(const TickInterval& lhs, const TickInterval& rhs)
148{
149 return lhs._interval <= rhs._interval;
150}
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000151
kjellander@webrtc.org9e7774f2011-09-23 11:33:31 +0000152inline bool operator>=(const TickInterval& lhs, const TickInterval& rhs)
153{
154 return lhs._interval >= rhs._interval;
155}
niklase@google.com470e71d2011-07-07 08:21:25 +0000156
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000157inline TickTime::TickTime()
158 : _ticks(0) {
159}
160
161inline TickTime::TickTime(WebRtc_Word64 ticks)
162 : _ticks(ticks) {
163}
164
niklase@google.com470e71d2011-07-07 08:21:25 +0000165inline TickTime TickTime::Now()
166{
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000167 if (_use_fake_clock)
168 return TickTime(_fake_ticks);
169 else
170 return TickTime(QueryOsForTicks());
171}
172
173inline WebRtc_Word64 TickTime::QueryOsForTicks() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000174 TickTime result;
175#if _WIN32
wu@webrtc.org6e6ea042012-03-12 19:42:22 +0000176 // TODO(wu): Remove QueryPerformanceCounter implementation.
niklase@google.com470e71d2011-07-07 08:21:25 +0000177 #ifdef USE_QUERY_PERFORMANCE_COUNTER
178 // QueryPerformanceCounter returns the value from the TSC which is
179 // incremented at the CPU frequency. The algorithm used requires
180 // the CPU frequency to be constant. Technology like speed stepping
181 // which has variable CPU frequency will therefore yield unpredictable,
182 // incorrect time estimations.
183 LARGE_INTEGER qpcnt;
184 QueryPerformanceCounter(&qpcnt);
185 result._ticks = qpcnt.QuadPart;
186 #else
187 static volatile LONG lastTimeGetTime = 0;
188 static volatile WebRtc_Word64 numWrapTimeGetTime = 0;
189 volatile LONG* lastTimeGetTimePtr = &lastTimeGetTime;
190 DWORD now = timeGetTime();
191 // Atomically update the last gotten time
192 DWORD old = InterlockedExchange(lastTimeGetTimePtr, now);
193 if(now < old)
194 {
195 // If now is earlier than old, there may have been a race between
196 // threads.
197 // 0x0fffffff ~3.1 days, the code will not take that long to execute
198 // so it must have been a wrap around.
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000199 if(old > 0xf0000000 && now < 0x0fffffff)
niklase@google.com470e71d2011-07-07 08:21:25 +0000200 {
201 numWrapTimeGetTime++;
202 }
203 }
204 result._ticks = now + (numWrapTimeGetTime<<32);
205 #endif
206#elif defined(WEBRTC_LINUX)
207 struct timespec ts;
wu@webrtc.org6e6ea042012-03-12 19:42:22 +0000208 // TODO(wu): Remove CLOCK_REALTIME implementation.
niklase@google.com470e71d2011-07-07 08:21:25 +0000209 #ifdef WEBRTC_CLOCK_TYPE_REALTIME
210 clock_gettime(CLOCK_REALTIME, &ts);
211 #else
212 clock_gettime(CLOCK_MONOTONIC, &ts);
213 #endif
214 result._ticks = 1000000000LL * static_cast<WebRtc_Word64>(ts.tv_sec) + static_cast<WebRtc_Word64>(ts.tv_nsec);
wu@webrtc.org6e6ea042012-03-12 19:42:22 +0000215#elif defined(WEBRTC_MAC)
216 static mach_timebase_info_data_t timebase;
217 if (timebase.denom == 0) {
218 // Get the timebase if this is the first time we run.
219 // Recommended by Apple's QA1398.
220 kern_return_t retval = mach_timebase_info(&timebase);
221 if (retval != KERN_SUCCESS) {
222 // TODO(wu): Implement CHECK similar to chrome for all the platforms.
223 // Then replace this with a CHECK(retval == KERN_SUCCESS);
sjlee@webrtc.org414fa7f2012-09-11 17:25:46 +0000224#ifndef WEBRTC_IOS
wu@webrtc.org6e6ea042012-03-12 19:42:22 +0000225 asm("int3");
sjlee@webrtc.org4b425082012-09-10 17:58:21 +0000226#else
227 __builtin_trap();
sjlee@webrtc.org414fa7f2012-09-11 17:25:46 +0000228#endif // WEBRTC_IOS
wu@webrtc.org6e6ea042012-03-12 19:42:22 +0000229 }
230 }
231 // Use timebase to convert absolute time tick units into nanoseconds.
232 result._ticks = mach_absolute_time() * timebase.numer / timebase.denom;
niklase@google.com470e71d2011-07-07 08:21:25 +0000233#else
234 struct timeval tv;
235 gettimeofday(&tv, NULL);
236 result._ticks = 1000000LL * static_cast<WebRtc_Word64>(tv.tv_sec) + static_cast<WebRtc_Word64>(tv.tv_usec);
237#endif
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000238 return result._ticks;
niklase@google.com470e71d2011-07-07 08:21:25 +0000239}
240
241inline WebRtc_Word64 TickTime::MillisecondTimestamp()
242{
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000243 WebRtc_Word64 ticks = TickTime::Now().Ticks();
niklase@google.com470e71d2011-07-07 08:21:25 +0000244#if _WIN32
245 #ifdef USE_QUERY_PERFORMANCE_COUNTER
246 LARGE_INTEGER qpfreq;
247 QueryPerformanceFrequency(&qpfreq);
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000248 return (ticks * 1000) / qpfreq.QuadPart;
niklase@google.com470e71d2011-07-07 08:21:25 +0000249 #else
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000250 return ticks;
niklase@google.com470e71d2011-07-07 08:21:25 +0000251 #endif
wu@webrtc.org6e6ea042012-03-12 19:42:22 +0000252#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000253 return ticks / 1000000LL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000254#else
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000255 return ticks / 1000LL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000256#endif
257}
258
259inline WebRtc_Word64 TickTime::MicrosecondTimestamp()
260{
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000261 WebRtc_Word64 ticks = TickTime::Now().Ticks();
niklase@google.com470e71d2011-07-07 08:21:25 +0000262#if _WIN32
263 #ifdef USE_QUERY_PERFORMANCE_COUNTER
264 LARGE_INTEGER qpfreq;
265 QueryPerformanceFrequency(&qpfreq);
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000266 return (ticks * 1000) / (qpfreq.QuadPart/1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000267 #else
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000268 return ticks *1000LL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000269 #endif
wu@webrtc.org6e6ea042012-03-12 19:42:22 +0000270#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000271 return ticks / 1000LL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000272#else
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000273 return ticks;
niklase@google.com470e71d2011-07-07 08:21:25 +0000274#endif
275}
276
277inline WebRtc_Word64 TickTime::Ticks() const
278{
279 return _ticks;
280}
281
282inline WebRtc_Word64 TickTime::MillisecondsToTicks(const WebRtc_Word64 ms)
283{
284#if _WIN32
285 #ifdef USE_QUERY_PERFORMANCE_COUNTER
286 LARGE_INTEGER qpfreq;
287 QueryPerformanceFrequency(&qpfreq);
288 return (qpfreq.QuadPart * ms) / 1000;
289 #else
290 return ms;
291 #endif
wu@webrtc.org6e6ea042012-03-12 19:42:22 +0000292#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
niklase@google.com470e71d2011-07-07 08:21:25 +0000293 return ms * 1000000LL;
294#else
295 return ms * 1000LL;
296#endif
297}
298
299inline WebRtc_Word64 TickTime::TicksToMilliseconds(const WebRtc_Word64 ticks)
300{
301#if _WIN32
302 #ifdef USE_QUERY_PERFORMANCE_COUNTER
303 LARGE_INTEGER qpfreq;
304 QueryPerformanceFrequency(&qpfreq);
305 return (ticks * 1000) / qpfreq.QuadPart;
306 #else
307 return ticks;
308 #endif
wu@webrtc.org6e6ea042012-03-12 19:42:22 +0000309#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
niklase@google.com470e71d2011-07-07 08:21:25 +0000310 return ticks / 1000000LL;
311#else
312 return ticks / 1000LL;
313#endif
314}
315
316inline TickTime& TickTime::operator+=(const WebRtc_Word64& ticks)
317{
318 _ticks += ticks;
319 return *this;
320}
321
322inline TickInterval::TickInterval() : _interval(0)
323{
324}
325
326inline TickInterval::TickInterval(const WebRtc_Word64 interval)
327 : _interval(interval)
328{
329}
330
331inline WebRtc_Word64 TickInterval::Milliseconds() const
332{
333#if _WIN32
334 #ifdef USE_QUERY_PERFORMANCE_COUNTER
335 LARGE_INTEGER qpfreq;
336 QueryPerformanceFrequency(&qpfreq);
337 return (_interval * 1000) / qpfreq.QuadPart;
338 #else
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000339 // _interval is in ms
niklase@google.com470e71d2011-07-07 08:21:25 +0000340 return _interval;
341 #endif
wu@webrtc.org6e6ea042012-03-12 19:42:22 +0000342#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
niklase@google.com470e71d2011-07-07 08:21:25 +0000343 // _interval is in ns
344 return _interval / 1000000;
345#else
346 // _interval is usecs
347 return _interval / 1000;
348#endif
349}
350
351inline WebRtc_Word64 TickInterval::Microseconds() const
352{
353#if _WIN32
354 #ifdef USE_QUERY_PERFORMANCE_COUNTER
355 LARGE_INTEGER qpfreq;
356 QueryPerformanceFrequency(&qpfreq);
357 return (_interval * 1000000) / qpfreq.QuadPart;
358 #else
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000359 // _interval is in ms
niklase@google.com470e71d2011-07-07 08:21:25 +0000360 return _interval *1000LL;
361 #endif
wu@webrtc.org6e6ea042012-03-12 19:42:22 +0000362#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
niklase@google.com470e71d2011-07-07 08:21:25 +0000363 // _interval is in ns
364 return _interval / 1000;
365#else
366 // _interval is usecs
367 return _interval;
368#endif
369}
370
371inline TickInterval& TickInterval::operator+=(const TickInterval& rhs)
372{
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000373 _interval += rhs._interval;
374 return *this;
niklase@google.com470e71d2011-07-07 08:21:25 +0000375}
376
377inline TickInterval& TickInterval::operator-=(const TickInterval& rhs)
378{
379 _interval -= rhs._interval;
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000380 return *this;
niklase@google.com470e71d2011-07-07 08:21:25 +0000381}
phoglund@webrtc.org4cebe6c2012-11-07 13:37:19 +0000382
niklase@google.com470e71d2011-07-07 08:21:25 +0000383} // namespace webrtc
384
385#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TICK_UTIL_H_