summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormithro <mithro@mithis.com>2014-09-09 18:03:36 -0700
committerCommit bot <commit-bot@chromium.org>2014-09-10 01:18:39 +0000
commit0c0ac6a1616778e3852e3f8b3248688ca9d899b2 (patch)
tree0f79cee120a2dbaba414e6828ce555f14b0f0c7c
parentdc6bae3bdc5154b73600a1180c0a82859b271a3f (diff)
downloadchromium_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.gn2
-rw-r--r--cc/cc_tests.gyp2
-rw-r--r--cc/scheduler/scheduler.cc44
-rw-r--r--cc/scheduler/scheduler.h8
-rw-r--r--cc/scheduler/scheduler_unittest.cc215
-rw-r--r--cc/test/begin_frame_args_test.cc16
-rw-r--r--cc/test/begin_frame_args_test.h8
-rw-r--r--cc/test/ordered_simple_task_runner.cc322
-rw-r--r--cc/test/ordered_simple_task_runner.h126
-rw-r--r--cc/test/ordered_simple_task_runner_unittest.cc420
-rw-r--r--cc/test/scheduler_test_common.cc48
-rw-r--r--cc/test/scheduler_test_common.h74
-rw-r--r--cc/test/test_now_source.cc125
-rw-r--r--cc/test/test_now_source.h60
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_