Commit 954146a5 authored by Gabriel Charette's avatar Gabriel Charette Committed by Commit Bot

Make TimeTicks::Now() high-resolution whenever possible with low-latency.

It was already always high-resolution on POSIX but was never high
resolution on Windows. Windows does support low latency high-resolution
timers for the majority of our user base.

TimeTicks::HighResolutionNow() was only explicitly requested in testing
frameworks. As such I left the call in place but made it DCHECK that
it's running on a Windows machine on which high-resolution clocks are
used. This confirms that none of our test fleet has regressed with this
change (the previous HighResolutionNow() used to be slightly more
aggressive and also do it in a few configurations where we now fallback
to low-resolution now).

This implementation was copied as-is (modulo minor v8 API
compatibility tweaks). These implementations were the same in the
past but had diverged when, sadly, the same bug was fixed separately
years apart, in Chromium and V8:
chromium: https://codereview.chromium.org/1284053004 + https://codereview.chromium.org/2393953003
v8: https://codereview.chromium.org/1304873011

This is a prerequisite to add metrics around parallel task execution
(low-resolution clocks are useless at that level, but we also don't want
to incur high-latency clocks on machines that can't afford it cheaply).

Bug: chromium:807606
Change-Id: Id18e7be895d8431ebd0e565a1bdf358fe7838489
Reviewed-on: https://chromium-review.googlesource.com/897485Reviewed-by: 's avatarHannes Payer <hpayer@chromium.org>
Commit-Queue: Gabriel Charette <gab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51027}
parent 0320986a
This diff is collapsed.
......@@ -5,6 +5,8 @@
#ifndef V8_BASE_PLATFORM_TIME_H_
#define V8_BASE_PLATFORM_TIME_H_
#include <stdint.h>
#include <ctime>
#include <iosfwd>
#include <limits>
......@@ -177,22 +179,29 @@ namespace time_internal {
template<class TimeClass>
class TimeBase {
public:
static const int64_t kHoursPerDay = 24;
static const int64_t kMillisecondsPerSecond = 1000;
static const int64_t kMillisecondsPerDay =
static constexpr int64_t kHoursPerDay = 24;
static constexpr int64_t kMillisecondsPerSecond = 1000;
static constexpr int64_t kMillisecondsPerDay =
kMillisecondsPerSecond * 60 * 60 * kHoursPerDay;
static const int64_t kMicrosecondsPerMillisecond = 1000;
static const int64_t kMicrosecondsPerSecond =
static constexpr int64_t kMicrosecondsPerMillisecond = 1000;
static constexpr int64_t kMicrosecondsPerSecond =
kMicrosecondsPerMillisecond * kMillisecondsPerSecond;
static const int64_t kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
static const int64_t kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
static const int64_t kMicrosecondsPerDay =
static constexpr int64_t kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
static constexpr int64_t kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
static constexpr int64_t kMicrosecondsPerDay =
kMicrosecondsPerHour * kHoursPerDay;
static const int64_t kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
static const int64_t kNanosecondsPerMicrosecond = 1000;
static const int64_t kNanosecondsPerSecond =
static constexpr int64_t kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
static constexpr int64_t kNanosecondsPerMicrosecond = 1000;
static constexpr int64_t kNanosecondsPerSecond =
kNanosecondsPerMicrosecond * kMicrosecondsPerSecond;
#if V8_OS_WIN
// To avoid overflow in QPC to Microseconds calculations, since we multiply
// by kMicrosecondsPerSecond, then the QPC value should not exceed
// (2^63 - 1) / 1E6. If it exceeds that threshold, we divide then multiply.
static constexpr int64_t kQPCOverflowThreshold = INT64_C(0x8637BD05AF7);
#endif
// Returns true if this object has not been initialized.
//
// Warning: Be careful when writing code that performs math on time values,
......@@ -345,21 +354,20 @@ class V8_BASE_EXPORT TimeTicks final
public:
TimeTicks() : TimeBase(0) {}
// Platform-dependent tick count representing "right now."
// The resolution of this clock is ~1-15ms. Resolution varies depending
// on hardware/operating system configuration.
// Platform-dependent tick count representing "right now." When
// IsHighResolution() returns false, the resolution of the clock could be as
// coarse as ~15.6ms. Otherwise, the resolution should be no worse than one
// microsecond.
// This method never returns a null TimeTicks.
static TimeTicks Now();
// Returns a platform-dependent high-resolution tick count. Implementation
// is hardware dependent and may or may not return sub-millisecond
// resolution. THIS CALL IS GENERALLY MUCH MORE EXPENSIVE THAN Now() AND
// SHOULD ONLY BE USED WHEN IT IS REALLY NEEDED.
// This method never returns a null TimeTicks.
// This is equivalent to Now() but DCHECKs that IsHighResolution(). Useful for
// test frameworks that rely on high resolution clocks (in practice all
// platforms but low-end Windows devices have high resolution clocks).
static TimeTicks HighResolutionNow();
// Returns true if the high-resolution clock is working on this system.
static bool IsHighResolutionClockWorking();
static bool IsHighResolution();
private:
friend class time_internal::TimeBase<TimeTicks>;
......
......@@ -153,21 +153,15 @@ TEST(Time, NowResolution) {
TEST(TimeTicks, NowResolution) {
// We assume that TimeTicks::Now() has at least 16ms resolution.
static const TimeDelta kTargetGranularity = TimeDelta::FromMilliseconds(16);
// TimeTicks::Now() is documented as having "no worse than one microsecond"
// resolution. Unless !TimeTicks::IsHighResolution() in which case the clock
// could be as coarse as ~15.6ms.
const TimeDelta kTargetGranularity = TimeTicks::IsHighResolution()
? TimeDelta::FromMicroseconds(1)
: TimeDelta::FromMilliseconds(16);
ResolutionTest<TimeTicks>(&TimeTicks::Now, kTargetGranularity);
}
TEST(TimeTicks, HighResolutionNowResolution) {
if (!TimeTicks::IsHighResolutionClockWorking()) return;
// We assume that TimeTicks::HighResolutionNow() has sub-ms resolution.
static const TimeDelta kTargetGranularity = TimeDelta::FromMilliseconds(1);
ResolutionTest<TimeTicks>(&TimeTicks::HighResolutionNow, kTargetGranularity);
}
TEST(TimeTicks, IsMonotonic) {
TimeTicks previous_normal_ticks;
TimeTicks previous_highres_ticks;
......
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