Revert of Move throttling of background timers into the renderer scheduler (patchset #16 id:300001 of https://codereview.chromium.org/1441073006/ )
Reason for revert:
Oops I'd meant to upload one final patchset before committing.
Original issue's description:
> Move throttling of background timers into the renderer scheduler
>
> Not only does this simplify the code, it's more efficent since
> previously setting the timer alignment resulted in mass cancellation
> and reposting of timers.
>
> BUG=510398, 546953, 560402
>
> Committed: https://crrev.com/ec5adec0a9879a31866e98c65ddc7b506b9f49c3
> Cr-Commit-Position: refs/heads/master@{#361971}
[email protected],[email protected]
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=510398, 546953, 560402
Review URL: https://codereview.chromium.org/1477353002
Cr-Commit-Position: refs/heads/master@{#361972}
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 2b9f6c9..14194f6 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -619,7 +619,6 @@
'scheduler/renderer/renderer_scheduler_impl_unittest.cc',
'scheduler/renderer/render_widget_signals_unittest.cpp',
'scheduler/renderer/task_cost_estimator_unittest.cc',
- 'scheduler/renderer/throttling_helper_unittest.cc',
'scheduler/renderer/user_model_unittest.cc',
'scheduler/renderer/web_view_scheduler_impl_unittest.cc',
'scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc',
diff --git a/components/scheduler/BUILD.gn b/components/scheduler/BUILD.gn
index c1070f1..5031a61 100644
--- a/components/scheduler/BUILD.gn
+++ b/components/scheduler/BUILD.gn
@@ -62,7 +62,6 @@
"renderer/render_widget_signals_unittest.cpp",
"renderer/renderer_scheduler_impl_unittest.cc",
"renderer/task_cost_estimator_unittest.cc",
- "renderer/throttling_helper_unittest.cc",
"renderer/user_model_unittest.cc",
"renderer/web_view_scheduler_impl_unittest.cc",
"renderer/webthread_impl_for_renderer_scheduler_unittest.cc",
diff --git a/components/scheduler/base/real_time_domain.cc b/components/scheduler/base/real_time_domain.cc
index d894eca..c3b4505 100644
--- a/components/scheduler/base/real_time_domain.cc
+++ b/components/scheduler/base/real_time_domain.cc
@@ -10,7 +10,7 @@
namespace scheduler {
-RealTimeDomain::RealTimeDomain() : TimeDomain(nullptr), weak_factory_(this) {}
+RealTimeDomain::RealTimeDomain() : weak_factory_(this) {}
RealTimeDomain::~RealTimeDomain() {}
diff --git a/components/scheduler/base/real_time_domain.h b/components/scheduler/base/real_time_domain.h
index 82525637..f382fad 100644
--- a/components/scheduler/base/real_time_domain.h
+++ b/components/scheduler/base/real_time_domain.h
@@ -17,7 +17,6 @@
class SCHEDULER_EXPORT RealTimeDomain : public TimeDomain {
public:
RealTimeDomain();
- ~RealTimeDomain() override;
// TimeDomain implementation:
LazyNow CreateLazyNow() override;
@@ -41,6 +40,8 @@
base::Closure do_work_closure_;
base::WeakPtrFactory<RealTimeDomain> weak_factory_;
+ ~RealTimeDomain() override;
+
DISALLOW_COPY_AND_ASSIGN(RealTimeDomain);
};
diff --git a/components/scheduler/base/task_queue.cc b/components/scheduler/base/task_queue.cc
index 24aadb7..85786055 100644
--- a/components/scheduler/base/task_queue.cc
+++ b/components/scheduler/base/task_queue.cc
@@ -6,9 +6,8 @@
namespace scheduler {
-bool TaskQueue::HasPendingImmediateTask() const {
- QueueState state = GetQueueState();
- return state == QueueState::NEEDS_PUMPING || state == QueueState::HAS_WORK;
+bool TaskQueue::IsQueueEmpty() const {
+ return GetQueueState() == QueueState::EMPTY;
}
} // namespace scheduler
diff --git a/components/scheduler/base/task_queue.h b/components/scheduler/base/task_queue.h
index fbbbc25..393cc50 100644
--- a/components/scheduler/base/task_queue.h
+++ b/components/scheduler/base/task_queue.h
@@ -20,6 +20,12 @@
// the TaskQueueManager's reference to it will be released soon.
virtual void UnregisterTaskQueue() = 0;
+ // Post a delayed task at an absolute desired run time instead of a time
+ // delta from the current time.
+ virtual bool PostDelayedTaskAt(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeTicks desired_run_time) = 0;
+
enum QueuePriority {
// Queues with control priority will run before any other queue, and will
// explicitly starve other queues. Typically this should only be used for
@@ -85,9 +91,6 @@
// A queue in the HAS_WORK state has tasks in the work task queue which
// are runnable.
HAS_WORK,
- // The work and incomming queues are empty but there is delayed work
- // scheduled.
- NO_IMMEDIATE_WORK,
};
// Options for constructing a TaskQueue. Once set the |name|,
@@ -142,11 +145,10 @@
virtual bool IsQueueEnabled() const = 0;
// Returns true if there no tasks in either the work or incoming task queue.
- // This method ignores delayed tasks that are scheduled to run in the future.
// Note that this function involves taking a lock, so calling it has some
// overhead. NOTE this must be called on the thread this TaskQueue was created
// by.
- virtual bool HasPendingImmediateTask() const;
+ virtual bool IsQueueEmpty() const;
// Returns the QueueState. Note that this function involves taking a lock, so
// calling it has some overhead.
@@ -181,7 +183,7 @@
// Removes the task queue from the previous TimeDomain and adds it to
// |domain|. This is a moderately expensive operation.
- virtual void SetTimeDomain(TimeDomain* domain) = 0;
+ virtual void SetTimeDomain(const scoped_refptr<TimeDomain>& domain) = 0;
protected:
~TaskQueue() override {}
diff --git a/components/scheduler/base/task_queue_impl.cc b/components/scheduler/base/task_queue_impl.cc
index 14b6c314..0ad965b 100644
--- a/components/scheduler/base/task_queue_impl.cc
+++ b/components/scheduler/base/task_queue_impl.cc
@@ -13,7 +13,7 @@
TaskQueueImpl::TaskQueueImpl(
TaskQueueManager* task_queue_manager,
- TimeDomain* time_domain,
+ const scoped_refptr<TimeDomain>& time_domain,
const Spec& spec,
const char* disabled_by_default_tracing_category,
const char* disabled_by_default_verbose_tracing_category)
@@ -28,15 +28,10 @@
wakeup_policy_(spec.wakeup_policy),
should_monitor_quiescence_(spec.should_monitor_quiescence),
should_notify_observers_(spec.should_notify_observers) {
- DCHECK(time_domain);
- time_domain->RegisterQueue(this);
+ DCHECK(time_domain.get());
}
-TaskQueueImpl::~TaskQueueImpl() {
- base::AutoLock lock(any_thread_lock_);
- if (any_thread().time_domain)
- any_thread().time_domain->UnregisterQueue(this);
-}
+TaskQueueImpl::~TaskQueueImpl() {}
TaskQueueImpl::Task::Task()
: PendingTask(tracked_objects::Location(),
@@ -62,9 +57,10 @@
sequence_num = sequence_number;
}
-TaskQueueImpl::AnyThread::AnyThread(TaskQueueManager* task_queue_manager,
- PumpPolicy pump_policy,
- TimeDomain* time_domain)
+TaskQueueImpl::AnyThread::AnyThread(
+ TaskQueueManager* task_queue_manager,
+ PumpPolicy pump_policy,
+ const scoped_refptr<TimeDomain>& time_domain)
: task_queue_manager(task_queue_manager),
pump_policy(pump_policy),
time_domain(time_domain) {}
@@ -82,8 +78,7 @@
base::AutoLock lock(any_thread_lock_);
if (!any_thread().task_queue_manager)
return;
- if (any_thread().time_domain)
- any_thread().time_domain->UnregisterQueue(this);
+ any_thread().time_domain->UnregisterQueue(this);
any_thread().time_domain = nullptr;
any_thread().task_queue_manager->UnregisterTaskQueue(this);
@@ -112,6 +107,18 @@
return PostDelayedTaskImpl(from_here, task, delay, TaskType::NON_NESTABLE);
}
+bool TaskQueueImpl::PostDelayedTaskAt(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeTicks desired_run_time) {
+ base::AutoLock lock(any_thread_lock_);
+ if (!any_thread().task_queue_manager)
+ return false;
+ LazyNow lazy_now(any_thread().time_domain->CreateLazyNow());
+ return PostDelayedTaskLocked(&lazy_now, from_here, task, desired_run_time,
+ TaskType::NORMAL);
+}
+
bool TaskQueueImpl::PostDelayedTaskImpl(
const tracked_objects::Location& from_here,
const base::Closure& task,
@@ -169,8 +176,9 @@
return true;
}
-void TaskQueueImpl::ScheduleDelayedWorkTask(TimeDomain* time_domain,
- base::TimeTicks desired_run_time) {
+void TaskQueueImpl::ScheduleDelayedWorkTask(
+ const scoped_refptr<TimeDomain> time_domain,
+ base::TimeTicks desired_run_time) {
DCHECK(main_thread_checker_.CalledOnValidThread());
LazyNow lazy_now(time_domain->CreateLazyNow());
time_domain->ScheduleDelayedWork(this, desired_run_time, &lazy_now);
@@ -211,15 +219,13 @@
{
base::AutoLock lock(any_thread_lock_);
if (any_thread().incoming_queue.empty()) {
- if (any_thread().delayed_task_queue.empty())
- return QueueState::EMPTY;
- else
- return QueueState::NO_IMMEDIATE_WORK;
+ return QueueState::EMPTY;
} else {
return QueueState::NEEDS_PUMPING;
}
}
}
+
bool TaskQueueImpl::TaskIsOlderThanQueuedTasks(const Task* task) {
// A null task is passed when UpdateQueue is called before any task is run.
// In this case we don't want to pump an after_wakeup queue, so return true
@@ -499,14 +505,14 @@
DidProcessTask(pending_task));
}
-void TaskQueueImpl::SetTimeDomain(TimeDomain* time_domain) {
+void TaskQueueImpl::SetTimeDomain(
+ const scoped_refptr<TimeDomain>& time_domain) {
base::AutoLock lock(any_thread_lock_);
DCHECK(main_thread_checker_.CalledOnValidThread());
if (time_domain == any_thread().time_domain)
return;
- if (time_domain)
- any_thread().time_domain->MigrateQueue(this, time_domain);
+ any_thread().time_domain->MigrateQueue(this, time_domain.get());
any_thread().time_domain = time_domain;
}
diff --git a/components/scheduler/base/task_queue_impl.h b/components/scheduler/base/task_queue_impl.h
index aa846394..1f130e124 100644
--- a/components/scheduler/base/task_queue_impl.h
+++ b/components/scheduler/base/task_queue_impl.h
@@ -23,7 +23,7 @@
class SCHEDULER_EXPORT TaskQueueImpl final : public TaskQueue {
public:
TaskQueueImpl(TaskQueueManager* task_queue_manager,
- TimeDomain* time_domain,
+ const scoped_refptr<TimeDomain>& time_domain,
const Spec& spec,
const char* disabled_by_default_tracing_category,
const char* disabled_by_default_verbose_tracing_category);
@@ -70,6 +70,9 @@
bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) override;
+ bool PostDelayedTaskAt(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeTicks desired_run_time) override;
bool IsQueueEnabled() const override;
QueueState GetQueueState() const override;
@@ -79,7 +82,7 @@
void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override;
void RemoveTaskObserver(
base::MessageLoop::TaskObserver* task_observer) override;
- void SetTimeDomain(TimeDomain* time_domain) override;
+ void SetTimeDomain(const scoped_refptr<TimeDomain>& time_domain) override;
void UpdateWorkQueue(LazyNow* lazy_now,
bool should_trigger_wakeup,
@@ -151,7 +154,7 @@
struct AnyThread {
AnyThread(TaskQueueManager* task_queue_manager,
PumpPolicy pump_policy,
- TimeDomain* time_domain);
+ const scoped_refptr<TimeDomain>& time_domain);
~AnyThread();
// TaskQueueManager is maintained in two copies: inside AnyThread and inside
@@ -162,7 +165,7 @@
std::queue<Task> incoming_queue;
PumpPolicy pump_policy;
std::priority_queue<Task> delayed_task_queue;
- TimeDomain* time_domain;
+ scoped_refptr<TimeDomain> time_domain;
};
struct MainThreadOnly {
@@ -189,7 +192,7 @@
const base::Closure& task,
base::TimeTicks desired_run_time,
TaskType task_type);
- void ScheduleDelayedWorkTask(TimeDomain* time_domain,
+ void ScheduleDelayedWorkTask(const scoped_refptr<TimeDomain> time_domain,
base::TimeTicks desired_run_time);
// Enqueues any delayed tasks which should be run now on the incoming_queue_.
diff --git a/components/scheduler/base/task_queue_manager.cc b/components/scheduler/base/task_queue_manager.cc
index ec478db..b9df8756 100644
--- a/components/scheduler/base/task_queue_manager.cc
+++ b/components/scheduler/base/task_queue_manager.cc
@@ -21,8 +21,7 @@
const char* tracing_category,
const char* disabled_by_default_tracing_category,
const char* disabled_by_default_verbose_tracing_category)
- : real_time_domain_(new RealTimeDomain()),
- delegate_(delegate),
+ : delegate_(delegate),
task_was_run_on_quiescence_monitored_queue_(false),
pending_dowork_count_(0),
work_batch_size_(1),
@@ -45,7 +44,8 @@
base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), false);
// TODO(alexclarke): Change this to be a parameter that's passed in.
- RegisterTimeDomain(real_time_domain_.get());
+ real_time_domain_ = make_scoped_refptr(new RealTimeDomain());
+ RegisterTimeDomain(real_time_domain_);
}
TaskQueueManager::~TaskQueueManager() {
@@ -58,13 +58,15 @@
selector_.SetTaskQueueSelectorObserver(nullptr);
}
-void TaskQueueManager::RegisterTimeDomain(TimeDomain* time_domain) {
+void TaskQueueManager::RegisterTimeDomain(
+ const scoped_refptr<TimeDomain>& time_domain) {
time_domains_.insert(time_domain);
time_domain->OnRegisterWithTaskQueueManager(delegate_.get(),
do_work_closure_);
}
-void TaskQueueManager::UnregisterTimeDomain(TimeDomain* time_domain) {
+void TaskQueueManager::UnregisterTimeDomain(
+ const scoped_refptr<TimeDomain>& time_domain) {
time_domains_.erase(time_domain);
}
@@ -75,7 +77,8 @@
DCHECK(main_thread_checker_.CalledOnValidThread());
TimeDomain* time_domain =
spec.time_domain ? spec.time_domain : real_time_domain_.get();
- DCHECK(time_domains_.find(time_domain) != time_domains_.end());
+ DCHECK(time_domains_.find(make_scoped_refptr(time_domain)) !=
+ time_domains_.end());
scoped_refptr<internal::TaskQueueImpl> queue(
make_scoped_refptr(new internal::TaskQueueImpl(
this, time_domain, spec, disabled_by_default_tracing_category_,
@@ -112,7 +115,7 @@
TRACE_EVENT0(disabled_by_default_tracing_category_,
"TaskQueueManager::UpdateWorkQueues");
- for (TimeDomain* time_domain : time_domains_) {
+ for (const scoped_refptr<TimeDomain>& time_domain : time_domains_) {
time_domain->UpdateWorkQueues(should_trigger_wakeup, previous_task);
}
}
@@ -186,7 +189,7 @@
bool TaskQueueManager::TryAdvanceTimeDomains() {
bool can_advance = false;
- for (TimeDomain* time_domain : time_domains_) {
+ for (const scoped_refptr<TimeDomain>& time_domain : time_domains_) {
can_advance |= time_domain->MaybeAdvanceTime();
}
return can_advance;
diff --git a/components/scheduler/base/task_queue_manager.h b/components/scheduler/base/task_queue_manager.h
index f7090bd..f6af854 100644
--- a/components/scheduler/base/task_queue_manager.h
+++ b/components/scheduler/base/task_queue_manager.h
@@ -100,10 +100,12 @@
const scoped_refptr<TaskQueueManagerDelegate>& delegate() const;
// Time domains must be registered for the task queues to get updated.
- void RegisterTimeDomain(TimeDomain* time_domain);
- void UnregisterTimeDomain(TimeDomain* time_domain);
+ void RegisterTimeDomain(const scoped_refptr<TimeDomain>& time_domain);
+ void UnregisterTimeDomain(const scoped_refptr<TimeDomain>& time_domain);
- RealTimeDomain* real_time_domain() const { return real_time_domain_.get(); }
+ const scoped_refptr<RealTimeDomain>& real_time_domain() const {
+ return real_time_domain_;
+ }
private:
friend class LazyNow;
@@ -174,8 +176,8 @@
AsValueWithSelectorResult(bool should_run,
internal::TaskQueueImpl* selected_queue) const;
- std::set<TimeDomain*> time_domains_;
- scoped_ptr<RealTimeDomain> real_time_domain_;
+ std::set<scoped_refptr<TimeDomain>> time_domains_;
+ scoped_refptr<RealTimeDomain> real_time_domain_;
std::set<scoped_refptr<internal::TaskQueueImpl>> queues_;
@@ -210,6 +212,7 @@
Observer* observer_; // NOT OWNED
scoped_refptr<DeletionSentinel> deletion_sentinel_;
+ scoped_refptr<TimeDomain> time_domain_;
base::WeakPtrFactory<TaskQueueManager> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(TaskQueueManager);
diff --git a/components/scheduler/base/task_queue_manager_unittest.cc b/components/scheduler/base/task_queue_manager_unittest.cc
index f1d9dc4..251ac56 100644
--- a/components/scheduler/base/task_queue_manager_unittest.cc
+++ b/components/scheduler/base/task_queue_manager_unittest.cc
@@ -216,12 +216,12 @@
Initialize(1u);
std::vector<int> run_order;
- EXPECT_FALSE(runners_[0]->HasPendingImmediateTask());
+ EXPECT_TRUE(runners_[0]->IsQueueEmpty());
runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
- EXPECT_TRUE(runners_[0]->HasPendingImmediateTask());
+ EXPECT_FALSE(runners_[0]->IsQueueEmpty());
test_task_runner_->RunUntilIdle();
- EXPECT_FALSE(runners_[0]->HasPendingImmediateTask());
+ EXPECT_TRUE(runners_[0]->IsQueueEmpty());
}
TEST_F(TaskQueueManagerTest, DelayedTaskPosting) {
@@ -232,8 +232,7 @@
runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
delay);
EXPECT_EQ(delay, test_task_runner_->DelayToNextTaskTime());
- EXPECT_EQ(TaskQueue::QueueState::NO_IMMEDIATE_WORK,
- runners_[0]->GetQueueState());
+ EXPECT_TRUE(runners_[0]->IsQueueEmpty());
EXPECT_TRUE(run_order.empty());
// The task doesn't run before the delay has completed.
@@ -243,7 +242,6 @@
// After the delay has completed, the task runs normally.
test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(1));
EXPECT_THAT(run_order, ElementsAre(1));
- EXPECT_EQ(TaskQueue::QueueState::EMPTY, runners_[0]->GetQueueState());
}
bool MessageLoopTaskCounter(size_t* count) {
@@ -377,7 +375,7 @@
EXPECT_FALSE(test_task_runner_->HasPendingTasks());
// However polling still works.
- EXPECT_TRUE(runners_[0]->HasPendingImmediateTask());
+ EXPECT_FALSE(runners_[0]->IsQueueEmpty());
// After pumping the task runs normally.
runners_[0]->PumpQueue();
@@ -1005,32 +1003,32 @@
EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit());
}
-TEST_F(TaskQueueManagerTest, HasPendingImmediateTask) {
+TEST_F(TaskQueueManagerTest, IsQueueEmpty) {
Initialize(2u);
internal::TaskQueueImpl* queue0 = runners_[0].get();
internal::TaskQueueImpl* queue1 = runners_[1].get();
queue0->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO);
queue1->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
- EXPECT_FALSE(queue0->HasPendingImmediateTask());
- EXPECT_FALSE(queue1->HasPendingImmediateTask());
+ EXPECT_TRUE(queue0->IsQueueEmpty());
+ EXPECT_TRUE(queue1->IsQueueEmpty());
queue0->PostTask(FROM_HERE, base::Bind(NullTask));
queue1->PostTask(FROM_HERE, base::Bind(NullTask));
- EXPECT_TRUE(queue0->HasPendingImmediateTask());
- EXPECT_TRUE(queue1->HasPendingImmediateTask());
+ EXPECT_FALSE(queue0->IsQueueEmpty());
+ EXPECT_FALSE(queue1->IsQueueEmpty());
test_task_runner_->RunUntilIdle();
- EXPECT_FALSE(queue0->HasPendingImmediateTask());
- EXPECT_TRUE(queue1->HasPendingImmediateTask());
+ EXPECT_TRUE(queue0->IsQueueEmpty());
+ EXPECT_FALSE(queue1->IsQueueEmpty());
queue1->PumpQueue();
- EXPECT_FALSE(queue0->HasPendingImmediateTask());
- EXPECT_TRUE(queue1->HasPendingImmediateTask());
+ EXPECT_TRUE(queue0->IsQueueEmpty());
+ EXPECT_FALSE(queue1->IsQueueEmpty());
test_task_runner_->RunUntilIdle();
- EXPECT_FALSE(queue0->HasPendingImmediateTask());
- EXPECT_FALSE(queue1->HasPendingImmediateTask());
+ EXPECT_TRUE(queue0->IsQueueEmpty());
+ EXPECT_TRUE(queue1->IsQueueEmpty());
}
TEST_F(TaskQueueManagerTest, GetQueueState) {
@@ -1104,6 +1102,33 @@
EXPECT_THAT(run_order, ElementsAre(2, 1));
}
+TEST_F(TaskQueueManagerTest, DelayedTaskWithAbsoluteRunTime) {
+ Initialize(1u);
+
+ // One task in the past, two with the exact same run time and one in the
+ // future.
+ base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
+ base::TimeTicks runTime1 = now_src_->NowTicks() - delay;
+ base::TimeTicks runTime2 = now_src_->NowTicks();
+ base::TimeTicks runTime3 = now_src_->NowTicks();
+ base::TimeTicks runTime4 = now_src_->NowTicks() + delay;
+
+ std::vector<int> run_order;
+ runners_[0]->PostDelayedTaskAt(
+ FROM_HERE, base::Bind(&TestTask, 1, &run_order), runTime1);
+ runners_[0]->PostDelayedTaskAt(
+ FROM_HERE, base::Bind(&TestTask, 2, &run_order), runTime2);
+ runners_[0]->PostDelayedTaskAt(
+ FROM_HERE, base::Bind(&TestTask, 3, &run_order), runTime3);
+ runners_[0]->PostDelayedTaskAt(
+ FROM_HERE, base::Bind(&TestTask, 4, &run_order), runTime4);
+
+ now_src_->Advance(2 * delay);
+ test_task_runner_->RunUntilIdle();
+
+ EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4));
+}
+
void CheckIsNested(bool* is_nested) {
*is_nested = base::MessageLoop::current()->IsNested();
}
@@ -1298,6 +1323,20 @@
manager_->SetObserver(nullptr);
}
+TEST_F(TaskQueueManagerTest, ScheduleDelayedWorkIsNotReEntrant) {
+ Initialize(1u);
+
+ // Post two tasks into the past. The second one used to trigger a deadlock
+ // because it tried to re-entrantly wake the first task in the same queue.
+ runners_[0]->PostDelayedTaskAt(
+ FROM_HERE, base::Bind(&NullTask),
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(100));
+ runners_[0]->PostDelayedTaskAt(
+ FROM_HERE, base::Bind(&NullTask),
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(200));
+ test_task_runner_->RunUntilIdle();
+}
+
void HasOneRefTask(std::vector<bool>* log, internal::TaskQueueImpl* tq) {
log->push_back(tq->HasOneRef());
}
@@ -1348,14 +1387,12 @@
Initialize(2u);
base::TimeTicks start_time = manager_->delegate()->NowTicks();
- scoped_ptr<VirtualTimeDomain> domain_a(
- new VirtualTimeDomain(nullptr, start_time));
- scoped_ptr<VirtualTimeDomain> domain_b(
- new VirtualTimeDomain(nullptr, start_time));
- manager_->RegisterTimeDomain(domain_a.get());
- manager_->RegisterTimeDomain(domain_b.get());
- runners_[0]->SetTimeDomain(domain_a.get());
- runners_[1]->SetTimeDomain(domain_b.get());
+ scoped_refptr<VirtualTimeDomain> domain_a(new VirtualTimeDomain(start_time));
+ scoped_refptr<VirtualTimeDomain> domain_b(new VirtualTimeDomain(start_time));
+ manager_->RegisterTimeDomain(domain_a);
+ manager_->RegisterTimeDomain(domain_b);
+ runners_[0]->SetTimeDomain(domain_a);
+ runners_[1]->SetTimeDomain(domain_b);
std::vector<int> run_order;
runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
@@ -1382,18 +1419,17 @@
test_task_runner_->RunUntilIdle();
EXPECT_THAT(run_order, ElementsAre(4, 5, 6, 1, 2, 3));
- manager_->UnregisterTimeDomain(domain_a.get());
- manager_->UnregisterTimeDomain(domain_b.get());
+ manager_->UnregisterTimeDomain(domain_a);
+ manager_->UnregisterTimeDomain(domain_b);
}
TEST_F(TaskQueueManagerTest, TimeDomainMigration) {
Initialize(1u);
base::TimeTicks start_time = manager_->delegate()->NowTicks();
- scoped_ptr<VirtualTimeDomain> domain_a(
- new VirtualTimeDomain(nullptr, start_time));
- manager_->RegisterTimeDomain(domain_a.get());
- runners_[0]->SetTimeDomain(domain_a.get());
+ scoped_refptr<VirtualTimeDomain> domain_a(new VirtualTimeDomain(start_time));
+ manager_->RegisterTimeDomain(domain_a);
+ runners_[0]->SetTimeDomain(domain_a);
std::vector<int> run_order;
runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
@@ -1409,18 +1445,17 @@
test_task_runner_->RunUntilIdle();
EXPECT_THAT(run_order, ElementsAre(1, 2));
- scoped_ptr<VirtualTimeDomain> domain_b(
- new VirtualTimeDomain(nullptr, start_time));
- manager_->RegisterTimeDomain(domain_b.get());
- runners_[0]->SetTimeDomain(domain_b.get());
+ scoped_refptr<VirtualTimeDomain> domain_b(new VirtualTimeDomain(start_time));
+ manager_->RegisterTimeDomain(domain_b);
+ runners_[0]->SetTimeDomain(domain_b);
domain_b->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(50));
test_task_runner_->RunUntilIdle();
EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4));
- manager_->UnregisterTimeDomain(domain_a.get());
- manager_->UnregisterTimeDomain(domain_b.get());
+ manager_->UnregisterTimeDomain(domain_a);
+ manager_->UnregisterTimeDomain(domain_b);
}
namespace {
diff --git a/components/scheduler/base/task_queue_selector_unittest.cc b/components/scheduler/base/task_queue_selector_unittest.cc
index da64fac..382a440d 100644
--- a/components/scheduler/base/task_queue_selector_unittest.cc
+++ b/components/scheduler/base/task_queue_selector_unittest.cc
@@ -75,11 +75,11 @@
protected:
void SetUp() final {
- virtual_time_domain_ = make_scoped_ptr<VirtualTimeDomain>(
- new VirtualTimeDomain(nullptr, base::TimeTicks()));
+ virtual_time_domain_ = make_scoped_refptr<VirtualTimeDomain>(
+ new VirtualTimeDomain(base::TimeTicks()));
for (size_t i = 0; i < kTaskQueueCount; i++) {
scoped_refptr<TaskQueueImpl> task_queue = make_scoped_refptr(
- new TaskQueueImpl(nullptr, virtual_time_domain_.get(),
+ new TaskQueueImpl(nullptr, virtual_time_domain_,
TaskQueue::Spec("test queue"), "test", "test"));
selector_.AddQueue(task_queue.get());
task_queues_.push_back(task_queue);
@@ -93,7 +93,7 @@
const size_t kTaskQueueCount = 5;
base::Closure test_closure_;
TaskQueueSelector selector_;
- scoped_ptr<VirtualTimeDomain> virtual_time_domain_;
+ scoped_refptr<VirtualTimeDomain> virtual_time_domain_;
std::vector<scoped_refptr<TaskQueueImpl>> task_queues_;
std::map<TaskQueueImpl*, size_t> queue_to_index_map_;
};
diff --git a/components/scheduler/base/task_queue_sets_unittest.cc b/components/scheduler/base/task_queue_sets_unittest.cc
index 8d42503a..568c0d1 100644
--- a/components/scheduler/base/task_queue_sets_unittest.cc
+++ b/components/scheduler/base/task_queue_sets_unittest.cc
@@ -16,8 +16,8 @@
class TaskQueueSetsTest : public testing::Test {
public:
void SetUp() override {
- virtual_time_domain_ = make_scoped_ptr<VirtualTimeDomain>(
- new VirtualTimeDomain(nullptr, base::TimeTicks()));
+ virtual_time_domain_ = make_scoped_refptr<VirtualTimeDomain>(
+ new VirtualTimeDomain(base::TimeTicks()));
task_queue_sets_.reset(new TaskQueueSets(kNumSets));
}
@@ -29,8 +29,8 @@
TaskQueueImpl* NewTaskQueue(const char* queue_name) {
scoped_refptr<internal::TaskQueueImpl> queue =
make_scoped_refptr(new internal::TaskQueueImpl(
- nullptr, virtual_time_domain_.get(), TaskQueue::Spec(queue_name),
- "test", "test"));
+ nullptr, virtual_time_domain_, TaskQueue::Spec(queue_name), "test",
+ "test"));
task_queues_.push_back(queue);
return queue.get();
}
@@ -41,7 +41,7 @@
return fake_task;
}
- scoped_ptr<VirtualTimeDomain> virtual_time_domain_;
+ scoped_refptr<VirtualTimeDomain> virtual_time_domain_;
std::vector<scoped_refptr<internal::TaskQueueImpl>> task_queues_;
scoped_ptr<TaskQueueSets> task_queue_sets_;
};
diff --git a/components/scheduler/base/time_domain.cc b/components/scheduler/base/time_domain.cc
index e64b4e9..2abfb52 100644
--- a/components/scheduler/base/time_domain.cc
+++ b/components/scheduler/base/time_domain.cc
@@ -12,21 +12,11 @@
namespace scheduler {
-TimeDomain::TimeDomain(Observer* observer) : observer_(observer) {}
+TimeDomain::TimeDomain() {}
-TimeDomain::~TimeDomain() {
- for (internal::TaskQueueImpl* queue : registered_task_queues_) {
- queue->SetTimeDomain(nullptr);
- }
-}
-
-void TimeDomain::RegisterQueue(internal::TaskQueueImpl* queue) {
- registered_task_queues_.insert(queue);
-}
+TimeDomain::~TimeDomain() {}
void TimeDomain::UnregisterQueue(internal::TaskQueueImpl* queue) {
- registered_task_queues_.erase(queue);
-
// We need to remove |task_queue| from delayed_wakeup_multimap_ which is a
// little awkward since it's keyed by time. O(n) running time.
for (DelayedWakeupMultimap::iterator iter = delayed_wakeup_multimap_.begin();
@@ -49,9 +39,6 @@
void TimeDomain::MigrateQueue(internal::TaskQueueImpl* queue,
TimeDomain* destination_time_domain) {
- DCHECK(destination_time_domain);
- registered_task_queues_.erase(queue);
-
LazyNow destination_lazy_now = destination_time_domain->CreateLazyNow();
// We need to remove |task_queue| from delayed_wakeup_multimap_ which is a
// little awkward since it's keyed by time. O(n) running time.
@@ -73,8 +60,6 @@
// MoveNewlyUpdatableQueuesIntoUpdatableQueueSet to flush it out.
MoveNewlyUpdatableQueuesIntoUpdatableQueueSet();
updatable_queue_set_.erase(queue);
-
- destination_time_domain->RegisterQueue(queue);
}
void TimeDomain::ScheduleDelayedWork(internal::TaskQueueImpl* queue,
@@ -82,26 +67,18 @@
LazyNow* lazy_now) {
DCHECK(main_thread_checker_.CalledOnValidThread());
- bool delayed_wakeup_multimap_was_empty = delayed_wakeup_multimap_.empty();
- if (delayed_wakeup_multimap_was_empty ||
+ if (delayed_wakeup_multimap_.empty() ||
delayed_run_time < delayed_wakeup_multimap_.begin()->first) {
base::TimeDelta delay =
std::max(base::TimeDelta(), delayed_run_time - lazy_now->Now());
RequestWakeup(lazy_now, delay);
}
-
- if (observer_ && delayed_wakeup_multimap_was_empty)
- observer_->OnTimeDomainHasDelayedWork();
delayed_wakeup_multimap_.insert(std::make_pair(delayed_run_time, queue));
}
void TimeDomain::RegisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue) {
- {
- base::AutoLock lock(newly_updatable_lock_);
- newly_updatable_.push_back(queue);
- }
- if (observer_)
- observer_->OnTimeDomainHasImmediateWork();
+ base::AutoLock lock(newly_updatable_lock_);
+ newly_updatable_.push_back(queue);
}
void TimeDomain::UnregisterAsUpdatableTaskQueue(
diff --git a/components/scheduler/base/time_domain.h b/components/scheduler/base/time_domain.h
index 5cf39b70..476a68e 100644
--- a/components/scheduler/base/time_domain.h
+++ b/components/scheduler/base/time_domain.h
@@ -23,24 +23,9 @@
class TaskQueueManager;
class TaskQueueManagerDelegate;
-class SCHEDULER_EXPORT TimeDomain {
+class SCHEDULER_EXPORT TimeDomain : public base::RefCounted<TimeDomain> {
public:
- class SCHEDULER_EXPORT Observer {
- public:
- virtual ~Observer() {}
-
- // Called when an empty TaskQueue registered with this TimeDomain has a task
- // enqueued.
- virtual void OnTimeDomainHasImmediateWork() = 0;
-
- // Called when a TaskQueue registered with this TimeDomain has a delayed
- // task enqueued and no other delayed tasks associated with this TimeDomain
- // are pending.
- virtual void OnTimeDomainHasDelayedWork() = 0;
- };
-
- explicit TimeDomain(Observer* observer);
- virtual ~TimeDomain();
+ TimeDomain();
// Returns a LazyNow that evaluate this TimeDomain's Now. Can be called from
// any thread.
@@ -61,6 +46,9 @@
protected:
friend class internal::TaskQueueImpl;
friend class TaskQueueManager;
+ friend class base::RefCounted<TimeDomain>;
+
+ virtual ~TimeDomain();
void AsValueInto(base::trace_event::TracedValue* state) const;
@@ -82,9 +70,6 @@
base::TimeTicks delayed_run_time,
LazyNow* lazy_now);
- // Registers the |queue|.
- void RegisterQueue(internal::TaskQueueImpl* queue);
-
// Removes |queue| from the set of task queues that UpdateWorkQueues calls
// UpdateWorkQueue on.
void UnregisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue);
@@ -130,10 +115,6 @@
// only be accessed from the main thread.
std::set<internal::TaskQueueImpl*> updatable_queue_set_;
- std::set<internal::TaskQueueImpl*> registered_task_queues_;
-
- Observer* observer_;
-
base::ThreadChecker main_thread_checker_;
DISALLOW_COPY_AND_ASSIGN(TimeDomain);
diff --git a/components/scheduler/base/time_domain_unittest.cc b/components/scheduler/base/time_domain_unittest.cc
index e699e18..d41305a 100644
--- a/components/scheduler/base/time_domain_unittest.cc
+++ b/components/scheduler/base/time_domain_unittest.cc
@@ -19,18 +19,14 @@
class MockTimeDomain : public TimeDomain {
public:
- explicit MockTimeDomain(TimeDomain::Observer* observer)
- : TimeDomain(observer),
- now_(base::TimeTicks() + base::TimeDelta::FromSeconds(1)) {}
-
- ~MockTimeDomain() override {}
+ MockTimeDomain()
+ : now_(base::TimeTicks() + base::TimeDelta::FromSeconds(1)) {}
using TimeDomain::NextScheduledRunTime;
using TimeDomain::NextScheduledTaskQueue;
using TimeDomain::ScheduleDelayedWork;
using TimeDomain::UnregisterQueue;
using TimeDomain::UpdateWorkQueues;
- using TimeDomain::RegisterAsUpdatableTaskQueue;
// TimeSource implementation:
LazyNow CreateLazyNow() override { return LazyNow(now_); }
@@ -53,23 +49,21 @@
private:
base::TimeTicks now_;
+ ~MockTimeDomain() override {}
+
DISALLOW_COPY_AND_ASSIGN(MockTimeDomain);
};
class TimeDomainTest : public testing::Test {
public:
void SetUp() final {
- time_domain_ = make_scoped_ptr(CreateMockTimeDomain());
+ time_domain_ = make_scoped_refptr(new MockTimeDomain());
task_queue_ = make_scoped_refptr(new internal::TaskQueueImpl(
- nullptr, time_domain_.get(), TaskQueue::Spec("test_queue"),
- "test.category", "test.category"));
+ nullptr, time_domain_, TaskQueue::Spec("test_queue"), "test.category",
+ "test.category"));
}
- virtual MockTimeDomain* CreateMockTimeDomain() {
- return new MockTimeDomain(nullptr);
- }
-
- scoped_ptr<MockTimeDomain> time_domain_;
+ scoped_refptr<MockTimeDomain> time_domain_;
scoped_refptr<internal::TaskQueueImpl> task_queue_;
};
@@ -121,7 +115,7 @@
TEST_F(TimeDomainTest, UnregisterQueue) {
scoped_refptr<internal::TaskQueueImpl> task_queue2_ =
make_scoped_refptr(new internal::TaskQueueImpl(
- nullptr, time_domain_.get(), TaskQueue::Spec("test_queue2"),
+ nullptr, time_domain_, TaskQueue::Spec("test_queue2"),
"test.category", "test.category"));
EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(1);
@@ -146,7 +140,7 @@
}
TEST_F(TimeDomainTest, UpdateWorkQueues) {
- scoped_ptr<MockTimeDomain> dummy_delegate(new MockTimeDomain(nullptr));
+ scoped_refptr<MockTimeDomain> dummy_delegate(new MockTimeDomain());
base::SimpleTestTickClock dummy_time_source;
scoped_refptr<cc::OrderedSimpleTaskRunner> dummy_task_runner(
new cc::OrderedSimpleTaskRunner(&dummy_time_source, false));
@@ -182,38 +176,4 @@
EXPECT_EQ(1UL, dummy_queue->IncomingQueueSizeForTest());
}
-namespace {
-class MockObserver : public TimeDomain::Observer {
- public:
- ~MockObserver() override {}
-
- MOCK_METHOD0(OnTimeDomainHasImmediateWork, void());
- MOCK_METHOD0(OnTimeDomainHasDelayedWork, void());
-};
-} // namespace
-
-class TimeDomainWithObserverTest : public TimeDomainTest {
- public:
- MockTimeDomain* CreateMockTimeDomain() override {
- observer_.reset(new MockObserver());
- return new MockTimeDomain(observer_.get());
- }
-
- scoped_ptr<MockObserver> observer_;
-};
-
-TEST_F(TimeDomainWithObserverTest, OnTimeDomainHasImmediateWork) {
- EXPECT_CALL(*observer_, OnTimeDomainHasImmediateWork());
- time_domain_->RegisterAsUpdatableTaskQueue(task_queue_.get());
-}
-
-TEST_F(TimeDomainWithObserverTest, OnTimeDomainHasDelayedWork) {
- EXPECT_CALL(*observer_, OnTimeDomainHasDelayedWork());
- EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _));
- LazyNow lazy_now = time_domain_->CreateLazyNow();
- time_domain_->ScheduleDelayedWork(
- task_queue_.get(),
- time_domain_->Now() + base::TimeDelta::FromMilliseconds(10), &lazy_now);
-}
-
} // namespace scheduler
diff --git a/components/scheduler/base/virtual_time_domain.cc b/components/scheduler/base/virtual_time_domain.cc
index 0ed6abb..3251039 100644
--- a/components/scheduler/base/virtual_time_domain.cc
+++ b/components/scheduler/base/virtual_time_domain.cc
@@ -10,9 +10,8 @@
namespace scheduler {
-VirtualTimeDomain::VirtualTimeDomain(TimeDomain::Observer* observer,
- base::TimeTicks initial_time)
- : TimeDomain(observer), now_(initial_time) {}
+VirtualTimeDomain::VirtualTimeDomain(base::TimeTicks initial_time)
+ : now_(initial_time) {}
VirtualTimeDomain::~VirtualTimeDomain() {}
@@ -45,8 +44,6 @@
base::AutoLock lock(lock_);
DCHECK_GE(now, now_);
now_ = now;
- DCHECK(task_queue_manager_delegate_);
-
task_queue_manager_delegate_->PostTask(FROM_HERE, do_work_closure_);
}
diff --git a/components/scheduler/base/virtual_time_domain.h b/components/scheduler/base/virtual_time_domain.h
index 78239c1c..ce1f99a 100644
--- a/components/scheduler/base/virtual_time_domain.h
+++ b/components/scheduler/base/virtual_time_domain.h
@@ -15,9 +15,7 @@
class SCHEDULER_EXPORT VirtualTimeDomain : public TimeDomain {
public:
- VirtualTimeDomain(TimeDomain::Observer* observer,
- base::TimeTicks initial_time);
- ~VirtualTimeDomain() override;
+ VirtualTimeDomain(base::TimeTicks initial_time);
// TimeDomain implementation:
LazyNow CreateLazyNow() override;
@@ -43,6 +41,8 @@
TaskQueueManagerDelegate* task_queue_manager_delegate_; // NOT OWNED
base::Closure do_work_closure_;
+ ~VirtualTimeDomain() override;
+
DISALLOW_COPY_AND_ASSIGN(VirtualTimeDomain);
};
diff --git a/components/scheduler/child/idle_helper.cc b/components/scheduler/child/idle_helper.cc
index b0fb06a..f007baec 100644
--- a/components/scheduler/child/idle_helper.cc
+++ b/components/scheduler/child/idle_helper.cc
@@ -93,7 +93,7 @@
if (long_idle_period_duration >=
base::TimeDelta::FromMilliseconds(kMinimumIdlePeriodDurationMillis)) {
*next_long_idle_period_delay_out = long_idle_period_duration;
- if (!idle_queue_->HasPendingImmediateTask()) {
+ if (idle_queue_->IsQueueEmpty()) {
return IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED;
} else if (long_idle_period_duration == max_long_idle_period_duration) {
return IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE;
diff --git a/components/scheduler/child/scheduler_helper.cc b/components/scheduler/child/scheduler_helper.cc
index 793f2599..f4081fd 100644
--- a/components/scheduler/child/scheduler_helper.cc
+++ b/components/scheduler/child/scheduler_helper.cc
@@ -124,28 +124,16 @@
task_queue_manager_->SetObserver(this);
}
-RealTimeDomain* SchedulerHelper::real_time_domain() const {
- CheckOnValidThread();
- DCHECK(task_queue_manager_);
- return task_queue_manager_->real_time_domain();
-}
-
-void SchedulerHelper::RegisterTimeDomain(TimeDomain* time_domain) {
- CheckOnValidThread();
- DCHECK(task_queue_manager_);
- task_queue_manager_->RegisterTimeDomain(time_domain);
-}
-
-void SchedulerHelper::UnregisterTimeDomain(TimeDomain* time_domain) {
- CheckOnValidThread();
- if (task_queue_manager_)
- task_queue_manager_->UnregisterTimeDomain(time_domain);
-}
-
void SchedulerHelper::OnUnregisterTaskQueue(
const scoped_refptr<internal::TaskQueueImpl>& queue) {
if (observer_)
observer_->OnUnregisterTaskQueue(queue);
}
+const scoped_refptr<RealTimeDomain>& SchedulerHelper::real_time_domain() const {
+ CheckOnValidThread();
+ DCHECK(task_queue_manager_);
+ return task_queue_manager_->real_time_domain();
+}
+
} // namespace scheduler
diff --git a/components/scheduler/child/scheduler_helper.h b/components/scheduler/child/scheduler_helper.h
index ee727f7e..27e33aa 100644
--- a/components/scheduler/child/scheduler_helper.h
+++ b/components/scheduler/child/scheduler_helper.h
@@ -83,9 +83,7 @@
void SetObserver(Observer* observer);
// Accessor methods.
- RealTimeDomain* real_time_domain() const;
- void RegisterTimeDomain(TimeDomain* time_domain);
- void UnregisterTimeDomain(TimeDomain* time_domain);
+ const scoped_refptr<RealTimeDomain>& real_time_domain() const;
const scoped_refptr<SchedulerTqmDelegate>& scheduler_tqm_delegate() const;
bool GetAndClearSystemIsQuiescentBit();
diff --git a/components/scheduler/child/web_scheduler_impl.cc b/components/scheduler/child/web_scheduler_impl.cc
index cc08d38..ce5436e 100644
--- a/components/scheduler/child/web_scheduler_impl.cc
+++ b/components/scheduler/child/web_scheduler_impl.cc
@@ -87,6 +87,20 @@
return timer_web_task_runner_.get();
}
+void WebSchedulerImpl::postTimerTaskAt(
+ const blink::WebTraceLocation& web_location,
+ blink::WebTaskRunner::Task* task,
+ double monotonicTime) {
+ DCHECK(timer_task_runner_);
+ tracked_objects::Location location(web_location.functionName(),
+ web_location.fileName(), -1, nullptr);
+ timer_task_runner_->PostDelayedTaskAt(
+ location,
+ base::Bind(&WebTaskRunnerImpl::runTask,
+ base::Passed(scoped_ptr<blink::WebTaskRunner::Task>(task))),
+ base::TimeTicks() + base::TimeDelta::FromSecondsD(monotonicTime));
+}
+
blink::WebPassOwnPtr<blink::WebViewScheduler>
WebSchedulerImpl::createWebViewScheduler(blink::WebView*) {
NOTREACHED();
diff --git a/components/scheduler/child/web_scheduler_impl.h b/components/scheduler/child/web_scheduler_impl.h
index 724491f..84933ac 100644
--- a/components/scheduler/child/web_scheduler_impl.h
+++ b/components/scheduler/child/web_scheduler_impl.h
@@ -52,6 +52,11 @@
void removePendingNavigation() override {}
void onNavigationStarted() override {}
+ // TODO(alexclarke): Remove when possible.
+ void postTimerTaskAt(const blink::WebTraceLocation& location,
+ blink::WebTaskRunner::Task* task,
+ double monotonicTime) override;
+
private:
static void runIdleTask(scoped_ptr<blink::WebThread::IdleTask> task,
base::TimeTicks deadline);
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc
index 0ef81cd..0ee5481d 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/components/scheduler/renderer/renderer_scheduler_impl.cc
@@ -12,7 +12,6 @@
#include "cc/output/begin_frame_args.h"
#include "components/scheduler/base/task_queue_impl.h"
#include "components/scheduler/base/task_queue_selector.h"
-#include "components/scheduler/base/virtual_time_domain.h"
#include "components/scheduler/child/scheduler_tqm_delegate.h"
#include "components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h"
@@ -42,7 +41,6 @@
TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
"RendererSchedulerIdlePeriod",
base::TimeDelta()),
- throttling_helper_(this, "renderer.scheduler"),
render_widget_scheduler_signals_(this),
control_task_runner_(helper_.ControlTaskRunner()),
compositor_task_runner_(
@@ -178,11 +176,6 @@
return default_timer_task_runner_;
}
-scoped_refptr<TaskQueue> RendererSchedulerImpl::ControlTaskRunner() {
- helper_.CheckOnValidThread();
- return helper_.ControlTaskRunner();
-}
-
scoped_refptr<TaskQueue> RendererSchedulerImpl::NewLoadingTaskRunner(
const char* name) {
helper_.CheckOnValidThread();
@@ -542,7 +535,7 @@
case UseCase::MAIN_THREAD_GESTURE:
case UseCase::SYNCHRONIZED_GESTURE:
- return compositor_task_runner_->HasPendingImmediateTask() ||
+ return !compositor_task_runner_->IsQueueEmpty() ||
MainThreadOnly().touchstart_expected_soon;
case UseCase::TOUCHSTART:
@@ -1053,16 +1046,4 @@
static_cast<double>(base::Time::kMicrosecondsPerSecond);
}
-void RendererSchedulerImpl::RegisterTimeDomain(TimeDomain* time_domain) {
- helper_.RegisterTimeDomain(time_domain);
-}
-
-void RendererSchedulerImpl::UnregisterTimeDomain(TimeDomain* time_domain) {
- helper_.UnregisterTimeDomain(time_domain);
-}
-
-base::TickClock* RendererSchedulerImpl::tick_clock() const {
- return helper_.scheduler_tqm_delegate().get();
-}
-
} // namespace scheduler
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.h b/components/scheduler/renderer/renderer_scheduler_impl.h
index d4025da53..6fb097a1 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.h
+++ b/components/scheduler/renderer/renderer_scheduler_impl.h
@@ -15,7 +15,6 @@
#include "components/scheduler/renderer/render_widget_signals.h"
#include "components/scheduler/renderer/renderer_scheduler.h"
#include "components/scheduler/renderer/task_cost_estimator.h"
-#include "components/scheduler/renderer/throttling_helper.h"
#include "components/scheduler/renderer/user_model.h"
#include "components/scheduler/scheduler_export.h"
@@ -27,7 +26,6 @@
namespace scheduler {
class RenderWidgetSchedulingState;
-class ThrottlingHelper;
class SCHEDULER_EXPORT RendererSchedulerImpl
: public RendererScheduler,
@@ -84,12 +82,6 @@
// TaskQueueManager::Observer implementation:
void OnUnregisterTaskQueue(const scoped_refptr<TaskQueue>& queue) override;
- // Returns a task runner where tasks run at the highest possible priority.
- scoped_refptr<TaskQueue> ControlTaskRunner();
-
- void RegisterTimeDomain(TimeDomain* time_domain);
- void UnregisterTimeDomain(TimeDomain* time_domain);
-
// Test helpers.
SchedulerHelper* GetSchedulerHelperForTesting();
TaskCostEstimator* GetLoadingTaskCostEstimatorForTesting();
@@ -97,14 +89,6 @@
IdleTimeEstimator* GetIdleTimeEstimatorForTesting();
base::TimeTicks CurrentIdleTaskDeadlineForTesting() const;
- base::TickClock* tick_clock() const;
-
- RealTimeDomain* real_time_domain() const {
- return helper_.real_time_domain();
- }
-
- ThrottlingHelper* throttling_helper() { return &throttling_helper_; }
-
private:
friend class RendererSchedulerImplTest;
friend class RendererSchedulerImplForTest;
@@ -249,7 +233,6 @@
SchedulerHelper helper_;
IdleHelper idle_helper_;
- ThrottlingHelper throttling_helper_;
RenderWidgetSignals render_widget_scheduler_signals_;
const scoped_refptr<TaskQueue> control_task_runner_;
diff --git a/components/scheduler/renderer/throttling_helper.cc b/components/scheduler/renderer/throttling_helper.cc
deleted file mode 100644
index 88f9ae7..0000000
--- a/components/scheduler/renderer/throttling_helper.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// 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 "components/scheduler/renderer/throttling_helper.h"
-
-#include "base/logging.h"
-#include "components/scheduler/base/real_time_domain.h"
-#include "components/scheduler/base/virtual_time_domain.h"
-#include "components/scheduler/child/scheduler_tqm_delegate.h"
-#include "components/scheduler/renderer/renderer_scheduler_impl.h"
-#include "components/scheduler/renderer/web_frame_scheduler_impl.h"
-#include "third_party/WebKit/public/platform/WebFrameScheduler.h"
-
-namespace scheduler {
-
-ThrottlingHelper::ThrottlingHelper(RendererSchedulerImpl* renderer_scheduler,
- const char* tracing_category)
- : task_runner_(renderer_scheduler->ControlTaskRunner()),
- renderer_scheduler_(renderer_scheduler),
- tick_clock_(renderer_scheduler->tick_clock()),
- tracing_category_(tracing_category),
- time_domain_(new VirtualTimeDomain(this, tick_clock_->NowTicks())),
- pending_pump_throttled_tasks_(false),
- weak_factory_(this) {
- pump_throttled_tasks_closure_ = base::Bind(
- &ThrottlingHelper::PumpThrottledTasks, weak_factory_.GetWeakPtr());
- forward_immediate_work_closure_ =
- base::Bind(&ThrottlingHelper::OnTimeDomainHasImmediateWork,
- weak_factory_.GetWeakPtr());
- renderer_scheduler_->RegisterTimeDomain(time_domain_.get());
-}
-
-ThrottlingHelper::~ThrottlingHelper() {
- renderer_scheduler_->UnregisterTimeDomain(time_domain_.get());
-}
-
-void ThrottlingHelper::Throttle(TaskQueue* task_queue) {
- throttled_queues_.insert(task_queue);
-
- task_queue->SetTimeDomain(time_domain_.get());
- task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL);
-
- MaybeSchedulePumpThrottledTasksLocked();
-}
-
-void ThrottlingHelper::Unthrottle(TaskQueue* task_queue) {
- throttled_queues_.erase(task_queue);
-
- task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain());
- task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO);
-}
-
-void ThrottlingHelper::OnTimeDomainHasImmediateWork() {
- // Forward to the main thread if called from another thread.
- if (!task_runner_->RunsTasksOnCurrentThread()) {
- task_runner_->PostTask(FROM_HERE, forward_immediate_work_closure_);
- return;
- }
- TRACE_EVENT0(tracing_category_,
- "ThrottlingHelper::OnTimeDomainHasImmediateWork");
- MaybeSchedulePumpThrottledTasksLocked();
-}
-
-void ThrottlingHelper::OnTimeDomainHasDelayedWork() {
- TRACE_EVENT0(tracing_category_,
- "ThrottlingHelper::OnTimeDomainHasDelayedWork");
- MaybeSchedulePumpThrottledTasksLocked();
-}
-
-void ThrottlingHelper::PumpThrottledTasks() {
- TRACE_EVENT0(tracing_category_, "ThrottlingHelper::PumpThrottledTasks");
- pending_pump_throttled_tasks_ = false;
-
- time_domain_->AdvanceTo(tick_clock_->NowTicks());
- bool work_to_do = false;
- for (TaskQueue* task_queue : throttled_queues_) {
- if (task_queue->GetQueueState() == TaskQueue::QueueState::EMPTY)
- continue;
-
- work_to_do = true;
- task_queue->PumpQueue();
- }
-
- if (work_to_do)
- MaybeSchedulePumpThrottledTasksLocked();
-}
-
-/* static */
-base::TimeDelta ThrottlingHelper::DelayToNextRunTimeInSeconds(
- base::TimeTicks now) {
- const base::TimeDelta one_second = base::TimeDelta::FromSeconds(1);
- return one_second - ((now - base::TimeTicks()) % one_second);
-}
-
-void ThrottlingHelper::MaybeSchedulePumpThrottledTasksLocked() {
- if (pending_pump_throttled_tasks_)
- return;
-
- pending_pump_throttled_tasks_ = true;
- task_runner_->PostDelayedTask(
- FROM_HERE, pump_throttled_tasks_closure_,
- DelayToNextRunTimeInSeconds(tick_clock_->NowTicks()));
-}
-
-} // namespace scheduler
diff --git a/components/scheduler/renderer/throttling_helper.h b/components/scheduler/renderer/throttling_helper.h
deleted file mode 100644
index 8417d53..0000000
--- a/components/scheduler/renderer/throttling_helper.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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.
-
-#ifndef COMPONENTS_SCHEDULER_RENDERER_THROTTLING_HELPER_H_
-#define COMPONENTS_SCHEDULER_RENDERER_THROTTLING_HELPER_H_
-
-#include <set>
-
-#include "base/macros.h"
-#include "components/scheduler/base/time_domain.h"
-#include "components/scheduler/scheduler_export.h"
-#include "third_party/WebKit/public/platform/WebViewScheduler.h"
-
-namespace scheduler {
-
-class RendererSchedulerImpl;
-class VirtualTimeDomain;
-class WebFrameSchedulerImpl;
-
-class SCHEDULER_EXPORT ThrottlingHelper : public TimeDomain::Observer {
- public:
- ThrottlingHelper(RendererSchedulerImpl* renderer_scheduler,
- const char* tracing_category);
-
- ~ThrottlingHelper() override;
-
- // TimeDomain::Observer implementation:
- void OnTimeDomainHasImmediateWork() override;
- void OnTimeDomainHasDelayedWork() override;
-
- void Throttle(TaskQueue* task_queue);
- void Unthrottle(TaskQueue* task_queue);
-
- const VirtualTimeDomain* time_domain() const { return time_domain_.get(); }
-
- static base::TimeDelta DelayToNextRunTimeInSeconds(base::TimeTicks now);
-
- private:
- void PumpThrottledTasks();
- void MaybeSchedulePumpThrottledTasksLocked();
-
- std::set<TaskQueue*> throttled_queues_;
- base::Closure pump_throttled_tasks_closure_;
- base::Closure forward_immediate_work_closure_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- RendererSchedulerImpl* renderer_scheduler_; // NOT OWNED
- base::TickClock* tick_clock_; // NOT OWNED
- const char* tracing_category_; // NOT OWNED
- scoped_ptr<VirtualTimeDomain> time_domain_;
-
- bool pending_pump_throttled_tasks_;
-
- base::WeakPtrFactory<ThrottlingHelper> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ThrottlingHelper);
-};
-
-} // namespace scheduler
-
-#endif // COMPONENTS_SCHEDULER_RENDERER_THROTTLING_HELPER_H_
diff --git a/components/scheduler/renderer/throttling_helper_unittest.cc b/components/scheduler/renderer/throttling_helper_unittest.cc
deleted file mode 100644
index 9526f06..0000000
--- a/components/scheduler/renderer/throttling_helper_unittest.cc
+++ /dev/null
@@ -1,203 +0,0 @@
-// 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 "components/scheduler/renderer/throttling_helper.h"
-
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/test/simple_test_tick_clock.h"
-#include "cc/test/ordered_simple_task_runner.h"
-#include "components/scheduler/base/test_time_source.h"
-#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h"
-#include "components/scheduler/renderer/renderer_scheduler_impl.h"
-#include "components/scheduler/renderer/web_frame_scheduler_impl.h"
-#include "components/scheduler/renderer/web_view_scheduler_impl.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::ElementsAre;
-
-namespace scheduler {
-
-class ThrottlingHelperTest : public testing::Test {
- public:
- ThrottlingHelperTest() {}
- ~ThrottlingHelperTest() override {}
-
- void SetUp() override {
- clock_.reset(new base::SimpleTestTickClock());
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
- mock_task_runner_ =
- make_scoped_refptr(new cc::OrderedSimpleTaskRunner(clock_.get(), true));
- delegate_ = SchedulerTqmDelegateForTest::Create(
- mock_task_runner_, make_scoped_ptr(new TestTimeSource(clock_.get())));
- scheduler_.reset(new RendererSchedulerImpl(delegate_));
- throttling_helper_ = scheduler_->throttling_helper();
- timer_queue_ = scheduler_->NewTimerTaskRunner("test_queue");
- }
-
- void TearDown() override {
- scheduler_->Shutdown();
- scheduler_.reset();
- }
-
- protected:
- scoped_ptr<base::SimpleTestTickClock> clock_;
- scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
- scoped_refptr<SchedulerTqmDelegate> delegate_;
- scoped_ptr<RendererSchedulerImpl> scheduler_;
- scoped_refptr<TaskQueue> timer_queue_;
- ThrottlingHelper* throttling_helper_; // NOT OWNED
-
- DISALLOW_COPY_AND_ASSIGN(ThrottlingHelperTest);
-};
-
-TEST_F(ThrottlingHelperTest, DelayToNextRunTimeInSeconds) {
- EXPECT_EQ(base::TimeDelta::FromSecondsD(1.0),
- ThrottlingHelper::DelayToNextRunTimeInSeconds(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(0.0)));
-
- EXPECT_EQ(base::TimeDelta::FromSecondsD(0.9),
- ThrottlingHelper::DelayToNextRunTimeInSeconds(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(0.1)));
-
- EXPECT_EQ(base::TimeDelta::FromSecondsD(0.8),
- ThrottlingHelper::DelayToNextRunTimeInSeconds(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(0.2)));
-
- EXPECT_EQ(base::TimeDelta::FromSecondsD(0.5),
- ThrottlingHelper::DelayToNextRunTimeInSeconds(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(0.5)));
-
- EXPECT_EQ(base::TimeDelta::FromSecondsD(0.2),
- ThrottlingHelper::DelayToNextRunTimeInSeconds(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(0.8)));
-
- EXPECT_EQ(base::TimeDelta::FromSecondsD(0.1),
- ThrottlingHelper::DelayToNextRunTimeInSeconds(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(0.9)));
-
- EXPECT_EQ(base::TimeDelta::FromSecondsD(1.0),
- ThrottlingHelper::DelayToNextRunTimeInSeconds(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0)));
-
- EXPECT_EQ(base::TimeDelta::FromSecondsD(0.9),
- ThrottlingHelper::DelayToNextRunTimeInSeconds(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(1.1)));
-
- EXPECT_EQ(base::TimeDelta::FromSecondsD(1.0),
- ThrottlingHelper::DelayToNextRunTimeInSeconds(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(8.0)));
-
- EXPECT_EQ(base::TimeDelta::FromSecondsD(0.9),
- ThrottlingHelper::DelayToNextRunTimeInSeconds(
- base::TimeTicks() + base::TimeDelta::FromSecondsD(8.1)));
-}
-
-namespace {
-void TestTask(std::vector<base::TimeTicks>* run_times,
- base::SimpleTestTickClock* clock) {
- run_times->push_back(clock->NowTicks());
-}
-} // namespace
-
-TEST_F(ThrottlingHelperTest, TimerAlignment) {
- std::vector<base::TimeTicks> run_times;
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(200.0));
-
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(800.0));
-
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(1200.0));
-
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(8300.0));
-
- throttling_helper_->Throttle(timer_queue_.get());
-
- mock_task_runner_->RunUntilIdle();
-
- // Times are aligned to a multipple of 1000 milliseconds.
- EXPECT_THAT(
- run_times,
- ElementsAre(
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0),
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0),
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(2000.0),
- base::TimeTicks() + base::TimeDelta::FromMilliseconds(9000.0)));
-}
-
-TEST_F(ThrottlingHelperTest, TimerAlignment_Unthrottled) {
- std::vector<base::TimeTicks> run_times;
- base::TimeTicks start_time = clock_->NowTicks();
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(200.0));
-
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(800.0));
-
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(1200.0));
-
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(8300.0));
-
- throttling_helper_->Throttle(timer_queue_.get());
- throttling_helper_->Unthrottle(timer_queue_.get());
-
- mock_task_runner_->RunUntilIdle();
-
- // Times are not aligned.
- EXPECT_THAT(
- run_times,
- ElementsAre(start_time + base::TimeDelta::FromMilliseconds(200.0),
- start_time + base::TimeDelta::FromMilliseconds(800.0),
- start_time + base::TimeDelta::FromMilliseconds(1200.0),
- start_time + base::TimeDelta::FromMilliseconds(8300.0)));
-}
-
-TEST_F(ThrottlingHelperTest, WakeUpForNonDelayedTask) {
- std::vector<base::TimeTicks> run_times;
-
- // Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick.
- throttling_helper_->Throttle(timer_queue_.get());
-
- // Posting a task should trigger the pump.
- timer_queue_->PostTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()));
-
- mock_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_times,
- ElementsAre(base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(1000.0)));
-}
-
-TEST_F(ThrottlingHelperTest, WakeUpForDelayedTask) {
- std::vector<base::TimeTicks> run_times;
-
- // Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick.
- throttling_helper_->Throttle(timer_queue_.get());
-
- // Posting a task should trigger the pump.
- timer_queue_->PostDelayedTask(FROM_HERE,
- base::Bind(&TestTask, &run_times, clock_.get()),
- base::TimeDelta::FromMilliseconds(1200.0));
-
- mock_task_runner_->RunUntilIdle();
- EXPECT_THAT(run_times,
- ElementsAre(base::TimeTicks() +
- base::TimeDelta::FromMilliseconds(2000.0)));
-}
-
-} // namespace scheduler
diff --git a/components/scheduler/renderer/web_frame_scheduler_impl.cc b/components/scheduler/renderer/web_frame_scheduler_impl.cc
index b8c1c1a..15e4a7d 100644
--- a/components/scheduler/renderer/web_frame_scheduler_impl.cc
+++ b/components/scheduler/renderer/web_frame_scheduler_impl.cc
@@ -4,8 +4,6 @@
#include "components/scheduler/renderer/web_frame_scheduler_impl.h"
-#include "components/scheduler/base/real_time_domain.h"
-#include "components/scheduler/base/virtual_time_domain.h"
#include "components/scheduler/child/web_task_runner_impl.h"
#include "components/scheduler/renderer/renderer_scheduler_impl.h"
#include "components/scheduler/renderer/web_view_scheduler_impl.h"
@@ -18,18 +16,14 @@
WebViewSchedulerImpl* parent_web_view_scheduler)
: renderer_scheduler_(renderer_scheduler),
parent_web_view_scheduler_(parent_web_view_scheduler),
- visible_(true),
- page_in_background_(false) {}
+ visible_(true) {}
WebFrameSchedulerImpl::~WebFrameSchedulerImpl() {
if (loading_task_queue_.get())
loading_task_queue_->UnregisterTaskQueue();
- if (timer_task_queue_.get()) {
- renderer_scheduler_->throttling_helper()->Unthrottle(
- timer_task_queue_.get());
+ if (timer_task_queue_.get())
timer_task_queue_->UnregisterTaskQueue();
- }
if (parent_web_view_scheduler_)
parent_web_view_scheduler_->Unregister(this);
@@ -57,10 +51,6 @@
if (!timer_web_task_runner_) {
timer_task_queue_ =
renderer_scheduler_->NewTimerTaskRunner("frame_timer_tq");
- if (page_in_background_) {
- renderer_scheduler_->throttling_helper()->Throttle(
- timer_task_queue_.get());
- }
timer_web_task_runner_.reset(new WebTaskRunnerImpl(timer_task_queue_));
}
return timer_web_task_runner_.get();
@@ -73,21 +63,4 @@
// TODO(skyostil): Associate the task queues with this origin.
}
-void WebFrameSchedulerImpl::SetPageInBackground(bool page_in_background) {
- if (page_in_background_ == page_in_background)
- return;
-
- page_in_background_ = page_in_background;
-
- if (!timer_web_task_runner_)
- return;
-
- if (page_in_background_) {
- renderer_scheduler_->throttling_helper()->Throttle(timer_task_queue_.get());
- } else {
- renderer_scheduler_->throttling_helper()->Unthrottle(
- timer_task_queue_.get());
- }
-}
-
} // namespace scheduler
diff --git a/components/scheduler/renderer/web_frame_scheduler_impl.h b/components/scheduler/renderer/web_frame_scheduler_impl.h
index 96a9e19..eb14bc0 100644
--- a/components/scheduler/renderer/web_frame_scheduler_impl.h
+++ b/components/scheduler/renderer/web_frame_scheduler_impl.h
@@ -36,13 +36,10 @@
blink::WebTaskRunner* timerTaskRunner() override;
void setFrameOrigin(const blink::WebSecurityOrigin* origin) override;
- void SetPageInBackground(bool page_in_background);
-
private:
friend class WebViewSchedulerImpl;
void DetachFromWebViewScheduler();
- void ApplyPolicyToTimerQueue();
scoped_refptr<TaskQueue> loading_task_queue_;
scoped_refptr<TaskQueue> timer_task_queue_;
@@ -52,7 +49,6 @@
WebViewSchedulerImpl* parent_web_view_scheduler_; // NOT OWNED
blink::WebSecurityOrigin origin_;
bool visible_;
- bool page_in_background_;
DISALLOW_COPY_AND_ASSIGN(WebFrameSchedulerImpl);
};
diff --git a/components/scheduler/renderer/web_view_scheduler_impl.cc b/components/scheduler/renderer/web_view_scheduler_impl.cc
index 658fdbb..28bc216 100644
--- a/components/scheduler/renderer/web_view_scheduler_impl.cc
+++ b/components/scheduler/renderer/web_view_scheduler_impl.cc
@@ -5,9 +5,6 @@
#include "components/scheduler/renderer/web_view_scheduler_impl.h"
#include "base/logging.h"
-#include "components/scheduler/base/virtual_time_domain.h"
-#include "components/scheduler/child/scheduler_tqm_delegate.h"
-#include "components/scheduler/renderer/renderer_scheduler_impl.h"
#include "components/scheduler/renderer/web_frame_scheduler_impl.h"
#include "third_party/WebKit/public/platform/WebFrameScheduler.h"
@@ -18,7 +15,7 @@
RendererSchedulerImpl* renderer_scheduler)
: web_view_(web_view),
renderer_scheduler_(renderer_scheduler),
- page_in_background_(false) {}
+ background_(false) {}
WebViewSchedulerImpl::~WebViewSchedulerImpl() {
// TODO(alexclarke): Find out why we can't rely on the web view outliving the
@@ -28,29 +25,17 @@
}
}
-void WebViewSchedulerImpl::setPageInBackground(bool page_in_background) {
- if (page_in_background_ == page_in_background)
- return;
-
- page_in_background_ = page_in_background;
-
- for (WebFrameSchedulerImpl* frame_scheduler : frame_schedulers_) {
- frame_scheduler->SetPageInBackground(page_in_background_);
- }
-}
-
-scoped_ptr<WebFrameSchedulerImpl>
-WebViewSchedulerImpl::createWebFrameSchedulerImpl() {
- scoped_ptr<WebFrameSchedulerImpl> frame_scheduler(
- new WebFrameSchedulerImpl(renderer_scheduler_, this));
- frame_scheduler->SetPageInBackground(page_in_background_);
- frame_schedulers_.insert(frame_scheduler.get());
- return frame_scheduler.Pass();
+void WebViewSchedulerImpl::setPageInBackground(bool background) {
+ background_ = background;
+ // TODO(alexclarke): Do something with this flag.
}
blink::WebPassOwnPtr<blink::WebFrameScheduler>
WebViewSchedulerImpl::createFrameScheduler() {
- return blink::adoptWebPtr(createWebFrameSchedulerImpl().release());
+ scoped_ptr<WebFrameSchedulerImpl> frame_scheduler(
+ new WebFrameSchedulerImpl(renderer_scheduler_, this));
+ frame_schedulers_.insert(frame_scheduler.get());
+ return blink::adoptWebPtr(frame_scheduler.release());
}
void WebViewSchedulerImpl::Unregister(WebFrameSchedulerImpl* frame_scheduler) {
diff --git a/components/scheduler/renderer/web_view_scheduler_impl.h b/components/scheduler/renderer/web_view_scheduler_impl.h
index a5dd7d7..647d6d9 100644
--- a/components/scheduler/renderer/web_view_scheduler_impl.h
+++ b/components/scheduler/renderer/web_view_scheduler_impl.h
@@ -8,7 +8,6 @@
#include <set>
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
#include "components/scheduler/scheduler_export.h"
#include "third_party/WebKit/public/platform/WebViewScheduler.h"
@@ -33,14 +32,12 @@
~WebViewSchedulerImpl() override;
// blink::WebViewScheduler implementation:
- void setPageInBackground(bool page_in_background) override;
+ void setPageInBackground(bool background) override;
blink::WebPassOwnPtr<blink::WebFrameScheduler> createFrameScheduler()
override;
blink::WebView* web_view() const { return web_view_; }
- scoped_ptr<WebFrameSchedulerImpl> createWebFrameSchedulerImpl();
-
private:
friend class WebFrameSchedulerImpl;
@@ -49,7 +46,7 @@
std::set<WebFrameSchedulerImpl*> frame_schedulers_;
blink::WebView* web_view_;
RendererSchedulerImpl* renderer_scheduler_;
- bool page_in_background_;
+ bool background_;
DISALLOW_COPY_AND_ASSIGN(WebViewSchedulerImpl);
};
diff --git a/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc b/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc
index 750811c..401b39a0 100644
--- a/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc
+++ b/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc
@@ -13,8 +13,6 @@
#include "components/scheduler/renderer/renderer_scheduler_impl.h"
#include "components/scheduler/renderer/web_frame_scheduler_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebTaskRunner.h"
-#include "third_party/WebKit/public/platform/WebTraceLocation.h"
namespace scheduler {
@@ -26,29 +24,22 @@
void SetUp() override {
clock_.reset(new base::SimpleTestTickClock());
clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
- mock_task_runner_ =
- make_scoped_refptr(new cc::OrderedSimpleTaskRunner(clock_.get(), true));
- delagate_ = SchedulerTqmDelegateForTest::Create(
+ mock_task_runner_ = make_scoped_refptr(
+ new cc::OrderedSimpleTaskRunner(clock_.get(), false));
+ main_task_runner_ = SchedulerTqmDelegateForTest::Create(
mock_task_runner_, make_scoped_ptr(new TestTimeSource(clock_.get())));
- scheduler_.reset(new RendererSchedulerImpl(delagate_));
+ scheduler_.reset(new RendererSchedulerImpl(main_task_runner_));
web_view_scheduler_.reset(
new WebViewSchedulerImpl(nullptr, scheduler_.get()));
- web_frame_scheduler_ = web_view_scheduler_->createWebFrameSchedulerImpl();
}
- void TearDown() override {
- web_frame_scheduler_.reset();
- web_view_scheduler_.reset();
- scheduler_->Shutdown();
- scheduler_.reset();
- }
+ void TearDown() override { scheduler_->Shutdown(); }
scoped_ptr<base::SimpleTestTickClock> clock_;
scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
- scoped_refptr<SchedulerTqmDelegate> delagate_;
+ scoped_refptr<SchedulerTqmDelegate> main_task_runner_;
scoped_ptr<RendererSchedulerImpl> scheduler_;
scoped_ptr<WebViewSchedulerImpl> web_view_scheduler_;
- scoped_ptr<WebFrameSchedulerImpl> web_frame_scheduler_;
};
TEST_F(WebViewSchedulerImplTest, TestDestructionOfFrameSchedulersBefore) {
@@ -66,88 +57,4 @@
web_view_scheduler_.reset();
}
-namespace {
-class RepeatingTask : public blink::WebTaskRunner::Task {
- public:
- RepeatingTask(blink::WebTaskRunner* web_task_runner, int* run_count)
- : web_task_runner_(web_task_runner), run_count_(run_count) {}
-
- ~RepeatingTask() override {}
-
- void run() override {
- (*run_count_)++;
- web_task_runner_->postDelayedTask(
- BLINK_FROM_HERE, new RepeatingTask(web_task_runner_, run_count_), 1.0);
- }
-
- private:
- blink::WebTaskRunner* web_task_runner_; // NOT OWNED
- int* run_count_; // NOT OWNED
-};
-} // namespace
-
-TEST_F(WebViewSchedulerImplTest, RepeatingTimer_PageInForeground) {
- web_view_scheduler_->setPageInBackground(false);
-
- int run_count = 0;
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count),
- 1.0);
-
- mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
- EXPECT_EQ(1000, run_count);
-}
-
-TEST_F(WebViewSchedulerImplTest, RepeatingTimer_PageInBackground) {
- web_view_scheduler_->setPageInBackground(true);
-
- int run_count = 0;
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count),
- 1.0);
-
- mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
- EXPECT_EQ(1, run_count);
-}
-
-TEST_F(WebViewSchedulerImplTest, RepeatingLoadingTask_PageInBackground) {
- web_view_scheduler_->setPageInBackground(true);
-
- int run_count = 0;
- web_frame_scheduler_->loadingTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new RepeatingTask(web_frame_scheduler_->loadingTaskRunner(), &run_count),
- 1.0);
-
- mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
- EXPECT_EQ(1000, run_count); // Loading tasks should not be throttled
-}
-
-TEST_F(WebViewSchedulerImplTest, RepeatingTimers_OneBackgroundOneForeground) {
- scoped_ptr<WebViewSchedulerImpl> web_view_scheduler2(
- new WebViewSchedulerImpl(nullptr, scheduler_.get()));
- scoped_ptr<WebFrameSchedulerImpl> web_frame_scheduler2 =
- web_view_scheduler2->createWebFrameSchedulerImpl();
-
- web_view_scheduler_->setPageInBackground(false);
- web_view_scheduler2->setPageInBackground(true);
-
- int run_count1 = 0;
- int run_count2 = 0;
- web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count1),
- 1.0);
- web_frame_scheduler2->timerTaskRunner()->postDelayedTask(
- BLINK_FROM_HERE,
- new RepeatingTask(web_frame_scheduler2->timerTaskRunner(), &run_count2),
- 1.0);
-
- mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
- EXPECT_EQ(1000, run_count1);
- EXPECT_EQ(1, run_count2);
-}
-
} // namespace scheduler
diff --git a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc b/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
index c19e75e5..52f4ee85 100644
--- a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
+++ b/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
@@ -35,30 +35,27 @@
class WebThreadImplForRendererSchedulerTest : public testing::Test {
public:
- WebThreadImplForRendererSchedulerTest() {}
-
- void SetUp() override {
- clock_.reset(new base::SimpleTestTickClock());
- clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
- scheduler_.reset(new RendererSchedulerImpl(SchedulerTqmDelegateImpl::Create(
- &message_loop_, make_scoped_ptr(new TestTimeSource(clock_.get())))));
- default_task_runner_ = scheduler_->DefaultTaskRunner();
- thread_ = scheduler_->CreateMainThread();
- }
+ WebThreadImplForRendererSchedulerTest()
+ : clock_(new base::SimpleTestTickClock()),
+ scheduler_(SchedulerTqmDelegateImpl::Create(
+ &message_loop_,
+ make_scoped_ptr(new TestTimeSource(clock_.get())))),
+ default_task_runner_(scheduler_.DefaultTaskRunner()),
+ thread_(scheduler_.CreateMainThread()) {}
~WebThreadImplForRendererSchedulerTest() override {}
void SetWorkBatchSizeForTesting(size_t work_batch_size) {
- scheduler_->GetSchedulerHelperForTesting()->SetWorkBatchSizeForTesting(
+ scheduler_.GetSchedulerHelperForTesting()->SetWorkBatchSizeForTesting(
work_batch_size);
}
- void TearDown() override { scheduler_->Shutdown(); }
+ void TearDown() override { scheduler_.Shutdown(); }
protected:
base::MessageLoop message_loop_;
scoped_ptr<base::SimpleTestTickClock> clock_;
- scoped_ptr<RendererSchedulerImpl> scheduler_;
+ RendererSchedulerImpl scheduler_;
scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
scoped_ptr<blink::WebThread> thread_;
diff --git a/components/scheduler/scheduler.gypi b/components/scheduler/scheduler.gypi
index c6a79b78..dbd40ce 100644
--- a/components/scheduler/scheduler.gypi
+++ b/components/scheduler/scheduler.gypi
@@ -72,14 +72,12 @@
'renderer/render_widget_scheduling_state.h',
'renderer/render_widget_signals.cc',
'renderer/render_widget_signals.h',
- 'renderer/task_cost_estimator.cc',
- 'renderer/task_cost_estimator.h',
- 'renderer/throttling_helper.cc',
- 'renderer/throttling_helper.h',
'renderer/web_frame_scheduler_impl.cc',
'renderer/web_frame_scheduler_impl.h',
'renderer/web_view_scheduler_impl.cc',
'renderer/web_view_scheduler_impl.h',
+ 'renderer/task_cost_estimator.cc',
+ 'renderer/task_cost_estimator.h',
'renderer/user_model.cc',
'renderer/user_model.h',
'renderer/webthread_impl_for_renderer_scheduler.cc',
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 795e85ed..8b824c9 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -442,7 +442,7 @@
, m_timeline(AnimationTimeline::create(this))
, m_templateDocumentHost(nullptr)
, m_didAssociateFormControlsTimer(this, &Document::didAssociateFormControlsTimerFired)
- , m_timers(timerTaskRunner()->adoptClone())
+ , m_timers(Platform::current()->currentThread()->scheduler()->timerTaskRunner()->adoptClone())
, m_hasViewportUnits(false)
, m_styleRecalcElementCounter(0)
, m_parserSyncPolicy(AllowAsynchronousParsing)
@@ -453,6 +453,7 @@
provideContextFeaturesToDocumentFrom(*this, *m_frame->page());
m_fetcher = m_frame->loader().documentLoader()->fetcher();
+ m_timers.setTimerTaskRunner(m_frame->frameScheduler()->timerTaskRunner()->adoptClone());
FrameFetchContext::provideDocumentToContext(m_fetcher->context(), this);
} else if (m_importsController) {
m_fetcher = FrameFetchContext::createContextAndFetcher(nullptr);
@@ -2876,6 +2877,14 @@
return completeURL(url);
}
+double Document::timerAlignmentInterval() const
+{
+ Page* p = page();
+ if (!p)
+ return DOMTimer::visiblePageAlignmentInterval();
+ return p->timerAlignmentInterval();
+}
+
DOMTimerCoordinator* Document::timers()
{
return &m_timers;
@@ -3016,7 +3025,8 @@
void Document::didLoadAllScriptBlockingResources()
{
- loadingTaskRunner()->postTask(BLINK_FROM_HERE, m_executeScriptsWaitingForResourcesTask->cancelAndCreate());
+ Platform::current()->currentThread()->scheduler()->loadingTaskRunner()->postTask(
+ BLINK_FROM_HERE, m_executeScriptsWaitingForResourcesTask->cancelAndCreate());
if (frame())
frame()->loader().client()->didRemoveAllPendingStylesheet();
@@ -5740,22 +5750,12 @@
{
if (frame())
return frame()->frameScheduler()->loadingTaskRunner();
- if (m_importsController)
- return m_importsController->master()->loadingTaskRunner();
- if (m_contextDocument)
- return m_contextDocument->loadingTaskRunner();
return Platform::current()->currentThread()->scheduler()->loadingTaskRunner();
}
WebTaskRunner* Document::timerTaskRunner() const
{
- if (frame())
- return m_frame->frameScheduler()->timerTaskRunner();
- if (m_importsController)
- return m_importsController->master()->timerTaskRunner();
- if (m_contextDocument)
- return m_contextDocument->timerTaskRunner();
- return Platform::current()->currentThread()->scheduler()->timerTaskRunner();
+ return m_timers.timerTaskRunner();
}
DEFINE_TRACE(Document)
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index e4af2d6..22555f4 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -1116,6 +1116,8 @@
void reportBlockedScriptExecutionToInspector(const String& directiveText) final;
+ double timerAlignmentInterval() const final;
+
void updateTitle(const String&);
void updateFocusAppearanceTimerFired(Timer<Document>*);
void updateBaseURL();
diff --git a/third_party/WebKit/Source/core/dom/ExecutionContext.h b/third_party/WebKit/Source/core/dom/ExecutionContext.h
index 49b7e8f..ee4af7d 100644
--- a/third_party/WebKit/Source/core/dom/ExecutionContext.h
+++ b/third_party/WebKit/Source/core/dom/ExecutionContext.h
@@ -89,6 +89,7 @@
virtual LocalDOMWindow* executingWindow() { return 0; }
virtual String userAgent() const = 0;
virtual void postTask(const WebTraceLocation&, PassOwnPtr<ExecutionContextTask>) = 0; // Executes the task on context's thread asynchronously.
+ virtual double timerAlignmentInterval() const = 0;
// Gets the DOMTimerCoordinator which maintains the "active timer
// list" of tasks created by setTimeout and setInterval. The
diff --git a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
index db7a582..09e5579 100644
--- a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
@@ -137,6 +137,7 @@
void postIdleTask(const WebTraceLocation&, WebThread::IdleTask*) override { }
void postNonNestableIdleTask(const WebTraceLocation&, WebThread::IdleTask*) override { }
void postIdleTaskAfterWakeup(const WebTraceLocation&, WebThread::IdleTask*) override { }
+ void postTimerTaskAt(const WebTraceLocation&, WebTaskRunner::Task*, double monotonicTime) override { }
WebPassOwnPtr<WebViewScheduler> createWebViewScheduler(blink::WebView*) override { return nullptr; }
void suspendTimerQueue() override { }
void resumeTimerQueue() override { }
diff --git a/third_party/WebKit/Source/core/frame/DOMTimer.cpp b/third_party/WebKit/Source/core/frame/DOMTimer.cpp
index cdfb3d8..b820cc6 100644
--- a/third_party/WebKit/Source/core/frame/DOMTimer.cpp
+++ b/third_party/WebKit/Source/core/frame/DOMTimer.cpp
@@ -52,6 +52,19 @@
&& nestingLevel == 1; // Gestures should not be forwarded to nested timers.
}
+double DOMTimer::hiddenPageAlignmentInterval()
+{
+ // Timers on hidden pages are aligned so that they fire once per
+ // second at most.
+ return 1.0;
+}
+
+double DOMTimer::visiblePageAlignmentInterval()
+{
+ // Alignment does not apply to timers on visible pages.
+ return 0;
+}
+
int DOMTimer::install(ExecutionContext* context, PassOwnPtrWillBeRawPtr<ScheduledAction> action, int timeout, bool singleShot)
{
int timeoutID = context->timers()->installNewTimeout(context, action, timeout, singleShot);
@@ -151,6 +164,42 @@
m_action.clear();
}
+double DOMTimer::alignedFireTime(double fireTime) const
+{
+ double alignmentInterval = executionContext()->timerAlignmentInterval();
+ if (alignmentInterval) {
+ double currentTime = monotonicallyIncreasingTime();
+ if (fireTime <= currentTime)
+ return fireTime;
+
+ // When a repeating timer is scheduled for exactly the
+ // background page alignment interval, because it's impossible
+ // for the timer to be rescheduled instantaneously, it misses
+ // every other fire time. Avoid this by looking at the next
+ // fire time rounded both down and up.
+
+ double alignedTimeRoundedDown = floor(fireTime / alignmentInterval) * alignmentInterval;
+ double alignedTimeRoundedUp = ceil(fireTime / alignmentInterval) * alignmentInterval;
+
+ // If the version rounded down is in the past, discard it
+ // immediately.
+
+ if (alignedTimeRoundedDown <= currentTime)
+ return alignedTimeRoundedUp;
+
+ // Only use the rounded-down time if it's within a certain
+ // tolerance of the fire time. This avoids speeding up timers
+ // on background pages in the common case.
+
+ if (fireTime - alignedTimeRoundedDown < minimumInterval)
+ return alignedTimeRoundedDown;
+
+ return alignedTimeRoundedUp;
+ }
+
+ return fireTime;
+}
+
WebTaskRunner* DOMTimer::timerTaskRunner()
{
return executionContext()->timers()->timerTaskRunner();
diff --git a/third_party/WebKit/Source/core/frame/DOMTimer.h b/third_party/WebKit/Source/core/frame/DOMTimer.h
index 59236c8..4912ace9 100644
--- a/third_party/WebKit/Source/core/frame/DOMTimer.h
+++ b/third_party/WebKit/Source/core/frame/DOMTimer.h
@@ -52,6 +52,10 @@
// ActiveDOMObject
void stop() override;
+ // The following are essentially constants. All intervals are in seconds.
+ static double hiddenPageAlignmentInterval();
+ static double visiblePageAlignmentInterval();
+
// Eager finalization is needed to promptly stop this Timer object.
// Otherwise timer events might fire at an object that's slated for destruction
// (when lazily swept), but some of its members (m_action) may already have
@@ -72,6 +76,9 @@
DOMTimer(ExecutionContext*, PassOwnPtrWillBeRawPtr<ScheduledAction>, int interval, bool singleShot, int timeoutID);
void fired() override;
+ // Retuns timer fire time rounded to the next multiple of timer alignment interval.
+ double alignedFireTime(double) const override;
+
WebTaskRunner* timerTaskRunner() override;
int m_timeoutID;
diff --git a/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.cpp b/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.cpp
index 4401db92..240f8cb 100644
--- a/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.cpp
+++ b/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.cpp
@@ -42,6 +42,20 @@
m_timers.remove(timeoutID);
}
+void DOMTimerCoordinator::didChangeTimerAlignmentInterval()
+{
+ // Reschedule timers in increasing order of desired run time to maintain their relative order.
+ // TODO(skyostil): Move timer alignment into the scheduler.
+ WillBeHeapVector<RawPtrWillBeMember<DOMTimer>> timers;
+ timers.reserveCapacity(m_timers.size());
+ for (TimeoutMap::iterator iter = m_timers.begin(); iter != m_timers.end(); ++iter)
+ timers.append(iter->value.get());
+ std::sort(timers.begin(), timers.end(), TimerBase::Comparator());
+ double now = monotonicallyIncreasingTime();
+ for (DOMTimer* timer : timers)
+ timer->didChangeAlignmentInterval(now);
+}
+
DEFINE_TRACE(DOMTimerCoordinator)
{
#if ENABLE(OILPAN)
diff --git a/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.h b/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.h
index 2c7f0cde4..69c8d222 100644
--- a/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.h
+++ b/third_party/WebKit/Source/core/frame/DOMTimerCoordinator.h
@@ -34,6 +34,11 @@
// destroy the timer.
void removeTimeoutByID(int id);
+ // Notifies registered timers that
+ // ExecutionContext::timerAlignmentInterval has changed so that
+ // timers can adjust their schedule to the new alignment interval.
+ void didChangeTimerAlignmentInterval();
+
// Timers created during the execution of other timers, and
// repeating timers, are throttled. Timer nesting level tracks the
// number of linked timers or repetitions of a timer. See
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
index 4d289e4..34fa2a0 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -149,7 +149,10 @@
SuspendableTimer::trace(visitor);
}
- // TODO(alexclarke): Override timerTaskRunner() to pass in a document specific default task runner.
+ WebTaskRunner* timerTaskRunner() override
+ {
+ return m_window->document()->timerTaskRunner();
+ }
private:
void fired() override
diff --git a/third_party/WebKit/Source/core/frame/SuspendableTimer.cpp b/third_party/WebKit/Source/core/frame/SuspendableTimer.cpp
index b2d690a..8a9d048 100644
--- a/third_party/WebKit/Source/core/frame/SuspendableTimer.cpp
+++ b/third_party/WebKit/Source/core/frame/SuspendableTimer.cpp
@@ -66,7 +66,7 @@
m_suspended = true;
#endif
if (isActive()) {
- m_nextFireInterval = nextFireInterval();
+ m_nextFireInterval = nextUnalignedFireInterval();
ASSERT(m_nextFireInterval >= 0.0);
m_repeatInterval = repeatInterval();
TimerBase::stop();
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp
index 3ec85f1..dac637d 100644
--- a/third_party/WebKit/Source/core/page/Page.cpp
+++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -117,6 +117,7 @@
, m_tabKeyCyclesThroughElements(true)
, m_defersLoading(false)
, m_deviceScaleFactor(1)
+ , m_timerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval())
, m_visibilityState(PageVisibilityStateVisible)
, m_isCursorVisible(true)
#if ENABLE(ASSERT)
@@ -355,15 +356,41 @@
}
}
+void Page::setTimerAlignmentInterval(double interval)
+{
+ if (interval == m_timerAlignmentInterval)
+ return;
+
+ m_timerAlignmentInterval = interval;
+ for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) {
+ if (!frame->isLocalFrame())
+ continue;
+
+ if (Document* document = toLocalFrame(frame)->document()) {
+ if (DOMTimerCoordinator* timers = document->timers()) {
+ timers->didChangeTimerAlignmentInterval();
+ }
+ }
+ }
+}
+
+double Page::timerAlignmentInterval() const
+{
+ return m_timerAlignmentInterval;
+}
+
void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
{
if (m_visibilityState == visibilityState)
return;
m_visibilityState = visibilityState;
+ // TODO(alexclarke): Move throttling of timers to chromium.
if (visibilityState == PageVisibilityStateVisible) {
+ setTimerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval());
memoryPurgeController().pageBecameActive();
} else {
+ setTimerAlignmentInterval(DOMTimer::hiddenPageAlignmentInterval());
if (!isInitialState)
memoryPurgeController().pageBecameInactive();
}
diff --git a/third_party/WebKit/Source/core/page/Page.h b/third_party/WebKit/Source/core/page/Page.h
index 1ce3024..15cfbc5 100644
--- a/third_party/WebKit/Source/core/page/Page.h
+++ b/third_party/WebKit/Source/core/page/Page.h
@@ -185,6 +185,8 @@
bool isPainting() const { return m_isPainting; }
#endif
+ double timerAlignmentInterval() const;
+
class CORE_EXPORT MultisamplingChangedObserver : public WillBeGarbageCollectedMixin {
public:
virtual void multisamplingChanged(bool) = 0;
@@ -211,6 +213,8 @@
private:
void initGroup();
+ void setTimerAlignmentInterval(double);
+
void setNeedsLayoutInAllFrames();
// SettingsDelegate overrides.
@@ -257,6 +261,8 @@
float m_deviceScaleFactor;
+ double m_timerAlignmentInterval;
+
PageVisibilityState m_visibilityState;
bool m_isCursorVisible;
diff --git a/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp b/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp
index 46ab161..e3e79bc 100644
--- a/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp
+++ b/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp
@@ -34,6 +34,11 @@
{
}
+double NullExecutionContext::timerAlignmentInterval() const
+{
+ return DOMTimer::visiblePageAlignmentInterval();
+}
+
bool NullExecutionContext::isSecureContext(String& errorMessage, const SecureContextCheck privilegeContextCheck) const
{
return true;
diff --git a/third_party/WebKit/Source/core/testing/NullExecutionContext.h b/third_party/WebKit/Source/core/testing/NullExecutionContext.h
index 4838afd..9cb49be3 100644
--- a/third_party/WebKit/Source/core/testing/NullExecutionContext.h
+++ b/third_party/WebKit/Source/core/testing/NullExecutionContext.h
@@ -37,6 +37,8 @@
SecurityContext& securityContext() override { return *this; }
DOMTimerCoordinator* timers() override { return nullptr; }
+ double timerAlignmentInterval() const;
+
void addConsoleMessage(PassRefPtrWillBeRawPtr<ConsoleMessage>) override { }
void logExceptionToConsole(const String& errorMessage, int scriptId, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtrWillBeRawPtr<ScriptCallStack>) override { }
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
index d5776efe..adfe55e 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -148,6 +148,11 @@
m_script->disableEval(errorMessage);
}
+double WorkerGlobalScope::timerAlignmentInterval() const
+{
+ return DOMTimer::visiblePageAlignmentInterval();
+}
+
DOMTimerCoordinator* WorkerGlobalScope::timers()
{
return &m_timers;
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
index b03f823..0a0c4cb 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -120,6 +120,7 @@
bool isContextThread() const final;
bool isJSExecutionForbidden() const final;
+ double timerAlignmentInterval() const final;
DOMTimerCoordinator* timers() final;
WorkerInspectorController* workerInspectorController() { return m_workerInspectorController.get(); }
diff --git a/third_party/WebKit/Source/platform/Timer.cpp b/third_party/WebKit/Source/platform/Timer.cpp
index e27520d..ad619a3c 100644
--- a/third_party/WebKit/Source/platform/Timer.cpp
+++ b/third_party/WebKit/Source/platform/Timer.cpp
@@ -43,6 +43,7 @@
TimerBase::TimerBase()
: m_nextFireTime(0)
+ , m_unalignedNextFireTime(0)
, m_repeatInterval(0)
, m_cancellableTimerTask(nullptr)
, m_webScheduler(Platform::current()->currentThread()->scheduler())
@@ -95,16 +96,23 @@
{
ASSERT(m_thread == currentThread());
- double newTime = now + delay;
+ m_unalignedNextFireTime = now + delay;
+ double newTime = alignedFireTime(m_unalignedNextFireTime);
if (m_nextFireTime != newTime) {
m_nextFireTime = newTime;
if (m_cancellableTimerTask)
m_cancellableTimerTask->cancel();
m_cancellableTimerTask = new CancellableTimerTask(this);
-
- double delayMs = 1000.0 * (newTime - now);
- timerTaskRunner()->postDelayedTask(m_location, m_cancellableTimerTask, delayMs);
+ if (newTime != m_unalignedNextFireTime) {
+ // If the timer is being aligned, use postTimerTaskAt() to schedule it
+ // so that the relative order of aligned timers is preserved.
+ // TODO(skyostil): Move timer alignment into the scheduler.
+ m_webScheduler->postTimerTaskAt(m_location, m_cancellableTimerTask, m_nextFireTime);
+ } else {
+ double delayMs = 1000.0 * (newTime - now);
+ m_webScheduler->timerTaskRunner()->postDelayedTask(m_location, m_cancellableTimerTask, delayMs);
+ }
}
}
@@ -118,24 +126,34 @@
ASSERT_WITH_MESSAGE(m_thread == currentThread(), "Timer posted by %s %s was run on a different thread", m_location.functionName(), m_location.fileName());
TRACE_EVENT_SET_SAMPLING_STATE("blink", "BlinkInternal");
+ m_nextFireTime = 0;
if (m_repeatInterval) {
double now = monotonicallyIncreasingTime();
// This computation should be drift free, and it will cope if we miss a beat,
// which can easily happen if the thread is busy. It will also cope if we get
// called slightly before m_unalignedNextFireTime, which can happen due to lack
// of timer precision.
- double intervalToNextFireTime = m_repeatInterval - fmod(now - m_nextFireTime, m_repeatInterval);
+ double intervalToNextFireTime = m_repeatInterval - fmod(now - m_unalignedNextFireTime, m_repeatInterval);
setNextFireTime(monotonicallyIncreasingTime(), intervalToNextFireTime);
- } else {
- m_nextFireTime = 0;
}
fired();
TRACE_EVENT_SET_SAMPLING_STATE("blink", "Sleeping");
}
+void TimerBase::didChangeAlignmentInterval(double now)
+{
+ setNextFireTime(now, m_unalignedNextFireTime - now);
+}
+
+double TimerBase::nextUnalignedFireInterval() const
+{
+ ASSERT(isActive());
+ return std::max(m_unalignedNextFireTime - monotonicallyIncreasingTime(), 0.0);
+}
+
bool TimerBase::Comparator::operator()(const TimerBase* a, const TimerBase* b) const
{
- return a->m_nextFireTime < b->m_nextFireTime;
+ return a->m_unalignedNextFireTime < b->m_unalignedNextFireTime;
}
} // namespace blink
diff --git a/third_party/WebKit/Source/platform/Timer.h b/third_party/WebKit/Source/platform/Timer.h
index d6616a8..f2c4aa3 100644
--- a/third_party/WebKit/Source/platform/Timer.h
+++ b/third_party/WebKit/Source/platform/Timer.h
@@ -61,6 +61,7 @@
const WebTraceLocation& location() const { return m_location; }
double nextFireInterval() const;
+ double nextUnalignedFireInterval() const;
double repeatInterval() const { return m_repeatInterval; }
void augmentRepeatInterval(double delta) {
@@ -69,6 +70,8 @@
m_repeatInterval += delta;
}
+ void didChangeAlignmentInterval(double now);
+
struct PLATFORM_EXPORT Comparator {
bool operator()(const TimerBase* a, const TimerBase* b) const;
};
@@ -118,6 +121,7 @@
};
double m_nextFireTime; // 0 if inactive
+ double m_unalignedNextFireTime; // m_nextFireTime not considering alignment interval
double m_repeatInterval; // 0 if not repeating
WebTraceLocation m_location;
CancellableTimerTask* m_cancellableTimerTask; // NOT OWNED
diff --git a/third_party/WebKit/Source/platform/TimerTest.cpp b/third_party/WebKit/Source/platform/TimerTest.cpp
index 9f7bd52..4585d950 100644
--- a/third_party/WebKit/Source/platform/TimerTest.cpp
+++ b/third_party/WebKit/Source/platform/TimerTest.cpp
@@ -136,6 +136,11 @@
return nullptr;
}
+ void postTimerTaskAt(const WebTraceLocation&, WebTaskRunner::Task* task, double monotonicTime) override
+ {
+ m_timerTasks.push(DelayedTask(task, (monotonicTime - monotonicallyIncreasingTime()) * 1000));
+ }
+
void runUntilIdle()
{
while (m_timerTasks.size()) {
@@ -693,6 +698,80 @@
EXPECT_THAT(m_runTimes, ElementsAre(m_startTime + 20.0, m_startTime + 40.0));
}
+class MockTimerWithAlignment : public TimerBase {
+public:
+ MockTimerWithAlignment() : m_lastFireTime(0.0), m_alignedFireTime(0.0) { }
+
+ void fired() override
+ {
+ }
+
+ double alignedFireTime(double fireTime) const override
+ {
+ m_lastFireTime = fireTime;
+ return m_alignedFireTime;
+ }
+
+ void setAlignedFireTime(double alignedFireTime)
+ {
+ m_alignedFireTime = alignedFireTime;
+ }
+
+ double lastFireTime() const
+ {
+ return m_lastFireTime;
+ }
+
+private:
+ mutable double m_lastFireTime;
+ double m_alignedFireTime;
+};
+
+TEST_F(TimerTest, TimerAlignment_OneShotZero)
+{
+ MockTimerWithAlignment timer;
+ timer.setAlignedFireTime(m_startTime + 1.0);
+
+ timer.start(0.0, 0.0, BLINK_FROM_HERE);
+
+ // The nextFireInterval gets overrriden.
+ EXPECT_FLOAT_EQ(1.0, timer.nextFireInterval());
+ EXPECT_FLOAT_EQ(0.0, timer.nextUnalignedFireInterval());
+ EXPECT_FLOAT_EQ(m_startTime, timer.lastFireTime());
+}
+
+TEST_F(TimerTest, TimerAlignment_OneShotNonZero)
+{
+ MockTimerWithAlignment timer;
+ timer.setAlignedFireTime(m_startTime + 1.0);
+
+ timer.start(0.5, 0.0, BLINK_FROM_HERE);
+
+ // The nextFireInterval gets overrriden.
+ EXPECT_FLOAT_EQ(1.0, timer.nextFireInterval());
+ EXPECT_FLOAT_EQ(0.5, timer.nextUnalignedFireInterval());
+ EXPECT_FLOAT_EQ(m_startTime + 0.5, timer.lastFireTime());
+}
+
+TEST_F(TimerTest, DidChangeAlignmentInterval)
+{
+ MockTimerWithAlignment timer;
+ timer.setAlignedFireTime(m_startTime + 1.0);
+
+ timer.start(0.0, 0.0, BLINK_FROM_HERE);
+
+ EXPECT_FLOAT_EQ(1.0, timer.nextFireInterval());
+ EXPECT_FLOAT_EQ(0.0, timer.nextUnalignedFireInterval());
+ EXPECT_FLOAT_EQ(m_startTime, timer.lastFireTime());
+
+ timer.setAlignedFireTime(m_startTime);
+ timer.didChangeAlignmentInterval(monotonicallyIncreasingTime());
+
+ EXPECT_FLOAT_EQ(0.0, timer.nextFireInterval());
+ EXPECT_FLOAT_EQ(0.0, timer.nextUnalignedFireInterval());
+ EXPECT_FLOAT_EQ(m_startTime, timer.lastFireTime());
+}
+
TEST_F(TimerTest, RepeatingTimerDoesNotDrift)
{
Timer<TimerTest> timer(this, &TimerTest::recordNextFireTimeTask);
diff --git a/third_party/WebKit/public/platform/WebScheduler.h b/third_party/WebKit/public/platform/WebScheduler.h
index aeeb8f4..0af83a2d 100644
--- a/third_party/WebKit/public/platform/WebScheduler.h
+++ b/third_party/WebKit/public/platform/WebScheduler.h
@@ -60,6 +60,15 @@
// Takes ownership of |IdleTask|. Can be called from any thread.
virtual void postIdleTaskAfterWakeup(const WebTraceLocation&, WebThread::IdleTask*) = 0;
+ // Schedule a timer task to be run on the the associated WebThread. Timer Tasks
+ // tasks usually have the default priority, but may be delayed
+ // when the user is interacting with the device.
+ // |monotonicTime| is in the timebase of WTF::monotonicallyIncreasingTime().
+ // Takes ownership of |WebTaskRunner::Task|. Can be called from any thread.
+ // TODO(alexclarke): Move timer throttling for background pages to the
+ // chromium side and remove this.
+ virtual void postTimerTaskAt(const WebTraceLocation&, WebTaskRunner::Task*, double monotonicTime) = 0;
+
// Returns a WebTaskRunner for loading tasks. Can be called from any thread.
virtual WebTaskRunner* loadingTaskRunner() = 0;