1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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>
22 #elif WEBRTC_MAC
23 #include <mach/mach_time.h>
24 #include <string.h>
25 #else
26 #include <sys/time.h>
27 #include <time.h>
28 #endif
29
30 #include "typedefs.h"
31
32 namespace webrtc {
33 class TickInterval;
34
35 class TickTime
36 {
37 public:
38 // Current time in the tick domain.
39 static TickTime Now();
40
41 // Now in the time domain in ms.
42 static WebRtc_Word64 MillisecondTimestamp();
43
44 // Now in the time domain in us.
45 static WebRtc_Word64 MicrosecondTimestamp();
46
47 WebRtc_Word64 Ticks() const;
48
49 static WebRtc_Word64 MillisecondsToTicks(const WebRtc_Word64 ms);
50
51 static WebRtc_Word64 TicksToMilliseconds(const WebRtc_Word64 ticks);
52
53 // Returns a TickTime that is ticks later than the passed TickTime
54 friend TickTime operator+(const TickTime lhs, const WebRtc_Word64 ticks);
55 TickTime& operator+=(const WebRtc_Word64& rhs);
56
57
58 // Returns a TickInterval that is the difference in ticks beween rhs and lhs
59 friend TickInterval operator-(const TickTime& lhs, const TickTime& rhs);
60 private:
61 WebRtc_Word64 _ticks;
62 };
63
64 class TickInterval
65 {
66 public:
67 TickInterval();
68
69 WebRtc_Word64 Milliseconds() const;
70 WebRtc_Word64 Microseconds() const;
71
72 // Returns the sum of two TickIntervals as a TickInterval
73 friend TickInterval operator+(const TickInterval& lhs,
74 const TickInterval& rhs);
75 TickInterval& operator-=(const TickInterval& rhs);
76
77 // Returns a TickInterval corresponding to rhs - lhs
78 friend TickInterval operator-(const TickInterval& lhs,
79 const TickInterval& rhs);
80 TickInterval& operator+=(const TickInterval& rhs);
81
82 friend bool operator>(const TickInterval& lhs, const TickInterval& rhs);
83 friend bool operator<=(const TickInterval& lhs, const TickInterval& rhs);
84 friend bool operator<(const TickInterval& lhs, const TickInterval& rhs);
85 friend bool operator>=(const TickInterval& lhs, const TickInterval& rhs);
86
87 private:
88 TickInterval(WebRtc_Word64 interval);
89
90 friend class TickTime;
91 friend TickInterval operator-(const TickTime& lhs, const TickTime& rhs);
92
93 private:
94 WebRtc_Word64 _interval;
95 };
96
97 inline TickInterval operator+(const TickInterval& lhs, const TickInterval& rhs)
98 {
99 return TickInterval(lhs._interval + rhs._interval);
100 }
101
102 inline TickInterval operator-(const TickInterval& lhs, const TickInterval& rhs)
103 {
104 return TickInterval(lhs._interval - rhs._interval);
105 }
106
107 inline TickInterval operator-(const TickTime& lhs,const TickTime& rhs)
108 {
109 return TickInterval(lhs._ticks - rhs._ticks);
110 }
111
112 inline TickTime operator+(const TickTime lhs, const WebRtc_Word64 ticks)
113 {
114 TickTime time = lhs;
115 time._ticks += ticks;
116 return time;
117 }
118 inline bool operator>(const TickInterval& lhs, const TickInterval& rhs)
119 {
120 return lhs._interval > rhs._interval;
121 }
122 inline bool operator<=(const TickInterval& lhs, const TickInterval& rhs)
123 {
124 return lhs._interval <= rhs._interval;
125 }
126 inline bool operator<(const TickInterval& lhs, const TickInterval& rhs)
127 {
128 return lhs._interval <= rhs._interval;
129 }
130 inline bool operator>=(const TickInterval& lhs, const TickInterval& rhs)
131 {
132 return lhs._interval >= rhs._interval;
133 }
134
Now()135 inline TickTime TickTime::Now()
136 {
137 TickTime result;
138 #if _WIN32
139 // TODO(wu): Remove QueryPerformanceCounter implementation.
140 #ifdef USE_QUERY_PERFORMANCE_COUNTER
141 // QueryPerformanceCounter returns the value from the TSC which is
142 // incremented at the CPU frequency. The algorithm used requires
143 // the CPU frequency to be constant. Technology like speed stepping
144 // which has variable CPU frequency will therefore yield unpredictable,
145 // incorrect time estimations.
146 LARGE_INTEGER qpcnt;
147 QueryPerformanceCounter(&qpcnt);
148 result._ticks = qpcnt.QuadPart;
149 #else
150 static volatile LONG lastTimeGetTime = 0;
151 static volatile WebRtc_Word64 numWrapTimeGetTime = 0;
152 volatile LONG* lastTimeGetTimePtr = &lastTimeGetTime;
153 DWORD now = timeGetTime();
154 // Atomically update the last gotten time
155 DWORD old = InterlockedExchange(lastTimeGetTimePtr, now);
156 if(now < old)
157 {
158 // If now is earlier than old, there may have been a race between
159 // threads.
160 // 0x0fffffff ~3.1 days, the code will not take that long to execute
161 // so it must have been a wrap around.
162 if(old > 0xf0000000 && now < 0x0fffffff)
163 {
164 numWrapTimeGetTime++;
165 }
166 }
167 result._ticks = now + (numWrapTimeGetTime<<32);
168 #endif
169 #elif defined(WEBRTC_LINUX)
170 struct timespec ts;
171 // TODO(wu): Remove CLOCK_REALTIME implementation.
172 #ifdef WEBRTC_CLOCK_TYPE_REALTIME
173 clock_gettime(CLOCK_REALTIME, &ts);
174 #else
175 clock_gettime(CLOCK_MONOTONIC, &ts);
176 #endif
177 result._ticks = 1000000000LL * static_cast<WebRtc_Word64>(ts.tv_sec) + static_cast<WebRtc_Word64>(ts.tv_nsec);
178 #elif defined(WEBRTC_MAC)
179 static mach_timebase_info_data_t timebase;
180 if (timebase.denom == 0) {
181 // Get the timebase if this is the first time we run.
182 // Recommended by Apple's QA1398.
183 kern_return_t retval = mach_timebase_info(&timebase);
184 if (retval != KERN_SUCCESS) {
185 // TODO(wu): Implement CHECK similar to chrome for all the platforms.
186 // Then replace this with a CHECK(retval == KERN_SUCCESS);
187 asm("int3");
188 }
189 }
190 // Use timebase to convert absolute time tick units into nanoseconds.
191 result._ticks = mach_absolute_time() * timebase.numer / timebase.denom;
192 #else
193 struct timeval tv;
194 gettimeofday(&tv, NULL);
195 result._ticks = 1000000LL * static_cast<WebRtc_Word64>(tv.tv_sec) + static_cast<WebRtc_Word64>(tv.tv_usec);
196 #endif
197 return result;
198 }
199
MillisecondTimestamp()200 inline WebRtc_Word64 TickTime::MillisecondTimestamp()
201 {
202 TickTime now = TickTime::Now();
203 #if _WIN32
204 #ifdef USE_QUERY_PERFORMANCE_COUNTER
205 LARGE_INTEGER qpfreq;
206 QueryPerformanceFrequency(&qpfreq);
207 return (now._ticks * 1000) / qpfreq.QuadPart;
208 #else
209 return now._ticks;
210 #endif
211 #elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
212 return now._ticks / 1000000LL;
213 #else
214 return now._ticks / 1000LL;
215 #endif
216 }
217
MicrosecondTimestamp()218 inline WebRtc_Word64 TickTime::MicrosecondTimestamp()
219 {
220 TickTime now = TickTime::Now();
221
222 #if _WIN32
223 #ifdef USE_QUERY_PERFORMANCE_COUNTER
224 LARGE_INTEGER qpfreq;
225 QueryPerformanceFrequency(&qpfreq);
226 return (now._ticks * 1000) / (qpfreq.QuadPart/1000);
227 #else
228 return now._ticks *1000LL;
229 #endif
230 #elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
231 return now._ticks / 1000LL;
232 #else
233 return now._ticks;
234 #endif
235 }
236
Ticks()237 inline WebRtc_Word64 TickTime::Ticks() const
238 {
239 return _ticks;
240 }
241
MillisecondsToTicks(const WebRtc_Word64 ms)242 inline WebRtc_Word64 TickTime::MillisecondsToTicks(const WebRtc_Word64 ms)
243 {
244 #if _WIN32
245 #ifdef USE_QUERY_PERFORMANCE_COUNTER
246 LARGE_INTEGER qpfreq;
247 QueryPerformanceFrequency(&qpfreq);
248 return (qpfreq.QuadPart * ms) / 1000;
249 #else
250 return ms;
251 #endif
252 #elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
253 return ms * 1000000LL;
254 #else
255 return ms * 1000LL;
256 #endif
257 }
258
TicksToMilliseconds(const WebRtc_Word64 ticks)259 inline WebRtc_Word64 TickTime::TicksToMilliseconds(const WebRtc_Word64 ticks)
260 {
261 #if _WIN32
262 #ifdef USE_QUERY_PERFORMANCE_COUNTER
263 LARGE_INTEGER qpfreq;
264 QueryPerformanceFrequency(&qpfreq);
265 return (ticks * 1000) / qpfreq.QuadPart;
266 #else
267 return ticks;
268 #endif
269 #elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
270 return ticks / 1000000LL;
271 #else
272 return ticks / 1000LL;
273 #endif
274 }
275
276 inline TickTime& TickTime::operator+=(const WebRtc_Word64& ticks)
277 {
278 _ticks += ticks;
279 return *this;
280 }
281
TickInterval()282 inline TickInterval::TickInterval() : _interval(0)
283 {
284 }
285
TickInterval(const WebRtc_Word64 interval)286 inline TickInterval::TickInterval(const WebRtc_Word64 interval)
287 : _interval(interval)
288 {
289 }
290
Milliseconds()291 inline WebRtc_Word64 TickInterval::Milliseconds() const
292 {
293 #if _WIN32
294 #ifdef USE_QUERY_PERFORMANCE_COUNTER
295 LARGE_INTEGER qpfreq;
296 QueryPerformanceFrequency(&qpfreq);
297 return (_interval * 1000) / qpfreq.QuadPart;
298 #else
299 // _interval is in ms
300 return _interval;
301 #endif
302 #elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
303 // _interval is in ns
304 return _interval / 1000000;
305 #else
306 // _interval is usecs
307 return _interval / 1000;
308 #endif
309 }
310
Microseconds()311 inline WebRtc_Word64 TickInterval::Microseconds() const
312 {
313 #if _WIN32
314 #ifdef USE_QUERY_PERFORMANCE_COUNTER
315 LARGE_INTEGER qpfreq;
316 QueryPerformanceFrequency(&qpfreq);
317 return (_interval * 1000000) / qpfreq.QuadPart;
318 #else
319 // _interval is in ms
320 return _interval *1000LL;
321 #endif
322 #elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
323 // _interval is in ns
324 return _interval / 1000;
325 #else
326 // _interval is usecs
327 return _interval;
328 #endif
329 }
330
331 inline TickInterval& TickInterval::operator+=(const TickInterval& rhs)
332 {
333 _interval += rhs._interval;
334 return *this;
335 }
336
337 inline TickInterval& TickInterval::operator-=(const TickInterval& rhs)
338 {
339 _interval -= rhs._interval;
340 return *this;
341 }
342 } // namespace webrtc
343
344 #endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TICK_UTIL_H_
345