| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/scheduler/task_queue_manager.h" | 5 #include "content/renderer/scheduler/task_queue_manager.h" |
| 6 | 6 |
| 7 #include <queue> | 7 #include <queue> |
| 8 #include <set> |
| 8 | 9 |
| 9 #include "base/bind.h" | 10 #include "base/bind.h" |
| 10 #include "base/trace_event/trace_event.h" | 11 #include "base/trace_event/trace_event.h" |
| 11 #include "base/trace_event/trace_event_argument.h" | 12 #include "base/trace_event/trace_event_argument.h" |
| 12 #include "cc/test/test_now_source.h" | 13 #include "cc/test/test_now_source.h" |
| 13 #include "content/renderer/scheduler/nestable_single_thread_task_runner.h" | 14 #include "content/renderer/scheduler/nestable_single_thread_task_runner.h" |
| 14 #include "content/renderer/scheduler/task_queue_selector.h" | 15 #include "content/renderer/scheduler/task_queue_selector.h" |
| 15 | 16 |
| 16 namespace { | 17 namespace { |
| 17 const int64_t kMaxTimeTicks = std::numeric_limits<int64>::max(); | 18 const int64_t kMaxTimeTicks = std::numeric_limits<int64>::max(); |
| 18 } | 19 } |
| 19 | 20 |
| 20 namespace content { | 21 namespace content { |
| 21 namespace internal { | 22 namespace internal { |
| 22 | 23 |
| 24 // Now() is somewhat expensive so it makes sense not to call Now() unless we |
| 25 // really need to. |
| 26 class LazyNow { |
| 27 public: |
| 28 explicit LazyNow(base::TimeTicks now) |
| 29 : task_queue_manager_(nullptr), now_(now) { |
| 30 DCHECK(!now.is_null()); |
| 31 } |
| 32 |
| 33 explicit LazyNow(TaskQueueManager* task_queue_manager) |
| 34 : task_queue_manager_(task_queue_manager) {} |
| 35 |
| 36 base::TimeTicks Now() { |
| 37 if (now_.is_null()) |
| 38 now_ = task_queue_manager_->Now(); |
| 39 return now_; |
| 40 } |
| 41 |
| 42 private: |
| 43 TaskQueueManager* task_queue_manager_; // NOT OWNED |
| 44 base::TimeTicks now_; |
| 45 }; |
| 46 |
| 23 class TaskQueue : public base::SingleThreadTaskRunner { | 47 class TaskQueue : public base::SingleThreadTaskRunner { |
| 24 public: | 48 public: |
| 25 TaskQueue(TaskQueueManager* task_queue_manager); | 49 TaskQueue(TaskQueueManager* task_queue_manager); |
| 26 | 50 |
| 27 // base::SingleThreadTaskRunner implementation. | 51 // base::SingleThreadTaskRunner implementation. |
| 28 bool RunsTasksOnCurrentThread() const override; | 52 bool RunsTasksOnCurrentThread() const override; |
| 29 bool PostDelayedTask(const tracked_objects::Location& from_here, | 53 bool PostDelayedTask(const tracked_objects::Location& from_here, |
| 30 const base::Closure& task, | 54 const base::Closure& task, |
| 31 base::TimeDelta delay) override { | 55 base::TimeDelta delay) override { |
| 32 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL); | 56 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL); |
| 33 } | 57 } |
| 34 | 58 |
| 35 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, | 59 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, |
| 36 const base::Closure& task, | 60 const base::Closure& task, |
| 37 base::TimeDelta delay) override { | 61 base::TimeDelta delay) override { |
| 38 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NON_NESTABLE); | 62 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NON_NESTABLE); |
| 39 } | 63 } |
| 40 | 64 |
| 41 bool IsQueueEmpty() const; | 65 bool IsQueueEmpty() const; |
| 42 | 66 |
| 43 void SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy); | 67 void SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy); |
| 44 void PumpQueue(); | 68 void PumpQueue(); |
| 45 | 69 |
| 46 bool NextPendingDelayedTaskRunTime( | 70 bool NextPendingDelayedTaskRunTime( |
| 47 base::TimeTicks* next_pending_delayed_task); | 71 base::TimeTicks* next_pending_delayed_task); |
| 48 | 72 |
| 49 bool UpdateWorkQueue(base::TimeTicks* next_pending_delayed_task, | 73 bool UpdateWorkQueue(LazyNow* lazy_now, |
| 50 const base::PendingTask* previous_task); | 74 const base::PendingTask* previous_task); |
| 51 base::PendingTask TakeTaskFromWorkQueue(); | 75 base::PendingTask TakeTaskFromWorkQueue(); |
| 52 | 76 |
| 53 void WillDeleteTaskQueueManager(); | 77 void WillDeleteTaskQueueManager(); |
| 54 | 78 |
| 55 base::TaskQueue& work_queue() { return work_queue_; } | 79 base::TaskQueue& work_queue() { return work_queue_; } |
| 56 | 80 |
| 57 void set_name(const char* name) { name_ = name; } | 81 void set_name(const char* name) { name_ = name; } |
| 58 | 82 |
| 59 void AsValueInto(base::trace_event::TracedValue* state) const; | 83 void AsValueInto(base::trace_event::TracedValue* state) const; |
| 60 | 84 |
| 61 private: | 85 private: |
| 62 enum class TaskType { | 86 enum class TaskType { |
| 63 NORMAL, | 87 NORMAL, |
| 64 NON_NESTABLE, | 88 NON_NESTABLE, |
| 65 }; | 89 }; |
| 66 | 90 |
| 67 ~TaskQueue() override; | 91 ~TaskQueue() override; |
| 68 | 92 |
| 69 bool PostDelayedTaskImpl(const tracked_objects::Location& from_here, | 93 bool PostDelayedTaskImpl(const tracked_objects::Location& from_here, |
| 70 const base::Closure& task, | 94 const base::Closure& task, |
| 71 base::TimeDelta delay, | 95 base::TimeDelta delay, |
| 72 TaskType task_type); | 96 TaskType task_type); |
| 73 | 97 |
| 74 // Adds a task at the end of the incoming task queue and schedules a call to | 98 // Delayed task posted to the underlying run loop, which locks |lock_| and |
| 75 // TaskQueueManager::DoWork() if the incoming queue was empty and automatic | 99 // calls MoveReadyDelayedTasksToIncomingQueueLocked to process dealyed tasks |
| 76 // pumping is enabled. Can be called on an arbitrary thread. | 100 // that need to be run now. |
| 77 void EnqueueTask(const base::PendingTask& pending_task); | 101 void MoveReadyDelayedTasksToIncomingQueue(); |
| 102 |
| 103 // Enqueues any delayed tasks which should be run now on the incoming_queue_ |
| 104 // and calls ScheduleDelayedWorkLocked to ensure future tasks are scheduled. |
| 105 // Must be called with |lock_| locked. |
| 106 void MoveReadyDelayedTasksToIncomingQueueLocked(LazyNow* lazy_now); |
| 107 |
| 108 // Posts MoveReadyDelayedTasksToIncomingQueue if there isn't already a task |
| 109 // posted on the underlying runloop for the next task's scheduled run time. |
| 110 void ScheduleDelayedWorkLocked(LazyNow* lazy_now); |
| 78 | 111 |
| 79 void PumpQueueLocked(); | 112 void PumpQueueLocked(); |
| 80 bool TaskIsOlderThanQueuedTasks(const base::PendingTask* task); | 113 bool TaskIsOlderThanQueuedTasks(const base::PendingTask* task); |
| 81 bool ShouldAutoPumpQueueLocked(const base::PendingTask* previous_task); | 114 bool ShouldAutoPumpQueueLocked(const base::PendingTask* previous_task); |
| 82 void EnqueueTaskLocked(const base::PendingTask& pending_task); | 115 void EnqueueTaskLocked(const base::PendingTask& pending_task); |
| 83 bool NextPendingDelayedTaskRunTimeLocked( | |
| 84 base::TimeTicks* next_pending_delayed_task); | |
| 85 | 116 |
| 86 void TraceQueueSize(bool is_locked) const; | 117 void TraceQueueSize(bool is_locked) const; |
| 87 static const char* PumpPolicyToString( | 118 static const char* PumpPolicyToString( |
| 88 TaskQueueManager::PumpPolicy pump_policy); | 119 TaskQueueManager::PumpPolicy pump_policy); |
| 89 static void QueueAsValueInto(const base::TaskQueue& queue, | 120 static void QueueAsValueInto(const base::TaskQueue& queue, |
| 90 base::trace_event::TracedValue* state); | 121 base::trace_event::TracedValue* state); |
| 122 static void QueueAsValueInto(const base::DelayedTaskQueue& queue, |
| 123 base::trace_event::TracedValue* state); |
| 91 static void TaskAsValueInto(const base::PendingTask& task, | 124 static void TaskAsValueInto(const base::PendingTask& task, |
| 92 base::trace_event::TracedValue* state); | 125 base::trace_event::TracedValue* state); |
| 93 | 126 |
| 94 // This lock protects all members except the work queue. | 127 // This lock protects all members except the work queue and the |
| 128 // main_thread_checker_. |
| 95 mutable base::Lock lock_; | 129 mutable base::Lock lock_; |
| 96 base::PlatformThreadId thread_id_; | 130 base::PlatformThreadId thread_id_; |
| 97 TaskQueueManager* task_queue_manager_; | 131 TaskQueueManager* task_queue_manager_; |
| 98 base::TaskQueue incoming_queue_; | 132 base::TaskQueue incoming_queue_; |
| 99 TaskQueueManager::PumpPolicy pump_policy_; | 133 TaskQueueManager::PumpPolicy pump_policy_; |
| 100 const char* name_; | 134 const char* name_; |
| 101 std::priority_queue<base::TimeTicks, | 135 base::DelayedTaskQueue delayed_task_queue_; |
| 102 std::vector<base::TimeTicks>, | 136 std::set<base::TimeTicks> in_flight_kick_delayed_tasks_; |
| 103 std::greater<base::TimeTicks>> delayed_task_run_times_; | |
| 104 | 137 |
| 138 base::ThreadChecker main_thread_checker_; |
| 105 base::TaskQueue work_queue_; | 139 base::TaskQueue work_queue_; |
| 106 | 140 |
| 107 DISALLOW_COPY_AND_ASSIGN(TaskQueue); | 141 DISALLOW_COPY_AND_ASSIGN(TaskQueue); |
| 108 }; | 142 }; |
| 109 | 143 |
| 110 TaskQueue::TaskQueue(TaskQueueManager* task_queue_manager) | 144 TaskQueue::TaskQueue(TaskQueueManager* task_queue_manager) |
| 111 : thread_id_(base::PlatformThread::CurrentId()), | 145 : thread_id_(base::PlatformThread::CurrentId()), |
| 112 task_queue_manager_(task_queue_manager), | 146 task_queue_manager_(task_queue_manager), |
| 113 pump_policy_(TaskQueueManager::PumpPolicy::AUTO), | 147 pump_policy_(TaskQueueManager::PumpPolicy::AUTO), |
| 114 name_(nullptr) { | 148 name_(nullptr) { |
| 115 } | 149 } |
| 116 | 150 |
| 117 TaskQueue::~TaskQueue() { | 151 TaskQueue::~TaskQueue() { |
| 118 } | 152 } |
| 119 | 153 |
| 120 void TaskQueue::WillDeleteTaskQueueManager() { | 154 void TaskQueue::WillDeleteTaskQueueManager() { |
| 121 base::AutoLock lock(lock_); | 155 base::AutoLock lock(lock_); |
| 122 task_queue_manager_ = nullptr; | 156 task_queue_manager_ = nullptr; |
| 157 // TODO(scheduler-dev): Should we also clear the other queues here too? |
| 158 delayed_task_queue_ = base::DelayedTaskQueue(); |
| 123 } | 159 } |
| 124 | 160 |
| 125 bool TaskQueue::RunsTasksOnCurrentThread() const { | 161 bool TaskQueue::RunsTasksOnCurrentThread() const { |
| 126 base::AutoLock lock(lock_); | 162 base::AutoLock lock(lock_); |
| 127 return base::PlatformThread::CurrentId() == thread_id_; | 163 return base::PlatformThread::CurrentId() == thread_id_; |
| 128 } | 164 } |
| 129 | 165 |
| 130 bool TaskQueue::PostDelayedTaskImpl(const tracked_objects::Location& from_here, | 166 bool TaskQueue::PostDelayedTaskImpl(const tracked_objects::Location& from_here, |
| 131 const base::Closure& task, | 167 const base::Closure& task, |
| 132 base::TimeDelta delay, | 168 base::TimeDelta delay, |
| 133 TaskType task_type) { | 169 TaskType task_type) { |
| 134 base::AutoLock lock(lock_); | 170 base::AutoLock lock(lock_); |
| 135 if (!task_queue_manager_) | 171 if (!task_queue_manager_) |
| 136 return false; | 172 return false; |
| 137 | 173 |
| 138 base::PendingTask pending_task(from_here, task, base::TimeTicks(), | 174 base::PendingTask pending_task(from_here, task, base::TimeTicks(), |
| 139 task_type != TaskType::NON_NESTABLE); | 175 task_type != TaskType::NON_NESTABLE); |
| 140 task_queue_manager_->DidQueueTask(&pending_task); | 176 task_queue_manager_->DidQueueTask(&pending_task); |
| 141 | 177 |
| 142 if (delay > base::TimeDelta()) { | 178 if (delay > base::TimeDelta()) { |
| 143 pending_task.delayed_run_time = task_queue_manager_->Now() + delay; | 179 base::TimeTicks now = task_queue_manager_->Now(); |
| 144 delayed_task_run_times_.push(pending_task.delayed_run_time); | 180 pending_task.delayed_run_time = now + delay; |
| 145 return task_queue_manager_->PostDelayedTask( | 181 delayed_task_queue_.push(pending_task); |
| 146 FROM_HERE, Bind(&TaskQueue::EnqueueTask, this, pending_task), delay); | 182 TraceQueueSize(true); |
| 183 // If we changed the topmost task, then it is time to reschedule. |
| 184 if (delayed_task_queue_.top().task.Equals(pending_task.task)) { |
| 185 LazyNow lazy_now(now); |
| 186 ScheduleDelayedWorkLocked(&lazy_now); |
| 187 } |
| 188 return true; |
| 147 } | 189 } |
| 148 EnqueueTaskLocked(pending_task); | 190 EnqueueTaskLocked(pending_task); |
| 149 return true; | 191 return true; |
| 150 } | 192 } |
| 151 | 193 |
| 194 void TaskQueue::MoveReadyDelayedTasksToIncomingQueue() { |
| 195 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 196 base::AutoLock lock(lock_); |
| 197 if (!task_queue_manager_) |
| 198 return; |
| 199 |
| 200 LazyNow lazy_now(task_queue_manager_); |
| 201 MoveReadyDelayedTasksToIncomingQueueLocked(&lazy_now); |
| 202 } |
| 203 |
| 204 void TaskQueue::MoveReadyDelayedTasksToIncomingQueueLocked(LazyNow* lazy_now) { |
| 205 lock_.AssertAcquired(); |
| 206 // Enqueue all delayed tasks that should be running now. |
| 207 while (!delayed_task_queue_.empty() && |
| 208 delayed_task_queue_.top().delayed_run_time <= lazy_now->Now()) { |
| 209 in_flight_kick_delayed_tasks_.erase( |
| 210 delayed_task_queue_.top().delayed_run_time); |
| 211 EnqueueTaskLocked(delayed_task_queue_.top()); |
| 212 delayed_task_queue_.pop(); |
| 213 } |
| 214 TraceQueueSize(true); |
| 215 ScheduleDelayedWorkLocked(lazy_now); |
| 216 } |
| 217 |
| 218 void TaskQueue::ScheduleDelayedWorkLocked(LazyNow* lazy_now) { |
| 219 lock_.AssertAcquired(); |
| 220 // Any remaining tasks are in the future, so queue a task to kick them. |
| 221 if (!delayed_task_queue_.empty()) { |
| 222 base::TimeTicks next_run_time = delayed_task_queue_.top().delayed_run_time; |
| 223 DCHECK_GT(next_run_time, lazy_now->Now()); |
| 224 // Make sure we don't have more than one |
| 225 // MoveReadyDelayedTasksToIncomingQueue posted for a particular scheduled |
| 226 // run time (note it's fine to have multiple ones in flight for distinct |
| 227 // run times). |
| 228 if (in_flight_kick_delayed_tasks_.find(next_run_time) == |
| 229 in_flight_kick_delayed_tasks_.end()) { |
| 230 in_flight_kick_delayed_tasks_.insert(next_run_time); |
| 231 base::TimeDelta delay = next_run_time - lazy_now->Now(); |
| 232 task_queue_manager_->PostDelayedTask( |
| 233 FROM_HERE, |
| 234 Bind(&TaskQueue::MoveReadyDelayedTasksToIncomingQueue, this), delay); |
| 235 } |
| 236 } |
| 237 } |
| 238 |
| 152 bool TaskQueue::IsQueueEmpty() const { | 239 bool TaskQueue::IsQueueEmpty() const { |
| 153 if (!work_queue_.empty()) | 240 if (!work_queue_.empty()) |
| 154 return false; | 241 return false; |
| 155 | 242 |
| 156 { | 243 { |
| 157 base::AutoLock lock(lock_); | 244 base::AutoLock lock(lock_); |
| 158 return incoming_queue_.empty(); | 245 return incoming_queue_.empty(); |
| 159 } | 246 } |
| 160 } | 247 } |
| 161 | 248 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 190 TaskIsOlderThanQueuedTasks(previous_task)) | 277 TaskIsOlderThanQueuedTasks(previous_task)) |
| 191 return false; | 278 return false; |
| 192 if (incoming_queue_.empty()) | 279 if (incoming_queue_.empty()) |
| 193 return false; | 280 return false; |
| 194 return true; | 281 return true; |
| 195 } | 282 } |
| 196 | 283 |
| 197 bool TaskQueue::NextPendingDelayedTaskRunTime( | 284 bool TaskQueue::NextPendingDelayedTaskRunTime( |
| 198 base::TimeTicks* next_pending_delayed_task) { | 285 base::TimeTicks* next_pending_delayed_task) { |
| 199 base::AutoLock lock(lock_); | 286 base::AutoLock lock(lock_); |
| 200 return NextPendingDelayedTaskRunTimeLocked(next_pending_delayed_task); | 287 if (delayed_task_queue_.empty()) |
| 288 return false; |
| 289 *next_pending_delayed_task = delayed_task_queue_.top().delayed_run_time; |
| 290 return true; |
| 201 } | 291 } |
| 202 | 292 |
| 203 bool TaskQueue::NextPendingDelayedTaskRunTimeLocked( | 293 bool TaskQueue::UpdateWorkQueue(LazyNow* lazy_now, |
| 204 base::TimeTicks* next_pending_delayed_task) { | 294 const base::PendingTask* previous_task) { |
| 205 lock_.AssertAcquired(); | |
| 206 if (!delayed_task_run_times_.empty()) { | |
| 207 *next_pending_delayed_task = | |
| 208 std::min(*next_pending_delayed_task, delayed_task_run_times_.top()); | |
| 209 return true; | |
| 210 } | |
| 211 return false; | |
| 212 } | |
| 213 | |
| 214 bool TaskQueue::UpdateWorkQueue( | |
| 215 base::TimeTicks* next_pending_delayed_task, | |
| 216 const base::PendingTask* previous_task) { | |
| 217 if (!work_queue_.empty()) | 295 if (!work_queue_.empty()) |
| 218 return true; | 296 return true; |
| 219 | 297 |
| 220 { | 298 { |
| 221 base::AutoLock lock(lock_); | 299 base::AutoLock lock(lock_); |
| 222 NextPendingDelayedTaskRunTimeLocked(next_pending_delayed_task); | 300 MoveReadyDelayedTasksToIncomingQueueLocked(lazy_now); |
| 223 if (!ShouldAutoPumpQueueLocked(previous_task)) | 301 if (!ShouldAutoPumpQueueLocked(previous_task)) |
| 224 return false; | 302 return false; |
| 303 MoveReadyDelayedTasksToIncomingQueueLocked(lazy_now); |
| 225 work_queue_.Swap(&incoming_queue_); | 304 work_queue_.Swap(&incoming_queue_); |
| 226 TraceQueueSize(true); | 305 TraceQueueSize(true); |
| 227 return true; | 306 return true; |
| 228 } | 307 } |
| 229 } | 308 } |
| 230 | 309 |
| 231 base::PendingTask TaskQueue::TakeTaskFromWorkQueue() { | 310 base::PendingTask TaskQueue::TakeTaskFromWorkQueue() { |
| 232 base::PendingTask pending_task = work_queue_.front(); | 311 base::PendingTask pending_task = work_queue_.front(); |
| 233 work_queue_.pop(); | 312 work_queue_.pop(); |
| 234 TraceQueueSize(false); | 313 TraceQueueSize(false); |
| 235 return pending_task; | 314 return pending_task; |
| 236 } | 315 } |
| 237 | 316 |
| 238 void TaskQueue::TraceQueueSize(bool is_locked) const { | 317 void TaskQueue::TraceQueueSize(bool is_locked) const { |
| 239 bool is_tracing; | 318 bool is_tracing; |
| 240 TRACE_EVENT_CATEGORY_GROUP_ENABLED( | 319 TRACE_EVENT_CATEGORY_GROUP_ENABLED( |
| 241 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), &is_tracing); | 320 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), &is_tracing); |
| 242 if (!is_tracing || !name_) | 321 if (!is_tracing || !name_) |
| 243 return; | 322 return; |
| 244 if (!is_locked) | 323 if (!is_locked) |
| 245 lock_.Acquire(); | 324 lock_.Acquire(); |
| 246 else | 325 else |
| 247 lock_.AssertAcquired(); | 326 lock_.AssertAcquired(); |
| 248 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), name_, | 327 TRACE_COUNTER1( |
| 249 incoming_queue_.size() + work_queue_.size()); | 328 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), name_, |
| 329 incoming_queue_.size() + work_queue_.size() + delayed_task_queue_.size()); |
| 250 if (!is_locked) | 330 if (!is_locked) |
| 251 lock_.Release(); | 331 lock_.Release(); |
| 252 } | 332 } |
| 253 | 333 |
| 254 void TaskQueue::EnqueueTask(const base::PendingTask& pending_task) { | |
| 255 base::AutoLock lock(lock_); | |
| 256 EnqueueTaskLocked(pending_task); | |
| 257 } | |
| 258 | |
| 259 void TaskQueue::EnqueueTaskLocked(const base::PendingTask& pending_task) { | 334 void TaskQueue::EnqueueTaskLocked(const base::PendingTask& pending_task) { |
| 260 lock_.AssertAcquired(); | 335 lock_.AssertAcquired(); |
| 261 if (!task_queue_manager_) | 336 if (!task_queue_manager_) |
| 262 return; | 337 return; |
| 263 if (pump_policy_ == TaskQueueManager::PumpPolicy::AUTO && | 338 if (pump_policy_ == TaskQueueManager::PumpPolicy::AUTO && |
| 264 incoming_queue_.empty()) | 339 incoming_queue_.empty()) |
| 265 task_queue_manager_->MaybePostDoWorkOnMainRunner(); | 340 task_queue_manager_->MaybePostDoWorkOnMainRunner(); |
| 266 incoming_queue_.push(pending_task); | 341 incoming_queue_.push(pending_task); |
| 267 | 342 |
| 268 if (!pending_task.delayed_run_time.is_null()) { | 343 if (!pending_task.delayed_run_time.is_null()) { |
| 269 // Update the time of the next pending delayed task. | |
| 270 while (!delayed_task_run_times_.empty() && | |
| 271 delayed_task_run_times_.top() <= pending_task.delayed_run_time) { | |
| 272 delayed_task_run_times_.pop(); | |
| 273 } | |
| 274 // Clear the delayed run time because we've already applied the delay | 344 // Clear the delayed run time because we've already applied the delay |
| 275 // before getting here. | 345 // before getting here. |
| 276 incoming_queue_.back().delayed_run_time = base::TimeTicks(); | 346 incoming_queue_.back().delayed_run_time = base::TimeTicks(); |
| 277 } | 347 } |
| 278 TraceQueueSize(true); | 348 TraceQueueSize(true); |
| 279 } | 349 } |
| 280 | 350 |
| 281 void TaskQueue::SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy) { | 351 void TaskQueue::SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy) { |
| 282 base::AutoLock lock(lock_); | 352 base::AutoLock lock(lock_); |
| 283 if (pump_policy == TaskQueueManager::PumpPolicy::AUTO && | 353 if (pump_policy == TaskQueueManager::PumpPolicy::AUTO && |
| 284 pump_policy_ != TaskQueueManager::PumpPolicy::AUTO) { | 354 pump_policy_ != TaskQueueManager::PumpPolicy::AUTO) { |
| 285 PumpQueueLocked(); | 355 PumpQueueLocked(); |
| 286 } | 356 } |
| 287 pump_policy_ = pump_policy; | 357 pump_policy_ = pump_policy; |
| 288 } | 358 } |
| 289 | 359 |
| 290 void TaskQueue::PumpQueueLocked() { | 360 void TaskQueue::PumpQueueLocked() { |
| 291 lock_.AssertAcquired(); | 361 lock_.AssertAcquired(); |
| 362 if (task_queue_manager_) { |
| 363 LazyNow lazy_now(task_queue_manager_); |
| 364 MoveReadyDelayedTasksToIncomingQueueLocked(&lazy_now); |
| 365 } |
| 292 while (!incoming_queue_.empty()) { | 366 while (!incoming_queue_.empty()) { |
| 293 work_queue_.push(incoming_queue_.front()); | 367 work_queue_.push(incoming_queue_.front()); |
| 294 incoming_queue_.pop(); | 368 incoming_queue_.pop(); |
| 295 } | 369 } |
| 296 if (!work_queue_.empty()) | 370 if (!work_queue_.empty()) |
| 297 task_queue_manager_->MaybePostDoWorkOnMainRunner(); | 371 task_queue_manager_->MaybePostDoWorkOnMainRunner(); |
| 298 } | 372 } |
| 299 | 373 |
| 300 void TaskQueue::PumpQueue() { | 374 void TaskQueue::PumpQueue() { |
| 301 base::AutoLock lock(lock_); | 375 base::AutoLock lock(lock_); |
| 302 PumpQueueLocked(); | 376 PumpQueueLocked(); |
| 303 } | 377 } |
| 304 | 378 |
| 305 void TaskQueue::AsValueInto(base::trace_event::TracedValue* state) const { | 379 void TaskQueue::AsValueInto(base::trace_event::TracedValue* state) const { |
| 306 base::AutoLock lock(lock_); | 380 base::AutoLock lock(lock_); |
| 307 state->BeginDictionary(); | 381 state->BeginDictionary(); |
| 308 if (name_) | 382 if (name_) |
| 309 state->SetString("name", name_); | 383 state->SetString("name", name_); |
| 310 state->SetString("pump_policy", PumpPolicyToString(pump_policy_)); | 384 state->SetString("pump_policy", PumpPolicyToString(pump_policy_)); |
| 311 state->BeginArray("incoming_queue"); | 385 state->BeginArray("incoming_queue"); |
| 312 QueueAsValueInto(incoming_queue_, state); | 386 QueueAsValueInto(incoming_queue_, state); |
| 313 state->EndArray(); | 387 state->EndArray(); |
| 314 state->BeginArray("work_queue"); | 388 state->BeginArray("work_queue"); |
| 315 QueueAsValueInto(work_queue_, state); | 389 QueueAsValueInto(work_queue_, state); |
| 390 state->BeginArray("delayed_task_queue"); |
| 391 QueueAsValueInto(delayed_task_queue_, state); |
| 316 state->EndArray(); | 392 state->EndArray(); |
| 317 state->EndDictionary(); | 393 state->EndDictionary(); |
| 318 } | 394 } |
| 319 | 395 |
| 320 // static | 396 // static |
| 321 const char* TaskQueue::PumpPolicyToString( | 397 const char* TaskQueue::PumpPolicyToString( |
| 322 TaskQueueManager::PumpPolicy pump_policy) { | 398 TaskQueueManager::PumpPolicy pump_policy) { |
| 323 switch (pump_policy) { | 399 switch (pump_policy) { |
| 324 case TaskQueueManager::PumpPolicy::AUTO: | 400 case TaskQueueManager::PumpPolicy::AUTO: |
| 325 return "auto"; | 401 return "auto"; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 337 void TaskQueue::QueueAsValueInto(const base::TaskQueue& queue, | 413 void TaskQueue::QueueAsValueInto(const base::TaskQueue& queue, |
| 338 base::trace_event::TracedValue* state) { | 414 base::trace_event::TracedValue* state) { |
| 339 base::TaskQueue queue_copy(queue); | 415 base::TaskQueue queue_copy(queue); |
| 340 while (!queue_copy.empty()) { | 416 while (!queue_copy.empty()) { |
| 341 TaskAsValueInto(queue_copy.front(), state); | 417 TaskAsValueInto(queue_copy.front(), state); |
| 342 queue_copy.pop(); | 418 queue_copy.pop(); |
| 343 } | 419 } |
| 344 } | 420 } |
| 345 | 421 |
| 346 // static | 422 // static |
| 423 void TaskQueue::QueueAsValueInto(const base::DelayedTaskQueue& queue, |
| 424 base::trace_event::TracedValue* state) { |
| 425 base::DelayedTaskQueue queue_copy(queue); |
| 426 while (!queue_copy.empty()) { |
| 427 TaskAsValueInto(queue_copy.top(), state); |
| 428 queue_copy.pop(); |
| 429 } |
| 430 } |
| 431 |
| 432 // static |
| 347 void TaskQueue::TaskAsValueInto(const base::PendingTask& task, | 433 void TaskQueue::TaskAsValueInto(const base::PendingTask& task, |
| 348 base::trace_event::TracedValue* state) { | 434 base::trace_event::TracedValue* state) { |
| 349 state->BeginDictionary(); | 435 state->BeginDictionary(); |
| 350 state->SetString("posted_from", task.posted_from.ToString()); | 436 state->SetString("posted_from", task.posted_from.ToString()); |
| 351 state->SetInteger("sequence_num", task.sequence_num); | 437 state->SetInteger("sequence_num", task.sequence_num); |
| 352 state->SetBoolean("nestable", task.nestable); | 438 state->SetBoolean("nestable", task.nestable); |
| 353 state->SetBoolean("is_high_res", task.is_high_res); | 439 state->SetBoolean("is_high_res", task.is_high_res); |
| 354 state->SetDouble( | 440 state->SetDouble( |
| 355 "delayed_run_time", | 441 "delayed_run_time", |
| 356 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L); | 442 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 409 internal::TaskQueue* queue = Queue(queue_index); | 495 internal::TaskQueue* queue = Queue(queue_index); |
| 410 return queue->IsQueueEmpty(); | 496 return queue->IsQueueEmpty(); |
| 411 } | 497 } |
| 412 | 498 |
| 413 base::TimeTicks TaskQueueManager::NextPendingDelayedTaskRunTime() { | 499 base::TimeTicks TaskQueueManager::NextPendingDelayedTaskRunTime() { |
| 414 DCHECK(main_thread_checker_.CalledOnValidThread()); | 500 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 415 bool found_pending_task = false; | 501 bool found_pending_task = false; |
| 416 base::TimeTicks next_pending_delayed_task( | 502 base::TimeTicks next_pending_delayed_task( |
| 417 base::TimeTicks::FromInternalValue(kMaxTimeTicks)); | 503 base::TimeTicks::FromInternalValue(kMaxTimeTicks)); |
| 418 for (auto& queue : queues_) { | 504 for (auto& queue : queues_) { |
| 419 found_pending_task |= | 505 base::TimeTicks queues_next_pending_delayed_task; |
| 420 queue->NextPendingDelayedTaskRunTime(&next_pending_delayed_task); | 506 if (queue->NextPendingDelayedTaskRunTime( |
| 507 &queues_next_pending_delayed_task)) { |
| 508 found_pending_task = true; |
| 509 next_pending_delayed_task = |
| 510 std::min(next_pending_delayed_task, queues_next_pending_delayed_task); |
| 511 } |
| 421 } | 512 } |
| 422 | 513 |
| 423 if (!found_pending_task) | 514 if (!found_pending_task) |
| 424 return base::TimeTicks(); | 515 return base::TimeTicks(); |
| 425 | 516 |
| 426 DCHECK_NE(next_pending_delayed_task, | 517 DCHECK_NE(next_pending_delayed_task, |
| 427 base::TimeTicks::FromInternalValue(kMaxTimeTicks)); | 518 base::TimeTicks::FromInternalValue(kMaxTimeTicks)); |
| 428 return next_pending_delayed_task; | 519 return next_pending_delayed_task; |
| 429 } | 520 } |
| 430 | 521 |
| 431 void TaskQueueManager::SetPumpPolicy(size_t queue_index, | 522 void TaskQueueManager::SetPumpPolicy(size_t queue_index, |
| 432 PumpPolicy pump_policy) { | 523 PumpPolicy pump_policy) { |
| 433 DCHECK(main_thread_checker_.CalledOnValidThread()); | 524 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 434 internal::TaskQueue* queue = Queue(queue_index); | 525 internal::TaskQueue* queue = Queue(queue_index); |
| 435 queue->SetPumpPolicy(pump_policy); | 526 queue->SetPumpPolicy(pump_policy); |
| 436 } | 527 } |
| 437 | 528 |
| 438 void TaskQueueManager::PumpQueue(size_t queue_index) { | 529 void TaskQueueManager::PumpQueue(size_t queue_index) { |
| 439 DCHECK(main_thread_checker_.CalledOnValidThread()); | 530 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 440 internal::TaskQueue* queue = Queue(queue_index); | 531 internal::TaskQueue* queue = Queue(queue_index); |
| 441 queue->PumpQueue(); | 532 queue->PumpQueue(); |
| 442 } | 533 } |
| 443 | 534 |
| 444 bool TaskQueueManager::UpdateWorkQueues( | 535 bool TaskQueueManager::UpdateWorkQueues( |
| 445 base::TimeTicks* next_pending_delayed_task, | |
| 446 const base::PendingTask* previous_task) { | 536 const base::PendingTask* previous_task) { |
| 447 // TODO(skyostil): This is not efficient when the number of queues grows very | 537 // TODO(skyostil): This is not efficient when the number of queues grows very |
| 448 // large due to the number of locks taken. Consider optimizing when we get | 538 // large due to the number of locks taken. Consider optimizing when we get |
| 449 // there. | 539 // there. |
| 450 DCHECK(main_thread_checker_.CalledOnValidThread()); | 540 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 541 internal::LazyNow lazy_now(this); |
| 451 bool has_work = false; | 542 bool has_work = false; |
| 452 for (auto& queue : queues_) { | 543 for (auto& queue : queues_) { |
| 453 has_work |= queue->UpdateWorkQueue(next_pending_delayed_task, | 544 has_work |= queue->UpdateWorkQueue(&lazy_now, previous_task); |
| 454 previous_task); | |
| 455 if (!queue->work_queue().empty()) { | 545 if (!queue->work_queue().empty()) { |
| 456 // Currently we should not be getting tasks with delayed run times in any | 546 // Currently we should not be getting tasks with delayed run times in any |
| 457 // of the work queues. | 547 // of the work queues. |
| 458 DCHECK(queue->work_queue().front().delayed_run_time.is_null()); | 548 DCHECK(queue->work_queue().front().delayed_run_time.is_null()); |
| 459 } | 549 } |
| 460 } | 550 } |
| 461 return has_work; | 551 return has_work; |
| 462 } | 552 } |
| 463 | 553 |
| 464 void TaskQueueManager::MaybePostDoWorkOnMainRunner() { | 554 void TaskQueueManager::MaybePostDoWorkOnMainRunner() { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 477 on_main_thread)); | 567 on_main_thread)); |
| 478 } | 568 } |
| 479 | 569 |
| 480 void TaskQueueManager::DoWork(bool posted_from_main_thread) { | 570 void TaskQueueManager::DoWork(bool posted_from_main_thread) { |
| 481 if (posted_from_main_thread) { | 571 if (posted_from_main_thread) { |
| 482 pending_dowork_count_--; | 572 pending_dowork_count_--; |
| 483 DCHECK_GE(pending_dowork_count_, 0); | 573 DCHECK_GE(pending_dowork_count_, 0); |
| 484 } | 574 } |
| 485 DCHECK(main_thread_checker_.CalledOnValidThread()); | 575 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 486 | 576 |
| 487 base::TimeTicks next_pending_delayed_task( | 577 // Pass nullptr to UpdateWorkQueues here to prevent waking up a |
| 488 base::TimeTicks::FromInternalValue(kMaxTimeTicks)); | |
| 489 | |
| 490 // Pass nullptr to UpdateWorkQueues here to prevent waking up an | |
| 491 // pump-after-wakeup queue. | 578 // pump-after-wakeup queue. |
| 492 if (!UpdateWorkQueues(&next_pending_delayed_task, nullptr)) | 579 if (!UpdateWorkQueues(nullptr)) |
| 493 return; | 580 return; |
| 494 | 581 |
| 495 base::PendingTask previous_task((tracked_objects::Location()), | 582 base::PendingTask previous_task((tracked_objects::Location()), |
| 496 (base::Closure())); | 583 (base::Closure())); |
| 497 for (int i = 0; i < work_batch_size_; i++) { | 584 for (int i = 0; i < work_batch_size_; i++) { |
| 498 // Interrupt the work batch if we should run the next delayed task. | |
| 499 if (i > 0 && next_pending_delayed_task.ToInternalValue() != kMaxTimeTicks && | |
| 500 Now() >= next_pending_delayed_task) | |
| 501 return; | |
| 502 | |
| 503 size_t queue_index; | 585 size_t queue_index; |
| 504 if (!SelectWorkQueueToService(&queue_index)) | 586 if (!SelectWorkQueueToService(&queue_index)) |
| 505 return; | 587 return; |
| 506 // Note that this function won't post another call to DoWork if one is | 588 // Note that this function won't post another call to DoWork if one is |
| 507 // already pending, so it is safe to call it in a loop. | 589 // already pending, so it is safe to call it in a loop. |
| 508 MaybePostDoWorkOnMainRunner(); | 590 MaybePostDoWorkOnMainRunner(); |
| 509 ProcessTaskFromWorkQueue(queue_index, i > 0, &previous_task); | 591 ProcessTaskFromWorkQueue(queue_index, i > 0, &previous_task); |
| 510 | 592 |
| 511 if (!UpdateWorkQueues(&next_pending_delayed_task, &previous_task)) | 593 if (!UpdateWorkQueues(&previous_task)) |
| 512 return; | 594 return; |
| 513 } | 595 } |
| 514 } | 596 } |
| 515 | 597 |
| 516 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) { | 598 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) { |
| 517 bool should_run = selector_->SelectWorkQueueToService(out_queue_index); | 599 bool should_run = selector_->SelectWorkQueueToService(out_queue_index); |
| 518 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( | 600 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( |
| 519 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this, | 601 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this, |
| 520 AsValueWithSelectorResult(should_run, *out_queue_index)); | 602 AsValueWithSelectorResult(should_run, *out_queue_index)); |
| 521 return should_run; | 603 return should_run; |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 state->EndArray(); | 697 state->EndArray(); |
| 616 state->BeginDictionary("selector"); | 698 state->BeginDictionary("selector"); |
| 617 selector_->AsValueInto(state.get()); | 699 selector_->AsValueInto(state.get()); |
| 618 state->EndDictionary(); | 700 state->EndDictionary(); |
| 619 if (should_run) | 701 if (should_run) |
| 620 state->SetInteger("selected_queue", selected_queue); | 702 state->SetInteger("selected_queue", selected_queue); |
| 621 return state; | 703 return state; |
| 622 } | 704 } |
| 623 | 705 |
| 624 } // namespace content | 706 } // namespace content |
| OLD | NEW |