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
32namespace webrtc {
33class TickInterval;
34
35class TickTime
36{
37public:
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);
60private:
61    WebRtc_Word64 _ticks;
62};
63
64class TickInterval
65{
66public:
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
87private:
88    TickInterval(WebRtc_Word64 interval);
89
90    friend class TickTime;
91    friend TickInterval operator-(const TickTime& lhs, const TickTime& rhs);
92
93private:
94    WebRtc_Word64 _interval;
95};
96
97inline TickInterval operator+(const TickInterval& lhs, const TickInterval& rhs)
98{
99    return TickInterval(lhs._interval + rhs._interval);
100}
101
102inline TickInterval operator-(const TickInterval& lhs, const TickInterval& rhs)
103{
104    return TickInterval(lhs._interval - rhs._interval);
105}
106
107inline TickInterval operator-(const TickTime& lhs,const TickTime& rhs)
108{
109    return TickInterval(lhs._ticks - rhs._ticks);
110}
111
112inline TickTime operator+(const TickTime lhs, const WebRtc_Word64 ticks)
113{
114    TickTime time = lhs;
115    time._ticks += ticks;
116    return time;
117}
118inline bool operator>(const TickInterval& lhs, const TickInterval& rhs)
119{
120    return lhs._interval > rhs._interval;
121}
122inline bool operator<=(const TickInterval& lhs, const TickInterval& rhs)
123{
124    return lhs._interval <= rhs._interval;
125}
126inline bool operator<(const TickInterval& lhs, const TickInterval& rhs)
127{
128    return lhs._interval <= rhs._interval;
129}
130inline bool operator>=(const TickInterval& lhs, const TickInterval& rhs)
131{
132    return lhs._interval >= rhs._interval;
133}
134
135inline 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
200inline 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
218inline 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
237inline WebRtc_Word64 TickTime::Ticks() const
238{
239    return _ticks;
240}
241
242inline 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
259inline 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
276inline TickTime& TickTime::operator+=(const WebRtc_Word64& ticks)
277{
278    _ticks += ticks;
279    return *this;
280}
281
282inline TickInterval::TickInterval() : _interval(0)
283{
284}
285
286inline TickInterval::TickInterval(const WebRtc_Word64 interval)
287    : _interval(interval)
288{
289}
290
291inline 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
311inline 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
331inline TickInterval& TickInterval::operator+=(const TickInterval& rhs)
332{
333    _interval += rhs._interval;
334    return *this;
335}
336
337inline 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