Commit c7da6db3 authored by Kevin McNee's avatar Kevin McNee Committed by Commit Bot

Revert "//base/time cleanups:"

This reverts commit 5de0588a.

Reason for revert: A few time related unit tests started flaking on win-asan, starting from the build containing this CL (13964). Suspecting this CL to be the culprit.

https://ci.chromium.org/p/chromium/builders/ci/win-asan
https://ci.chromium.org/p/chromium/builders/ci/win-asan/13964

e.g.
[ RUN      ] ElapsedThreadTimerTest.Simple
../../base/timer/elapsed_timer_unittest.cc(72): error: Expected: (timer.Elapsed()) >= (kLoopingTime), actual: 0.000988 s vs 0.001 s
Stack trace:
Backtrace:
	base::ElapsedThreadTimerTest_Simple_Test::TestBody [0x00007FF7C6A735B1+1351] (C:\b\s\w\ir\cache\builder\src\base\timer\elapsed_timer_unittest.cc:72)

[  FAILED  ] ElapsedThreadTimerTest.Simple (289 ms)

Original change's description:
> //base/time cleanups:
> 
> * Make more things constexpr and/or make it possible to do so later
> * Inline SaturatedAdd/Sub(), FromDouble(), FromProduct()
> * Order the FromUnits{,D}() pairs together
> * Init members in declaration
> * Briefer implementations of various functions
> * IWYU
> * Fix declared-but-not-defined issue for FromTimeSpec() w/OS_FUSCHIA
> * Use more specific DCHECKs
> * No else after return
> * Omit needless qualifiers
> * EXPECT -> static_assert where possible
> * <atomic> is legal now
> * Don't handle DCHECK failure
> 
> The inlines don't hurt size: this saves 4 KB off chrome.dll in my local
> release build.
> 
> Bug: none
> TBR: stevenjb@chromium.org
> Change-Id: I269d6426ac1587569e7a4c785250a4dd5e95d5bf
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2358997
> Reviewed-by: Peter Kasting <pkasting@chromium.org>
> Reviewed-by: Yuri Wiitala <miu@chromium.org>
> Reviewed-by: Tom Sepez <tsepez@chromium.org>
> Commit-Queue: Peter Kasting <pkasting@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#799459}

TBR=stevenjb@chromium.org,pkasting@chromium.org,miu@chromium.org,tsepez@chromium.org,khegde@chromium.org

Change-Id: Ic855d54ae010859b82c55848fb14d8af2cb778d1
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: none
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2364062Reviewed-by: default avatarKevin McNee <mcnee@chromium.org>
Commit-Queue: Kevin McNee <mcnee@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799731}
parent 9bf028be
...@@ -30,7 +30,7 @@ namespace internal { ...@@ -30,7 +30,7 @@ namespace internal {
#if !BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS #if !BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS
template <typename Dst, typename Src> template <typename Dst, typename Src>
struct SaturateFastAsmOp { struct SaturateFastAsmOp {
static constexpr bool is_supported = false; static const bool is_supported = false;
static constexpr Dst Do(Src) { static constexpr Dst Do(Src) {
// Force a compile failure if instantiated. // Force a compile failure if instantiated.
return CheckOnFailure::template HandleFailure<Dst>(); return CheckOnFailure::template HandleFailure<Dst>();
...@@ -43,7 +43,7 @@ struct SaturateFastAsmOp { ...@@ -43,7 +43,7 @@ struct SaturateFastAsmOp {
// eke out better performance than range checking. // eke out better performance than range checking.
template <typename Dst, typename Src, typename Enable = void> template <typename Dst, typename Src, typename Enable = void>
struct IsValueInRangeFastOp { struct IsValueInRangeFastOp {
static constexpr bool is_supported = false; static const bool is_supported = false;
static constexpr bool Do(Src value) { static constexpr bool Do(Src value) {
// Force a compile failure if instantiated. // Force a compile failure if instantiated.
return CheckOnFailure::template HandleFailure<bool>(); return CheckOnFailure::template HandleFailure<bool>();
...@@ -59,7 +59,7 @@ struct IsValueInRangeFastOp< ...@@ -59,7 +59,7 @@ struct IsValueInRangeFastOp<
std::is_integral<Dst>::value && std::is_integral<Src>::value && std::is_integral<Dst>::value && std::is_integral<Src>::value &&
std::is_signed<Dst>::value && std::is_signed<Src>::value && std::is_signed<Dst>::value && std::is_signed<Src>::value &&
!IsTypeInRangeForNumericType<Dst, Src>::value>::type> { !IsTypeInRangeForNumericType<Dst, Src>::value>::type> {
static constexpr bool is_supported = true; static const bool is_supported = true;
static constexpr bool Do(Src value) { static constexpr bool Do(Src value) {
// Just downcast to the smaller type, sign extend it back to the original // Just downcast to the smaller type, sign extend it back to the original
...@@ -77,7 +77,7 @@ struct IsValueInRangeFastOp< ...@@ -77,7 +77,7 @@ struct IsValueInRangeFastOp<
std::is_integral<Dst>::value && std::is_integral<Src>::value && std::is_integral<Dst>::value && std::is_integral<Src>::value &&
!std::is_signed<Dst>::value && std::is_signed<Src>::value && !std::is_signed<Dst>::value && std::is_signed<Src>::value &&
!IsTypeInRangeForNumericType<Dst, Src>::value>::type> { !IsTypeInRangeForNumericType<Dst, Src>::value>::type> {
static constexpr bool is_supported = true; static const bool is_supported = true;
static constexpr bool Do(Src value) { static constexpr bool Do(Src value) {
// We cast a signed as unsigned to overflow negative values to the top, // We cast a signed as unsigned to overflow negative values to the top,
...@@ -156,7 +156,7 @@ constexpr Dst saturated_cast_impl(Src value, RangeCheck constraint) { ...@@ -156,7 +156,7 @@ constexpr Dst saturated_cast_impl(Src value, RangeCheck constraint) {
// Arm, we can use the optimized saturation instructions. // Arm, we can use the optimized saturation instructions.
template <typename Dst, typename Src, typename Enable = void> template <typename Dst, typename Src, typename Enable = void>
struct SaturateFastOp { struct SaturateFastOp {
static constexpr bool is_supported = false; static const bool is_supported = false;
static constexpr Dst Do(Src value) { static constexpr Dst Do(Src value) {
// Force a compile failure if instantiated. // Force a compile failure if instantiated.
return CheckOnFailure::template HandleFailure<Dst>(); return CheckOnFailure::template HandleFailure<Dst>();
...@@ -170,7 +170,7 @@ struct SaturateFastOp< ...@@ -170,7 +170,7 @@ struct SaturateFastOp<
typename std::enable_if<std::is_integral<Src>::value && typename std::enable_if<std::is_integral<Src>::value &&
std::is_integral<Dst>::value && std::is_integral<Dst>::value &&
SaturateFastAsmOp<Dst, Src>::is_supported>::type> { SaturateFastAsmOp<Dst, Src>::is_supported>::type> {
static constexpr bool is_supported = true; static const bool is_supported = true;
static constexpr Dst Do(Src value) { return SaturateFastAsmOp<Dst, Src>::Do(value); } static constexpr Dst Do(Src value) { return SaturateFastAsmOp<Dst, Src>::Do(value); }
}; };
...@@ -181,12 +181,12 @@ struct SaturateFastOp< ...@@ -181,12 +181,12 @@ struct SaturateFastOp<
typename std::enable_if<std::is_integral<Src>::value && typename std::enable_if<std::is_integral<Src>::value &&
std::is_integral<Dst>::value && std::is_integral<Dst>::value &&
!SaturateFastAsmOp<Dst, Src>::is_supported>::type> { !SaturateFastAsmOp<Dst, Src>::is_supported>::type> {
static constexpr bool is_supported = true; static const bool is_supported = true;
static constexpr Dst Do(Src value) { static constexpr Dst Do(Src value) {
// The exact order of the following is structured to hit the correct // The exact order of the following is structured to hit the correct
// optimization heuristics across compilers. Do not change without // optimization heuristics across compilers. Do not change without
// checking the emitted code. // checking the emitted code.
const Dst saturated = CommonMaxOrMin<Dst, Src>( Dst saturated = CommonMaxOrMin<Dst, Src>(
IsMaxInRangeForNumericType<Dst, Src>() || IsMaxInRangeForNumericType<Dst, Src>() ||
(!IsMinInRangeForNumericType<Dst, Src>() && IsValueNegative(value))); (!IsMinInRangeForNumericType<Dst, Src>() && IsValueNegative(value)));
return BASE_NUMERICS_LIKELY(IsValueInRangeForNumericType<Dst>(value)) return BASE_NUMERICS_LIKELY(IsValueInRangeForNumericType<Dst>(value))
...@@ -241,7 +241,7 @@ constexpr Dst strict_cast(Src value) { ...@@ -241,7 +241,7 @@ constexpr Dst strict_cast(Src value) {
// Some wrappers to statically check that a type is in range. // Some wrappers to statically check that a type is in range.
template <typename Dst, typename Src, class Enable = void> template <typename Dst, typename Src, class Enable = void>
struct IsNumericRangeContained { struct IsNumericRangeContained {
static constexpr bool value = false; static const bool value = false;
}; };
template <typename Dst, typename Src> template <typename Dst, typename Src>
...@@ -250,9 +250,8 @@ struct IsNumericRangeContained< ...@@ -250,9 +250,8 @@ struct IsNumericRangeContained<
Src, Src,
typename std::enable_if<ArithmeticOrUnderlyingEnum<Dst>::value && typename std::enable_if<ArithmeticOrUnderlyingEnum<Dst>::value &&
ArithmeticOrUnderlyingEnum<Src>::value>::type> { ArithmeticOrUnderlyingEnum<Src>::value>::type> {
static constexpr bool value = static const bool value = StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
StaticDstRangeRelationToSrcRange<Dst, Src>::value == NUMERIC_RANGE_CONTAINED;
NUMERIC_RANGE_CONTAINED;
}; };
// StrictNumeric implements compile time range checking between numeric types by // StrictNumeric implements compile time range checking between numeric types by
......
This diff is collapsed.
This diff is collapsed.
...@@ -33,7 +33,7 @@ Time TimeNowFromSystemTimeIgnoringOverride() { ...@@ -33,7 +33,7 @@ Time TimeNowFromSystemTimeIgnoringOverride() {
namespace subtle { namespace subtle {
TimeTicks TimeTicksNowIgnoringOverride() { TimeTicks TimeTicksNowIgnoringOverride() {
const zx_time_t nanos_since_boot = zx_clock_get_monotonic(); const zx_time_t nanos_since_boot = zx_clock_get_monotonic();
CHECK_NE(0, nanos_since_boot); CHECK(nanos_since_boot != 0);
return TimeTicks::FromZxTime(nanos_since_boot); return TimeTicks::FromZxTime(nanos_since_boot);
} }
} // namespace subtle } // namespace subtle
...@@ -49,11 +49,11 @@ zx_duration_t TimeDelta::ToZxDuration() const { ...@@ -49,11 +49,11 @@ zx_duration_t TimeDelta::ToZxDuration() const {
// static // static
Time Time::FromZxTime(zx_time_t nanos_since_unix_epoch) { Time Time::FromZxTime(zx_time_t nanos_since_unix_epoch) {
return UnixEpoch() + TimeDelta::FromNanoseconds(nanos_since_unix_epoch); return Time::UnixEpoch() + TimeDelta::FromNanoseconds(nanos_since_unix_epoch);
} }
zx_time_t Time::ToZxTime() const { zx_time_t Time::ToZxTime() const {
return (*this - UnixEpoch()).InNanoseconds(); return (*this - Time::UnixEpoch()).InNanoseconds();
} }
// static // static
......
...@@ -156,10 +156,11 @@ Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) { ...@@ -156,10 +156,11 @@ Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
"CFAbsoluteTime must have an infinity value"); "CFAbsoluteTime must have an infinity value");
if (t == 0) if (t == 0)
return Time(); // Consider 0 as a null Time. return Time(); // Consider 0 as a null Time.
return (t == std::numeric_limits<CFAbsoluteTime>::infinity()) if (t == std::numeric_limits<CFAbsoluteTime>::infinity())
? Max() return Max();
: (UnixEpoch() + TimeDelta::FromSecondsD(double{ return Time(static_cast<int64_t>((t + kCFAbsoluteTimeIntervalSince1970) *
t + kCFAbsoluteTimeIntervalSince1970})); kMicrosecondsPerSecond) +
kTimeTToMicrosecondsOffset);
} }
CFAbsoluteTime Time::ToCFAbsoluteTime() const { CFAbsoluteTime Time::ToCFAbsoluteTime() const {
...@@ -167,9 +168,11 @@ CFAbsoluteTime Time::ToCFAbsoluteTime() const { ...@@ -167,9 +168,11 @@ CFAbsoluteTime Time::ToCFAbsoluteTime() const {
"CFAbsoluteTime must have an infinity value"); "CFAbsoluteTime must have an infinity value");
if (is_null()) if (is_null())
return 0; // Consider 0 as a null Time. return 0; // Consider 0 as a null Time.
return is_max() ? std::numeric_limits<CFAbsoluteTime>::infinity() if (is_max())
: (CFAbsoluteTime{(*this - UnixEpoch()).InSecondsF()} - return std::numeric_limits<CFAbsoluteTime>::infinity();
kCFAbsoluteTimeIntervalSince1970); return (static_cast<CFAbsoluteTime>(us_ - kTimeTToMicrosecondsOffset) /
kMicrosecondsPerSecond) -
kCFAbsoluteTimeIntervalSince1970;
} }
// TimeDelta ------------------------------------------------------------------ // TimeDelta ------------------------------------------------------------------
......
...@@ -1385,8 +1385,8 @@ TEST(TimeDelta, FromAndIn) { ...@@ -1385,8 +1385,8 @@ TEST(TimeDelta, FromAndIn) {
TimeDelta::FromMillisecondsD(2.5) == TimeDelta::FromMicroseconds(2500), TimeDelta::FromMillisecondsD(2.5) == TimeDelta::FromMicroseconds(2500),
""); "");
EXPECT_EQ(TimeDelta::FromDays(13).InDays(), 13); EXPECT_EQ(TimeDelta::FromDays(13).InDays(), 13);
static_assert(TimeDelta::FromHours(13).InHours() == 13, ""); EXPECT_EQ(TimeDelta::FromHours(13).InHours(), 13);
static_assert(TimeDelta::FromMinutes(13).InMinutes() == 13, ""); EXPECT_EQ(TimeDelta::FromMinutes(13).InMinutes(), 13);
EXPECT_EQ(TimeDelta::FromSeconds(13).InSeconds(), 13); EXPECT_EQ(TimeDelta::FromSeconds(13).InSeconds(), 13);
EXPECT_EQ(TimeDelta::FromSeconds(13).InSecondsF(), 13.0); EXPECT_EQ(TimeDelta::FromSeconds(13).InSecondsF(), 13.0);
EXPECT_EQ(TimeDelta::FromMilliseconds(13).InMilliseconds(), 13); EXPECT_EQ(TimeDelta::FromMilliseconds(13).InMilliseconds(), 13);
...@@ -1395,21 +1395,20 @@ TEST(TimeDelta, FromAndIn) { ...@@ -1395,21 +1395,20 @@ TEST(TimeDelta, FromAndIn) {
EXPECT_EQ(TimeDelta::FromSecondsD(13.1).InSecondsF(), 13.1); EXPECT_EQ(TimeDelta::FromSecondsD(13.1).InSecondsF(), 13.1);
EXPECT_EQ(TimeDelta::FromMillisecondsD(13.3).InMilliseconds(), 13); EXPECT_EQ(TimeDelta::FromMillisecondsD(13.3).InMilliseconds(), 13);
EXPECT_EQ(TimeDelta::FromMillisecondsD(13.3).InMillisecondsF(), 13.3); EXPECT_EQ(TimeDelta::FromMillisecondsD(13.3).InMillisecondsF(), 13.3);
static_assert(TimeDelta::FromMicroseconds(13).InMicroseconds() == 13, ""); EXPECT_EQ(TimeDelta::FromMicroseconds(13).InMicroseconds(), 13);
static_assert(TimeDelta::FromMicrosecondsD(13.3).InMicroseconds() == 13, ""); EXPECT_EQ(TimeDelta::FromMicrosecondsD(13.3).InMicroseconds(), 13);
EXPECT_EQ(TimeDelta::FromMillisecondsD(3.45678).InMillisecondsF(), 3.456); EXPECT_EQ(TimeDelta::FromMillisecondsD(3.45678).InMillisecondsF(), 3.456);
static_assert(TimeDelta::FromNanoseconds(12345).InNanoseconds() == 12000, ""); EXPECT_EQ(TimeDelta::FromNanoseconds(12345).InNanoseconds(), 12000);
static_assert(TimeDelta::FromNanosecondsD(12345.678).InNanoseconds() == 12000, EXPECT_EQ(TimeDelta::FromNanosecondsD(12345.678).InNanoseconds(), 12000);
"");
} }
TEST(TimeDelta, InRoundsTowardsZero) { TEST(TimeDelta, InRoundsTowardsZero) {
EXPECT_EQ(TimeDelta::FromHours(23).InDays(), 0); EXPECT_EQ(TimeDelta::FromHours(23).InDays(), 0);
EXPECT_EQ(TimeDelta::FromHours(-23).InDays(), 0); EXPECT_EQ(TimeDelta::FromHours(-23).InDays(), 0);
static_assert(TimeDelta::FromMinutes(59).InHours() == 0, ""); EXPECT_EQ(TimeDelta::FromMinutes(59).InHours(), 0);
static_assert(TimeDelta::FromMinutes(-59).InHours() == 0, ""); EXPECT_EQ(TimeDelta::FromMinutes(-59).InHours(), 0);
static_assert(TimeDelta::FromSeconds(59).InMinutes() == 0, ""); EXPECT_EQ(TimeDelta::FromSeconds(59).InMinutes(), 0);
static_assert(TimeDelta::FromSeconds(-59).InMinutes() == 0, ""); EXPECT_EQ(TimeDelta::FromSeconds(-59).InMinutes(), 0);
EXPECT_EQ(TimeDelta::FromMilliseconds(999).InSeconds(), 0); EXPECT_EQ(TimeDelta::FromMilliseconds(999).InSeconds(), 0);
EXPECT_EQ(TimeDelta::FromMilliseconds(-999).InSeconds(), 0); EXPECT_EQ(TimeDelta::FromMilliseconds(-999).InSeconds(), 0);
EXPECT_EQ(TimeDelta::FromMicroseconds(999).InMilliseconds(), 0); EXPECT_EQ(TimeDelta::FromMicroseconds(999).InMilliseconds(), 0);
...@@ -1603,8 +1602,8 @@ TEST(TimeDelta, MaxConversions) { ...@@ -1603,8 +1602,8 @@ TEST(TimeDelta, MaxConversions) {
static_assert(kMax.ToInternalValue() == std::numeric_limits<int64_t>::max(), static_assert(kMax.ToInternalValue() == std::numeric_limits<int64_t>::max(),
""); "");
EXPECT_EQ(kMax.InDays(), std::numeric_limits<int>::max()); EXPECT_EQ(kMax.InDays(), std::numeric_limits<int>::max());
static_assert(kMax.InHours() == std::numeric_limits<int>::max(), ""); EXPECT_EQ(kMax.InHours(), std::numeric_limits<int>::max());
static_assert(kMax.InMinutes() == std::numeric_limits<int>::max(), ""); EXPECT_EQ(kMax.InMinutes(), std::numeric_limits<int>::max());
EXPECT_EQ(kMax.InSecondsF(), std::numeric_limits<double>::infinity()); EXPECT_EQ(kMax.InSecondsF(), std::numeric_limits<double>::infinity());
EXPECT_EQ(kMax.InSeconds(), std::numeric_limits<int64_t>::max()); EXPECT_EQ(kMax.InSeconds(), std::numeric_limits<int64_t>::max());
EXPECT_EQ(kMax.InMillisecondsF(), std::numeric_limits<double>::infinity()); EXPECT_EQ(kMax.InMillisecondsF(), std::numeric_limits<double>::infinity());
...@@ -1694,8 +1693,8 @@ TEST(TimeDelta, MinConversions) { ...@@ -1694,8 +1693,8 @@ TEST(TimeDelta, MinConversions) {
constexpr TimeDelta kMin = TimeDelta::Min(); constexpr TimeDelta kMin = TimeDelta::Min();
EXPECT_EQ(kMin.InDays(), std::numeric_limits<int>::min()); EXPECT_EQ(kMin.InDays(), std::numeric_limits<int>::min());
static_assert(kMin.InHours() == std::numeric_limits<int>::min(), ""); EXPECT_EQ(kMin.InHours(), std::numeric_limits<int>::min());
static_assert(kMin.InMinutes() == std::numeric_limits<int>::min(), ""); EXPECT_EQ(kMin.InMinutes(), std::numeric_limits<int>::min());
EXPECT_EQ(kMin.InSecondsF(), -std::numeric_limits<double>::infinity()); EXPECT_EQ(kMin.InSecondsF(), -std::numeric_limits<double>::infinity());
EXPECT_EQ(kMin.InSeconds(), std::numeric_limits<int64_t>::min()); EXPECT_EQ(kMin.InSeconds(), std::numeric_limits<int64_t>::min());
EXPECT_EQ(kMin.InMillisecondsF(), -std::numeric_limits<double>::infinity()); EXPECT_EQ(kMin.InMillisecondsF(), -std::numeric_limits<double>::infinity());
......
...@@ -38,8 +38,6 @@ ...@@ -38,8 +38,6 @@
#include <mmsystem.h> #include <mmsystem.h>
#include <stdint.h> #include <stdint.h>
#include <atomic>
#include "base/atomicops.h" #include "base/atomicops.h"
#include "base/bit_cast.h" #include "base/bit_cast.h"
#include "base/check_op.h" #include "base/check_op.h"
...@@ -343,8 +341,13 @@ bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) { ...@@ -343,8 +341,13 @@ bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) {
success = !!SystemTimeToFileTime(&st, &ft); success = !!SystemTimeToFileTime(&st, &ft);
} }
*time = Time(success ? FileTimeToMicroseconds(ft) : 0); if (!success) {
return success; *time = Time(0);
return false;
}
*time = Time(FileTimeToMicroseconds(ft));
return true;
} }
void Time::Explode(bool is_local, Exploded* exploded) const { void Time::Explode(bool is_local, Exploded* exploded) const {
...@@ -375,6 +378,7 @@ void Time::Explode(bool is_local, Exploded* exploded) const { ...@@ -375,6 +378,7 @@ void Time::Explode(bool is_local, Exploded* exploded) const {
} }
if (!success) { if (!success) {
NOTREACHED() << "Unable to convert time, don't know why";
ZeroMemory(exploded, sizeof(*exploded)); ZeroMemory(exploded, sizeof(*exploded));
return; return;
} }
...@@ -511,10 +515,15 @@ TimeTicksNowFunction g_time_ticks_now_ignoring_override_function = ...@@ -511,10 +515,15 @@ TimeTicksNowFunction g_time_ticks_now_ignoring_override_function =
&InitialNowFunction; &InitialNowFunction;
int64_t g_qpc_ticks_per_second = 0; int64_t g_qpc_ticks_per_second = 0;
// As of January 2015, use of <atomic> is forbidden in Chromium code. This is
// what std::atomic_thread_fence does on Windows on all Intel architectures when
// the memory_order argument is anything but std::memory_order_seq_cst:
#define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier();
TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) { TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) {
// Ensure that the assignment to |g_qpc_ticks_per_second|, made in // Ensure that the assignment to |g_qpc_ticks_per_second|, made in
// InitializeNowFunctionPointer(), has happened by this point. // InitializeNowFunctionPointer(), has happened by this point.
std::atomic_thread_fence(std::memory_order_acquire); ATOMIC_THREAD_FENCE(memory_order_acquire);
DCHECK_GT(g_qpc_ticks_per_second, 0); DCHECK_GT(g_qpc_ticks_per_second, 0);
...@@ -553,11 +562,13 @@ void InitializeNowFunctionPointer() { ...@@ -553,11 +562,13 @@ void InitializeNowFunctionPointer() {
// //
// Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015, // Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015,
// ~72% of users fall within this category. // ~72% of users fall within this category.
TimeTicksNowFunction now_function;
CPU cpu; CPU cpu;
const TimeTicksNowFunction now_function = if (ticks_per_sec.QuadPart <= 0 || !cpu.has_non_stop_time_stamp_counter()) {
(ticks_per_sec.QuadPart <= 0 || !cpu.has_non_stop_time_stamp_counter()) now_function = &RolloverProtectedNow;
? &RolloverProtectedNow } else {
: &QPCNow; now_function = &QPCNow;
}
// Threading note 1: In an unlikely race condition, it's possible for two or // Threading note 1: In an unlikely race condition, it's possible for two or
// more threads to enter InitializeNowFunctionPointer() in parallel. This is // more threads to enter InitializeNowFunctionPointer() in parallel. This is
...@@ -569,7 +580,7 @@ void InitializeNowFunctionPointer() { ...@@ -569,7 +580,7 @@ void InitializeNowFunctionPointer() {
// assignment to |g_qpc_ticks_per_second| happens before the function pointers // assignment to |g_qpc_ticks_per_second| happens before the function pointers
// are changed. // are changed.
g_qpc_ticks_per_second = ticks_per_sec.QuadPart; g_qpc_ticks_per_second = ticks_per_sec.QuadPart;
std::atomic_thread_fence(std::memory_order_release); ATOMIC_THREAD_FENCE(memory_order_release);
// Also set g_time_ticks_now_function to avoid the additional indirection via // Also set g_time_ticks_now_function to avoid the additional indirection via
// TimeTicksNowIgnoringOverride() for future calls to TimeTicks::Now(). But // TimeTicksNowIgnoringOverride() for future calls to TimeTicks::Now(). But
// g_time_ticks_now_function may have already be overridden. // g_time_ticks_now_function may have already be overridden.
...@@ -631,8 +642,8 @@ bool TimeTicks::IsConsistentAcrossProcesses() { ...@@ -631,8 +642,8 @@ bool TimeTicks::IsConsistentAcrossProcesses() {
// static // static
TimeTicks::Clock TimeTicks::GetClock() { TimeTicks::Clock TimeTicks::GetClock() {
return IsHighResolution() ? Clock::WIN_QPC return IsHighResolution() ?
: Clock::WIN_ROLLOVER_PROTECTED_TIME_GET_TIME; Clock::WIN_QPC : Clock::WIN_ROLLOVER_PROTECTED_TIME_GET_TIME;
} }
// ThreadTicks ---------------------------------------------------------------- // ThreadTicks ----------------------------------------------------------------
...@@ -659,24 +670,23 @@ ThreadTicks ThreadTicks::GetForThread( ...@@ -659,24 +670,23 @@ ThreadTicks ThreadTicks::GetForThread(
::GetThreadTimes(thread_handle.platform_handle(), &creation_time, &exit_time, ::GetThreadTimes(thread_handle.platform_handle(), &creation_time, &exit_time,
&kernel_time, &user_time); &kernel_time, &user_time);
const int64_t us = FileTimeToMicroseconds(user_time); int64_t us = FileTimeToMicroseconds(user_time);
return ThreadTicks(us);
#else #else
// Get the number of TSC ticks used by the current thread. // Get the number of TSC ticks used by the current thread.
ULONG64 thread_cycle_time = 0; ULONG64 thread_cycle_time = 0;
::QueryThreadCycleTime(thread_handle.platform_handle(), &thread_cycle_time); ::QueryThreadCycleTime(thread_handle.platform_handle(), &thread_cycle_time);
// Get the frequency of the TSC. // Get the frequency of the TSC.
const double tsc_ticks_per_second = TSCTicksPerSecond(); double tsc_ticks_per_second = TSCTicksPerSecond();
if (tsc_ticks_per_second == 0) if (tsc_ticks_per_second == 0)
return ThreadTicks(); return ThreadTicks();
// Return the CPU time of the current thread. // Return the CPU time of the current thread.
const double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second; double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second;
const int64_t us = return ThreadTicks(
static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond); static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond));
#endif #endif
return ThreadTicks(us);
} }
// static // static
...@@ -707,7 +717,7 @@ double ThreadTicks::TSCTicksPerSecond() { ...@@ -707,7 +717,7 @@ double ThreadTicks::TSCTicksPerSecond() {
// Increase the thread priority to reduces the chances of having a context // Increase the thread priority to reduces the chances of having a context
// switch during a reading of the TSC and the performance counter. // switch during a reading of the TSC and the performance counter.
const int previous_priority = ::GetThreadPriority(::GetCurrentThread()); int previous_priority = ::GetThreadPriority(::GetCurrentThread());
::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST); ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
// The first time that this function is called, make an initial reading of the // The first time that this function is called, make an initial reading of the
...@@ -718,8 +728,8 @@ double ThreadTicks::TSCTicksPerSecond() { ...@@ -718,8 +728,8 @@ double ThreadTicks::TSCTicksPerSecond() {
// Make a another reading of the TSC and the performance counter every time // Make a another reading of the TSC and the performance counter every time
// that this function is called. // that this function is called.
const uint64_t tsc_now = __rdtsc(); uint64_t tsc_now = __rdtsc();
const uint64_t perf_counter_now = QPCNowRaw(); uint64_t perf_counter_now = QPCNowRaw();
// Reset the thread priority. // Reset the thread priority.
::SetThreadPriority(::GetCurrentThread(), previous_priority); ::SetThreadPriority(::GetCurrentThread(), previous_priority);
...@@ -736,18 +746,20 @@ double ThreadTicks::TSCTicksPerSecond() { ...@@ -736,18 +746,20 @@ double ThreadTicks::TSCTicksPerSecond() {
LARGE_INTEGER perf_counter_frequency = {}; LARGE_INTEGER perf_counter_frequency = {};
::QueryPerformanceFrequency(&perf_counter_frequency); ::QueryPerformanceFrequency(&perf_counter_frequency);
DCHECK_GE(perf_counter_now, perf_counter_initial); DCHECK_GE(perf_counter_now, perf_counter_initial);
const uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial; uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
const double elapsed_time_seconds = double elapsed_time_seconds =
perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart); perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart);
constexpr double kMinimumEvaluationPeriodSeconds = 0.05; static constexpr double kMinimumEvaluationPeriodSeconds = 0.05;
if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds) if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
return 0; return 0;
// Compute the frequency of the TSC. // Compute the frequency of the TSC.
DCHECK_GE(tsc_now, tsc_initial); DCHECK_GE(tsc_now, tsc_initial);
const uint64_t tsc_ticks = tsc_now - tsc_initial; uint64_t tsc_ticks = tsc_now - tsc_initial;
return tsc_ticks / elapsed_time_seconds; tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds;
return tsc_ticks_per_second;
} }
#endif // defined(ARCH_CPU_ARM64) #endif // defined(ARCH_CPU_ARM64)
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <stdint.h> #include <stdint.h>
#include <windows.foundation.h> #include <windows.foundation.h>
#include <algorithm>
#include <cmath> #include <cmath>
#include <limits> #include <limits>
#include <vector> #include <vector>
...@@ -152,19 +151,23 @@ TEST(TimeTicks, SubMillisecondTimers) { ...@@ -152,19 +151,23 @@ TEST(TimeTicks, SubMillisecondTimers) {
if (!TimeTicks::IsHighResolution()) if (!TimeTicks::IsHighResolution())
return; return;
const int kRetries = 1000;
bool saw_submillisecond_timer = false;
// Run kRetries attempts to see a sub-millisecond timer. // Run kRetries attempts to see a sub-millisecond timer.
constexpr int kRetries = 1000;
for (int index = 0; index < kRetries; index++) { for (int index = 0; index < kRetries; index++) {
const TimeTicks start_time = TimeTicks::Now(); TimeTicks last_time = TimeTicks::Now();
TimeDelta delta; TimeDelta delta;
// Spin until the clock has detected a change. // Spin until the clock has detected a change.
do { do {
delta = TimeTicks::Now() - start_time; delta = TimeTicks::Now() - last_time;
} while (delta.is_zero()); } while (delta.InMicroseconds() == 0);
if (!delta.InMilliseconds()) if (delta.InMicroseconds() < 1000) {
return; saw_submillisecond_timer = true;
break;
}
} }
ADD_FAILURE() << "Never saw a sub-millisecond timer."; EXPECT_TRUE(saw_submillisecond_timer);
} }
TEST(TimeTicks, TimeGetTimeCaps) { TEST(TimeTicks, TimeGetTimeCaps) {
...@@ -321,7 +324,7 @@ TEST(TimeTicks, FromQPCValue) { ...@@ -321,7 +324,7 @@ TEST(TimeTicks, FromQPCValue) {
ticks_per_second; ticks_per_second;
const TimeTicks converted_value = TimeTicks::FromQPCValue(ticks); const TimeTicks converted_value = TimeTicks::FromQPCValue(ticks);
const double converted_microseconds_since_origin = const double converted_microseconds_since_origin =
(converted_value - TimeTicks()).InMicrosecondsF(); static_cast<double>((converted_value - TimeTicks()).InMicroseconds());
// When we test with very large numbers we end up in a range where adjacent // When we test with very large numbers we end up in a range where adjacent
// double values are far apart - 512.0 apart in one test failure. In that // double values are far apart - 512.0 apart in one test failure. In that
// situation it makes no sense for our epsilon to be 1.0 - it should be // situation it makes no sense for our epsilon to be 1.0 - it should be
...@@ -335,7 +338,9 @@ TEST(TimeTicks, FromQPCValue) { ...@@ -335,7 +338,9 @@ TEST(TimeTicks, FromQPCValue) {
// slightly larger than 1.0, even when the converted value is perfect. This // slightly larger than 1.0, even when the converted value is perfect. This
// epsilon value was chosen because it is slightly larger than the error // epsilon value was chosen because it is slightly larger than the error
// seen in a test failure caused by the double rounding. // seen in a test failure caused by the double rounding.
epsilon = std::max(epsilon, 1.002); const double min_epsilon = 1.002;
if (epsilon < min_epsilon)
epsilon = min_epsilon;
EXPECT_NEAR(expected_microseconds_since_origin, EXPECT_NEAR(expected_microseconds_since_origin,
converted_microseconds_since_origin, epsilon) converted_microseconds_since_origin, epsilon)
<< "ticks=" << ticks << ", to be converted via logic path: " << "ticks=" << ticks << ", to be converted via logic path: "
......
...@@ -31,10 +31,12 @@ const base::TimeDelta kSignificantlyAboveThresholdDelayMs = ...@@ -31,10 +31,12 @@ const base::TimeDelta kSignificantlyAboveThresholdDelayMs =
class FakeTickClock : public base::TickClock { class FakeTickClock : public base::TickClock {
public: public:
FakeTickClock() = default;
// The |dns_resolution_delay| fakes the duration of a DNS resolution. // The |dns_resolution_delay| fakes the duration of a DNS resolution.
explicit FakeTickClock( explicit FakeTickClock(const base::TimeDelta& dns_resolution_delay)
const base::TimeDelta& dns_resolution_delay = base::TimeDelta()) : current_time_(base::TimeTicks::Now()),
: dns_resolution_delay_(dns_resolution_delay) {} dns_resolution_delay_(dns_resolution_delay) {}
~FakeTickClock() override = default; ~FakeTickClock() override = default;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment