diff options
author | mithro <mithro@mithis.com> | 2014-09-09 18:03:36 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-10 01:18:39 +0000 |
commit | 0c0ac6a1616778e3852e3f8b3248688ca9d899b2 (patch) | |
tree | 0f79cee120a2dbaba414e6828ce555f14b0f0c7c | |
parent | dc6bae3bdc5154b73600a1180c0a82859b271a3f (diff) | |
download | chromium_src-0c0ac6a1616778e3852e3f8b3248688ca9d899b2.zip chromium_src-0c0ac6a1616778e3852e3f8b3248688ca9d899b2.tar.gz chromium_src-0c0ac6a1616778e3852e3f8b3248688ca9d899b2.tar.bz2 |
New features include;
* Actually running the tasks in the ordered you asked!
* Allow running only pending tasks, all tasks until idle, to a given time or
for a given period.
* Allow stopping of running tasks on *any* arbitrary condition. No longer will
your tasks stop working when someone adds a new task or changes the task
order!
* Task runner intimately connected to time and controls Now().
Supports both automatic management and manual control.
This change makes it possible for the scheduler_unit tests to be 100%
deterministic. It also allows them to be more flexible and less brittle.
BUG=380889
Review URL: https://codereview.chromium.org/387493002
Cr-Commit-Position: refs/heads/master@{#294059}
-rw-r--r-- | cc/BUILD.gn | 2 | ||||
-rw-r--r-- | cc/cc_tests.gyp | 2 | ||||
-rw-r--r-- | cc/scheduler/scheduler.cc | 44 | ||||
-rw-r--r-- | cc/scheduler/scheduler.h | 8 | ||||
-rw-r--r-- | cc/scheduler/scheduler_unittest.cc | 215 | ||||
-rw-r--r-- | cc/test/begin_frame_args_test.cc | 16 | ||||
-rw-r--r-- | cc/test/begin_frame_args_test.h | 8 | ||||
-rw-r--r-- | cc/test/ordered_simple_task_runner.cc | 322 | ||||
-rw-r--r-- | cc/test/ordered_simple_task_runner.h | 126 | ||||
-rw-r--r-- | cc/test/ordered_simple_task_runner_unittest.cc | 420 | ||||
-rw-r--r-- | cc/test/scheduler_test_common.cc | 48 | ||||
-rw-r--r-- | cc/test/scheduler_test_common.h | 74 | ||||
-rw-r--r-- | cc/test/test_now_source.cc | 125 | ||||
-rw-r--r-- | cc/test/test_now_source.h | 60 |
14 files changed, 1295 insertions, 175 deletions
diff --git a/cc/BUILD.gn b/cc/BUILD.gn index 4222804..300150f 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn @@ -599,6 +599,8 @@ source_set("test_support") { "test/test_context_support.h", "test/test_gles2_interface.cc", "test/test_gles2_interface.h", + "test/test_now_source.cc", + "test/test_now_source.h", "test/test_occlusion_tracker.h", "test/test_shared_bitmap_manager.cc", "test/test_shared_bitmap_manager.h", diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp index e9b99d0..90dc7974 100644 --- a/cc/cc_tests.gyp +++ b/cc/cc_tests.gyp @@ -234,6 +234,8 @@ 'test/test_context_support.h', 'test/test_gles2_interface.cc', 'test/test_gles2_interface.h', + 'test/test_now_source.cc', + 'test/test_now_source.h', 'test/test_occlusion_tracker.h', 'test/test_shared_bitmap_manager.cc', 'test/test_shared_bitmap_manager.h', diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index 65f63fc..1c66f01a 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc @@ -19,15 +19,8 @@ namespace cc { Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource( Scheduler* scheduler, - base::SingleThreadTaskRunner* task_runner) - : scheduler_(scheduler) { - if (gfx::FrameTime::TimestampsAreHighRes()) { - time_source_ = DelayBasedTimeSourceHighRes::Create( - scheduler_->VSyncInterval(), task_runner); - } else { - time_source_ = DelayBasedTimeSource::Create(scheduler_->VSyncInterval(), - task_runner); - } + scoped_refptr<DelayBasedTimeSource> time_source) + : scheduler_(scheduler), time_source_(time_source) { time_source_->SetClient(this); } @@ -126,9 +119,21 @@ Scheduler::~Scheduler() { } void Scheduler::SetupSyntheticBeginFrames() { + scoped_refptr<DelayBasedTimeSource> time_source; + if (gfx::FrameTime::TimestampsAreHighRes()) { + time_source = DelayBasedTimeSourceHighRes::Create(VSyncInterval(), + task_runner_.get()); + } else { + time_source = + DelayBasedTimeSource::Create(VSyncInterval(), task_runner_.get()); + } DCHECK(!synthetic_begin_frame_source_); synthetic_begin_frame_source_.reset( - new SyntheticBeginFrameSource(this, task_runner_.get())); + new SyntheticBeginFrameSource(this, time_source)); +} + +base::TimeTicks Scheduler::Now() const { + return gfx::FrameTime::Now(); } void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, @@ -262,7 +267,7 @@ base::TimeTicks Scheduler::AnticipatedDrawTime() const { begin_impl_frame_args_.interval <= base::TimeDelta()) return base::TimeTicks(); - base::TimeTicks now = gfx::FrameTime::Now(); + base::TimeTicks now = Now(); base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, begin_impl_frame_args_.deadline); int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); @@ -340,7 +345,7 @@ void Scheduler::BeginUnthrottledFrame() { DCHECK(!settings_.throttle_frame_production); DCHECK(begin_retro_frame_args_.empty()); - base::TimeTicks now = gfx::FrameTime::Now(); + base::TimeTicks now = Now(); base::TimeTicks deadline = now + vsync_interval_; BeginFrameArgs begin_frame_args = @@ -451,7 +456,7 @@ void Scheduler::BeginRetroFrame() { // TODO(brianderson): In the future, long deadlines could result in us not // draining the queue if we don't catch up. If we consistently can't catch // up, our fallback should be to lower our frame rate. - base::TimeTicks now = gfx::FrameTime::Now(); + base::TimeTicks now = Now(); base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); while (!begin_retro_frame_args_.empty() && now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(), @@ -479,6 +484,10 @@ void Scheduler::BeginRetroFrame() { // will check if there is a pending BeginRetroFrame to ensure we handle // BeginFrames in FIFO order. void Scheduler::PostBeginRetroFrameIfNeeded() { + TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), + "Scheduler::PostBeginRetroFrameIfNeeded", + "state", + AsValue()); if (!last_set_needs_begin_frame_) return; @@ -555,6 +564,8 @@ base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline( } void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { + TRACE_EVENT1( + "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline); if (settings_.using_synchronous_renderer_compositor) { // The synchronous renderer compositor has to make its GL calls // within this call. @@ -567,7 +578,7 @@ void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { begin_impl_frame_deadline_task_.Cancel(); begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); - base::TimeDelta delta = deadline - gfx::FrameTime::Now(); + base::TimeDelta delta = deadline - Now(); if (delta <= base::TimeDelta()) delta = base::TimeDelta(); task_runner_->PostDelayedTask( @@ -697,9 +708,8 @@ scoped_refptr<base::debug::ConvertableToTraceFormat> Scheduler::AsValue() } state->BeginDictionary("scheduler_state"); - state->SetDouble( - "time_until_anticipated_draw_time_ms", - (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF()); + state->SetDouble("time_until_anticipated_draw_time_ms", + (AnticipatedDrawTime() - Now()).InMillisecondsF()); state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF()); state->SetDouble("estimated_parent_draw_time_ms", estimated_parent_draw_time_.InMillisecondsF()); diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h index 97b17b7..70522eb 100644 --- a/cc/scheduler/scheduler.h +++ b/cc/scheduler/scheduler.h @@ -137,7 +137,7 @@ class CC_EXPORT Scheduler { class CC_EXPORT SyntheticBeginFrameSource : public TimeSourceClient { public: SyntheticBeginFrameSource(Scheduler* scheduler, - base::SingleThreadTaskRunner* task_runner); + scoped_refptr<DelayBasedTimeSource> time_source); virtual ~SyntheticBeginFrameSource(); // Updates the phase and frequency of the timer. @@ -168,6 +168,8 @@ class CC_EXPORT Scheduler { int layer_tree_host_id, const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); + virtual base::TimeTicks Now() const; + const SchedulerSettings settings_; SchedulerClient* client_; int layer_tree_host_id_; @@ -198,6 +200,8 @@ class CC_EXPORT Scheduler { bool inside_process_scheduled_actions_; SchedulerStateMachine::Action inside_action_; + base::TimeDelta VSyncInterval() { return vsync_interval_; } + private: base::TimeTicks AdjustedBeginImplFrameDeadline( const BeginFrameArgs& args, @@ -221,8 +225,6 @@ class CC_EXPORT Scheduler { void PollForAnticipatedDrawTriggers(); void PollToAdvanceCommitState(); - base::TimeDelta VSyncInterval() { return vsync_interval_; } - base::TimeDelta EstimatedParentDrawTime() { return estimated_parent_draw_time_; } diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index 7df5bf2..256acd5 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc @@ -43,47 +43,14 @@ class FakeSchedulerClient; void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler, FakeSchedulerClient* client); -class TestScheduler : public Scheduler { - public: - static scoped_ptr<TestScheduler> Create( - SchedulerClient* client, - const SchedulerSettings& scheduler_settings, - int layer_tree_host_id, - const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner) { - return make_scoped_ptr(new TestScheduler( - client, scheduler_settings, layer_tree_host_id, impl_task_runner)); - } - - virtual ~TestScheduler() {} - - bool IsBeginRetroFrameArgsEmpty() const { - return begin_retro_frame_args_.empty(); - } - - bool IsSyntheticBeginFrameSourceActive() const { - return synthetic_begin_frame_source_->IsActive(); - } - - private: - TestScheduler( - SchedulerClient* client, - const SchedulerSettings& scheduler_settings, - int layer_tree_host_id, - const scoped_refptr<base::SingleThreadTaskRunner> & impl_task_runner) - : Scheduler(client, - scheduler_settings, - layer_tree_host_id, - impl_task_runner) { - } -}; - class FakeSchedulerClient : public SchedulerClient { public: FakeSchedulerClient() : needs_begin_frame_(false), automatic_swap_ack_(true), swap_contains_incomplete_tile_(false), - redraw_will_happen_if_update_visible_tiles_happens_(false) { + redraw_will_happen_if_update_visible_tiles_happens_(false), + now_src_(TestNowSource::Create()) { Reset(); } @@ -97,8 +64,9 @@ class FakeSchedulerClient : public SchedulerClient { } TestScheduler* CreateScheduler(const SchedulerSettings& settings) { - task_runner_ = new OrderedSimpleTaskRunner; - scheduler_ = TestScheduler::Create(this, settings, 0, task_runner_); + scheduler_ = TestScheduler::Create(now_src_, this, settings, 0); + // Fail if we need to run 100 tasks in a row. + task_runner().SetRunTaskLimit(100); return scheduler_.get(); } @@ -116,7 +84,21 @@ class FakeSchedulerClient : public SchedulerClient { return posted_begin_impl_frame_deadline_; } - OrderedSimpleTaskRunner& task_runner() { return *task_runner_.get(); } + void AdvanceFrame() { + bool external_begin_frame = + scheduler_->settings().begin_frame_scheduling_enabled && + scheduler_->settings().throttle_frame_production; + + if (external_begin_frame) { + scheduler_->BeginFrame(CreateBeginFrameArgsForTesting(now_src_)); + } + + EXPECT_TRUE(task_runner().RunTasksWhile(ImplFrameDeadlinePending(false))); + EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); + } + + OrderedSimpleTaskRunner& task_runner() { return scheduler_->task_runner(); } + TestNowSource* now_src() { return now_src_.get(); } int ActionIndex(const char* action) const { for (size_t i = 0; i < actions_.size(); i++) @@ -228,7 +210,17 @@ class FakeSchedulerClient : public SchedulerClient { virtual void DidBeginImplFrameDeadline() OVERRIDE {} + base::Callback<bool(void)> ImplFrameDeadlinePending(bool state) { + return base::Bind(&FakeSchedulerClient::ImplFrameDeadlinePendingCallback, + base::Unretained(this), + state); + } + protected: + bool ImplFrameDeadlinePendingCallback(bool state) { + return scheduler_->BeginImplFrameDeadlinePending() == state; + } + bool needs_begin_frame_; bool draw_will_happen_; bool swap_will_happen_if_draw_happens_; @@ -241,14 +233,13 @@ class FakeSchedulerClient : public SchedulerClient { std::vector<const char*> actions_; std::vector<scoped_refptr<base::debug::ConvertableToTraceFormat> > states_; scoped_ptr<TestScheduler> scheduler_; - scoped_refptr<OrderedSimpleTaskRunner> task_runner_; + scoped_refptr<TestNowSource> now_src_; }; void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler, FakeSchedulerClient* client) { - bool client_initiates_begin_frame = - scheduler->settings().begin_frame_scheduling_enabled && - scheduler->settings().throttle_frame_production; + TRACE_EVENT0("cc", + "SchedulerUnitTest::InitializeOutputSurfaceAndFirstCommit"); scheduler->DidCreateAndInitializeOutputSurface(); scheduler->SetNeedsCommit(); @@ -256,27 +247,22 @@ void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler, scheduler->NotifyReadyToCommit(); if (scheduler->settings().impl_side_painting) scheduler->NotifyReadyToActivate(); + // Go through the motions to draw the commit. - if (client_initiates_begin_frame) - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); - else - client->task_runner().RunPendingTasks(); // Run posted BeginFrame. + client->AdvanceFrame(); // Run the posted deadline task. EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); - client->task_runner().RunPendingTasks(); + client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true)); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); // We need another BeginImplFrame so Scheduler calls // SetNeedsBeginFrame(false). - if (client_initiates_begin_frame) - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); - else - client->task_runner().RunPendingTasks(); // Run posted BeginFrame. + client->AdvanceFrame(); // Run the posted deadline task. EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); - client->task_runner().RunPendingTasks(); + client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true)); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); } @@ -312,7 +298,7 @@ TEST(SchedulerTest, RequestCommit) { EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -334,7 +320,7 @@ TEST(SchedulerTest, RequestCommit) { client.Reset(); // BeginImplFrame should prepare the draw. - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -350,7 +336,7 @@ TEST(SchedulerTest, RequestCommit) { // The following BeginImplFrame deadline should SetNeedsBeginFrame(false) // to avoid excessive toggles. - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); client.Reset(); @@ -378,7 +364,7 @@ TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -408,7 +394,7 @@ TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { client.Reset(); // Since another commit is needed, the next BeginImplFrame should initiate // the second commit. - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -430,7 +416,7 @@ TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { // On the next BeginImplFrame, verify we go back to a quiescent state and // no longer request BeginImplFrames. - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_FALSE(client.needs_begin_frame()); client.Reset(); @@ -476,13 +462,13 @@ TEST(SchedulerTest, RequestRedrawInsideDraw) { EXPECT_TRUE(client.needs_begin_frame()); EXPECT_EQ(0, client.num_draws()); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(1, client.num_draws()); EXPECT_TRUE(scheduler->RedrawPending()); EXPECT_TRUE(client.needs_begin_frame()); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(2, client.num_draws()); EXPECT_FALSE(scheduler->RedrawPending()); @@ -490,7 +476,7 @@ TEST(SchedulerTest, RequestRedrawInsideDraw) { // We stop requesting BeginImplFrames after a BeginImplFrame where we don't // swap. - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(2, client.num_draws()); EXPECT_FALSE(scheduler->RedrawPending()); @@ -516,7 +502,7 @@ TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { EXPECT_EQ(0, client.num_draws()); // Fail the draw. - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(1, client.num_draws()); @@ -527,7 +513,7 @@ TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { EXPECT_TRUE(client.needs_begin_frame()); // Fail the draw again. - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(2, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); @@ -536,7 +522,7 @@ TEST(SchedulerTest, RequestRedrawInsideFailedDraw) { // Draw successfully. client.SetDrawWillHappen(true); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(3, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); @@ -594,7 +580,7 @@ TEST(SchedulerTest, RequestCommitInsideDraw) { EXPECT_TRUE(client.needs_begin_frame()); client.SetNeedsCommitOnNextDraw(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.SetNeedsCommitOnNextDraw(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(1, client.num_draws()); @@ -603,7 +589,7 @@ TEST(SchedulerTest, RequestCommitInsideDraw) { scheduler->NotifyBeginMainFrameStarted(); scheduler->NotifyReadyToCommit(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(2, client.num_draws()); @@ -613,7 +599,7 @@ TEST(SchedulerTest, RequestCommitInsideDraw) { // We stop requesting BeginImplFrames after a BeginImplFrame where we don't // swap. - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(2, client.num_draws()); EXPECT_FALSE(scheduler->RedrawPending()); @@ -640,7 +626,7 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) { EXPECT_EQ(0, client.num_draws()); // Fail the draw. - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(1, client.num_draws()); @@ -651,7 +637,7 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) { EXPECT_TRUE(client.needs_begin_frame()); // Fail the draw again. - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(2, client.num_draws()); @@ -661,7 +647,7 @@ TEST(SchedulerTest, RequestCommitInsideFailedDraw) { // Draw successfully. client.SetDrawWillHappen(true); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(3, client.num_draws()); EXPECT_TRUE(scheduler->CommitPending()); @@ -686,7 +672,7 @@ TEST(SchedulerTest, NoSwapWhenDrawFails) { // Draw successfully, this starts a new frame. client.SetNeedsCommitOnNextDraw(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(1, client.num_draws()); @@ -697,7 +683,7 @@ TEST(SchedulerTest, NoSwapWhenDrawFails) { // Fail to draw, this should not start a frame. client.SetDrawWillHappen(false); client.SetNeedsCommitOnNextDraw(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(2, client.num_draws()); } @@ -736,7 +722,7 @@ TEST(SchedulerTest, ManageTiles) { // We have no immediate actions to perform, so the BeginImplFrame should post // the deadline task. client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -764,7 +750,7 @@ TEST(SchedulerTest, ManageTiles) { // We have no immediate actions to perform, so the BeginImplFrame should post // the deadline task. client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -785,7 +771,7 @@ TEST(SchedulerTest, ManageTiles) { // We need a BeginImplFrame where we don't swap to go idle. client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); client.Reset(); @@ -806,7 +792,7 @@ TEST(SchedulerTest, ManageTiles) { // BeginImplFrame. There will be no draw, only ManageTiles. client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); client.Reset(); @@ -832,7 +818,7 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) { scheduler->SetNeedsManageTiles(); scheduler->SetNeedsRedraw(); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -854,7 +840,7 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) { scheduler->SetNeedsManageTiles(); scheduler->SetNeedsRedraw(); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -877,7 +863,7 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) { scheduler->SetNeedsManageTiles(); scheduler->SetNeedsRedraw(); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -900,7 +886,7 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) { scheduler->SetNeedsManageTiles(); scheduler->SetNeedsRedraw(); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -919,7 +905,7 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) { scheduler->SetNeedsManageTiles(); scheduler->SetNeedsRedraw(); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -955,7 +941,7 @@ TEST(SchedulerTest, ShouldUpdateVisibleTiles) { EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -977,7 +963,7 @@ TEST(SchedulerTest, ShouldUpdateVisibleTiles) { EXPECT_FALSE(scheduler->RedrawPending()); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -988,7 +974,7 @@ TEST(SchedulerTest, ShouldUpdateVisibleTiles) { EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 2, 3); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_SINGLE_ACTION("WillBeginImplFrame", client); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -1010,7 +996,7 @@ TEST(SchedulerTest, TriggerBeginFrameDeadlineEarly) { client.Reset(); scheduler->SetNeedsRedraw(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); // The deadline should be zero since there is no work other than drawing // pending. @@ -1066,7 +1052,7 @@ void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms, client.Reset(); scheduler->SetNeedsCommit(); EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode()); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode()); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); @@ -1078,7 +1064,7 @@ void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms, client.Reset(); scheduler->SetNeedsCommit(); EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode()); client.task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(scheduler->MainThreadIsInHighLatencyMode(), @@ -1135,7 +1121,7 @@ TEST(SchedulerTest, PollForCommitCompletion) { scheduler->NotifyReadyToCommit(); scheduler->SetNeedsRedraw(); - BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting(); + BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting(client.now_src()); frame_args.interval = base::TimeDelta::FromMilliseconds(1000); scheduler->BeginFrame(frame_args); @@ -1167,7 +1153,7 @@ TEST(SchedulerTest, PollForCommitCompletion) { // Does three iterations to make sure that the timer is properly repeating. for (int i = 0; i < 3; ++i) { EXPECT_EQ((frame_args.interval * 2).InMicroseconds(), - client.task_runner().NextPendingTaskDelay().InMicroseconds()) + client.task_runner().DelayToNextTaskTime().InMicroseconds()) << scheduler->AsValue()->ToString(); client.task_runner().RunPendingTasks(); EXPECT_GT(client.num_actions_(), actions_so_far); @@ -1180,7 +1166,7 @@ TEST(SchedulerTest, PollForCommitCompletion) { scheduler->NotifyBeginMainFrameStarted(); for (int i = 0; i < 3; ++i) { EXPECT_EQ((frame_args.interval * 2).InMicroseconds(), - client.task_runner().NextPendingTaskDelay().InMicroseconds()) + client.task_runner().DelayToNextTaskTime().InMicroseconds()) << scheduler->AsValue()->ToString(); client.task_runner().RunPendingTasks(); EXPECT_GT(client.num_actions_(), actions_so_far); @@ -1208,7 +1194,7 @@ TEST(SchedulerTest, BeginRetroFrame) { // Create a BeginFrame with a long deadline to avoid race conditions. // This is the first BeginFrame, which will be handled immediately. - BeginFrameArgs args = CreateBeginFrameArgsForTesting(); + BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src()); args.deadline += base::TimeDelta::FromHours(1); scheduler->BeginFrame(args); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); @@ -1287,7 +1273,7 @@ TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) { // Create a BeginFrame with a long deadline to avoid race conditions. // This is the first BeginFrame, which will be handled immediately. - BeginFrameArgs args = CreateBeginFrameArgsForTesting(); + BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src()); args.deadline += base::TimeDelta::FromHours(1); scheduler->BeginFrame(args); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); @@ -1345,7 +1331,10 @@ TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) { // BeginImplFrame deadline should draw. scheduler->SetNeedsRedraw(); - client.task_runner().RunPendingTasks(); // Run posted deadline. + + EXPECT_TRUE(client.task_runner().RunTasksWhile( + client.ImplFrameDeadlinePending(true))); + EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); @@ -1406,7 +1395,7 @@ void BeginFramesNotFromClient(bool begin_frame_scheduling_enabled, client.Reset(); // BeginImplFrame deadline should draw. - client.task_runner().RunPendingTasks(); // Run posted deadline. + client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true)); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); EXPECT_FALSE(client.needs_begin_frame()); @@ -1427,8 +1416,7 @@ void BeginFramesNotFromClient(bool begin_frame_scheduling_enabled, client.Reset(); } -// See: http://crbug.com/380889 -TEST(SchedulerTest, DISABLED_SyntheticBeginFrames) { +TEST(SchedulerTest, SyntheticBeginFrames) { bool begin_frame_scheduling_enabled = false; bool throttle_frame_production = true; BeginFramesNotFromClient(begin_frame_scheduling_enabled, @@ -1442,8 +1430,7 @@ TEST(SchedulerTest, VSyncThrottlingDisabled) { throttle_frame_production); } -// See: http://crbug.com/380889 -TEST(SchedulerTest, DISABLED_SyntheticBeginFrames_And_VSyncThrottlingDisabled) { +TEST(SchedulerTest, SyntheticBeginFrames_And_VSyncThrottlingDisabled) { bool begin_frame_scheduling_enabled = false; bool throttle_frame_production = false; BeginFramesNotFromClient(begin_frame_scheduling_enabled, @@ -1523,8 +1510,7 @@ void BeginFramesNotFromClient_SwapThrottled(bool begin_frame_scheduling_enabled, client.Reset(); } -// See: http://crbug.com/380889 -TEST(SchedulerTest, DISABLED_SyntheticBeginFrames_SwapThrottled) { +TEST(SchedulerTest, SyntheticBeginFrames_SwapThrottled) { bool begin_frame_scheduling_enabled = false; bool throttle_frame_production = true; BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled, @@ -1538,9 +1524,8 @@ TEST(SchedulerTest, VSyncThrottlingDisabled_SwapThrottled) { throttle_frame_production); } -// See: http://crbug.com/380889 TEST(SchedulerTest, - DISABLED_SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled) { + SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled) { bool begin_frame_scheduling_enabled = false; bool throttle_frame_production = false; BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled, @@ -1580,7 +1565,7 @@ TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStarted) { EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -1619,7 +1604,7 @@ void DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency( EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -1630,13 +1615,17 @@ void DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency( EXPECT_NO_ACTION(client); client.Reset(); - client.task_runner().RunPendingTasks(); // Run posted deadline. + // Run posted deadline. + EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); + client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true)); // OnBeginImplFrameDeadline didn't schedule any actions because main frame is // not yet completed. EXPECT_NO_ACTION(client); + EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); // BeginImplFrame is not started. - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.task_runner().RunUntilTime(client.now_src()->Now() + + base::TimeDelta::FromMilliseconds(10)); EXPECT_NO_ACTION(client); EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending()); @@ -1682,7 +1671,7 @@ void DidLoseOutputSurfaceAfterReadyToCommit(bool impl_side_painting) { EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -1731,7 +1720,7 @@ TEST(SchedulerTest, DidLoseOutputSurfaceAfterSetNeedsManageTiles) { EXPECT_TRUE(client.needs_begin_frame()); client.Reset(); - scheduler->BeginFrame(CreateBeginFrameArgsForTesting()); + client.AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2); EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending()); @@ -1764,7 +1753,7 @@ TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) { // Create a BeginFrame with a long deadline to avoid race conditions. // This is the first BeginFrame, which will be handled immediately. client.Reset(); - BeginFrameArgs args = CreateBeginFrameArgsForTesting(); + BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src()); args.deadline += base::TimeDelta::FromHours(1); scheduler->BeginFrame(args); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); @@ -1823,7 +1812,7 @@ TEST(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) { // Create a BeginFrame with a long deadline to avoid race conditions. // This is the first BeginFrame, which will be handled immediately. client.Reset(); - BeginFrameArgs args = CreateBeginFrameArgsForTesting(); + BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src()); args.deadline += base::TimeDelta::FromHours(1); scheduler->BeginFrame(args); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); @@ -1878,10 +1867,8 @@ TEST(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) { EXPECT_NO_ACTION(client); } -// See: http://crbug.com/380889 -TEST( - SchedulerTest, - DISABLED_StopBeginFrameAfterDidLoseOutputSurfaceWithSyntheticBeginFrameSource) { +TEST(SchedulerTest, + StopBeginFrameAfterDidLoseOutputSurfaceWithSyntheticBeginFrameSource) { FakeSchedulerClient client; SchedulerSettings scheduler_settings; scheduler_settings.begin_frame_scheduling_enabled = false; diff --git a/cc/test/begin_frame_args_test.cc b/cc/test/begin_frame_args_test.cc index 83051b2..137d5e1 100644 --- a/cc/test/begin_frame_args_test.cc +++ b/cc/test/begin_frame_args_test.cc @@ -36,6 +36,22 @@ BeginFrameArgs CreateExpiredBeginFrameArgsForTesting() { BeginFrameArgs::DefaultInterval()); } +BeginFrameArgs CreateBeginFrameArgsForTesting( + scoped_refptr<TestNowSource> now_src) { + base::TimeTicks now = now_src->Now(); + return BeginFrameArgs::Create(now, + now + (BeginFrameArgs::DefaultInterval() / 2), + BeginFrameArgs::DefaultInterval()); +} + +BeginFrameArgs CreateExpiredBeginFrameArgsForTesting( + scoped_refptr<TestNowSource> now_src) { + base::TimeTicks now = now_src->Now(); + return BeginFrameArgs::Create(now, + now - BeginFrameArgs::DefaultInterval(), + BeginFrameArgs::DefaultInterval()); +} + bool operator==(const BeginFrameArgs& lhs, const BeginFrameArgs& rhs) { return (lhs.frame_time == rhs.frame_time) && (lhs.deadline == rhs.deadline) && (lhs.interval == rhs.interval); diff --git a/cc/test/begin_frame_args_test.h b/cc/test/begin_frame_args_test.h index 0ab1daf..1c75c37 100644 --- a/cc/test/begin_frame_args_test.h +++ b/cc/test/begin_frame_args_test.h @@ -9,6 +9,7 @@ #include "base/time/time.h" #include "cc/output/begin_frame_args.h" +#include "cc/test/test_now_source.h" #include "testing/gtest/include/gtest/gtest.h" namespace cc { @@ -21,6 +22,13 @@ BeginFrameArgs CreateBeginFrameArgsForTesting(int64 frame_time, int64 interval); BeginFrameArgs CreateExpiredBeginFrameArgsForTesting(); +// Creates a BeginFrameArgs using the fake Now value stored on the +// OrderSimpleTaskRunner. +BeginFrameArgs CreateBeginFrameArgsForTesting( + scoped_refptr<TestNowSource> now_src); +BeginFrameArgs CreateExpiredBeginFrameArgsForTesting( + scoped_refptr<TestNowSource> now_src); + // gtest helpers -- these *must* be in the same namespace as the types they // operate on. diff --git a/cc/test/ordered_simple_task_runner.cc b/cc/test/ordered_simple_task_runner.cc index 188ffe7..9f7f789 100644 --- a/cc/test/ordered_simple_task_runner.cc +++ b/cc/test/ordered_simple_task_runner.cc @@ -4,38 +4,322 @@ #include "cc/test/ordered_simple_task_runner.h" -#include <algorithm> -#include <deque> +#include <limits> +#include <set> +#include <sstream> +#include <string> +#include <vector> -#include "base/logging.h" +#include "base/auto_reset.h" +#include "base/debug/trace_event.h" +#include "base/debug/trace_event_argument.h" +#include "base/strings/string_number_conversions.h" -namespace { +#define TRACE_TASK(function, task) \ + TRACE_EVENT_INSTANT1( \ + "cc", function, TRACE_EVENT_SCOPE_THREAD, "task", task.AsValue()); -bool TestPendingTaskComparator(const base::TestPendingTask& lhs, - const base::TestPendingTask& rhs) { - return lhs.ShouldRunBefore(rhs); +#define TRACE_TASK_RUN(function, tag, task) + +namespace cc { + +// TestOrderablePendingTask implementation +TestOrderablePendingTask::TestOrderablePendingTask() + : base::TestPendingTask(), + task_id_(TestOrderablePendingTask::task_id_counter++) { } +TestOrderablePendingTask::TestOrderablePendingTask( + const tracked_objects::Location& location, + const base::Closure& task, + base::TimeTicks post_time, + base::TimeDelta delay, + TestNestability nestability) + : base::TestPendingTask(location, task, post_time, delay, nestability), + task_id_(TestOrderablePendingTask::task_id_counter++) { } -namespace cc { +size_t TestOrderablePendingTask::task_id_counter = 0; + +TestOrderablePendingTask::~TestOrderablePendingTask() { +} + +bool TestOrderablePendingTask::operator==( + const TestOrderablePendingTask& other) const { + return task_id_ == other.task_id_; +} + +bool TestOrderablePendingTask::operator<( + const TestOrderablePendingTask& other) const { + if (*this == other) + return false; + + if (GetTimeToRun() == other.GetTimeToRun()) { + return task_id_ < other.task_id_; + } + return ShouldRunBefore(other); +} + +scoped_refptr<base::debug::ConvertableToTraceFormat> +TestOrderablePendingTask::AsValue() const { + scoped_refptr<base::debug::TracedValue> state = + new base::debug::TracedValue(); + AsValueInto(state.get()); + return state; +} -OrderedSimpleTaskRunner::OrderedSimpleTaskRunner() {} +void TestOrderablePendingTask::AsValueInto( + base::debug::TracedValue* state) const { + state->SetInteger("id", task_id_); + state->SetInteger("run_at", GetTimeToRun().ToInternalValue()); + state->SetString("posted_from", location.ToString()); +} + +OrderedSimpleTaskRunner::OrderedSimpleTaskRunner() + : advance_now_(true), + now_src_(TestNowSource::Create(0)), + inside_run_tasks_until_(false) { +} + +OrderedSimpleTaskRunner::OrderedSimpleTaskRunner( + scoped_refptr<TestNowSource> now_src, + bool advance_now) + : advance_now_(advance_now), + now_src_(now_src), + max_tasks_(kAbsoluteMaxTasks), + inside_run_tasks_until_(false) { +} OrderedSimpleTaskRunner::~OrderedSimpleTaskRunner() {} -void OrderedSimpleTaskRunner::RunPendingTasks() { +// base::TestSimpleTaskRunner implementation +bool OrderedSimpleTaskRunner::PostDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + DCHECK(thread_checker_.CalledOnValidThread()); + TestOrderablePendingTask pt( + from_here, task, now_src_->Now(), delay, base::TestPendingTask::NESTABLE); + + TRACE_TASK("OrderedSimpleTaskRunner::PostDelayedTask", pt); + pending_tasks_.insert(pt); + return true; +} + +bool OrderedSimpleTaskRunner::PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + DCHECK(thread_checker_.CalledOnValidThread()); + TestOrderablePendingTask pt(from_here, + task, + now_src_->Now(), + delay, + base::TestPendingTask::NON_NESTABLE); + + TRACE_TASK("OrderedSimpleTaskRunner::PostNonNestableDelayedTask", pt); + pending_tasks_.insert(pt); + return true; +} + +bool OrderedSimpleTaskRunner::RunsTasksOnCurrentThread() const { + DCHECK(thread_checker_.CalledOnValidThread()); + return true; +} + +base::TimeTicks OrderedSimpleTaskRunner::NextTaskTime() { + if (pending_tasks_.size() <= 0) { + return TestNowSource::kAbsoluteMaxNow; + } + + return pending_tasks_.begin()->GetTimeToRun(); +} + +base::TimeDelta OrderedSimpleTaskRunner::DelayToNextTaskTime() { DCHECK(thread_checker_.CalledOnValidThread()); - // Swap with a local variable to avoid re-entrancy problems. - std::deque<base::TestPendingTask> tasks_to_run; - tasks_to_run.swap(pending_tasks_); - std::stable_sort(tasks_to_run.begin(), - tasks_to_run.end(), - TestPendingTaskComparator); - for (std::deque<base::TestPendingTask>::iterator it = tasks_to_run.begin(); - it != tasks_to_run.end(); ++it) { - it->task.Run(); + + if (pending_tasks_.size() <= 0) { + return TestNowSource::kAbsoluteMaxNow - base::TimeTicks(); + } + + base::TimeDelta delay = NextTaskTime() - now_src_->Now(); + if (delay > base::TimeDelta()) + return delay; + return base::TimeDelta(); +} + +const size_t OrderedSimpleTaskRunner::kAbsoluteMaxTasks = + std::numeric_limits<size_t>::max(); + +bool OrderedSimpleTaskRunner::RunTasksWhile( + base::Callback<bool(void)> condition) { + std::vector<base::Callback<bool(void)> > conditions(1); + conditions[0] = condition; + return RunTasksWhile(conditions); +} + +bool OrderedSimpleTaskRunner::RunTasksWhile( + const std::vector<base::Callback<bool(void)> >& conditions) { + TRACE_EVENT2("cc", + "OrderedSimpleTaskRunner::RunPendingTasks", + "this", + AsValue(), + "nested", + inside_run_tasks_until_); + DCHECK(thread_checker_.CalledOnValidThread()); + + if (inside_run_tasks_until_) + return true; + + base::AutoReset<bool> reset_inside_run_tasks_until_(&inside_run_tasks_until_, + true); + + // Make a copy so we can append some extra run checks. + std::vector<base::Callback<bool(void)> > modifiable_conditions(conditions); + + // Provide a timeout base on number of tasks run so this doesn't loop + // forever. + modifiable_conditions.push_back(TaskRunCountBelow(max_tasks_)); + + // If to advance now or not + if (!advance_now_) { + modifiable_conditions.push_back(NowBefore(now_src_->Now())); + } else { + modifiable_conditions.push_back(AdvanceNow()); + } + + while (pending_tasks_.size() > 0) { + // Check if we should continue to run pending tasks. + bool condition_success = true; + for (std::vector<base::Callback<bool(void)> >::iterator it = + modifiable_conditions.begin(); + it != modifiable_conditions.end(); + it++) { + condition_success = it->Run(); + if (!condition_success) + break; + } + + // Conditions could modify the pending task length, so we need to recheck + // that there are tasks to run. + if (!condition_success || pending_tasks_.size() == 0) { + break; + } + + std::set<TestOrderablePendingTask>::iterator task_to_run = + pending_tasks_.begin(); + { + TRACE_EVENT1("cc", + "OrderedSimpleTaskRunner::RunPendingTasks running", + "task", + task_to_run->AsValue()); + task_to_run->task.Run(); + } + + pending_tasks_.erase(task_to_run); + } + + return pending_tasks_.size() > 0; +} + +bool OrderedSimpleTaskRunner::RunPendingTasks() { + return RunTasksWhile(TaskExistedInitially()); +} + +bool OrderedSimpleTaskRunner::RunUntilIdle() { + return RunTasksWhile(std::vector<base::Callback<bool(void)> >()); +} + +bool OrderedSimpleTaskRunner::RunUntilTime(base::TimeTicks time) { + // If we are not auto advancing, force now forward to the time. + if (!advance_now_ && now_src_->Now() < time) + now_src_->SetNow(time); + + // Run tasks + bool result = RunTasksWhile(NowBefore(time)); + + // If the next task is after the stopping time and auto-advancing now, then + // force time to be the stopping time. + if (!result && advance_now_ && now_src_->Now() < time) { + now_src_->SetNow(time); + } + + return result; +} + +bool OrderedSimpleTaskRunner::RunForPeriod(base::TimeDelta period) { + return RunUntilTime(now_src_->Now() + period); +} + +// base::debug tracing functionality +scoped_refptr<base::debug::ConvertableToTraceFormat> +OrderedSimpleTaskRunner::AsValue() const { + scoped_refptr<base::debug::TracedValue> state = + new base::debug::TracedValue(); + AsValueInto(state.get()); + return state; +} + +void OrderedSimpleTaskRunner::AsValueInto( + base::debug::TracedValue* state) const { + state->SetInteger("pending_tasks", pending_tasks_.size()); + for (std::set<TestOrderablePendingTask>::const_iterator it = + pending_tasks_.begin(); + it != pending_tasks_.end(); + ++it) { + state->BeginDictionary( + base::SizeTToString(std::distance(pending_tasks_.begin(), it)).c_str()); + it->AsValueInto(state); + state->EndDictionary(); + } + now_src_->AsValueInto(state); +} + +base::Callback<bool(void)> OrderedSimpleTaskRunner::TaskRunCountBelow( + size_t max_tasks) { + return base::Bind(&OrderedSimpleTaskRunner::TaskRunCountBelowCallback, + max_tasks, + base::Owned(new size_t(0))); +} + +bool OrderedSimpleTaskRunner::TaskRunCountBelowCallback(size_t max_tasks, + size_t* tasks_run) { + return (*tasks_run)++ < max_tasks; +} + +base::Callback<bool(void)> OrderedSimpleTaskRunner::TaskExistedInitially() { + // base::Bind takes a copy of pending_tasks_ + return base::Bind(&OrderedSimpleTaskRunner::TaskExistedInitiallyCallback, + base::Unretained(this), + pending_tasks_); +} + +bool OrderedSimpleTaskRunner::TaskExistedInitiallyCallback( + const std::set<TestOrderablePendingTask>& existing_tasks) { + return existing_tasks.find(*pending_tasks_.begin()) != existing_tasks.end(); +} + +base::Callback<bool(void)> OrderedSimpleTaskRunner::NowBefore( + base::TimeTicks stop_at) { + return base::Bind(&OrderedSimpleTaskRunner::NowBeforeCallback, + base::Unretained(this), + stop_at); +} +bool OrderedSimpleTaskRunner::NowBeforeCallback(base::TimeTicks stop_at) { + return NextTaskTime() <= stop_at; +} + +base::Callback<bool(void)> OrderedSimpleTaskRunner::AdvanceNow() { + return base::Bind(&OrderedSimpleTaskRunner::AdvanceNowCallback, + base::Unretained(this)); +} + +bool OrderedSimpleTaskRunner::AdvanceNowCallback() { + base::TimeTicks next_task_time = NextTaskTime(); + if (now_src_->Now() < next_task_time) { + now_src_->SetNow(next_task_time); } + return true; } } // namespace cc diff --git a/cc/test/ordered_simple_task_runner.h b/cc/test/ordered_simple_task_runner.h index 8850a76..61b5ab05 100644 --- a/cc/test/ordered_simple_task_runner.h +++ b/cc/test/ordered_simple_task_runner.h @@ -5,24 +5,146 @@ #ifndef CC_TEST_ORDERED_SIMPLE_TASK_RUNNER_H_ #define CC_TEST_ORDERED_SIMPLE_TASK_RUNNER_H_ +#include <limits> +#include <set> +#include <vector> + #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/debug/trace_event.h" +#include "base/logging.h" #include "base/test/test_simple_task_runner.h" +#include "cc/test/test_now_source.h" namespace cc { +// Subclass of TestPendingTask which has a unique ID for every task, supports +// being used inside a std::set and has debug tracing support. +class TestOrderablePendingTask : public base::TestPendingTask { + public: + TestOrderablePendingTask(); + TestOrderablePendingTask(const tracked_objects::Location& location, + const base::Closure& task, + base::TimeTicks post_time, + base::TimeDelta delay, + TestNestability nestability); + ~TestOrderablePendingTask(); + + // operators needed by std::set and comparison + bool operator==(const TestOrderablePendingTask& other) const; + bool operator<(const TestOrderablePendingTask& other) const; + + // debug tracing functions + scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const; + void AsValueInto(base::debug::TracedValue* state) const; + + private: + static size_t task_id_counter; + const size_t task_id_; +}; + // This runs pending tasks based on task's post_time + delay. // We should not execute a delayed task sooner than some of the queued tasks // which don't have a delay even though it is queued early. -class OrderedSimpleTaskRunner : public base::TestSimpleTaskRunner { +class OrderedSimpleTaskRunner : public base::SingleThreadTaskRunner { public: OrderedSimpleTaskRunner(); + OrderedSimpleTaskRunner(scoped_refptr<TestNowSource> now_src, + bool advance_now); + + // base::TestSimpleTaskRunner implementation: + virtual bool PostDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) OVERRIDE; + virtual bool PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) OVERRIDE; + + virtual bool RunsTasksOnCurrentThread() const OVERRIDE; + + // Set a maximum number of tasks to run at once. Useful as a timeout to + // prevent infinite task loops. + static const size_t kAbsoluteMaxTasks; + void SetRunTaskLimit(size_t max_tasks) { max_tasks_ = max_tasks; } + void ClearRunTaskLimit() { max_tasks_ = kAbsoluteMaxTasks; } + + // Allow task runner to advance now when running tasks. + void SetAutoAdvanceNowToPendingTasks(bool advance_now) { + advance_now_ = advance_now; + } + + base::TimeTicks NextTaskTime(); + base::TimeDelta DelayToNextTaskTime(); + + // Run tasks while the callback returns true or too many tasks have been run. + // Returns true if there are still pending tasks left. + bool RunTasksWhile(base::Callback<bool(void)> condition); - virtual void RunPendingTasks() OVERRIDE; + // Run tasks while *all* of the callbacks return true or too many tasks have + // been run. Exits on the *first* condition which returns false, skipping + // calling all remaining conditions. Conditions can have side effects, + // including modifying the task queue. + // Returns true if there are still pending tasks left. + bool RunTasksWhile( + const std::vector<base::Callback<bool(void)> >& conditions); + + // Convenience functions to run tasks with common conditions. + + // Run tasks which existed at the start of this call. + // Return code indicates tasks still exist to run. + bool RunPendingTasks(); + // Keep running tasks until no tasks are left. + // Return code indicates tasks still exist to run which also indicates if + // runner reached idle. + bool RunUntilIdle(); + // Keep running tasks until given time period. + // Return code indicates tasks still exist to run. + bool RunUntilTime(base::TimeTicks time); + bool RunForPeriod(base::TimeDelta period); + + // base::debug tracing functionality + scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const; + virtual void AsValueInto(base::debug::TracedValue* state) const; + + // Common conditions to run for, exposed publicly to allow external users to + // use their own combinations. + // ------------------------------------------------------------------------- + + // Keep running until the given number of tasks have run. + // You generally shouldn't use this check as it will cause your tests to fail + // when code is changed adding a new task. It is useful as a "timeout" type + // solution. + base::Callback<bool(void)> TaskRunCountBelow(size_t max_tasks); + + // Keep running until a task which didn't exist initially would run. + base::Callback<bool(void)> TaskExistedInitially(); + + // Stop running tasks when NextTaskTime() >= stop_at + base::Callback<bool(void)> NowBefore(base::TimeTicks stop_at); + + // Advance Now() to the next task to run. + base::Callback<bool(void)> AdvanceNow(); protected: + static bool TaskRunCountBelowCallback(size_t max_tasks, size_t* task_run); + bool TaskExistedInitiallyCallback( + const std::set<TestOrderablePendingTask>& existing_tasks); + bool NowBeforeCallback(base::TimeTicks stop_at); + bool AdvanceNowCallback(); + virtual ~OrderedSimpleTaskRunner(); + base::ThreadChecker thread_checker_; + + bool advance_now_; + scoped_refptr<TestNowSource> now_src_; + + size_t max_tasks_; + + bool inside_run_tasks_until_; + std::set<TestOrderablePendingTask> pending_tasks_; + private: DISALLOW_COPY_AND_ASSIGN(OrderedSimpleTaskRunner); }; diff --git a/cc/test/ordered_simple_task_runner_unittest.cc b/cc/test/ordered_simple_task_runner_unittest.cc index 3fbfd3b..8cafa16 100644 --- a/cc/test/ordered_simple_task_runner_unittest.cc +++ b/cc/test/ordered_simple_task_runner_unittest.cc @@ -5,62 +5,442 @@ #include <string> #include "base/cancelable_callback.h" +#include "base/format_macros.h" #include "base/memory/scoped_ptr.h" #include "base/strings/stringprintf.h" #include "base/test/test_pending_task.h" #include "cc/test/ordered_simple_task_runner.h" #include "testing/gtest/include/gtest/gtest.h" +// We pass EXPECT_TRUE / EXPECT_FALSE macros rather than a boolean as on some +// compilers EXPECT_EQ(false, XXXX) fails to compile as gtest tries to convert +// the false value to null causing a -Werror=conversion-null error. +#define RUN_AND_CHECK_RESULT( \ + tasks_remain_expect_macro, run_func, expected_result) \ + tasks_remain_expect_macro(task_runner_->run_func); \ + EXPECT_EQ(expected_result, executed_tasks_); \ + executed_tasks_ = ""; + +namespace { + +bool ReturnTrue() { + return true; +} + +bool ReturnFalse() { + return false; +} +}; + namespace cc { +TEST(TestOrderablePendingTask, Ordering) { + TestOrderablePendingTask a; + TestOrderablePendingTask b; + TestOrderablePendingTask c; + + EXPECT_EQ(a, a); + EXPECT_EQ(b, b); + EXPECT_EQ(c, c); + EXPECT_LT(a, b); + EXPECT_LT(b, c); + EXPECT_LT(a, c); + + TestOrderablePendingTask a2 = a; + EXPECT_EQ(a, a2); + EXPECT_LT(a2, b); + EXPECT_LT(b, c); + EXPECT_LT(a2, c); +} + class OrderedSimpleTaskRunnerTest : public testing::Test { public: - OrderedSimpleTaskRunnerTest() { - task_runner_ = new OrderedSimpleTaskRunner; + OrderedSimpleTaskRunnerTest() + : now_src_(TestNowSource::Create(base::TimeTicks())) { + task_runner_ = new OrderedSimpleTaskRunner(now_src_, true); } virtual ~OrderedSimpleTaskRunnerTest() {} protected: - void CreateAndPostTask(int task_num, base::TimeDelta delay) { + std::string executed_tasks_; + scoped_refptr<TestNowSource> now_src_; + scoped_refptr<OrderedSimpleTaskRunner> task_runner_; + + void PostTask(int task_num, base::TimeDelta delay) { base::Closure test_task = base::Bind(&OrderedSimpleTaskRunnerTest::Task, base::Unretained(this), task_num); task_runner_->PostDelayedTask(FROM_HERE, test_task, delay); } - void RunAndCheckResult(const std::string expected_result) { - task_runner_->RunPendingTasks(); - EXPECT_EQ(expected_result, executed_tasks_); + void PostTaskWhichPostsInstantTask(int task_num, base::TimeDelta delay) { + base::Closure test_task = + base::Bind(&OrderedSimpleTaskRunnerTest::TaskWhichPostsInstantTask, + base::Unretained(this), + task_num); + task_runner_->PostDelayedTask(FROM_HERE, test_task, delay); } - private: - std::string executed_tasks_; - scoped_refptr<OrderedSimpleTaskRunner> task_runner_; + void PostTaskWhichPostsDelayedTask(int task_num, + base::TimeDelta delay1, + base::TimeDelta delay2) { + base::Closure test_task = + base::Bind(&OrderedSimpleTaskRunnerTest::TaskWhichPostsDelayedTask, + base::Unretained(this), + task_num, + delay2); + task_runner_->PostDelayedTask(FROM_HERE, test_task, delay1); + } + void PostTaskWhichCallsRun(int task_num, base::TimeDelta delay) { + base::Closure test_task = + base::Bind(&OrderedSimpleTaskRunnerTest::TaskWhichCallsRun, + base::Unretained(this), + task_num); + task_runner_->PostDelayedTask(FROM_HERE, test_task, delay); + } + + void PostTaskWhichPostsTaskAgain(int task_num, base::TimeDelta delay) { + base::Closure test_task = + base::Bind(&OrderedSimpleTaskRunnerTest::TaskWhichPostsAgain, + base::Unretained(this), + task_num, + delay); + task_runner_->PostDelayedTask(FROM_HERE, test_task, delay); + } + + private: void Task(int task_num) { if (!executed_tasks_.empty()) executed_tasks_ += " "; - executed_tasks_ += base::StringPrintf("%d", task_num); + executed_tasks_ += + base::StringPrintf("%d(%" PRId64 "ms)", + task_num, + now_src_->Now().ToInternalValue() / + base::Time::kMicrosecondsPerMillisecond); + } + + void TaskWhichPostsInstantTask(int task_num) { + Task(task_num); + PostTask(-task_num, base::TimeDelta()); + } + + void TaskWhichPostsDelayedTask(int task_num, base::TimeDelta delay) { + Task(task_num); + PostTask(-task_num, delay); + } + + void TaskWhichCallsRun(int task_num) { + Task(task_num); + task_runner_->RunPendingTasks(); + } + + void TaskWhichPostsAgain(int task_num, base::TimeDelta delay) { + Task(task_num); + PostTaskWhichPostsTaskAgain(task_num, delay); } DISALLOW_COPY_AND_ASSIGN(OrderedSimpleTaskRunnerTest); }; -TEST_F(OrderedSimpleTaskRunnerTest, BasicOrderingTest) { - CreateAndPostTask(1, base::TimeDelta()); - CreateAndPostTask(2, base::TimeDelta()); - CreateAndPostTask(3, base::TimeDelta()); +TEST_F(OrderedSimpleTaskRunnerTest, SimpleOrderingTest) { + PostTask(1, base::TimeDelta()); + PostTask(2, base::TimeDelta()); + PostTask(3, base::TimeDelta()); + + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "1(0ms) 2(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); + + PostTask(4, base::TimeDelta()); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "4(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, SimpleOrderingTestPostingTasks) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + PostTaskWhichPostsInstantTask(2, base::TimeDelta()); + PostTaskWhichPostsInstantTask(3, base::TimeDelta()); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 2(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunPendingTasks(), "-1(0ms) -2(0ms) -3(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, SimpleOrderingTestPostingDelayedTasks) { + PostTaskWhichPostsDelayedTask( + 1, base::TimeDelta(), base::TimeDelta::FromMilliseconds(1)); + PostTaskWhichPostsDelayedTask( + 2, base::TimeDelta(), base::TimeDelta::FromMilliseconds(1)); + PostTaskWhichPostsDelayedTask( + 3, base::TimeDelta(), base::TimeDelta::FromMilliseconds(1)); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 2(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunPendingTasks(), "-1(1ms) -2(1ms) -3(1ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, + SimpleOrderingTestPostingReordingDelayedTasks) { + PostTaskWhichPostsDelayedTask(1, + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMilliseconds(20)); + PostTaskWhichPostsDelayedTask(2, + base::TimeDelta::FromMilliseconds(2), + base::TimeDelta::FromMilliseconds(5)); + PostTaskWhichPostsDelayedTask(3, + base::TimeDelta::FromMilliseconds(3), + base::TimeDelta::FromMilliseconds(5)); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(1ms) 2(2ms) 3(3ms)"); + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunPendingTasks(), "-2(7ms) -3(8ms) -1(21ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, + SimpleOrderingTestPostingReordingDelayedTasksOverlap) { + PostTaskWhichPostsDelayedTask(1, + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMilliseconds(5)); + PostTaskWhichPostsDelayedTask(2, + base::TimeDelta::FromMilliseconds(5), + base::TimeDelta::FromMilliseconds(10)); + PostTaskWhichPostsDelayedTask(3, + base::TimeDelta::FromMilliseconds(10), + base::TimeDelta::FromMilliseconds(1)); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(1ms) 2(5ms)"); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "-1(6ms) 3(10ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "-3(11ms) -2(15ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, SimpleOrderingTestPostingAndRentrantTasks) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + PostTaskWhichCallsRun(2, base::TimeDelta()); + PostTaskWhichPostsInstantTask(3, base::TimeDelta()); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 2(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "-1(0ms) -3(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, + SimpleOrderingTestPostingDelayedAndRentrantTasks) { + PostTaskWhichPostsDelayedTask( + 1, base::TimeDelta(), base::TimeDelta::FromMilliseconds(1)); + PostTaskWhichCallsRun(2, base::TimeDelta()); + PostTaskWhichPostsDelayedTask( + 3, base::TimeDelta(), base::TimeDelta::FromMilliseconds(1)); - RunAndCheckResult("1 2 3"); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 2(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "-1(1ms) -3(1ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); } TEST_F(OrderedSimpleTaskRunnerTest, OrderingTestWithDelayedTasks) { - CreateAndPostTask(1, base::TimeDelta()); - CreateAndPostTask(2, base::TimeDelta::FromMilliseconds(15)); - CreateAndPostTask(3, base::TimeDelta()); - CreateAndPostTask(4, base::TimeDelta::FromMilliseconds(8)); + PostTask(1, base::TimeDelta()); + PostTask(2, base::TimeDelta::FromMilliseconds(15)); + PostTask(3, base::TimeDelta()); + PostTask(4, base::TimeDelta::FromMilliseconds(8)); + + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunPendingTasks(), "1(0ms) 3(0ms) 4(8ms) 2(15ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, OrderingTestWithDelayedPostingTasks) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + PostTaskWhichPostsInstantTask(2, base::TimeDelta::FromMilliseconds(15)); + PostTaskWhichPostsInstantTask(3, base::TimeDelta()); + PostTaskWhichPostsInstantTask(4, base::TimeDelta::FromMilliseconds(8)); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT( + EXPECT_TRUE, RunPendingTasks(), "-1(0ms) -3(0ms) 4(8ms)"); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "-4(8ms) 2(15ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "-2(15ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, OrderingTestWithDelayedTasksManualNow) { + task_runner_->SetAutoAdvanceNowToPendingTasks(false); + PostTask(1, base::TimeDelta()); + PostTask(2, base::TimeDelta::FromMilliseconds(15)); + PostTask(3, base::TimeDelta()); + PostTask(4, base::TimeDelta::FromMilliseconds(8)); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 3(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), ""); + EXPECT_EQ(task_runner_->DelayToNextTaskTime(), + base::TimeDelta::FromMilliseconds(8)); + now_src_->SetNow(base::TimeTicks::FromInternalValue(5000)); + EXPECT_EQ(task_runner_->DelayToNextTaskTime(), + base::TimeDelta::FromMilliseconds(3)); + now_src_->SetNow(base::TimeTicks::FromInternalValue(25000)); + EXPECT_EQ(task_runner_->DelayToNextTaskTime(), base::TimeDelta()); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), "4(25ms) 2(25ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunUntilIdle) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilIdle(), "1(0ms) -1(0ms)"); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilIdle(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunUntilTimeAutoNow) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + PostTaskWhichPostsInstantTask(2, base::TimeDelta::FromMilliseconds(2)); + PostTaskWhichPostsInstantTask(3, base::TimeDelta::FromMilliseconds(3)); + + task_runner_->SetAutoAdvanceNowToPendingTasks(true); + + base::TimeTicks run_at = base::TimeTicks(); + + run_at += base::TimeDelta::FromMilliseconds(2); + RUN_AND_CHECK_RESULT( + EXPECT_TRUE, RunUntilTime(run_at), "1(0ms) -1(0ms) 2(2ms) -2(2ms)"); + EXPECT_EQ(run_at, now_src_->Now()); + + run_at += base::TimeDelta::FromMilliseconds(1); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilTime(run_at), "3(3ms) -3(3ms)"); + EXPECT_EQ(run_at, now_src_->Now()); + + run_at += base::TimeDelta::FromMilliseconds(1); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilTime(run_at), ""); + EXPECT_EQ(run_at, now_src_->Now()); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunUntilTimeManualNow) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + PostTaskWhichPostsInstantTask(2, base::TimeDelta::FromMilliseconds(2)); + PostTaskWhichPostsInstantTask(3, base::TimeDelta::FromMilliseconds(3)); + + task_runner_->SetAutoAdvanceNowToPendingTasks(false); + + base::TimeTicks run_at = base::TimeTicks(); + + run_at += base::TimeDelta::FromMilliseconds(2); + RUN_AND_CHECK_RESULT( + EXPECT_TRUE, RunUntilTime(run_at), "1(2ms) 2(2ms) -1(2ms) -2(2ms)"); + EXPECT_EQ(run_at, now_src_->Now()); + + run_at += base::TimeDelta::FromMilliseconds(1); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilTime(run_at), "3(3ms) -3(3ms)"); + EXPECT_EQ(run_at, now_src_->Now()); + + run_at += base::TimeDelta::FromMilliseconds(1); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilTime(run_at), ""); + EXPECT_EQ(run_at, now_src_->Now()); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunForPeriod) { + PostTaskWhichPostsInstantTask(1, base::TimeDelta()); + PostTaskWhichPostsInstantTask(2, base::TimeDelta::FromMilliseconds(2)); + PostTaskWhichPostsInstantTask(3, base::TimeDelta::FromMilliseconds(3)); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, + RunForPeriod(base::TimeDelta::FromMilliseconds(2)), + "1(0ms) -1(0ms) 2(2ms) -2(2ms)"); + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromMilliseconds(2), + now_src_->Now()); + + RUN_AND_CHECK_RESULT(EXPECT_FALSE, + RunForPeriod(base::TimeDelta::FromMilliseconds(1)), + "3(3ms) -3(3ms)"); + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromMilliseconds(3), + now_src_->Now()); + + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunForPeriod(base::TimeDelta::FromMilliseconds(1)), ""); + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromMilliseconds(4), + now_src_->Now()); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunTasksWhileWithCallback) { + base::Callback<bool(void)> return_true = base::Bind(&ReturnTrue); + base::Callback<bool(void)> return_false = base::Bind(&ReturnFalse); + + PostTask(1, base::TimeDelta()); + + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunTasksWhile(return_false), ""); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunTasksWhile(return_true), "1(0ms)"); +} + +TEST_F(OrderedSimpleTaskRunnerTest, EmptyTaskList) { + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunPendingTasks(), ""); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilIdle(), ""); + + ASSERT_EQ(base::TimeTicks(), now_src_->Now()); + + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunUntilTime(base::TimeTicks::FromInternalValue(100)), ""); + EXPECT_EQ(base::TimeTicks::FromInternalValue(100), now_src_->Now()); + + RUN_AND_CHECK_RESULT( + EXPECT_FALSE, RunForPeriod(base::TimeDelta::FromInternalValue(100)), ""); + EXPECT_EQ(base::TimeTicks::FromInternalValue(200), now_src_->Now()); + + base::Callback<bool(void)> return_true = base::Bind(&ReturnTrue); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunTasksWhile(return_true), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunPendingTasksTimeout) { + PostTask(1, base::TimeDelta()); + PostTask(2, base::TimeDelta()); + PostTask(3, base::TimeDelta()); + PostTask(4, base::TimeDelta()); + PostTask(5, base::TimeDelta()); + PostTask(6, base::TimeDelta()); + + task_runner_->SetRunTaskLimit(3); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "1(0ms) 2(0ms) 3(0ms)"); + + task_runner_->SetRunTaskLimit(2); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), "4(0ms) 5(0ms)"); + + task_runner_->SetRunTaskLimit(0); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunPendingTasks(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunUntilIdleTimeout) { + PostTaskWhichPostsTaskAgain(1, base::TimeDelta::FromMilliseconds(3)); + + task_runner_->SetRunTaskLimit(3); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunUntilIdle(), "1(3ms) 1(6ms) 1(9ms)"); + + task_runner_->SetRunTaskLimit(2); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunUntilIdle(), "1(12ms) 1(15ms)"); + + task_runner_->SetRunTaskLimit(0); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunUntilIdle(), ""); +} + +TEST_F(OrderedSimpleTaskRunnerTest, RunUntilTimeout) { + base::TimeTicks run_to = base::TimeTicks() + base::TimeDelta::FromSeconds(1); + + PostTask(1, base::TimeDelta::FromMilliseconds(1)); + PostTask(2, base::TimeDelta::FromMilliseconds(2)); + PostTask(3, base::TimeDelta::FromMilliseconds(3)); + PostTask(4, base::TimeDelta::FromMilliseconds(4)); + PostTask(5, base::TimeDelta::FromMilliseconds(5)); + + EXPECT_EQ(base::TimeTicks(), now_src_->Now()); + task_runner_->SetRunTaskLimit(3); + RUN_AND_CHECK_RESULT( + EXPECT_TRUE, RunUntilTime(run_to), "1(1ms) 2(2ms) 3(3ms)"); + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromMilliseconds(3), + now_src_->Now()); + + task_runner_->SetRunTaskLimit(0); + RUN_AND_CHECK_RESULT(EXPECT_TRUE, RunUntilTime(run_to), ""); - RunAndCheckResult("1 3 4 2"); + task_runner_->SetRunTaskLimit(100); + RUN_AND_CHECK_RESULT(EXPECT_FALSE, RunUntilTime(run_to), "4(4ms) 5(5ms)"); + EXPECT_EQ(run_to, now_src_->Now()); } } // namespace cc diff --git a/cc/test/scheduler_test_common.cc b/cc/test/scheduler_test_common.cc index 3b35a54..7001b59 100644 --- a/cc/test/scheduler_test_common.cc +++ b/cc/test/scheduler_test_common.cc @@ -4,6 +4,8 @@ #include "cc/test/scheduler_test_common.h" +#include <string> + #include "base/logging.h" namespace cc { @@ -14,4 +16,50 @@ void FakeTimeSourceClient::OnTimerTick() { base::TimeTicks FakeDelayBasedTimeSource::Now() const { return now_; } +TestDelayBasedTimeSource::TestDelayBasedTimeSource( + scoped_refptr<TestNowSource> now_src, + base::TimeDelta interval, + OrderedSimpleTaskRunner* task_runner) + : DelayBasedTimeSource(interval, task_runner), now_src_(now_src) { +} + +base::TimeTicks TestDelayBasedTimeSource::Now() const { + return now_src_->Now(); +} + +std::string TestDelayBasedTimeSource::TypeString() const { + return "TestDelayBasedTimeSource"; +} + +TestDelayBasedTimeSource::~TestDelayBasedTimeSource() { +} + +TestScheduler::TestScheduler( + scoped_refptr<TestNowSource> now_src, + SchedulerClient* client, + const SchedulerSettings& scheduler_settings, + int layer_tree_host_id, + const scoped_refptr<OrderedSimpleTaskRunner>& test_task_runner) + : Scheduler(client, + scheduler_settings, + layer_tree_host_id, + test_task_runner), + now_src_(now_src), + test_task_runner_(test_task_runner.get()) { + if (!settings_.begin_frame_scheduling_enabled) { + scoped_refptr<DelayBasedTimeSource> time_source = + TestDelayBasedTimeSource::Create( + now_src, VSyncInterval(), test_task_runner_); + synthetic_begin_frame_source_.reset( + new SyntheticBeginFrameSource(this, time_source)); + } +} + +base::TimeTicks TestScheduler::Now() const { + return now_src_->Now(); +} + +TestScheduler::~TestScheduler() { +} + } // namespace cc diff --git a/cc/test/scheduler_test_common.h b/cc/test/scheduler_test_common.h index 596358a..a502336 100644 --- a/cc/test/scheduler_test_common.h +++ b/cc/test/scheduler_test_common.h @@ -5,10 +5,14 @@ #ifndef CC_TEST_SCHEDULER_TEST_COMMON_H_ #define CC_TEST_SCHEDULER_TEST_COMMON_H_ +#include <string> + #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "cc/scheduler/delay_based_time_source.h" +#include "cc/scheduler/scheduler.h" +#include "cc/test/ordered_simple_task_runner.h" #include "testing/gtest/include/gtest/gtest.h" namespace cc { @@ -46,6 +50,76 @@ class FakeDelayBasedTimeSource : public DelayBasedTimeSource { base::TimeTicks now_; }; +class TestDelayBasedTimeSource : public DelayBasedTimeSource { + public: + static scoped_refptr<TestDelayBasedTimeSource> Create( + scoped_refptr<TestNowSource> now_src, + base::TimeDelta interval, + OrderedSimpleTaskRunner* task_runner) { + return make_scoped_refptr( + new TestDelayBasedTimeSource(now_src, interval, task_runner)); + } + + protected: + TestDelayBasedTimeSource(scoped_refptr<TestNowSource> now_src, + base::TimeDelta interval, + OrderedSimpleTaskRunner* task_runner); + + // Overridden from DelayBasedTimeSource + virtual ~TestDelayBasedTimeSource(); + virtual base::TimeTicks Now() const OVERRIDE; + virtual std::string TypeString() const OVERRIDE; + + scoped_refptr<TestNowSource> now_src_; +}; + +class TestScheduler : public Scheduler { + public: + static scoped_ptr<TestScheduler> Create( + scoped_refptr<TestNowSource> now_src, + SchedulerClient* client, + const SchedulerSettings& scheduler_settings, + int layer_tree_host_id) { + // A bunch of tests require Now() to be > BeginFrameArgs::DefaultInterval() + now_src->AdvanceNow(base::TimeDelta::FromMilliseconds(100)); + + scoped_refptr<OrderedSimpleTaskRunner> test_task_runner = + new OrderedSimpleTaskRunner(now_src, true); + return make_scoped_ptr(new TestScheduler(now_src, + client, + scheduler_settings, + layer_tree_host_id, + test_task_runner)); + } + + // Extra test helper functionality + bool IsBeginRetroFrameArgsEmpty() const { + return begin_retro_frame_args_.empty(); + } + + bool IsSyntheticBeginFrameSourceActive() const { + return synthetic_begin_frame_source_->IsActive(); + } + + OrderedSimpleTaskRunner& task_runner() { return *test_task_runner_; } + + virtual ~TestScheduler(); + + protected: + // Overridden from Scheduler. + virtual base::TimeTicks Now() const OVERRIDE; + + private: + TestScheduler(scoped_refptr<TestNowSource> now_src, + SchedulerClient* client, + const SchedulerSettings& scheduler_settings, + int layer_tree_host_id, + const scoped_refptr<OrderedSimpleTaskRunner>& test_task_runner); + + scoped_refptr<TestNowSource> now_src_; + OrderedSimpleTaskRunner* test_task_runner_; +}; + } // namespace cc #endif // CC_TEST_SCHEDULER_TEST_COMMON_H_ diff --git a/cc/test/test_now_source.cc b/cc/test/test_now_source.cc new file mode 100644 index 0000000..2ffb36e --- /dev/null +++ b/cc/test/test_now_source.cc @@ -0,0 +1,125 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <limits> +#include <string> + +#include "cc/test/test_now_source.h" + +namespace cc { + +// TestNowSource::Constructors +scoped_refptr<TestNowSource> TestNowSource::Create() { + return make_scoped_refptr(new TestNowSource()); +} + +scoped_refptr<TestNowSource> TestNowSource::Create(base::TimeTicks initial) { + return make_scoped_refptr(new TestNowSource(initial)); +} + +scoped_refptr<TestNowSource> TestNowSource::Create(int64_t initial) { + return make_scoped_refptr(new TestNowSource(initial)); +} + +TestNowSource::TestNowSource() + : initial_(base::TimeTicks::FromInternalValue(10000)), now_() { + Reset(); +} + +TestNowSource::TestNowSource(base::TimeTicks initial) + : initial_(initial), now_() { + Reset(); +} + +TestNowSource::TestNowSource(int64_t initial) + : initial_(base::TimeTicks::FromInternalValue(initial)), now_() { + Reset(); +} + +TestNowSource::~TestNowSource() { +} + +// TestNowSource actual functionality +void TestNowSource::Reset() { + TRACE_EVENT_INSTANT2("cc", + "TestNowSource::Reset", + TRACE_EVENT_SCOPE_THREAD, + "previous", + now_, + "initial", + initial_); + now_ = initial_; +} + +base::TimeTicks TestNowSource::Now() const { + return now_; +} + +void TestNowSource::SetNow(base::TimeTicks time) { + TRACE_EVENT_INSTANT2("cc", + "TestNowSource::SetNow", + TRACE_EVENT_SCOPE_THREAD, + "previous", + now_, + "new", + time); + DCHECK(time >= now_); // Time should always go forward. + now_ = time; +} + +void TestNowSource::AdvanceNow(base::TimeDelta period) { + TRACE_EVENT_INSTANT2("cc", + "TestNowSource::AdvanceNow", + TRACE_EVENT_SCOPE_THREAD, + "previous", + now_, + "by", + period.ToInternalValue()); + DCHECK(now_ != kAbsoluteMaxNow); + DCHECK(period >= base::TimeDelta()); // Time should always go forward. + now_ += period; +} + +const base::TimeTicks TestNowSource::kAbsoluteMaxNow = + base::TimeTicks::FromInternalValue(std::numeric_limits<int64_t>::max()); + +// TestNowSource::Convenience functions +void TestNowSource::AdvanceNowMicroseconds(int64_t period_in_microseconds) { + AdvanceNow(base::TimeDelta::FromMicroseconds(period_in_microseconds)); +} +void TestNowSource::SetNowMicroseconds(int64_t time_in_microseconds) { + SetNow(base::TimeTicks::FromInternalValue(time_in_microseconds)); +} + +// TestNowSource::Tracing functions +void TestNowSource::AsValueInto(base::debug::TracedValue* state) const { + state->SetInteger("now_in_microseconds", now_.ToInternalValue()); +} + +scoped_refptr<base::debug::ConvertableToTraceFormat> TestNowSource::AsValue() + const { + scoped_refptr<base::debug::TracedValue> state = + new base::debug::TracedValue(); + AsValueInto(state.get()); + return state; +} + +// TestNowSource::Pretty printing functions +std::string TestNowSource::ToString() const { + std::string output("TestNowSource("); + AsValue()->AppendAsTraceFormat(&output); + output += ")"; + return output; +} + +::std::ostream& operator<<(::std::ostream& os, + const scoped_refptr<TestNowSource>& src) { + os << src->ToString(); + return os; +} +void PrintTo(const scoped_refptr<TestNowSource>& src, ::std::ostream* os) { + *os << src; +} + +} // namespace cc diff --git a/cc/test/test_now_source.h b/cc/test/test_now_source.h new file mode 100644 index 0000000..178a56b --- /dev/null +++ b/cc/test/test_now_source.h @@ -0,0 +1,60 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_TEST_TEST_NOW_SOURCE_H_ +#define CC_TEST_TEST_NOW_SOURCE_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/debug/trace_event.h" +#include "base/debug/trace_event_argument.h" +#include "base/logging.h" + +namespace cc { + +class TestNowSource : public base::RefCounted<TestNowSource> { + public: + static scoped_refptr<TestNowSource> Create(); + static scoped_refptr<TestNowSource> Create(int64_t initial); + static scoped_refptr<TestNowSource> Create(base::TimeTicks initial); + + virtual void Reset(); + virtual base::TimeTicks Now() const; + virtual void SetNow(base::TimeTicks time); + virtual void AdvanceNow(base::TimeDelta period); + + // Convenience functions to make it the now source easier to use in unit + // tests. + void AdvanceNowMicroseconds(int64_t period_in_microseconds); + void SetNowMicroseconds(int64_t time_in_microseconds); + + static const base::TimeTicks kAbsoluteMaxNow; + + // Tracing functions + scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const; + void AsValueInto(base::debug::TracedValue* state) const; + std::string ToString() const; + + protected: + TestNowSource(); + explicit TestNowSource(int64_t initial); + explicit TestNowSource(base::TimeTicks initial); + + base::TimeTicks initial_; + base::TimeTicks now_; + + private: + friend class base::RefCounted<TestNowSource>; + virtual ~TestNowSource(); +}; + +// gtest pretty printing functions +void PrintTo(const scoped_refptr<TestNowSource>& src, ::std::ostream* os); +::std::ostream& operator<<(::std::ostream& os, + const scoped_refptr<TestNowSource>& src); + +} // namespace cc + +#endif // CC_TEST_TEST_NOW_SOURCE_H_ |