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
18 #include <mono/utils/mono-time.h>
19 #include <mono/utils/atomic.h>
21 #if HAVE_MACH_ABSOLUTE_TIME
22 #include <mach/mach_time.h>
25 #define MTICKS_PER_SEC (10 * 1000 * 1000)
27 typedef enum _TimeConversionConstants
29 tccSecondsToMillieSeconds
= 1000, // 10^3
30 tccSecondsToMicroSeconds
= 1000000, // 10^6
31 tccSecondsToNanoSeconds
= 1000000000, // 10^9
32 tccMillieSecondsToMicroSeconds
= 1000, // 10^3
33 tccMillieSecondsToNanoSeconds
= 1000000, // 10^6
34 tccMicroSecondsToNanoSeconds
= 1000, // 10^3
35 tccSecondsTo100NanoSeconds
= 10000000, // 10^7
36 tccMicroSecondsTo100NanoSeconds
= 10 // 10^1
37 } TimeConversionConstants
;
40 mono_msec_ticks (void)
42 return mono_100ns_ticks () / 10 / 1000;
49 /* we get "error: implicit declaration of function 'GetTickCount64'" */
50 WINBASEAPI ULONGLONG WINAPI
GetTickCount64(void);
54 mono_msec_boottime (void)
56 /* GetTickCount () is reportedly monotonic */
57 return GetTickCount64 ();
60 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
62 mono_100ns_ticks (void)
64 static LARGE_INTEGER freq
;
65 static UINT64 start_time
;
70 if (!QueryPerformanceFrequency (&freq
))
71 return mono_100ns_datetime ();
72 QueryPerformanceCounter (&value
);
73 start_time
= value
.QuadPart
;
75 QueryPerformanceCounter (&value
);
76 cur_time
= value
.QuadPart
;
77 /* we use unsigned numbers and return the difference to avoid overflows */
78 return (cur_time
- start_time
) * (double)MTICKS_PER_SEC
/ freq
.QuadPart
;
81 /* Returns the number of 100ns ticks since Jan 1, 1601, UTC timezone */
83 mono_100ns_datetime (void)
87 if (sizeof(ft
) != sizeof(FILETIME
))
88 g_assert_not_reached ();
90 GetSystemTimeAsFileTime ((FILETIME
*) &ft
);
97 #if defined (HAVE_SYS_PARAM_H)
98 #include <sys/param.h>
100 #if defined(HAVE_SYS_SYSCTL_H)
101 #include <sys/sysctl.h>
104 #if defined(HOST_DARWIN)
105 #include <mach/mach.h>
106 #include <mach/mach_time.h>
111 /* Returns the number of milliseconds from boot time: this should be monotonic */
112 /* Adapted from CoreCLR: https://github.com/dotnet/coreclr/blob/66d2738ea96fcce753dec1370e79a0c78f7b6adb/src/pal/src/misc/time.cpp */
114 mono_msec_boottime (void)
116 /* clock_gettime () is found by configure on Apple builds, but its only present from ios 10, macos 10.12, tvos 10 and watchos 3 */
117 #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)))
118 clockid_t clockType
=
119 #if HAVE_CLOCK_MONOTONIC_COARSE
120 CLOCK_MONOTONIC_COARSE
; /* good enough resolution, fastest speed */
125 if (clock_gettime (clockType
, &ts
) != 0) {
126 g_error ("clock_gettime(CLOCK_MONOTONIC*) failed; errno is %d", errno
, strerror (errno
));
129 return (ts
.tv_sec
* tccSecondsToMillieSeconds
) + (ts
.tv_nsec
/ tccMillieSecondsToNanoSeconds
);
131 #elif HAVE_MACH_ABSOLUTE_TIME
132 static gboolean timebase_inited
;
133 static mach_timebase_info_data_t s_TimebaseInfo
;
135 if (!timebase_inited
) {
136 kern_return_t machRet
;
137 mach_timebase_info_data_t tmp
;
138 machRet
= mach_timebase_info (&tmp
);
139 g_assert (machRet
== KERN_SUCCESS
);
140 /* Assume memcpy works correctly if ran concurrently */
141 memcpy (&s_TimebaseInfo
, &tmp
, sizeof (mach_timebase_info_data_t
));
142 mono_memory_barrier ();
143 timebase_inited
= TRUE
;
145 // This barrier prevents reading s_TimebaseInfo before reading timebase_inited.
146 mono_memory_barrier ();
148 return (mach_absolute_time () * s_TimebaseInfo
.numer
/ s_TimebaseInfo
.denom
) / tccMillieSecondsToNanoSeconds
;
151 return (gint64
)(gethrtime () / tccMillieSecondsToNanoSeconds
);
153 #elif HAVE_READ_REAL_TIME
155 read_real_time (&tb
, TIMEBASE_SZ
);
156 if (time_base_to_time (&tb
, TIMEBASE_SZ
) != 0) {
157 g_error ("time_base_to_time() failed; errno is %d (%s)", errno
, strerror (errno
));
160 return (tb
.tb_high
* tccSecondsToMillieSeconds
) + (tb
.tb_low
/ tccMillieSecondsToNanoSeconds
);
164 if (gettimeofday (&tv
, NULL
) == -1) {
165 g_error ("gettimeofday() failed; errno is %d (%s)", errno
, strerror (errno
));
168 return (tv
.tv_sec
* tccSecondsToMillieSeconds
) + (tv
.tv_usec
/ tccMillieSecondsToMicroSeconds
);
170 #endif /* HAVE_CLOCK_MONOTONIC */
173 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
175 mono_100ns_ticks (void)
178 #if defined(HOST_DARWIN)
179 /* http://developer.apple.com/library/mac/#qa/qa1398/_index.html */
180 static mach_timebase_info_data_t timebase
;
181 guint64 now
= mach_absolute_time ();
182 if (timebase
.denom
== 0) {
183 mach_timebase_info (&timebase
);
184 timebase
.denom
*= 100; /* we return 100ns ticks */
186 return now
* timebase
.numer
/ timebase
.denom
;
187 #elif defined(CLOCK_MONOTONIC) && !defined(__PASE__)
188 /* !__PASE__ is defined because i 7.1 doesn't have clock_getres */
189 struct timespec tspec
;
190 static struct timespec tspec_freq
= {0};
191 static int can_use_clock
= 0;
192 if (!tspec_freq
.tv_nsec
) {
193 can_use_clock
= clock_getres (CLOCK_MONOTONIC
, &tspec_freq
) == 0;
194 /*printf ("resolution: %lu.%lu\n", tspec_freq.tv_sec, tspec_freq.tv_nsec);*/
197 if (clock_gettime (CLOCK_MONOTONIC
, &tspec
) == 0) {
198 /*printf ("time: %lu.%lu\n", tspec.tv_sec, tspec.tv_nsec); */
199 return ((gint64
)tspec
.tv_sec
* MTICKS_PER_SEC
+ tspec
.tv_nsec
/ 100);
203 if (gettimeofday (&tv
, NULL
) == 0)
204 return ((gint64
)tv
.tv_sec
* 1000000 + tv
.tv_usec
) * 10;
209 * Magic number to convert unix epoch start to windows epoch start
210 * Jan 1, 1970 into a value which is relative to Jan 1, 1601.
212 #define EPOCH_ADJUST ((guint64)11644473600LL)
214 /* Returns the number of 100ns ticks since 1/1/1601, UTC timezone */
216 mono_100ns_datetime (void)
219 if (gettimeofday (&tv
, NULL
) == 0)
220 return mono_100ns_datetime_from_timeval (tv
);
225 mono_100ns_datetime_from_timeval (struct timeval tv
)
227 return (((gint64
)tv
.tv_sec
+ EPOCH_ADJUST
) * 1000000 + tv
.tv_usec
) * 10;