Commit 9985a686 authored by Sergio Villar Senin's avatar Sergio Villar Senin Committed by Commit Bot

OnionSoup: Replace WTF::ScopedMockClock by TestMockTimeTaskRunner

As part of removing wtf/time.h we are replacing almost all the usages of
WTF::ScopedMockClock by base::'s TestMockTimeTaskRunner. The remaining
migrations, web_view_test.cc and window_performance_test.cc, will be
done in a followup CL as they require additional changes.

The migrations are all pretty similar. A Clock/TickClock object is added to the
class that is being tested. That class will be internally used to retrieve the
current time/timeticks instead of directly using base/time functions. Production
code will use the DefaultClock/DefaultTickClock which are mostly wrappers to
base::Time::Now() and base::TimeTicks::Now() so there is no change in behaviour
(apart from an extra indirection). Using a clock class has the benefit of
allowing tests to overwrite, by using Set{Clock|TickClock}ForTesting(), that
clock with a mock one they can handle with no changes in the production code.

Note that setting a mock clock sometimes requires additional changes like
recomputing some timestamps that were calculated at object's creation time using
the default (real time) clock.

Last but not least, by using TestMockTimeTaskRunner we are avoiding all the
complications that overwritting the global time functions brings, like the lack
of protection of those global pointers or the inherent disparities of using a
mock and a real clock at the same time.

Bug: 919383
Change-Id: I4f1882643ae817cf68a05f2583a9756f4deff554
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1518518
Commit-Queue: Sergio Villar <svillar@igalia.com>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarJeremy Roman <jbroman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#660347}
parent 2a3edd0b
......@@ -13,6 +13,7 @@ include_rules = [
"+base/strings/stringprintf.h",
"+base/synchronization/waitable_event.h",
"+base/task/sequence_manager/task_time_observer.h",
"+base/time",
"+base/unguessable_token.h",
"+build/mac",
"+build/win",
......@@ -87,6 +88,7 @@ specific_include_rules = {
# Additional allowed includes for tests.
".*_test(_.*)?\.(cc|h)" : [
"+base/message_loop/message_loop.h",
"+base/test/test_mock_time_task_runner.h",
# Test harness may use cc directly instead of going through WebViewImpl etc.
"+cc",
"+components/ukm/test_ukm_recorder.h",
......
......@@ -3,12 +3,14 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/core/display_lock/display_lock_budget.h"
#include "base/time/default_tick_clock.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
namespace blink {
DisplayLockBudget::DisplayLockBudget(DisplayLockContext* context)
: context_(context) {}
: clock_(base::DefaultTickClock::GetInstance()), context_(context) {}
bool DisplayLockBudget::MarkAncestorsDirtyForPhaseIfNeeded(Phase phase) {
switch (phase) {
......
......@@ -8,6 +8,10 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/heap/member.h"
namespace base {
class TickClock;
}
namespace blink {
class DisplayLockContext;
......@@ -39,6 +43,10 @@ class CORE_EXPORT DisplayLockBudget {
// true indicating that another frame is needed.
virtual bool NeedsLifecycleUpdates() const = 0;
// The caller is the owner of the |clock|. The |clock| must outlive the
// DisplayLockBudget.
void SetTickClockForTesting(const base::TickClock* clock) { clock_ = clock; }
protected:
// Marks the ancestor chain dirty for the given phase if it's needed. Returns
// true if the ancestors were marked dirty and false otherwise.
......@@ -47,6 +55,8 @@ class CORE_EXPORT DisplayLockBudget {
// Returns true if there is likely to be work for the given phase.
bool IsElementDirtyForPhase(Phase) const;
const base::TickClock* clock_;
private:
// This is a backpointer to the context, which should always outlive this
// budget, so it's untraced.
......
......@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/core/display_lock/display_lock_budget.h"
#include "base/test/test_mock_time_task_runner.h"
#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
......@@ -12,7 +14,6 @@
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/testing/wtf/scoped_mock_clock.h"
namespace blink {
......@@ -22,6 +23,7 @@ class DisplayLockBudgetTest : public RenderingTest {
RenderingTest::SetUp();
features_backup_.emplace();
RuntimeEnabledFeatures::SetDisplayLockingEnabled(true);
test_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
}
void TearDown() override {
......@@ -46,6 +48,9 @@ class DisplayLockBudgetTest : public RenderingTest {
context->update_budget_ = std::move(budget);
}
protected:
scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
private:
base::Optional<RuntimeEnabledFeatures::Backup> features_backup_;
};
......@@ -295,8 +300,7 @@ TEST_F(DisplayLockBudgetTest, YieldingBudget) {
ASSERT_TRUE(element->GetDisplayLockContext());
YieldingDisplayLockBudget budget(element->GetDisplayLockContext());
WTF::ScopedMockClock clock;
budget.SetTickClockForTesting(test_task_runner_->GetMockTickClock());
// When acquiring, we need to update the layout with the locked size, so we
// need an update.
......@@ -314,13 +318,16 @@ TEST_F(DisplayLockBudgetTest, YieldingBudget) {
EXPECT_TRUE(budget.NeedsLifecycleUpdates());
// Advancing the clock a bit will make us still want to the phases.
clock.Advance(TimeDelta::FromMillisecondsD(GetBudgetMs(budget) / 2));
test_task_runner_->FastForwardBy(
TimeDelta::FromMillisecondsD(GetBudgetMs(budget) / 2));
EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
// However, once we're out of budget, we will only do the next phase.
clock.Advance(TimeDelta::FromMillisecondsD(GetBudgetMs(budget)));
test_task_runner_->FastForwardBy(
TimeDelta::FromMillisecondsD(GetBudgetMs(budget)));
EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
EXPECT_FALSE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
EXPECT_FALSE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
......@@ -340,7 +347,8 @@ TEST_F(DisplayLockBudgetTest, YieldingBudget) {
// Now that we're out of budget, phases performed previously should remain
// true.
clock.Advance(TimeDelta::FromMillisecondsD(GetBudgetMs(budget) * 2));
test_task_runner_->FastForwardBy(
TimeDelta::FromMillisecondsD(GetBudgetMs(budget) * 2));
EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
EXPECT_FALSE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
EXPECT_FALSE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
......@@ -354,7 +362,8 @@ TEST_F(DisplayLockBudgetTest, YieldingBudget) {
EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
clock.Advance(TimeDelta::FromMillisecondsD(GetBudgetMs(budget) * 2));
test_task_runner_->FastForwardBy(
TimeDelta::FromMillisecondsD(GetBudgetMs(budget) * 2));
EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
EXPECT_FALSE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
......@@ -368,7 +377,7 @@ TEST_F(DisplayLockBudgetTest, YieldingBudget) {
EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
EXPECT_TRUE(budget.ShouldPerformPhase(DisplayLockBudget::Phase::kPrePaint));
clock.Advance(TimeDelta::FromMillisecondsD(10000));
test_task_runner_->FastForwardBy(TimeDelta::FromMillisecondsD(10000));
}
}
......@@ -400,6 +409,7 @@ TEST_F(DisplayLockBudgetTest, YieldingBudgetMarksNextPhase) {
new YieldingDisplayLockBudget(element->GetDisplayLockContext()));
;
auto* budget = budget_owned.get();
budget->SetTickClockForTesting(test_task_runner_->GetMockTickClock());
{
auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
ScriptState::Scope scope(script_state);
......@@ -407,8 +417,6 @@ TEST_F(DisplayLockBudgetTest, YieldingBudgetMarksNextPhase) {
ResetBudget(std::move(budget_owned), element->GetDisplayLockContext());
}
WTF::ScopedMockClock clock;
// When acquiring, we need to update the layout with the locked size, so we
// need an update.
EXPECT_TRUE(budget->NeedsLifecycleUpdates());
......@@ -429,7 +437,8 @@ TEST_F(DisplayLockBudgetTest, YieldingBudgetMarksNextPhase) {
EXPECT_TRUE(parent->NeedsStyleRecalc() || parent->ChildNeedsStyleRecalc());
EXPECT_TRUE(element->NeedsStyleRecalc() || element->ChildNeedsStyleRecalc());
clock.Advance(TimeDelta::FromMillisecondsD(GetBudgetMs(*budget) * 2));
test_task_runner_->FastForwardBy(
TimeDelta::FromMillisecondsD(GetBudgetMs(*budget) * 2));
EXPECT_TRUE(budget->ShouldPerformPhase(DisplayLockBudget::Phase::kStyle));
EXPECT_FALSE(budget->ShouldPerformPhase(DisplayLockBudget::Phase::kLayout));
......
......@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/display_lock/yielding_display_lock_budget.h"
#include "base/time/tick_clock.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
#include <algorithm>
......@@ -24,7 +25,7 @@ bool YieldingDisplayLockBudget::ShouldPerformPhase(Phase phase) const {
return true;
// Otherwise, we can still do work while we're not past the deadline.
return CurrentTimeTicks() < deadline_;
return clock_->NowTicks() < deadline_;
}
void YieldingDisplayLockBudget::DidPerformPhase(Phase phase) {
......@@ -42,7 +43,7 @@ void YieldingDisplayLockBudget::DidPerformPhase(Phase phase) {
void YieldingDisplayLockBudget::WillStartLifecycleUpdate() {
++lifecycle_count_;
deadline_ =
CurrentTimeTicks() + TimeDelta::FromMillisecondsD(GetCurrentBudgetMs());
clock_->NowTicks() + TimeDelta::FromMillisecondsD(GetCurrentBudgetMs());
// Figure out the next phase we would run. If we had completed a phase before,
// then we should try to complete the next one, otherwise we'll start with the
......
......@@ -4,18 +4,20 @@
#include "third_party/blink/renderer/core/dom/idle_deadline.h"
#include "base/time/default_tick_clock.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/core/timing/performance.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
namespace blink {
IdleDeadline::IdleDeadline(TimeTicks deadline, CallbackType callback_type)
: deadline_(deadline), callback_type_(callback_type) {}
: deadline_(deadline),
callback_type_(callback_type),
clock_(base::DefaultTickClock::GetInstance()) {}
double IdleDeadline::timeRemaining() const {
TimeDelta time_remaining = deadline_ - CurrentTimeTicks();
TimeDelta time_remaining = deadline_ - clock_->NowTicks();
if (time_remaining < TimeDelta() ||
ThreadScheduler::Current()->ShouldYieldForHighPriorityWork()) {
return 0;
......
......@@ -10,6 +10,10 @@
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
namespace base {
class TickClock;
}
namespace blink {
class CORE_EXPORT IdleDeadline : public ScriptWrappable {
......@@ -32,9 +36,14 @@ class CORE_EXPORT IdleDeadline : public ScriptWrappable {
return callback_type_ == CallbackType::kCalledByTimeout;
}
// The caller is the owner of the |clock|. The |clock| must outlive the
// IdleDeadline.
void SetTickClockForTesting(const base::TickClock* clock) { clock_ = clock; }
private:
TimeTicks deadline_;
CallbackType callback_type_;
const base::TickClock* clock_;
};
} // namespace blink
......
......@@ -5,12 +5,11 @@
#include "third_party/blink/renderer/core/dom/idle_deadline.h"
#include "base/single_thread_task_runner.h"
#include "base/test/test_mock_time_task_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "third_party/blink/renderer/platform/testing/scoped_scheduler_overrider.h"
#include "third_party/blink/renderer/platform/testing/wtf/scoped_mock_clock.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
namespace blink {
namespace {
......@@ -74,16 +73,20 @@ class MockIdleDeadlineScheduler final : public ThreadScheduler {
class IdleDeadlineTest : public testing::Test {
public:
void SetUp() override { clock_.Advance(TimeDelta::FromSeconds(1)); }
void SetUp() override {
test_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
}
private:
WTF::ScopedMockClock clock_;
protected:
scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
};
TEST_F(IdleDeadlineTest, DeadlineInFuture) {
auto* deadline = MakeGarbageCollected<IdleDeadline>(
TimeTicks() + TimeDelta::FromSecondsD(1.25),
IdleDeadline::CallbackType::kCalledWhenIdle);
deadline->SetTickClockForTesting(test_task_runner_->GetMockTickClock());
test_task_runner_->FastForwardBy(TimeDelta::FromSeconds(1));
// Note: the deadline is computed with reduced resolution.
EXPECT_FLOAT_EQ(250.0, deadline->timeRemaining());
}
......@@ -92,6 +95,8 @@ TEST_F(IdleDeadlineTest, DeadlineInPast) {
auto* deadline = MakeGarbageCollected<IdleDeadline>(
TimeTicks() + TimeDelta::FromSecondsD(0.75),
IdleDeadline::CallbackType::kCalledWhenIdle);
deadline->SetTickClockForTesting(test_task_runner_->GetMockTickClock());
test_task_runner_->FastForwardBy(TimeDelta::FromSeconds(1));
EXPECT_FLOAT_EQ(0, deadline->timeRemaining());
}
......@@ -102,6 +107,8 @@ TEST_F(IdleDeadlineTest, YieldForHighPriorityWork) {
auto* deadline = MakeGarbageCollected<IdleDeadline>(
TimeTicks() + TimeDelta::FromSecondsD(1.25),
IdleDeadline::CallbackType::kCalledWhenIdle);
deadline->SetTickClockForTesting(test_task_runner_->GetMockTickClock());
test_task_runner_->FastForwardBy(TimeDelta::FromSeconds(1));
EXPECT_FLOAT_EQ(0, deadline->timeRemaining());
}
......
......@@ -4,12 +4,12 @@
#include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
#include "base/time/default_clock.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/platform/histogram.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
namespace blink {
......@@ -21,7 +21,8 @@ const double kUserGestureOutOfProcessTimeout = 10.0;
UserGestureToken::UserGestureToken(Status status)
: consumable_gestures_(0),
timestamp_(WTF::CurrentTime()),
clock_(base::DefaultClock::GetInstance()),
timestamp_(clock_->Now().ToDoubleT()),
timeout_policy_(kDefault),
was_forwarded_cross_process_(false) {
if (status == kNewGesture || !UserGestureIndicator::CurrentTokenThreadSafe())
......@@ -52,7 +53,7 @@ void UserGestureToken::SetTimeoutPolicy(TimeoutPolicy policy) {
}
void UserGestureToken::ResetTimestamp() {
timestamp_ = WTF::CurrentTime();
timestamp_ = clock_->Now().ToDoubleT();
}
bool UserGestureToken::HasTimedOut() const {
......@@ -61,7 +62,7 @@ bool UserGestureToken::HasTimedOut() const {
double timeout = timeout_policy_ == kOutOfProcess
? kUserGestureOutOfProcessTimeout
: kUserGestureTimeout;
return WTF::CurrentTime() - timestamp_ > timeout;
return clock_->Now().ToDoubleT() - timestamp_ > timeout;
}
bool UserGestureToken::WasForwardedCrossProcess() const {
......
......@@ -10,6 +10,10 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
namespace base {
class Clock;
}
namespace blink {
// A UserGestureToken represents the current state of a user gesture. It can be
......@@ -32,6 +36,9 @@ class CORE_EXPORT UserGestureToken : public RefCounted<UserGestureToken> {
// need to investigate the usecase closely.
bool HasGestures() const;
void SetClockForTesting(const base::Clock* clock) { clock_ = clock; }
void ResetTimestampForTesting() { ResetTimestamp(); }
private:
UserGestureToken(Status);
......@@ -44,6 +51,7 @@ class CORE_EXPORT UserGestureToken : public RefCounted<UserGestureToken> {
void SetWasForwardedCrossProcess();
size_t consumable_gestures_;
const base::Clock* clock_;
double timestamp_;
TimeoutPolicy timeout_policy_;
bool was_forwarded_cross_process_;
......
......@@ -4,10 +4,9 @@
#include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
#include "base/test/test_mock_time_task_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/platform/testing/wtf/scoped_mock_clock.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
namespace blink {
......@@ -112,17 +111,20 @@ TEST(UserGestureIndicatorTest, MultipleGesturesWithTheSameToken) {
}
TEST(UserGestureIndicatorTest, Timeouts) {
WTF::ScopedMockClock clock;
auto test_task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
{
// Token times out after 1 second.
std::unique_ptr<UserGestureIndicator> user_gesture_scope =
LocalFrame::NotifyUserActivation(nullptr);
scoped_refptr<UserGestureToken> token = user_gesture_scope->CurrentToken();
token->SetClockForTesting(test_task_runner->GetMockClock());
// Timestamp is initialized to Now() in constructor using the default clock,
// reset it so it gets the Now() of the mock clock.
token->ResetTimestampForTesting();
EXPECT_TRUE(token->HasGestures());
clock.Advance(TimeDelta::FromSecondsD(0.75));
test_task_runner->FastForwardBy(TimeDelta::FromSecondsD(0.75));
EXPECT_TRUE(token->HasGestures());
clock.Advance(TimeDelta::FromSecondsD(0.75));
test_task_runner->FastForwardBy(TimeDelta::FromSecondsD(0.75));
EXPECT_FALSE(token->HasGestures());
}
......@@ -134,16 +136,20 @@ TEST(UserGestureIndicatorTest, Timeouts) {
std::unique_ptr<UserGestureIndicator> user_gesture_scope =
LocalFrame::NotifyUserActivation(nullptr);
token = user_gesture_scope->CurrentToken();
token->SetClockForTesting(test_task_runner->GetMockClock());
// Timestamp is initialized to Now() in constructor using the default
// clock, reset it so it gets the Now() of the mock clock.
token->ResetTimestampForTesting();
EXPECT_TRUE(token->HasGestures());
clock.Advance(TimeDelta::FromSecondsD(0.75));
test_task_runner->FastForwardBy(TimeDelta::FromSecondsD(0.75));
EXPECT_TRUE(token->HasGestures());
}
{
UserGestureIndicator user_gesture_scope(token.get());
clock.Advance(TimeDelta::FromSecondsD(0.75));
test_task_runner->FastForwardBy(TimeDelta::FromSecondsD(0.75));
EXPECT_TRUE(token->HasGestures());
clock.Advance(TimeDelta::FromSecondsD(0.75));
test_task_runner->FastForwardBy(TimeDelta::FromSecondsD(0.75));
EXPECT_FALSE(token->HasGestures());
}
}
......
......@@ -6,6 +6,7 @@
#include "base/format_macros.h"
#include "base/rand_util.h"
#include "base/time/default_tick_clock.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
......@@ -15,15 +16,18 @@ namespace blink {
LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer::ScopedUkmHierarchicalTimer(
scoped_refptr<LocalFrameUkmAggregator> aggregator,
size_t metric_index)
size_t metric_index,
const base::TickClock* clock)
: aggregator_(aggregator),
metric_index_(metric_index),
start_time_(CurrentTimeTicks()) {}
clock_(clock),
start_time_(clock_->NowTicks()) {}
LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer::ScopedUkmHierarchicalTimer(
ScopedUkmHierarchicalTimer&& other)
: aggregator_(other.aggregator_),
metric_index_(other.metric_index_),
clock_(other.clock_),
start_time_(other.start_time_) {
other.aggregator_ = nullptr;
}
......@@ -31,7 +35,7 @@ LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer::ScopedUkmHierarchicalTimer(
LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer::
~ScopedUkmHierarchicalTimer() {
if (aggregator_ && base::TimeTicks::IsHighResolution()) {
aggregator_->RecordSample(metric_index_, start_time_, CurrentTimeTicks());
aggregator_->RecordSample(metric_index_, start_time_, clock_->NowTicks());
}
}
......@@ -39,6 +43,7 @@ LocalFrameUkmAggregator::LocalFrameUkmAggregator(int64_t source_id,
ukm::UkmRecorder* recorder)
: source_id_(source_id),
recorder_(recorder),
clock_(base::DefaultTickClock::GetInstance()),
event_name_("Blink.UpdateTime") {
// Record average and worst case for the primary metric.
primary_metric_.reset();
......@@ -111,7 +116,7 @@ LocalFrameUkmAggregator::LocalFrameUkmAggregator(int64_t source_id,
LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer
LocalFrameUkmAggregator::GetScopedTimer(size_t metric_index) {
return ScopedUkmHierarchicalTimer(this, metric_index);
return ScopedUkmHierarchicalTimer(this, metric_index, clock_);
}
void LocalFrameUkmAggregator::BeginMainFrame() {
......@@ -119,6 +124,11 @@ void LocalFrameUkmAggregator::BeginMainFrame() {
in_main_frame_update_ = true;
}
void LocalFrameUkmAggregator::SetTickClockForTesting(
const base::TickClock* clock) {
clock_ = clock;
}
void LocalFrameUkmAggregator::RecordSample(size_t metric_index,
TimeTicks start,
TimeTicks end) {
......
......@@ -11,6 +11,10 @@
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
namespace base {
class TickClock;
}
namespace ukm {
class UkmRecorder;
}
......@@ -194,10 +198,12 @@ class CORE_EXPORT LocalFrameUkmAggregator
friend class LocalFrameUkmAggregator;
ScopedUkmHierarchicalTimer(scoped_refptr<LocalFrameUkmAggregator>,
size_t metric_index);
size_t metric_index,
const base::TickClock* clock);
scoped_refptr<LocalFrameUkmAggregator> aggregator_;
const size_t metric_index_;
const base::TickClock* clock_;
const TimeTicks start_time_;
DISALLOW_COPY_AND_ASSIGN(ScopedUkmHierarchicalTimer);
......@@ -226,6 +232,10 @@ class CORE_EXPORT LocalFrameUkmAggregator
bool InMainFrame() { return in_main_frame_update_; }
// The caller is the owner of the |clock|. The |clock| must outlive the
// LocalFrameUkmAggregator.
void SetTickClockForTesting(const base::TickClock* clock);
private:
struct AbsoluteMetricRecord {
std::unique_ptr<CustomCountHistogram> uma_counter;
......@@ -261,6 +271,7 @@ class CORE_EXPORT LocalFrameUkmAggregator
// UKM system data
const int64_t source_id_;
ukm::UkmRecorder* const recorder_;
const base::TickClock* clock_;
// Event and metric data
const String event_name_;
......
......@@ -4,9 +4,9 @@
#include "third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h"
#include "base/test/test_mock_time_task_runner.h"
#include "components/ukm/test_ukm_recorder.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/testing/wtf/scoped_mock_clock.h"
namespace blink {
......@@ -16,14 +16,14 @@ class LocalFrameUkmAggregatorTest : public testing::Test {
~LocalFrameUkmAggregatorTest() override = default;
void SetUp() override {
clock_.emplace();
test_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
aggregator_ = base::MakeRefCounted<LocalFrameUkmAggregator>(
ukm::UkmRecorder::GetNewSourceID(), &recorder_);
aggregator_->SetTickClockForTesting(test_task_runner_->GetMockTickClock());
}
void TearDown() override {
aggregator_.reset();
clock_.reset();
}
LocalFrameUkmAggregator& aggregator() {
......@@ -35,8 +35,6 @@ class LocalFrameUkmAggregatorTest : public testing::Test {
void ResetAggregator() { aggregator_.reset(); }
WTF::ScopedMockClock& clock() { return *clock_; }
std::string GetPrimaryMetricName() {
return std::string(
LocalFrameUkmAggregator::primary_metric_name().Utf8().data());
......@@ -58,9 +56,10 @@ class LocalFrameUkmAggregatorTest : public testing::Test {
aggregator().FramesToNextEventForTest(delta);
}
base::TimeTicks Now() {
return base::TimeTicks() + base::TimeDelta::FromSecondsD(clock_->Now());
}
base::TimeTicks Now() { return test_task_runner_->NowTicks(); }
protected:
scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
void VerifyEntries(unsigned expected_num_entries,
unsigned expected_primary_metric,
......@@ -93,7 +92,6 @@ class LocalFrameUkmAggregatorTest : public testing::Test {
}
private:
base::Optional<WTF::ScopedMockClock> clock_;
scoped_refptr<LocalFrameUkmAggregator> aggregator_;
ukm::TestUkmRecorder recorder_;
};
......@@ -106,7 +104,7 @@ TEST_F(LocalFrameUkmAggregatorTest, EmptyEventsNotRecorded) {
return;
// There is no BeginMainFrame, so no metrics get recorded.
clock().Advance(TimeDelta::FromSeconds(10));
test_task_runner_->FastForwardBy(TimeDelta::FromSeconds(10));
ResetAggregator();
EXPECT_EQ(recorder().sources_count(), 0u);
......@@ -129,7 +127,8 @@ TEST_F(LocalFrameUkmAggregatorTest, FirstFrameIsRecorded) {
for (int i = 0; i < LocalFrameUkmAggregator::kCount; ++i) {
auto timer =
aggregator().GetScopedTimer(i % LocalFrameUkmAggregator::kCount);
clock().Advance(TimeDelta::FromMilliseconds(millisecond_for_step));
test_task_runner_->FastForwardBy(
TimeDelta::FromMilliseconds(millisecond_for_step));
}
aggregator().RecordEndOfFrameMetrics(start_time, Now());
......@@ -171,9 +170,11 @@ TEST_F(LocalFrameUkmAggregatorTest, EventsRecordedAtIntervals) {
aggregator().BeginMainFrame();
for (int i = 0; i < LocalFrameUkmAggregator::kCount; ++i) {
auto timer = aggregator().GetScopedTimer(i);
clock().Advance(TimeDelta::FromMilliseconds(millisecond_per_step));
test_task_runner_->FastForwardBy(
TimeDelta::FromMilliseconds(millisecond_per_step));
}
clock().Advance(TimeDelta::FromMilliseconds(millisecond_per_step));
test_task_runner_->FastForwardBy(
TimeDelta::FromMilliseconds(millisecond_per_step));
aggregator().RecordEndOfFrameMetrics(start_time, Now());
// We should have a sample after the very first step, regardless of the
......@@ -188,9 +189,11 @@ TEST_F(LocalFrameUkmAggregatorTest, EventsRecordedAtIntervals) {
aggregator().BeginMainFrame();
for (int i = 0; i < LocalFrameUkmAggregator::kCount; ++i) {
auto timer = aggregator().GetScopedTimer(i);
clock().Advance(TimeDelta::FromMilliseconds(millisecond_per_step));
test_task_runner_->FastForwardBy(
TimeDelta::FromMilliseconds(millisecond_per_step));
}
clock().Advance(TimeDelta::FromMilliseconds(millisecond_per_step));
test_task_runner_->FastForwardBy(
TimeDelta::FromMilliseconds(millisecond_per_step));
aggregator().RecordEndOfFrameMetrics(start_time, Now());
VerifyEntries(1u, millisecond_per_frame, millisecond_per_step,
......@@ -203,9 +206,11 @@ TEST_F(LocalFrameUkmAggregatorTest, EventsRecordedAtIntervals) {
aggregator().BeginMainFrame();
for (int i = 0; i < LocalFrameUkmAggregator::kCount; ++i) {
auto timer = aggregator().GetScopedTimer(i);
clock().Advance(TimeDelta::FromMilliseconds(millisecond_per_step));
test_task_runner_->FastForwardBy(
TimeDelta::FromMilliseconds(millisecond_per_step));
}
clock().Advance(TimeDelta::FromMilliseconds(millisecond_per_step));
test_task_runner_->FastForwardBy(
TimeDelta::FromMilliseconds(millisecond_per_step));
aggregator().RecordEndOfFrameMetrics(start_time, Now());
VerifyEntries(2u, millisecond_per_frame, millisecond_per_step,
......@@ -216,9 +221,11 @@ TEST_F(LocalFrameUkmAggregatorTest, EventsRecordedAtIntervals) {
aggregator().BeginMainFrame();
for (int i = 0; i < LocalFrameUkmAggregator::kCount; ++i) {
auto timer = aggregator().GetScopedTimer(i);
clock().Advance(TimeDelta::FromMilliseconds(millisecond_per_step));
test_task_runner_->FastForwardBy(
TimeDelta::FromMilliseconds(millisecond_per_step));
}
clock().Advance(TimeDelta::FromMilliseconds(millisecond_per_step));
test_task_runner_->FastForwardBy(
TimeDelta::FromMilliseconds(millisecond_per_step));
aggregator().RecordEndOfFrameMetrics(start_time, Now());
// Should be no more samples.
......@@ -230,9 +237,11 @@ TEST_F(LocalFrameUkmAggregatorTest, EventsRecordedAtIntervals) {
aggregator().BeginMainFrame();
for (int i = 0; i < LocalFrameUkmAggregator::kCount; ++i) {
auto timer = aggregator().GetScopedTimer(i);
clock().Advance(TimeDelta::FromMilliseconds(millisecond_per_step));
test_task_runner_->FastForwardBy(
TimeDelta::FromMilliseconds(millisecond_per_step));
}
clock().Advance(TimeDelta::FromMilliseconds(millisecond_per_step));
test_task_runner_->FastForwardBy(
TimeDelta::FromMilliseconds(millisecond_per_step));
aggregator().RecordEndOfFrameMetrics(start_time, Now());
// We should have 3 more events, once for the prior interval and 2 for the
......
......@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/paint/image_paint_timing_detector.h"
#include "base/bind.h"
#include "base/test/test_mock_time_task_runner.h"
#include "build/build_config.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/public/web/web_performance.h"
......@@ -23,7 +24,6 @@
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/wtf/scoped_mock_clock.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkSurface.h"
......@@ -38,6 +38,7 @@ class ImagePaintTimingDetectorTest
ImagePaintTimingDetectorTest()
: RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()),
ScopedFirstContentfulPaintPlusPlusForTest(true),
test_task_runner_(base::MakeRefCounted<base::TestMockTimeTaskRunner>()),
base_url_("http://www.test.com/") {}
~ImagePaintTimingDetectorTest() override {
......@@ -131,8 +132,16 @@ class ImagePaintTimingDetectorTest
return GetPaintTimingDetector().largest_image_paint_time_;
}
static constexpr TimeDelta kQuantumOfTime =
base::TimeDelta::FromMilliseconds(10);
void SimulatePassOfTime() {
test_task_runner_->FastForwardBy(kQuantumOfTime);
}
void UpdateAllLifecyclePhasesAndInvokeCallbackIfAny() {
UpdateAllLifecyclePhasesForTest();
SimulatePassOfTime();
if (!callback_queue_.empty())
InvokeCallback();
}
......@@ -140,7 +149,8 @@ class ImagePaintTimingDetectorTest
void InvokeCallback() {
DCHECK_GT(callback_queue_.size(), 0UL);
std::move(callback_queue_.front())
.Run(WebWidgetClient::SwapResult::kDidSwap, CurrentTimeTicks());
.Run(WebWidgetClient::SwapResult::kDidSwap,
test_task_runner_->NowTicks());
callback_queue_.pop();
}
......@@ -177,6 +187,8 @@ class ImagePaintTimingDetectorTest
void SimulateScroll() { GetPaintTimingDetector().NotifyScroll(kUserScroll); }
scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
private:
void FakeNotifySwapTime(WebWidgetClient::ReportTimeCallback callback) {
callback_queue_.push(std::move(callback));
......@@ -197,6 +209,8 @@ class ImagePaintTimingDetectorTest
std::string base_url_;
};
constexpr TimeDelta ImagePaintTimingDetectorTest::kQuantumOfTime;
TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_NoImage) {
SetBodyInnerHTML(R"HTML(
<div></div>
......@@ -452,7 +466,6 @@ TEST_F(ImagePaintTimingDetectorTest,
TEST_F(ImagePaintTimingDetectorTest,
LargestImagePaint_ReattachedNodeUseFirstPaint) {
WTF::ScopedMockClock clock;
SetBodyInnerHTML(R"HTML(
<div id="parent">
</div>
......@@ -461,26 +474,32 @@ TEST_F(ImagePaintTimingDetectorTest,
image->setAttribute("id", "target");
GetDocument().getElementById("parent")->AppendChild(image);
SetImageAndPaint("target", 5, 5);
clock.Advance(TimeDelta::FromSecondsD(1));
test_task_runner_->FastForwardBy(TimeDelta::FromSecondsD(1));
UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
ImageRecord* record;
record = FindLargestPaintCandidate();
EXPECT_TRUE(record);
EXPECT_EQ(record->paint_time, base::TimeTicks() + TimeDelta::FromSecondsD(1));
// UpdateAllLifecyclePhasesAndInvokeCallbackIfAny() moves time forward
// kQuantumOfTime so we should take that into account.
EXPECT_EQ(record->paint_time,
base::TimeTicks() + TimeDelta::FromSecondsD(1) + kQuantumOfTime);
GetDocument().getElementById("parent")->RemoveChild(image);
clock.Advance(TimeDelta::FromSecondsD(1));
test_task_runner_->FastForwardBy(TimeDelta::FromSecondsD(1));
UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
record = FindLargestPaintCandidate();
EXPECT_FALSE(record);
GetDocument().getElementById("parent")->AppendChild(image);
SetImageAndPaint("target", 5, 5);
clock.Advance(TimeDelta::FromSecondsD(1));
test_task_runner_->FastForwardBy(TimeDelta::FromSecondsD(1));
UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
record = FindLargestPaintCandidate();
EXPECT_TRUE(record);
EXPECT_EQ(record->paint_time, base::TimeTicks() + TimeDelta::FromSecondsD(1));
// UpdateAllLifecyclePhasesAndInvokeCallbackIfAny() moves time forward
// kQuantumOfTime so we should take that into account.
EXPECT_EQ(record->paint_time,
base::TimeTicks() + TimeDelta::FromSecondsD(1) + kQuantumOfTime);
}
// This is to prove that a swap time is assigned only to nodes of the frame who
......@@ -496,8 +515,10 @@ TEST_F(ImagePaintTimingDetectorTest, MatchSwapTimeToNodesOfDifferentFrames) {
SetImageAndPaint("larger", 9, 9);
UpdateAllLifecyclePhasesForTest();
SimulatePassOfTime();
SetImageAndPaint("smaller", 5, 5);
UpdateAllLifecyclePhasesForTest();
SimulatePassOfTime();
InvokeCallback();
// record1 is the larger.
ImageRecord* record1 = FindLargestPaintCandidate();
......@@ -505,6 +526,7 @@ TEST_F(ImagePaintTimingDetectorTest, MatchSwapTimeToNodesOfDifferentFrames) {
GetDocument().getElementById("parent")->RemoveChild(
GetDocument().getElementById("larger"));
UpdateAllLifecyclePhasesForTest();
SimulatePassOfTime();
InvokeCallback();
// record2 is the smaller.
ImageRecord* record2 = FindLargestPaintCandidate();
......@@ -513,7 +535,7 @@ TEST_F(ImagePaintTimingDetectorTest, MatchSwapTimeToNodesOfDifferentFrames) {
TEST_F(ImagePaintTimingDetectorTest,
LargestImagePaint_UpdateResultWhenLargestChanged) {
TimeTicks time1 = CurrentTimeTicks();
TimeTicks time1 = test_task_runner_->NowTicks();
SetBodyInnerHTML(R"HTML(
<div id="parent">
<img id="target1"></img>
......@@ -522,14 +544,14 @@ TEST_F(ImagePaintTimingDetectorTest,
)HTML");
SetImageAndPaint("target1", 5, 5);
UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
TimeTicks time2 = CurrentTimeTicks();
TimeTicks time2 = test_task_runner_->NowTicks();
TimeTicks result1 = LargestPaintStoredResult();
EXPECT_GE(result1, time1);
EXPECT_GE(time2, result1);
SetImageAndPaint("target2", 10, 10);
UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
TimeTicks time3 = CurrentTimeTicks();
TimeTicks time3 = test_task_runner_->NowTicks();
TimeTicks result2 = LargestPaintStoredResult();
EXPECT_GE(result2, time2);
EXPECT_GE(time3, result2);
......@@ -545,9 +567,11 @@ TEST_F(ImagePaintTimingDetectorTest, OneSwapPromiseForOneFrame) {
)HTML");
SetImageAndPaint("1", 5, 5);
UpdateAllLifecyclePhasesForTest();
SimulatePassOfTime();
SetImageAndPaint("2", 9, 9);
UpdateAllLifecyclePhasesForTest();
SimulatePassOfTime();
// This callback only assigns a time to the 5x5 image.
InvokeCallback();
......
......@@ -8,6 +8,7 @@
#include <stdint.h>
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
......@@ -70,37 +71,42 @@ class PLATFORM_EXPORT LinearHistogram : public CustomCountHistogram {
int32_t bucket_count);
};
class PLATFORM_EXPORT ScopedUsHistogramTimer {
USING_FAST_MALLOC(ScopedUsHistogramTimer);
template <typename Derived>
class ScopedUsHistogramTimerBase {
USING_FAST_MALLOC(ScopedUsHistogramTimerBase);
public:
explicit ScopedUsHistogramTimer(CustomCountHistogram& counter)
: start_time_(CurrentTimeTicks()), counter_(counter) {}
explicit ScopedUsHistogramTimerBase(CustomCountHistogram& counter)
: ScopedUsHistogramTimerBase(counter,
base::DefaultTickClock::GetInstance()) {}
~ScopedUsHistogramTimer() {
counter_.CountMicroseconds(CurrentTimeTicks() - start_time_);
ScopedUsHistogramTimerBase(CustomCountHistogram& counter,
const base::TickClock* clock)
: clock_(*clock), start_time_(clock_.NowTicks()), counter_(counter) {}
~ScopedUsHistogramTimerBase() {
if (Derived::ShouldRecord())
counter_.CountMicroseconds(clock_.NowTicks() - start_time_);
}
private:
const base::TickClock& clock_;
TimeTicks start_time_;
CustomCountHistogram& counter_;
};
class PLATFORM_EXPORT ScopedHighResUsHistogramTimer {
USING_FAST_MALLOC(ScopedUsHistogramTimer);
class ScopedUsHistogramTimer
: public ScopedUsHistogramTimerBase<ScopedUsHistogramTimer> {
public:
explicit ScopedHighResUsHistogramTimer(CustomCountHistogram& counter)
: start_time_(CurrentTimeTicks()), counter_(counter) {}
~ScopedHighResUsHistogramTimer() {
if (TimeTicks::IsHighResolution())
counter_.CountMicroseconds(CurrentTimeTicks() - start_time_);
}
using ScopedUsHistogramTimerBase::ScopedUsHistogramTimerBase;
static bool ShouldRecord() { return true; }
};
private:
TimeTicks start_time_;
CustomCountHistogram& counter_;
class ScopedHighResUsHistogramTimer
: public ScopedUsHistogramTimerBase<ScopedHighResUsHistogramTimer> {
public:
using ScopedUsHistogramTimerBase::ScopedUsHistogramTimerBase;
static bool ShouldRecord() { return TimeTicks::IsHighResolution(); }
};
#define SCOPED_BLINK_UMA_HISTOGRAM_TIMER_IMPL(name, allow_cross_thread) \
......
......@@ -5,9 +5,8 @@
#include "third_party/blink/renderer/platform/histogram.h"
#include "base/metrics/histogram_samples.h"
#include "base/test/test_mock_time_task_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/testing/wtf/scoped_mock_clock.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
namespace blink {
......@@ -22,25 +21,35 @@ class TestCustomCountHistogram : public CustomCountHistogram {
base::HistogramBase* Histogram() { return histogram_; }
};
TEST(ScopedUsHistogramTimerTest, Basic) {
class ScopedUsHistogramTimerTest : public testing::Test {
public:
void SetUp() override {
test_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
}
protected:
scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
};
TEST_F(ScopedUsHistogramTimerTest, Basic) {
TestCustomCountHistogram scoped_us_counter("ScopedUsHistogramTimerTest.Basic",
0, 10000000, 50);
{
WTF::ScopedMockClock clock;
ScopedUsHistogramTimer timer(scoped_us_counter);
clock.Advance(TimeDelta::FromMilliseconds(500));
ScopedUsHistogramTimer timer(scoped_us_counter,
test_task_runner_->GetMockTickClock());
test_task_runner_->FastForwardBy(TimeDelta::FromMilliseconds(500));
}
// 500ms == 500000us
EXPECT_EQ(500000, scoped_us_counter.Histogram()->SnapshotSamples()->sum());
}
TEST(ScopedHighResUsHistogramTimerTest, Basic) {
TEST_F(ScopedUsHistogramTimerTest, BasicHighRes) {
TestCustomCountHistogram scoped_us_counter(
"ScopedHighResUsHistogramTimerTest.Basic", 0, 10000000, 50);
{
WTF::ScopedMockClock clock;
ScopedHighResUsHistogramTimer timer(scoped_us_counter);
clock.Advance(TimeDelta::FromMilliseconds(500));
ScopedHighResUsHistogramTimer timer(scoped_us_counter,
test_task_runner_->GetMockTickClock());
test_task_runner_->FastForwardBy(TimeDelta::FromMilliseconds(500));
}
int64_t expected = TimeTicks::IsHighResolution() ? 500000 : 0;
EXPECT_EQ(expected, scoped_us_counter.Histogram()->SnapshotSamples()->sum());
......
......@@ -198,6 +198,12 @@ _CONFIG = [
# For MessageLoop::TaskObserver.
'base::PendingTask',
# Time
'base::Clock',
'base::DefaultClock',
'base::DefaultTickClock',
'base::TickClock',
# cc painting types.
'cc::PaintCanvas',
'cc::PaintFlags',
......
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