1 /* Copyright 2010 Jukka Jyl�nki
2
3    Licensed under the Apache License, Version 2.0 (the "License");
4    you may not use this file except in compliance with the License.
5    You may obtain a copy of the License at
6
7        http://www.apache.org/licenses/LICENSE-2.0
8
9    Unless required by applicable law or agreed to in writing, software
10    distributed under the License is distributed on an "AS IS" BASIS,
11    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12    See the License for the specific language governing permissions and
13    limitations under the License. */
14
15 /** @file Clock.cpp
16         @brief */
17
18 #if defined(__unix__) || defined(__native_client__) || defined(EMSCRIPTEN) || defined(ANDROID) || defined(__APPLE__) || defined (__CYGWIN__)
19 #include <time.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <sys/time.h>
23 #endif
24
25 #ifdef WIN32
26 #include "../Math/InclWindows.h"
27 #endif
28
29 #ifdef EMSCRIPTEN
30 #include <emscripten.h>
31 #endif
32
33 #ifdef __APPLE__
34 #include <mach/mach_time.h>
35 #endif
36
37 #include "Clock.h"
38 #include "../Math/myassert.h"
39 #include "../Math/assume.h"
40
41 MATH_BEGIN_NAMESPACE
42
43 #ifdef WIN32
44 u64 Clock::ddwTimerFrequency;
45 #endif
46
47 #ifdef __APPLE__
48 tick_t Clock::ticksPerSecond = 0;
49 #endif
50
51 tick_t Clock::appStartTime = 0;
52
53 Clock impl;
54
55 void Clock::InitClockData()
56 {
57         if (appStartTime == 0)
58                 appStartTime = Tick();
59
60 #ifdef WIN32
61         if (!QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&ddwTimerFrequency)))
62         {
63                 LOGE("The system doesn't support high-resolution timers!");
64                 ddwTimerFrequency = (u64)-1;
65         }
66
67         if (appStartTime == 0)
68         {
69 #if WINVER >= 0x0600 /* Vista or newer */ && !defined(MATH_ENABLE_WINXP_SUPPORT)
70                 appStartTime = (tick_t)GetTickCount64();
71 #else
72 // We are explicitly building with XP support, so GetTickCount() instead of GetTickCount64 is desired.
73 #if _MSC_VER >= 1700 // VS2012
74 #pragma warning(push)
75 #pragma warning(disable:28159) // warning C28159: Consider using 'GetTickCount64' instead of 'GetTickCount'. Reason: GetTickCount overflows roughly every 49 days.  Code that does not take that into account can loop indefinitely.  GetTickCount64 operates on 64 bit values and does not have that problem
76 #endif
77                 appStartTime = (tick_t)GetTickCount();
78 #if _MSC_VER >= 1700 // VS2012
79 #pragma warning(pop)
80 #endif
81
82 #endif
83         }
84 #endif
85
86 #ifdef __APPLE__
87         mach_timebase_info_data_t timeBaseInfo;
88         mach_timebase_info(&timeBaseInfo);
89         ticksPerSecond = 1000000000ULL * (uint64_t)timeBaseInfo.denom / (uint64_t)timeBaseInfo.numer;
90         assert(ticksPerSecond > (uint64_t)timeBaseInfo.denom/timeBaseInfo.numer); // Guard against overflow if OSX numer/denom change or similar.
91 #endif
92 }
93
94 Clock::Clock()
95 {
96         InitClockData();
97 }
98
99 void Clock::Sleep(int milliseconds)
100 {
101 #ifdef WIN8RT
102 #pragma warning(Clock::Sleep has not been implemented!)
103 #elif defined(WIN32)
104         ::Sleep(milliseconds);
105 #elif !defined(__native_client__) && !defined(EMSCRIPTEN)
106         // http://linux.die.net/man/2/nanosleep
107         timespec ts;
108         ts.tv_sec = milliseconds / 1000;
109         ts.tv_nsec = (milliseconds - ts.tv_sec * 1000) * 1000 * 1000;
110         int ret = nanosleep(&ts, NULL);
111         if (ret == -1)
112                 LOGI("nanosleep returned -1! Reason: %s(%d).", strerror(errno), (int)errno);
113 #else
114 #warning Clock::Sleep has not been implemented!
115 #endif
116 }
117
118 int Clock::Year()
119 {
120 #ifdef WIN32
121         SYSTEMTIME s;
122         GetSystemTime(&s);
123         return s.wYear;
124 #else
125         ///\todo.
126         return 0;
127 #endif
128 }
129
130 int Clock::Month()
131 {
132 #ifdef WIN32
133         SYSTEMTIME s;
134         GetSystemTime(&s);
135         return s.wMonth;
136 #else
137         ///\todo.
138         return 0;
139 #endif
140 }
141
142 int Clock::Day()
143 {
144 #ifdef WIN32
145         SYSTEMTIME s;
146         GetSystemTime(&s);
147         return s.wDay;
148 #else
149         ///\todo.
150         return 0;
151 #endif
152 }
153
154 int Clock::Hour()
155 {
156 #ifdef WIN32
157         SYSTEMTIME s;
158         GetSystemTime(&s);
159         return s.wHour;
160 #else
161         ///\todo.
162         return 0;
163 #endif
164 }
165
166 int Clock::Min()
167 {
168 #ifdef WIN32
169         SYSTEMTIME s;
170         GetSystemTime(&s);
171         return s.wMinute;
172 #else
173         ///\todo.
174         return 0;
175 #endif
176 }
177
178 int Clock::Sec()
179 {
180 #ifdef WIN32
181         SYSTEMTIME s;
182         GetSystemTime(&s);
183         return s.wSecond;
184 #else
185         ///\todo.
186         return 0;
187 #endif
188 }
189
190 unsigned long Clock::SystemTime()
191 {
192 #ifdef WIN32
193 #if WINVER >= 0x0600 /* Vista or newer */ && !defined(MATH_ENABLE_WINXP_SUPPORT)
194         return (unsigned long)GetTickCount64();
195 #else
196 // We are explicitly building with XP support, so GetTickCount() instead of GetTickCount64 is desired.
197 #if _MSC_VER >= 1700 // VS2012
198 #pragma warning(push)
199 #pragma warning(disable:28159) // warning C28159: Consider using 'GetTickCount64' instead of 'GetTickCount'. Reason: GetTickCount overflows roughly every 49 days.  Code that does not take that into account can loop indefinitely.  GetTickCount64 operates on 64 bit values and does not have that problem
200 #endif
201         return (unsigned long)GetTickCount();
202 #if _MSC_VER >= 1700 // VS2012
203 #pragma warning(pop)
204 #endif
205
206 #endif
207 #else
208         return TickU32();
209 #endif
210 }
211 /*
212 tick_t Clock::ApplicationStartupTick()
213 {
214         return appStartTime;
215 }
216 */
217 unsigned long Clock::Time()
218 {
219         return (unsigned long)(Tick() - appStartTime);
220 }
221
222 tick_t Clock::Tick()
223 {
224 #if defined(ANDROID)
225         struct timespec res;
226         clock_gettime(CLOCK_REALTIME, &res);
227         return 1000000000ULL*res.tv_sec + (tick_t)res.tv_nsec;
228 #elif defined(EMSCRIPTEN)
229
230 #ifdef MATH_TICK_IS_FLOAT
231         return (tick_t)emscripten_get_now();
232 #else
233         // emscripten_get_now() returns a wallclock time as a float in milliseconds (1e-3).
234         // scale it to microseconds (1e-6) and return as a tick.
235         return (tick_t)(((double)emscripten_get_now()) * 1e3);
236 #endif
237
238 #elif defined(WIN32)
239         LARGE_INTEGER ddwTimer;
240         BOOL success = QueryPerformanceCounter(&ddwTimer);
241         assume(success != 0);
242         MARK_UNUSED(success);
243         return ddwTimer.QuadPart;
244 #elif defined(__APPLE__)
245         return mach_absolute_time();
246 #elif defined(_POSIX_MONOTONIC_CLOCK)
247         timespec t;
248         clock_gettime(CLOCK_MONOTONIC, &t);
249         return (tick_t)t.tv_sec * 1000 * 1000 * 1000 + (tick_t)t.tv_nsec;
250 #elif defined(_POSIX_C_SOURCE)
251         timeval t;
252         gettimeofday(&t, NULL);
253         return (tick_t)t.tv_sec * 1000 * 1000 + (tick_t)t.tv_usec;
254 #else
255         return (tick_t)clock();
256 #endif
257 }
258
259 unsigned long Clock::TickU32()
260 {
261 #ifdef WIN32
262         LARGE_INTEGER ddwTimer;
263         BOOL success = QueryPerformanceCounter(&ddwTimer);
264         assume(success != 0);
265         MARK_UNUSED(success);
266         return ddwTimer.LowPart;
267 #else
268         return (unsigned long)Tick();
269 #endif
270 }
271
272 tick_t Clock::TicksPerSec()
273 {
274 #if defined(ANDROID)
275         return 1000000000ULL; // 1e9 == nanoseconds.
276 #elif defined(EMSCRIPTEN)
277
278 #ifdef MATH_TICK_IS_FLOAT
279         return (tick_t)1000.0;
280 #else
281         return 1000000ULL; // 1e6 == microseconds.
282 #endif
283
284 #elif defined(WIN32)
285         return ddwTimerFrequency;
286 #elif defined(__APPLE__)
287         return ticksPerSecond;
288 #elif defined(_POSIX_MONOTONIC_CLOCK)
289         return 1000 * 1000 * 1000;
290 #elif defined(_POSIX_C_SOURCE) || defined(__APPLE__)
291         return 1000 * 1000;
292 #else
293         return CLOCKS_PER_SEC;
294 #endif
295 }
296
297 unsigned long long Clock::Rdtsc()
298 {
299 #if defined(_MSC_VER) && !defined(WIN8PHONE)
300         return __rdtsc();
301 #elif defined(__x86_64__)
302         unsigned hi, lo;
303         __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
304         return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
305 #elif defined(__i386__) || defined(__X86__) || defined(_X86_)
306         unsigned long long int x;
307         __asm__ volatile ("rdtsc" : "=A" (x));
308         return x;
309 #else
310         return Clock::Tick();
311 #endif
312 }
313
314 MATH_END_NAMESPACE

Go back to previous page