3 * Time utility functions.
4 * Author: Paolo Molaro (<lupus@ximian.com>)
5 * Copyright (C) 2008 Novell, Inc.
6 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #ifdef HAVE_SYS_TIME_H
19 #include <mach/clock.h>
20 #include <mach/mach.h>
24 #include <mono/utils/mono-time.h>
25 #include <mono/utils/atomic.h>
27 #if HAVE_MACH_ABSOLUTE_TIME
28 #include <mach/mach_time.h>
31 #define MTICKS_PER_SEC (10 * 1000 * 1000)
33 typedef enum _TimeConversionConstants
35 tccSecondsToMillieSeconds
= 1000, // 10^3
36 tccSecondsToMicroSeconds
= 1000000, // 10^6
37 tccSecondsToNanoSeconds
= 1000000000, // 10^9
38 tccMillieSecondsToMicroSeconds
= 1000, // 10^3
39 tccMillieSecondsToNanoSeconds
= 1000000, // 10^6
40 tccMicroSecondsToNanoSeconds
= 1000, // 10^3
41 tccSecondsTo100NanoSeconds
= 10000000, // 10^7
42 tccMicroSecondsTo100NanoSeconds
= 10 // 10^1
43 } TimeConversionConstants
;
46 mono_msec_ticks (void)
48 return mono_100ns_ticks () / 10 / 1000;
55 /* we get "error: implicit declaration of function 'GetTickCount64'" */
56 WINBASEAPI ULONGLONG WINAPI
GetTickCount64(void);
60 mono_msec_boottime (void)
62 /* GetTickCount () is reportedly monotonic */
63 return GetTickCount64 ();
66 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
68 mono_100ns_ticks (void)
70 static LARGE_INTEGER freq
;
71 static UINT64 start_time
;
76 if (!QueryPerformanceFrequency (&freq
))
77 return mono_100ns_datetime ();
78 QueryPerformanceCounter (&value
);
79 start_time
= value
.QuadPart
;
81 QueryPerformanceCounter (&value
);
82 cur_time
= value
.QuadPart
;
83 /* we use unsigned numbers and return the difference to avoid overflows */
84 return (cur_time
- start_time
) * (double)MTICKS_PER_SEC
/ freq
.QuadPart
;
87 /* Returns the number of 100ns ticks since Jan 1, 1601, UTC timezone */
89 mono_100ns_datetime (void)
93 if (sizeof(ft
) != sizeof(FILETIME
))
94 g_assert_not_reached ();
96 GetSystemTimeAsFileTime ((FILETIME
*) &ft
);
103 #if defined (HAVE_SYS_PARAM_H)
104 #include <sys/param.h>
106 #if defined(HAVE_SYS_SYSCTL_H)
107 #include <sys/sysctl.h>
110 #if defined(HOST_DARWIN)
111 #include <mach/mach.h>
112 #include <mach/mach_time.h>
117 /* Returns the number of milliseconds from boot time: this should be monotonic */
118 /* Adapted from CoreCLR: https://github.com/dotnet/coreclr/blob/66d2738ea96fcce753dec1370e79a0c78f7b6adb/src/pal/src/misc/time.cpp */
120 mono_msec_boottime (void)
122 /* clock_gettime () is found by configure on Apple builds, but its only present from ios 10, macos 10.12, tvos 10 and watchos 3 */
123 #if !defined (TARGET_WASM) && ((defined(HAVE_CLOCK_MONOTONIC_COARSE) || defined(HAVE_CLOCK_MONOTONIC)) && !(defined(TARGET_IOS) || defined(TARGET_OSX) || defined(TARGET_WATCHOS) || defined(TARGET_TVOS)))
124 clockid_t clockType
=
125 #if HAVE_CLOCK_MONOTONIC_COARSE
126 CLOCK_MONOTONIC_COARSE
; /* good enough resolution, fastest speed */
131 if (clock_gettime (clockType
, &ts
) != 0) {
132 g_error ("clock_gettime(CLOCK_MONOTONIC*) failed; errno is %d", errno
, strerror (errno
));
135 return (ts
.tv_sec
* tccSecondsToMillieSeconds
) + (ts
.tv_nsec
/ tccMillieSecondsToNanoSeconds
);
137 #elif HAVE_MACH_ABSOLUTE_TIME
138 static gboolean timebase_inited
;
139 static mach_timebase_info_data_t s_TimebaseInfo
;
141 if (!timebase_inited
) {
142 kern_return_t machRet
;
143 mach_timebase_info_data_t tmp
;
144 machRet
= mach_timebase_info (&tmp
);
145 g_assert (machRet
== KERN_SUCCESS
);
146 /* Assume memcpy works correctly if ran concurrently */
147 memcpy (&s_TimebaseInfo
, &tmp
, sizeof (mach_timebase_info_data_t
));
148 mono_memory_barrier ();
149 timebase_inited
= TRUE
;
151 // This barrier prevents reading s_TimebaseInfo before reading timebase_inited.
152 mono_memory_barrier ();
154 return (mach_absolute_time () * s_TimebaseInfo
.numer
/ s_TimebaseInfo
.denom
) / tccMillieSecondsToNanoSeconds
;
157 return (gint64
)(gethrtime () / tccMillieSecondsToNanoSeconds
);
159 #elif HAVE_READ_REAL_TIME
161 read_real_time (&tb
, TIMEBASE_SZ
);
162 if (time_base_to_time (&tb
, TIMEBASE_SZ
) != 0) {
163 g_error ("time_base_to_time() failed; errno is %d (%s)", errno
, strerror (errno
));
166 return (tb
.tb_high
* tccSecondsToMillieSeconds
) + (tb
.tb_low
/ tccMillieSecondsToNanoSeconds
);
170 if (gettimeofday (&tv
, NULL
) == -1) {
171 g_error ("gettimeofday() failed; errno is %d (%s)", errno
, strerror (errno
));
174 return (tv
.tv_sec
* tccSecondsToMillieSeconds
) + (tv
.tv_usec
/ tccMillieSecondsToMicroSeconds
);
176 #endif /* HAVE_CLOCK_MONOTONIC */
179 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
181 mono_100ns_ticks (void)
184 #if defined(HOST_DARWIN)
185 /* http://developer.apple.com/library/mac/#qa/qa1398/_index.html */
186 static mach_timebase_info_data_t timebase
;
187 guint64 now
= mach_absolute_time ();
188 if (timebase
.denom
== 0) {
189 mach_timebase_info (&timebase
);
190 timebase
.denom
*= 100; /* we return 100ns ticks */
192 return now
* timebase
.numer
/ timebase
.denom
;
193 #elif defined(CLOCK_MONOTONIC) && !defined(__PASE__)
194 /* !__PASE__ is defined because i 7.1 doesn't have clock_getres */
195 struct timespec tspec
;
196 static struct timespec tspec_freq
= {0};
197 static int can_use_clock
= 0;
198 if (!tspec_freq
.tv_nsec
) {
199 can_use_clock
= clock_getres (CLOCK_MONOTONIC
, &tspec_freq
) == 0;
200 /*printf ("resolution: %lu.%lu\n", tspec_freq.tv_sec, tspec_freq.tv_nsec);*/
203 if (clock_gettime (CLOCK_MONOTONIC
, &tspec
) == 0) {
204 /*printf ("time: %lu.%lu\n", tspec.tv_sec, tspec.tv_nsec); */
205 return ((gint64
)tspec
.tv_sec
* MTICKS_PER_SEC
+ tspec
.tv_nsec
/ 100);
209 if (gettimeofday (&tv
, NULL
) == 0)
210 return ((gint64
)tv
.tv_sec
* 1000000 + tv
.tv_usec
) * 10;
215 * Magic number to convert unix epoch start to windows epoch start
216 * Jan 1, 1970 into a value which is relative to Jan 1, 1601.
218 #define EPOCH_ADJUST ((guint64)11644473600LL)
220 /* Returns the number of 100ns ticks since 1/1/1601, UTC timezone */
222 mono_100ns_datetime (void)
225 if (gettimeofday (&tv
, NULL
) == 0)
226 return mono_100ns_datetime_from_timeval (tv
);
231 mono_100ns_datetime_from_timeval (struct timeval tv
)
233 return (((gint64
)tv
.tv_sec
+ EPOCH_ADJUST
) * 1000000 + tv
.tv_usec
) * 10;
238 #if defined(HOST_DARWIN)
241 mono_clock_init (mono_clock_id_t
*clk_id
)
246 ret
= host_get_clock_service (mach_host_self (), SYSTEM_CLOCK
, clk_id
);
247 } while (ret
== KERN_ABORTED
);
249 if (ret
!= KERN_SUCCESS
)
250 g_error ("%s: host_get_clock_service () returned %d", __func__
, ret
);
254 mono_clock_cleanup (mono_clock_id_t clk_id
)
259 ret
= mach_port_deallocate (mach_task_self (), clk_id
);
260 } while (ret
== KERN_ABORTED
);
262 if (ret
!= KERN_SUCCESS
)
263 g_error ("%s: mach_port_deallocate () returned %d", __func__
, ret
);
267 mono_clock_get_time_ns (mono_clock_id_t clk_id
)
270 mach_timespec_t mach_ts
;
273 ret
= clock_get_time (clk_id
, &mach_ts
);
274 } while (ret
== KERN_ABORTED
);
276 if (ret
!= KERN_SUCCESS
)
277 g_error ("%s: clock_get_time () returned %d", __func__
, ret
);
279 return ((guint64
) mach_ts
.tv_sec
* 1000000000) + (guint64
) mach_ts
.tv_nsec
;
282 // TODO: Potentially make this the default?
283 // Can we assume clock_gettime exists on all modern POSIX systems? Maybe add a better check for it in configure.ac?
284 #elif defined(__linux__) || defined (TARGET_WASM)
287 mono_clock_init (mono_clock_id_t
*clk_id
)
289 #ifdef HAVE_CLOCK_MONOTONIC
290 *clk_id
= CLOCK_MONOTONIC
;
295 mono_clock_cleanup (mono_clock_id_t clk_id
)
300 mono_clock_get_time_ns (mono_clock_id_t clk_id
)
302 #ifdef HAVE_CLOCK_GETTIME
305 if (clock_gettime (clk_id
, &ts
) == -1)
306 g_error ("%s: clock_gettime () returned -1, errno = %d", __func__
, errno
);
308 return ((guint64
) ts
.tv_sec
* 1000000000) + (guint64
) ts
.tv_nsec
;
317 mono_clock_init (mono_clock_id_t
*clk_id
)
319 // TODO: need to implement this function for Windows
323 mono_clock_cleanup (mono_clock_id_t clk_id
)
325 // TODO: need to implement this function for Windows
329 mono_clock_get_time_ns (mono_clock_id_t clk_id
)
331 // TODO: need to implement time stamp function for Windows