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