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