1 //===------------------------- chrono.cpp ---------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "chrono" 10 #include "cerrno" // errno 11 #include "system_error" // __throw_system_error 12 #include <time.h> // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME 13 #include "include/apple_availability.h" 14 15 #if !defined(__APPLE__) 16 #define _LIBCPP_USE_CLOCK_GETTIME 17 #endif // __APPLE__ 18 19 #if defined(_LIBCPP_WIN32API) 20 #define WIN32_LEAN_AND_MEAN 21 #define VC_EXTRA_LEAN 22 #include <windows.h> 23 #if _WIN32_WINNT >= _WIN32_WINNT_WIN8 24 #include <winapifamily.h> 25 #endif 26 #else 27 #if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME) 28 #include <sys/time.h> // for gettimeofday and timeval 29 #endif // !defined(CLOCK_REALTIME) 30 #endif // defined(_LIBCPP_WIN32API) 31 32 #if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK) 33 #if __APPLE__ 34 #include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t 35 #elif !defined(_LIBCPP_WIN32API) && !defined(CLOCK_MONOTONIC) 36 #error "Monotonic clock not implemented" 37 #endif 38 #endif 39 40 #if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB) 41 #pragma comment(lib, "rt") 42 #endif 43 44 _LIBCPP_BEGIN_NAMESPACE_STD 45 46 namespace chrono 47 { 48 49 // system_clock 50 51 const bool system_clock::is_steady; 52 53 system_clock::time_point 54 system_clock::now() _NOEXCEPT 55 { 56 #if defined(_LIBCPP_WIN32API) 57 // FILETIME is in 100ns units 58 using filetime_duration = 59 _VSTD::chrono::duration<__int64, 60 _VSTD::ratio_multiply<_VSTD::ratio<100, 1>, 61 nanoseconds::period>>; 62 63 // The Windows epoch is Jan 1 1601, the Unix epoch Jan 1 1970. 64 static _LIBCPP_CONSTEXPR const seconds nt_to_unix_epoch{11644473600}; 65 66 FILETIME ft; 67 #if _WIN32_WINNT >= _WIN32_WINNT_WIN8 68 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 69 GetSystemTimePreciseAsFileTime(&ft); 70 #else 71 GetSystemTimeAsFileTime(&ft); 72 #endif 73 #else 74 GetSystemTimeAsFileTime(&ft); 75 #endif 76 77 filetime_duration d{(static_cast<__int64>(ft.dwHighDateTime) << 32) | 78 static_cast<__int64>(ft.dwLowDateTime)}; 79 return time_point(duration_cast<duration>(d - nt_to_unix_epoch)); 80 #else 81 #if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) 82 struct timespec tp; 83 if (0 != clock_gettime(CLOCK_REALTIME, &tp)) 84 __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed"); 85 return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000)); 86 #else 87 timeval tv; 88 gettimeofday(&tv, 0); 89 return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec)); 90 #endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME 91 #endif 92 } 93 94 time_t 95 system_clock::to_time_t(const time_point& t) _NOEXCEPT 96 { 97 return time_t(duration_cast<seconds>(t.time_since_epoch()).count()); 98 } 99 100 system_clock::time_point 101 system_clock::from_time_t(time_t t) _NOEXCEPT 102 { 103 return system_clock::time_point(seconds(t)); 104 } 105 106 #ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK 107 // steady_clock 108 // 109 // Warning: If this is not truly steady, then it is non-conforming. It is 110 // better for it to not exist and have the rest of libc++ use system_clock 111 // instead. 112 113 const bool steady_clock::is_steady; 114 115 #if defined(__APPLE__) 116 117 // Darwin libc versions >= 1133 provide ns precision via CLOCK_UPTIME_RAW 118 #if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW) 119 steady_clock::time_point 120 steady_clock::now() _NOEXCEPT 121 { 122 struct timespec tp; 123 if (0 != clock_gettime(CLOCK_UPTIME_RAW, &tp)) 124 __throw_system_error(errno, "clock_gettime(CLOCK_UPTIME_RAW) failed"); 125 return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec)); 126 } 127 128 #else 129 // mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of 130 // nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom 131 // are run time constants supplied by the OS. This clock has no relationship 132 // to the Gregorian calendar. It's main use is as a high resolution timer. 133 134 // MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize 135 // for that case as an optimization. 136 137 static 138 steady_clock::rep 139 steady_simplified() 140 { 141 return static_cast<steady_clock::rep>(mach_absolute_time()); 142 } 143 144 static 145 double 146 compute_steady_factor() 147 { 148 mach_timebase_info_data_t MachInfo; 149 mach_timebase_info(&MachInfo); 150 return static_cast<double>(MachInfo.numer) / MachInfo.denom; 151 } 152 153 static 154 steady_clock::rep 155 steady_full() 156 { 157 static const double factor = compute_steady_factor(); 158 return static_cast<steady_clock::rep>(mach_absolute_time() * factor); 159 } 160 161 typedef steady_clock::rep (*FP)(); 162 163 static 164 FP 165 init_steady_clock() 166 { 167 mach_timebase_info_data_t MachInfo; 168 mach_timebase_info(&MachInfo); 169 if (MachInfo.numer == MachInfo.denom) 170 return &steady_simplified; 171 return &steady_full; 172 } 173 174 steady_clock::time_point 175 steady_clock::now() _NOEXCEPT 176 { 177 static FP fp = init_steady_clock(); 178 return time_point(duration(fp())); 179 } 180 #endif // defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW) 181 182 #elif defined(_LIBCPP_WIN32API) 183 184 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx says: 185 // If the function fails, the return value is zero. <snip> 186 // On systems that run Windows XP or later, the function will always succeed 187 // and will thus never return zero. 188 189 static LARGE_INTEGER 190 __QueryPerformanceFrequency() 191 { 192 LARGE_INTEGER val; 193 (void) QueryPerformanceFrequency(&val); 194 return val; 195 } 196 197 steady_clock::time_point 198 steady_clock::now() _NOEXCEPT 199 { 200 static const LARGE_INTEGER freq = __QueryPerformanceFrequency(); 201 202 LARGE_INTEGER counter; 203 (void) QueryPerformanceCounter(&counter); 204 return time_point(duration(counter.QuadPart * nano::den / freq.QuadPart)); 205 } 206 207 #elif defined(CLOCK_MONOTONIC) 208 209 // On Apple platforms only CLOCK_UPTIME_RAW or mach_absolute_time are able to 210 // time functions in the nanosecond range. Thus, they are the only acceptable 211 // implementations of steady_clock. 212 #ifdef __APPLE__ 213 #error "Never use CLOCK_MONOTONIC for steady_clock::now on Apple platforms" 214 #endif 215 216 steady_clock::time_point 217 steady_clock::now() _NOEXCEPT 218 { 219 struct timespec tp; 220 if (0 != clock_gettime(CLOCK_MONOTONIC, &tp)) 221 __throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed"); 222 return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec)); 223 } 224 225 #else 226 #error "Monotonic clock not implemented" 227 #endif 228 229 #endif // !_LIBCPP_HAS_NO_MONOTONIC_CLOCK 230 231 } 232 233 _LIBCPP_END_NAMESPACE_STD 234