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