Summary: In D27429, we switched the Apple implementation of steady_clock::now() from clock_gettime(CLOCK_MONOTONIC) to clock_gettime(CLOCK_UPTIME_RAW). The purpose was to get nanosecond precision, and also to improve the performance of the implementation. However, it appears that CLOCK_UPTIME_RAW does not satisfy the requirements of the Standard, since it is not strictly speaking monotonic. Indeed, the clock does not increment while the system is asleep, which had been mentioned in D27429 but somehow not addressed. This patch switches to CLOCK_MONOTONIC_RAW, which is monotonic, increased during sleep, and also has nanosecond precision. https://llvm.org/PR44773 Reviewers: bruno, howard.hinnant, EricWF Subscribers: christof, jkorous, dexonsmith, libcxx-commits, mclow.lists, EricWF Tags: #libc Differential Revision: https://reviews.llvm.org/D74341
234 lines
6.6 KiB
C++
234 lines
6.6 KiB
C++
//===------------------------- chrono.cpp ---------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "chrono"
|
|
#include "cerrno" // errno
|
|
#include "system_error" // __throw_system_error
|
|
#include <time.h> // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME
|
|
#include "include/apple_availability.h"
|
|
|
|
#if !defined(__APPLE__)
|
|
#define _LIBCPP_USE_CLOCK_GETTIME
|
|
#endif // __APPLE__
|
|
|
|
#if defined(_LIBCPP_WIN32API)
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#define VC_EXTRA_LEAN
|
|
#include <windows.h>
|
|
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
|
|
#include <winapifamily.h>
|
|
#endif
|
|
#else
|
|
#if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME)
|
|
#include <sys/time.h> // for gettimeofday and timeval
|
|
#endif // !defined(CLOCK_REALTIME)
|
|
#endif // defined(_LIBCPP_WIN32API)
|
|
|
|
#if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
|
|
#if __APPLE__
|
|
#include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t
|
|
#elif !defined(_LIBCPP_WIN32API) && !defined(CLOCK_MONOTONIC)
|
|
#error "Monotonic clock not implemented"
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB)
|
|
#pragma comment(lib, "rt")
|
|
#endif
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
namespace chrono
|
|
{
|
|
|
|
// system_clock
|
|
|
|
const bool system_clock::is_steady;
|
|
|
|
system_clock::time_point
|
|
system_clock::now() _NOEXCEPT
|
|
{
|
|
#if defined(_LIBCPP_WIN32API)
|
|
// FILETIME is in 100ns units
|
|
using filetime_duration =
|
|
_VSTD::chrono::duration<__int64,
|
|
_VSTD::ratio_multiply<_VSTD::ratio<100, 1>,
|
|
nanoseconds::period>>;
|
|
|
|
// The Windows epoch is Jan 1 1601, the Unix epoch Jan 1 1970.
|
|
static _LIBCPP_CONSTEXPR const seconds nt_to_unix_epoch{11644473600};
|
|
|
|
FILETIME ft;
|
|
#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
|
GetSystemTimePreciseAsFileTime(&ft);
|
|
#else
|
|
GetSystemTimeAsFileTime(&ft);
|
|
#endif
|
|
#else
|
|
GetSystemTimeAsFileTime(&ft);
|
|
#endif
|
|
|
|
filetime_duration d{(static_cast<__int64>(ft.dwHighDateTime) << 32) |
|
|
static_cast<__int64>(ft.dwLowDateTime)};
|
|
return time_point(duration_cast<duration>(d - nt_to_unix_epoch));
|
|
#else
|
|
#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
|
|
struct timespec tp;
|
|
if (0 != clock_gettime(CLOCK_REALTIME, &tp))
|
|
__throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
|
|
return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000));
|
|
#else
|
|
timeval tv;
|
|
gettimeofday(&tv, 0);
|
|
return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
|
|
#endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME
|
|
#endif
|
|
}
|
|
|
|
time_t
|
|
system_clock::to_time_t(const time_point& t) _NOEXCEPT
|
|
{
|
|
return time_t(duration_cast<seconds>(t.time_since_epoch()).count());
|
|
}
|
|
|
|
system_clock::time_point
|
|
system_clock::from_time_t(time_t t) _NOEXCEPT
|
|
{
|
|
return system_clock::time_point(seconds(t));
|
|
}
|
|
|
|
#ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK
|
|
// steady_clock
|
|
//
|
|
// Warning: If this is not truly steady, then it is non-conforming. It is
|
|
// better for it to not exist and have the rest of libc++ use system_clock
|
|
// instead.
|
|
|
|
const bool steady_clock::is_steady;
|
|
|
|
#if defined(__APPLE__)
|
|
|
|
// Darwin libc versions >= 1133 provide ns precision via CLOCK_MONOTONIC_RAW
|
|
#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC_RAW)
|
|
steady_clock::time_point
|
|
steady_clock::now() _NOEXCEPT
|
|
{
|
|
struct timespec tp;
|
|
if (0 != clock_gettime(CLOCK_MONOTONIC_RAW, &tp))
|
|
__throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC_RAW) failed");
|
|
return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
|
|
}
|
|
|
|
#else
|
|
// mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
|
|
// nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom
|
|
// are run time constants supplied by the OS. This clock has no relationship
|
|
// to the Gregorian calendar. It's main use is as a high resolution timer.
|
|
|
|
// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize
|
|
// for that case as an optimization.
|
|
|
|
static
|
|
steady_clock::rep
|
|
steady_simplified()
|
|
{
|
|
return static_cast<steady_clock::rep>(mach_absolute_time());
|
|
}
|
|
|
|
static
|
|
double
|
|
compute_steady_factor()
|
|
{
|
|
mach_timebase_info_data_t MachInfo;
|
|
mach_timebase_info(&MachInfo);
|
|
return static_cast<double>(MachInfo.numer) / MachInfo.denom;
|
|
}
|
|
|
|
static
|
|
steady_clock::rep
|
|
steady_full()
|
|
{
|
|
static const double factor = compute_steady_factor();
|
|
return static_cast<steady_clock::rep>(mach_absolute_time() * factor);
|
|
}
|
|
|
|
typedef steady_clock::rep (*FP)();
|
|
|
|
static
|
|
FP
|
|
init_steady_clock()
|
|
{
|
|
mach_timebase_info_data_t MachInfo;
|
|
mach_timebase_info(&MachInfo);
|
|
if (MachInfo.numer == MachInfo.denom)
|
|
return &steady_simplified;
|
|
return &steady_full;
|
|
}
|
|
|
|
steady_clock::time_point
|
|
steady_clock::now() _NOEXCEPT
|
|
{
|
|
static FP fp = init_steady_clock();
|
|
return time_point(duration(fp()));
|
|
}
|
|
#endif // defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC_RAW)
|
|
|
|
#elif defined(_LIBCPP_WIN32API)
|
|
|
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx says:
|
|
// If the function fails, the return value is zero. <snip>
|
|
// On systems that run Windows XP or later, the function will always succeed
|
|
// and will thus never return zero.
|
|
|
|
static LARGE_INTEGER
|
|
__QueryPerformanceFrequency()
|
|
{
|
|
LARGE_INTEGER val;
|
|
(void) QueryPerformanceFrequency(&val);
|
|
return val;
|
|
}
|
|
|
|
steady_clock::time_point
|
|
steady_clock::now() _NOEXCEPT
|
|
{
|
|
static const LARGE_INTEGER freq = __QueryPerformanceFrequency();
|
|
|
|
LARGE_INTEGER counter;
|
|
(void) QueryPerformanceCounter(&counter);
|
|
return time_point(duration(counter.QuadPart * nano::den / freq.QuadPart));
|
|
}
|
|
|
|
#elif defined(CLOCK_MONOTONIC)
|
|
|
|
// On Apple platforms only CLOCK_UPTIME_RAW, CLOCK_MONOTONIC_RAW or
|
|
// mach_absolute_time are able to time functions in the nanosecond range.
|
|
// Thus, they are the only acceptable implementations of steady_clock.
|
|
#ifdef __APPLE__
|
|
#error "Never use CLOCK_MONOTONIC for steady_clock::now on Apple platforms"
|
|
#endif
|
|
|
|
steady_clock::time_point
|
|
steady_clock::now() _NOEXCEPT
|
|
{
|
|
struct timespec tp;
|
|
if (0 != clock_gettime(CLOCK_MONOTONIC, &tp))
|
|
__throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed");
|
|
return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
|
|
}
|
|
|
|
#else
|
|
#error "Monotonic clock not implemented"
|
|
#endif
|
|
|
|
#endif // !_LIBCPP_HAS_NO_MONOTONIC_CLOCK
|
|
|
|
}
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|