Commit 0c0ac6a1 authored by mithro's avatar mithro Committed by Commit bot

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}
parent dc6bae3b
......@@ -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",
......
......@@ -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',
......
......@@ -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());
......
......@@ -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_;
}
......
......@@ -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;
......
......@@ -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);
......
......@@ -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.
......
......@@ -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
......@@ -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);
};
......
......@@ -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
......@@ -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
......@@ -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_
// 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
// 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_
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