Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(874)

Unified Diff: content/child/scheduler/worker_scheduler_impl_unittest.cc

Issue 1085863002: Revert of Revert of Add a WorkerScheduler and a WebThreadImplForWorker (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/child/scheduler/worker_scheduler_impl.cc ('k') | content/child/threaded_data_provider.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/child/scheduler/worker_scheduler_impl_unittest.cc
diff --git a/content/child/scheduler/worker_scheduler_impl_unittest.cc b/content/child/scheduler/worker_scheduler_impl_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..eed8f55b3d523a1763a847c993616074643b965a
--- /dev/null
+++ b/content/child/scheduler/worker_scheduler_impl_unittest.cc
@@ -0,0 +1,420 @@
+// Copyright 2015 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 "content/child/scheduler/worker_scheduler_impl.h"
+
+#include "base/callback.h"
+#include "base/strings/stringprintf.h"
+#include "cc/test/ordered_simple_task_runner.h"
+#include "content/child/scheduler/nestable_task_runner_for_test.h"
+#include "content/child/scheduler/scheduler_message_loop_delegate.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::ElementsAreArray;
+
+namespace content {
+
+namespace {
+void NopTask() {
+}
+
+int TimeTicksToIntMs(const base::TimeTicks& time) {
+ return static_cast<int>((time - base::TimeTicks()).InMilliseconds());
+}
+
+void WakeUpTask(std::vector<std::string>* timeline, cc::TestNowSource* clock) {
+ if (timeline) {
+ timeline->push_back(base::StringPrintf(
+ "run WakeUpTask @ %d", TimeTicksToIntMs(clock->Now())));
+ }
+}
+
+void RecordTimelineTask(std::vector<std::string>* timeline,
+ cc::TestNowSource* clock) {
+ timeline->push_back(base::StringPrintf(
+ "run RecordTimelineTask @ %d", TimeTicksToIntMs(clock->Now())));
+}
+
+void AppendToVectorTestTask(std::vector<std::string>* vector,
+ std::string value) {
+ vector->push_back(value);
+}
+
+void AppendToVectorIdleTestTask(std::vector<std::string>* vector,
+ std::string value,
+ base::TimeTicks deadline) {
+ AppendToVectorTestTask(vector, value);
+}
+
+void TimelineIdleTestTask(std::vector<std::string>* timeline,
+ base::TimeTicks deadline) {
+ timeline->push_back(base::StringPrintf("run TimelineIdleTestTask deadline %d",
+ TimeTicksToIntMs(deadline)));
+}
+
+}; // namespace
+
+class WorkerSchedulerImplForTest : public WorkerSchedulerImpl {
+ public:
+ WorkerSchedulerImplForTest(
+ scoped_refptr<NestableSingleThreadTaskRunner> main_task_runner,
+ scoped_refptr<cc::TestNowSource> clock_)
+ : WorkerSchedulerImpl(main_task_runner),
+ clock_(clock_),
+ timeline_(nullptr) {}
+
+ void RecordTimelineEvents(std::vector<std::string>* timeline) {
+ timeline_ = timeline;
+ }
+
+ private:
+ bool CanEnterLongIdlePeriod(
+ base::TimeTicks now,
+ base::TimeDelta* next_long_idle_period_delay_out) override {
+ if (timeline_) {
+ timeline_->push_back(base::StringPrintf("CanEnterLongIdlePeriod @ %d",
+ TimeTicksToIntMs(now)));
+ }
+ return WorkerSchedulerImpl::CanEnterLongIdlePeriod(
+ now, next_long_idle_period_delay_out);
+ }
+
+ void IsNotQuiescent() override {
+ if (timeline_) {
+ timeline_->push_back(base::StringPrintf("IsNotQuiescent @ %d",
+ TimeTicksToIntMs(clock_->Now())));
+ }
+ WorkerSchedulerImpl::IsNotQuiescent();
+ }
+
+ scoped_refptr<cc::TestNowSource> clock_;
+ std::vector<std::string>* timeline_; // NOT OWNED
+};
+
+class WorkerSchedulerImplTest : public testing::Test {
+ public:
+ WorkerSchedulerImplTest()
+ : clock_(cc::TestNowSource::Create(5000)),
+ mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_, true)),
+ nestable_task_runner_(
+ NestableTaskRunnerForTest::Create(mock_task_runner_)),
+ scheduler_(
+ new WorkerSchedulerImplForTest(nestable_task_runner_, clock_)),
+ timeline_(nullptr) {
+ scheduler_->SetTimeSourceForTesting(clock_);
+ }
+
+ ~WorkerSchedulerImplTest() override {}
+
+ void TearDown() override {
+ // Check that all tests stop posting tasks.
+ while (mock_task_runner_->RunUntilIdle()) {
+ }
+ }
+
+ void Init() {
+ scheduler_->Init();
+ default_task_runner_ = scheduler_->DefaultTaskRunner();
+ idle_task_runner_ = scheduler_->IdleTaskRunner();
+ timeline_ = nullptr;
+ }
+
+ void RecordTimelineEvents(std::vector<std::string>* timeline) {
+ timeline_ = timeline;
+ scheduler_->RecordTimelineEvents(timeline);
+ }
+
+ void RunUntilIdle() {
+ if (timeline_) {
+ timeline_->push_back(base::StringPrintf("RunUntilIdle begin @ %d",
+ TimeTicksToIntMs(clock_->Now())));
+ }
+ mock_task_runner_->RunUntilIdle();
+ if (timeline_) {
+ timeline_->push_back(base::StringPrintf("RunUntilIdle end @ %d",
+ TimeTicksToIntMs(clock_->Now())));
+ }
+ }
+
+ void InitAndPostDelayedWakeupTask() {
+ Init();
+ // WorkerSchedulerImpl::Init causes a delayed task to be posted on the
+ // after wakeup control runner. We need a task to wake the system up
+ // AFTER the delay for this has expired.
+ default_task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&WakeUpTask, base::Unretained(timeline_),
+ base::Unretained(clock_.get())),
+ base::TimeDelta::FromMilliseconds(100));
+ }
+
+ // Helper for posting several tasks of specific types. |task_descriptor| is a
+ // string with space delimited task identifiers. The first letter of each
+ // task identifier specifies the task type:
+ // - 'D': Default task
+ // - 'I': Idle task
+ void PostTestTasks(std::vector<std::string>* run_order,
+ const std::string& task_descriptor) {
+ std::istringstream stream(task_descriptor);
+ while (!stream.eof()) {
+ std::string task;
+ stream >> task;
+ switch (task[0]) {
+ case 'D':
+ default_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
+ break;
+ case 'I':
+ idle_task_runner_->PostIdleTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorIdleTestTask, run_order, task));
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+ }
+
+ static base::TimeDelta maximum_idle_period_duration() {
+ return base::TimeDelta::FromMilliseconds(
+ SchedulerHelper::kMaximumIdlePeriodMillis);
+ }
+
+ protected:
+ scoped_refptr<cc::TestNowSource> clock_;
+ // Only one of mock_task_runner_ or message_loop_ will be set.
+ scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
+
+ scoped_refptr<NestableSingleThreadTaskRunner> nestable_task_runner_;
+ scoped_ptr<WorkerSchedulerImplForTest> scheduler_;
+ scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
+ scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
+ std::vector<std::string>* timeline_; // NOT OWNED
+
+ DISALLOW_COPY_AND_ASSIGN(WorkerSchedulerImplTest);
+};
+
+TEST_F(WorkerSchedulerImplTest, TestPostDefaultTask) {
+ InitAndPostDelayedWakeupTask();
+
+ std::vector<std::string> run_order;
+ PostTestTasks(&run_order, "D1 D2 D3 D4");
+
+ RunUntilIdle();
+ EXPECT_THAT(run_order,
+ testing::ElementsAre(std::string("D1"), std::string("D2"),
+ std::string("D3"), std::string("D4")));
+}
+
+TEST_F(WorkerSchedulerImplTest, TestPostIdleTask) {
+ InitAndPostDelayedWakeupTask();
+
+ std::vector<std::string> run_order;
+ PostTestTasks(&run_order, "I1");
+
+ RunUntilIdle();
+ EXPECT_THAT(run_order, testing::ElementsAre(std::string("I1")));
+}
+
+TEST_F(WorkerSchedulerImplTest, TestPostIdleTask_NoWakeup) {
+ Init();
+ std::vector<std::string> run_order;
+ PostTestTasks(&run_order, "I1");
+
+ RunUntilIdle();
+ EXPECT_TRUE(run_order.empty());
+}
+
+TEST_F(WorkerSchedulerImplTest, TestPostDefaultAndIdleTasks) {
+ InitAndPostDelayedWakeupTask();
+
+ std::vector<std::string> run_order;
+ PostTestTasks(&run_order, "I1 D2 D3 D4");
+
+ RunUntilIdle();
+ EXPECT_THAT(run_order,
+ testing::ElementsAre(std::string("D2"), std::string("D3"),
+ std::string("D4"), std::string("I1")));
+}
+
+TEST_F(WorkerSchedulerImplTest, TestPostIdleTaskWithWakeupNeeded_NoWakeup) {
+ InitAndPostDelayedWakeupTask();
+
+ RunUntilIdle();
+ // The delayed call to EnableLongIdlePeriod happened and it posted a call to
+ // EnableLongIdlePeriod on the after wakeup control queue.
+
+ std::vector<std::string> run_order;
+ PostTestTasks(&run_order, "I1");
+
+ RunUntilIdle();
+ EXPECT_TRUE(run_order.empty());
+}
+
+TEST_F(WorkerSchedulerImplTest, TestPostDefaultDelayedAndIdleTasks) {
+ InitAndPostDelayedWakeupTask();
+
+ std::vector<std::string> run_order;
+ PostTestTasks(&run_order, "I1 D2 D3 D4");
+
+ default_task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "DELAYED"),
+ base::TimeDelta::FromMilliseconds(1000));
+
+ RunUntilIdle();
+ EXPECT_THAT(run_order,
+ testing::ElementsAre(std::string("D2"), std::string("D3"),
+ std::string("D4"), std::string("I1"),
+ std::string("DELAYED")));
+}
+
+TEST_F(WorkerSchedulerImplTest, TestIdleDeadlineWithPendingDelayedTask) {
+ std::vector<std::string> timeline;
+ RecordTimelineEvents(&timeline);
+ InitAndPostDelayedWakeupTask();
+
+ timeline.push_back("Post delayed and idle tasks");
+ // Post a delayed task timed to occur mid way during the long idle period.
+ default_task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline),
+ base::Unretained(clock_.get())),
+ base::TimeDelta::FromMilliseconds(420));
+ idle_task_runner_->PostIdleTask(FROM_HERE,
+ base::Bind(&TimelineIdleTestTask, &timeline));
+
+ RunUntilIdle();
+
+ std::string expected_timeline[] = {
+ "CanEnterLongIdlePeriod @ 5",
+ "Post delayed and idle tasks",
+ "IsNotQuiescent @ 105",
+ "CanEnterLongIdlePeriod @ 405",
+ "run TimelineIdleTestTask deadline 425", // Note the short 20ms deadline.
+ "CanEnterLongIdlePeriod @ 425",
+ "run RecordTimelineTask @ 425"};
+
+ EXPECT_THAT(timeline, ElementsAreArray(expected_timeline));
+}
+
+TEST_F(WorkerSchedulerImplTest,
+ TestIdleDeadlineWithPendingDelayedTaskFarInTheFuture) {
+ std::vector<std::string> timeline;
+ RecordTimelineEvents(&timeline);
+ InitAndPostDelayedWakeupTask();
+
+ timeline.push_back("Post delayed and idle tasks");
+ // Post a delayed task timed to occur well after the long idle period.
+ default_task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline),
+ base::Unretained(clock_.get())),
+ base::TimeDelta::FromMilliseconds(1000));
+ idle_task_runner_->PostIdleTask(FROM_HERE,
+ base::Bind(&TimelineIdleTestTask, &timeline));
+
+ RunUntilIdle();
+
+ std::string expected_timeline[] = {
+ "CanEnterLongIdlePeriod @ 5",
+ "Post delayed and idle tasks",
+ "IsNotQuiescent @ 105",
+ "CanEnterLongIdlePeriod @ 405",
+ "run TimelineIdleTestTask deadline 455", // Note the full 50ms deadline.
+ "CanEnterLongIdlePeriod @ 455",
+ "run RecordTimelineTask @ 1005"};
+
+ EXPECT_THAT(timeline, ElementsAreArray(expected_timeline));
+}
+
+TEST_F(WorkerSchedulerImplTest,
+ TestPostIdleTaskAfterRunningUntilIdle_NoWakeUp) {
+ InitAndPostDelayedWakeupTask();
+
+ default_task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&NopTask), base::TimeDelta::FromMilliseconds(1000));
+ RunUntilIdle();
+
+ // The delayed call to EnableLongIdlePeriod happened and it posted a call to
+ // EnableLongIdlePeriod on the after wakeup control queue. Without an other
+ // non-idle task posted, the idle tasks won't run.
+ std::vector<std::string> run_order;
+ PostTestTasks(&run_order, "I1 I2");
+
+ RunUntilIdle();
+ EXPECT_TRUE(run_order.empty());
+}
+
+TEST_F(WorkerSchedulerImplTest,
+ TestPostIdleTaskAfterRunningUntilIdle_WithWakeUp) {
+ InitAndPostDelayedWakeupTask();
+
+ default_task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&NopTask), base::TimeDelta::FromMilliseconds(1000));
+ RunUntilIdle();
+ // The delayed call to EnableLongIdlePeriod happened and it posted a call to
+ // EnableLongIdlePeriod on the after wakeup control queue. Without an other
+ // non-idle task posted, the idle tasks won't run.
+
+ std::vector<std::string> run_order;
+ PostTestTasks(&run_order, "I1 I2 D3");
+
+ RunUntilIdle();
+ EXPECT_THAT(run_order,
+ testing::ElementsAre(std::string("D3"), std::string("I1"),
+ std::string("I2")));
+}
+
+TEST_F(WorkerSchedulerImplTest, TestLongIdlePeriodTimeline) {
+ Init();
+
+ std::vector<std::string> timeline;
+ RecordTimelineEvents(&timeline);
+
+ // The scheduler should not run the initiate_next_long_idle_period task if
+ // there are no idle tasks and no other task woke up the scheduler, thus
+ // the idle period deadline shouldn't update at the end of the current long
+ // idle period.
+ base::TimeTicks idle_period_deadline =
+ scheduler_->CurrentIdleTaskDeadlineForTesting();
+ clock_->AdvanceNow(maximum_idle_period_duration());
+ RunUntilIdle();
+
+ base::TimeTicks new_idle_period_deadline =
+ scheduler_->CurrentIdleTaskDeadlineForTesting();
+ EXPECT_EQ(idle_period_deadline, new_idle_period_deadline);
+
+ // Posting a after-wakeup idle task also shouldn't wake the scheduler or
+ // initiate the next long idle period.
+ timeline.push_back("PostIdleTaskAfterWakeup");
+ idle_task_runner_->PostIdleTaskAfterWakeup(
+ FROM_HERE, base::Bind(&TimelineIdleTestTask, &timeline));
+ RunUntilIdle();
+ new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting();
+
+ // Running a normal task should initiate a new long idle period after waiting
+ // 300ms for quiescence.
+ timeline.push_back("Post RecordTimelineTask");
+ default_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline),
+ base::Unretained(clock_.get())));
+ RunUntilIdle();
+
+ std::string expected_timeline[] = {
+ "RunUntilIdle begin @ 55",
+ "RunUntilIdle end @ 55",
+ "PostIdleTaskAfterWakeup",
+ "RunUntilIdle begin @ 55", // NOTE idle task doesn't run till later.
+ "RunUntilIdle end @ 55",
+ "Post RecordTimelineTask",
+ "RunUntilIdle begin @ 55",
+ "run RecordTimelineTask @ 55",
+ "IsNotQuiescent @ 55", // NOTE we have to wait for quiescence.
+ "CanEnterLongIdlePeriod @ 355",
+ "run TimelineIdleTestTask deadline 405",
+ "CanEnterLongIdlePeriod @ 405",
+ "RunUntilIdle end @ 455"};
+
+ EXPECT_THAT(timeline, ElementsAreArray(expected_timeline));
+}
+
+} // namespace content
« no previous file with comments | « content/child/scheduler/worker_scheduler_impl.cc ('k') | content/child/threaded_data_provider.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698