1227825Stheraven//===------------------------- chrono.cpp ---------------------------------===//
2227825Stheraven//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6227825Stheraven//
7227825Stheraven//===----------------------------------------------------------------------===//
8227825Stheraven
9227825Stheraven#include "chrono"
10288943Sdim#include "cerrno"        // errno
11288943Sdim#include "system_error"  // __throw_system_error
12288943Sdim#include <time.h>        // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME
13341825Sdim#include "include/apple_availability.h"
14288943Sdim
15341825Sdim#if !defined(__APPLE__)
16341825Sdim#define _LIBCPP_USE_CLOCK_GETTIME
17314564Sdim#endif // __APPLE__
18288943Sdim
19314564Sdim#if defined(_LIBCPP_WIN32API)
20314564Sdim#define WIN32_LEAN_AND_MEAN
21314564Sdim#define VC_EXTRA_LEAN
22321369Sdim#include <windows.h>
23314564Sdim#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
24314564Sdim#include <winapifamily.h>
25314564Sdim#endif
26314564Sdim#else
27341825Sdim#if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME)
28314564Sdim#include <sys/time.h>        // for gettimeofday and timeval
29314564Sdim#endif // !defined(CLOCK_REALTIME)
30314564Sdim#endif // defined(_LIBCPP_WIN32API)
31314564Sdim
32314564Sdim#if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
33288943Sdim#if __APPLE__
34227825Stheraven#include <mach/mach_time.h>  // mach_absolute_time, mach_timebase_info_data_t
35314564Sdim#elif !defined(_LIBCPP_WIN32API) && !defined(CLOCK_MONOTONIC)
36288943Sdim#error "Monotonic clock not implemented"
37288943Sdim#endif
38288943Sdim#endif
39227825Stheraven
40360784Sdim#if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB)
41353358Sdim#pragma comment(lib, "rt")
42353358Sdim#endif
43353358Sdim
44227825Stheraven_LIBCPP_BEGIN_NAMESPACE_STD
45227825Stheraven
46227825Stheravennamespace chrono
47227825Stheraven{
48227825Stheraven
49227825Stheraven// system_clock
50227825Stheraven
51246468Stheravenconst bool system_clock::is_steady;
52246468Stheraven
53227825Stheravensystem_clock::time_point
54227825Stheravensystem_clock::now() _NOEXCEPT
55227825Stheraven{
56314564Sdim#if defined(_LIBCPP_WIN32API)
57314564Sdim  // FILETIME is in 100ns units
58314564Sdim  using filetime_duration =
59314564Sdim      _VSTD::chrono::duration<__int64,
60314564Sdim                              _VSTD::ratio_multiply<_VSTD::ratio<100, 1>,
61314564Sdim                                                    nanoseconds::period>>;
62314564Sdim
63314564Sdim  // The Windows epoch is Jan 1 1601, the Unix epoch Jan 1 1970.
64314564Sdim  static _LIBCPP_CONSTEXPR const seconds nt_to_unix_epoch{11644473600};
65314564Sdim
66314564Sdim  FILETIME ft;
67314564Sdim#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
68314564Sdim#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
69314564Sdim  GetSystemTimePreciseAsFileTime(&ft);
70314564Sdim#else
71314564Sdim  GetSystemTimeAsFileTime(&ft);
72314564Sdim#endif
73314564Sdim#else
74314564Sdim  GetSystemTimeAsFileTime(&ft);
75314564Sdim#endif
76314564Sdim
77314564Sdim  filetime_duration d{(static_cast<__int64>(ft.dwHighDateTime) << 32) |
78314564Sdim                       static_cast<__int64>(ft.dwLowDateTime)};
79314564Sdim  return time_point(duration_cast<duration>(d - nt_to_unix_epoch));
80314564Sdim#else
81341825Sdim#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
82341825Sdim  struct timespec tp;
83341825Sdim  if (0 != clock_gettime(CLOCK_REALTIME, &tp))
84341825Sdim    __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
85341825Sdim  return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000));
86314564Sdim#else
87227825Stheraven    timeval tv;
88227825Stheraven    gettimeofday(&tv, 0);
89227825Stheraven    return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
90341825Sdim#endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME
91314564Sdim#endif
92227825Stheraven}
93227825Stheraven
94227825Stheraventime_t
95227825Stheravensystem_clock::to_time_t(const time_point& t) _NOEXCEPT
96227825Stheraven{
97227825Stheraven    return time_t(duration_cast<seconds>(t.time_since_epoch()).count());
98227825Stheraven}
99227825Stheraven
100227825Stheravensystem_clock::time_point
101227825Stheravensystem_clock::from_time_t(time_t t) _NOEXCEPT
102227825Stheraven{
103227825Stheraven    return system_clock::time_point(seconds(t));
104227825Stheraven}
105227825Stheraven
106276792Sdim#ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK
107227825Stheraven// steady_clock
108288943Sdim//
109288943Sdim// Warning:  If this is not truly steady, then it is non-conforming.  It is
110288943Sdim//  better for it to not exist and have the rest of libc++ use system_clock
111288943Sdim//  instead.
112227825Stheraven
113246468Stheravenconst bool steady_clock::is_steady;
114246468Stheraven
115314564Sdim#if defined(__APPLE__)
116288943Sdim
117314564Sdim// Darwin libc versions >= 1133 provide ns precision via CLOCK_UPTIME_RAW
118341825Sdim#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)
119288943Sdimsteady_clock::time_point
120288943Sdimsteady_clock::now() _NOEXCEPT
121288943Sdim{
122288943Sdim    struct timespec tp;
123314564Sdim    if (0 != clock_gettime(CLOCK_UPTIME_RAW, &tp))
124314564Sdim        __throw_system_error(errno, "clock_gettime(CLOCK_UPTIME_RAW) failed");
125288943Sdim    return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
126288943Sdim}
127288943Sdim
128314564Sdim#else
129227825Stheraven//   mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
130227825Stheraven//   nanoseconds since the computer booted up.  MachInfo.numer and MachInfo.denom
131227825Stheraven//   are run time constants supplied by the OS.  This clock has no relationship
132227825Stheraven//   to the Gregorian calendar.  It's main use is as a high resolution timer.
133227825Stheraven
134227825Stheraven// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment.  Specialize
135227825Stheraven//   for that case as an optimization.
136227825Stheraven
137227825Stheravenstatic
138227825Stheravensteady_clock::rep
139227825Stheravensteady_simplified()
140227825Stheraven{
141232924Stheraven    return static_cast<steady_clock::rep>(mach_absolute_time());
142227825Stheraven}
143227825Stheraven
144227825Stheravenstatic
145227825Stheravendouble
146227825Stheravencompute_steady_factor()
147227825Stheraven{
148227825Stheraven    mach_timebase_info_data_t MachInfo;
149227825Stheraven    mach_timebase_info(&MachInfo);
150227825Stheraven    return static_cast<double>(MachInfo.numer) / MachInfo.denom;
151227825Stheraven}
152227825Stheraven
153227825Stheravenstatic
154227825Stheravensteady_clock::rep
155227825Stheravensteady_full()
156227825Stheraven{
157227825Stheraven    static const double factor = compute_steady_factor();
158227825Stheraven    return static_cast<steady_clock::rep>(mach_absolute_time() * factor);
159227825Stheraven}
160227825Stheraven
161227825Stheraventypedef steady_clock::rep (*FP)();
162227825Stheraven
163227825Stheravenstatic
164227825StheravenFP
165227825Stheraveninit_steady_clock()
166227825Stheraven{
167227825Stheraven    mach_timebase_info_data_t MachInfo;
168227825Stheraven    mach_timebase_info(&MachInfo);
169227825Stheraven    if (MachInfo.numer == MachInfo.denom)
170227825Stheraven        return &steady_simplified;
171227825Stheraven    return &steady_full;
172227825Stheraven}
173227825Stheraven
174227825Stheravensteady_clock::time_point
175227825Stheravensteady_clock::now() _NOEXCEPT
176227825Stheraven{
177227825Stheraven    static FP fp = init_steady_clock();
178227825Stheraven    return time_point(duration(fp()));
179227825Stheraven}
180341825Sdim#endif // defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_UPTIME_RAW)
181227825Stheraven
182314564Sdim#elif defined(_LIBCPP_WIN32API)
183314564Sdim
184353358Sdim// https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx says:
185353358Sdim//    If the function fails, the return value is zero. <snip>
186360784Sdim//    On systems that run Windows XP or later, the function will always succeed
187353358Sdim//      and will thus never return zero.
188353358Sdim
189353358Sdimstatic LARGE_INTEGER
190353358Sdim__QueryPerformanceFrequency()
191353358Sdim{
192353358Sdim	LARGE_INTEGER val;
193353358Sdim	(void) QueryPerformanceFrequency(&val);
194353358Sdim	return val;
195353358Sdim}
196353358Sdim
197314564Sdimsteady_clock::time_point
198314564Sdimsteady_clock::now() _NOEXCEPT
199314564Sdim{
200353358Sdim  static const LARGE_INTEGER freq = __QueryPerformanceFrequency();
201314564Sdim
202314564Sdim  LARGE_INTEGER counter;
203353358Sdim  (void) QueryPerformanceCounter(&counter);
204314564Sdim  return time_point(duration(counter.QuadPart * nano::den / freq.QuadPart));
205314564Sdim}
206314564Sdim
207314564Sdim#elif defined(CLOCK_MONOTONIC)
208314564Sdim
209314564Sdim// On Apple platforms only CLOCK_UPTIME_RAW or mach_absolute_time are able to
210314564Sdim// time functions in the nanosecond range. Thus, they are the only acceptable
211314564Sdim// implementations of steady_clock.
212314564Sdim#ifdef __APPLE__
213314564Sdim#error "Never use CLOCK_MONOTONIC for steady_clock::now on Apple platforms"
214314564Sdim#endif
215314564Sdim
216314564Sdimsteady_clock::time_point
217314564Sdimsteady_clock::now() _NOEXCEPT
218314564Sdim{
219314564Sdim    struct timespec tp;
220314564Sdim    if (0 != clock_gettime(CLOCK_MONOTONIC, &tp))
221314564Sdim        __throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed");
222314564Sdim    return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
223314564Sdim}
224314564Sdim
225288943Sdim#else
226288943Sdim#error "Monotonic clock not implemented"
227288943Sdim#endif
228227825Stheraven
229276792Sdim#endif // !_LIBCPP_HAS_NO_MONOTONIC_CLOCK
230276792Sdim
231227825Stheraven}
232227825Stheraven
233227825Stheraven_LIBCPP_END_NAMESPACE_STD
234