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

Side by Side Diff: content/renderer/scheduler/task_queue_manager.cc

Issue 966813003: [content]: Ensure TaskQueueManager AFTER_WAKEUP autopump policy wakes only on newer tasks. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review comments Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/trace_event/trace_event.h" 10 #include "base/trace_event/trace_event.h"
(...skipping 25 matching lines...) Expand all
36 base::TimeDelta delay) override { 36 base::TimeDelta delay) override {
37 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NON_NESTABLE); 37 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NON_NESTABLE);
38 } 38 }
39 39
40 bool IsQueueEmpty() const; 40 bool IsQueueEmpty() const;
41 41
42 void SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy); 42 void SetPumpPolicy(TaskQueueManager::PumpPolicy pump_policy);
43 void PumpQueue(); 43 void PumpQueue();
44 44
45 bool UpdateWorkQueue(base::TimeTicks* next_pending_delayed_task, 45 bool UpdateWorkQueue(base::TimeTicks* next_pending_delayed_task,
46 TaskQueueManager::WorkQueueUpdateEventType event_type); 46 const base::PendingTask* previous_task);
47 base::PendingTask TakeTaskFromWorkQueue(); 47 base::PendingTask TakeTaskFromWorkQueue();
48 48
49 void WillDeleteTaskQueueManager(); 49 void WillDeleteTaskQueueManager();
50 50
51 base::TaskQueue& work_queue() { return work_queue_; } 51 base::TaskQueue& work_queue() { return work_queue_; }
52 52
53 void set_name(const char* name) { name_ = name; } 53 void set_name(const char* name) { name_ = name; }
54 54
55 void AsValueInto(base::trace_event::TracedValue* state) const; 55 void AsValueInto(base::trace_event::TracedValue* state) const;
56 56
57 private: 57 private:
58 enum class TaskType { 58 enum class TaskType {
59 NORMAL, 59 NORMAL,
60 NON_NESTABLE, 60 NON_NESTABLE,
61 }; 61 };
62 62
63 ~TaskQueue() override; 63 ~TaskQueue() override;
64 64
65 bool PostDelayedTaskImpl(const tracked_objects::Location& from_here, 65 bool PostDelayedTaskImpl(const tracked_objects::Location& from_here,
66 const base::Closure& task, 66 const base::Closure& task,
67 base::TimeDelta delay, 67 base::TimeDelta delay,
68 TaskType task_type); 68 TaskType task_type);
69 69
70 // Adds a task at the end of the incoming task queue and schedules a call to 70 // Adds a task at the end of the incoming task queue and schedules a call to
71 // TaskQueueManager::DoWork() if the incoming queue was empty and automatic 71 // TaskQueueManager::DoWork() if the incoming queue was empty and automatic
72 // pumping is enabled. Can be called on an arbitrary thread. 72 // pumping is enabled. Can be called on an arbitrary thread.
73 void EnqueueTask(const base::PendingTask& pending_task); 73 void EnqueueTask(const base::PendingTask& pending_task);
74 74
75 void PumpQueueLocked(); 75 void PumpQueueLocked();
76 bool ShouldAutoPumpQueueLocked( 76 bool TaskIsOlderThanQueuedTasks(const base::PendingTask* task);
77 TaskQueueManager::WorkQueueUpdateEventType event_type); 77 bool ShouldAutoPumpQueueLocked(const base::PendingTask* previous_task);
78 void EnqueueTaskLocked(const base::PendingTask& pending_task); 78 void EnqueueTaskLocked(const base::PendingTask& pending_task);
79 79
80 void TraceQueueSize(bool is_locked) const; 80 void TraceQueueSize(bool is_locked) const;
81 static const char* PumpPolicyToString( 81 static const char* PumpPolicyToString(
82 TaskQueueManager::PumpPolicy pump_policy); 82 TaskQueueManager::PumpPolicy pump_policy);
83 static void QueueAsValueInto(const base::TaskQueue& queue, 83 static void QueueAsValueInto(const base::TaskQueue& queue,
84 base::trace_event::TracedValue* state); 84 base::trace_event::TracedValue* state);
85 static void TaskAsValueInto(const base::PendingTask& task, 85 static void TaskAsValueInto(const base::PendingTask& task,
86 base::trace_event::TracedValue* state); 86 base::trace_event::TracedValue* state);
87 87
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 bool TaskQueue::IsQueueEmpty() const { 146 bool TaskQueue::IsQueueEmpty() const {
147 if (!work_queue_.empty()) 147 if (!work_queue_.empty())
148 return false; 148 return false;
149 149
150 { 150 {
151 base::AutoLock lock(lock_); 151 base::AutoLock lock(lock_);
152 return incoming_queue_.empty(); 152 return incoming_queue_.empty();
153 } 153 }
154 } 154 }
155 155
156 bool TaskQueue::TaskIsOlderThanQueuedTasks(const base::PendingTask* task) {
157 lock_.AssertAcquired();
158 // A null task is passed when UpdateQueue is called before any task is run.
159 // In this case we don't want to pump an after_wakeup queue, so return true
160 // here.
161 if (!task)
162 return true;
163
164 // Return false if there are no task in the incoming queue.
165 if (incoming_queue_.empty())
166 return false;
167
168 base::PendingTask oldest_queued_task = incoming_queue_.front();
169
170 // Note: the comparison is correct due to the fact that the PendingTask
171 // operator inverts its comparison operation in order to work well in a heap
172 // based priority queue.
173 return oldest_queued_task < *task;
174 }
175
156 bool TaskQueue::ShouldAutoPumpQueueLocked( 176 bool TaskQueue::ShouldAutoPumpQueueLocked(
157 TaskQueueManager::WorkQueueUpdateEventType event_type) { 177 const base::PendingTask* previous_task) {
158 lock_.AssertAcquired(); 178 lock_.AssertAcquired();
159 if (pump_policy_ == TaskQueueManager::PumpPolicy::MANUAL) 179 if (pump_policy_ == TaskQueueManager::PumpPolicy::MANUAL)
160 return false; 180 return false;
161 if (pump_policy_ == TaskQueueManager::PumpPolicy::AFTER_WAKEUP && 181 if (pump_policy_ == TaskQueueManager::PumpPolicy::AFTER_WAKEUP &&
162 event_type != TaskQueueManager::WorkQueueUpdateEventType::AFTER_WAKEUP) 182 TaskIsOlderThanQueuedTasks(previous_task))
163 return false; 183 return false;
164 if (incoming_queue_.empty()) 184 if (incoming_queue_.empty())
165 return false; 185 return false;
166 return true; 186 return true;
167 } 187 }
168 188
169 bool TaskQueue::UpdateWorkQueue( 189 bool TaskQueue::UpdateWorkQueue(
170 base::TimeTicks* next_pending_delayed_task, 190 base::TimeTicks* next_pending_delayed_task,
171 TaskQueueManager::WorkQueueUpdateEventType event_type) { 191 const base::PendingTask* previous_task) {
172 if (!work_queue_.empty()) 192 if (!work_queue_.empty())
173 return true; 193 return true;
174 194
175 { 195 {
176 base::AutoLock lock(lock_); 196 base::AutoLock lock(lock_);
177 if (!delayed_task_run_times_.empty()) { 197 if (!delayed_task_run_times_.empty()) {
178 *next_pending_delayed_task = 198 *next_pending_delayed_task =
179 std::min(*next_pending_delayed_task, delayed_task_run_times_.top()); 199 std::min(*next_pending_delayed_task, delayed_task_run_times_.top());
180 } 200 }
181 if (!ShouldAutoPumpQueueLocked(event_type)) 201 if (!ShouldAutoPumpQueueLocked(previous_task))
182 return false; 202 return false;
183 work_queue_.Swap(&incoming_queue_); 203 work_queue_.Swap(&incoming_queue_);
184 TraceQueueSize(true); 204 TraceQueueSize(true);
185 return true; 205 return true;
186 } 206 }
187 } 207 }
188 208
189 base::PendingTask TaskQueue::TakeTaskFromWorkQueue() { 209 base::PendingTask TaskQueue::TakeTaskFromWorkQueue() {
190 base::PendingTask pending_task = work_queue_.front(); 210 base::PendingTask pending_task = work_queue_.front();
191 work_queue_.pop(); 211 work_queue_.pop();
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 } 396 }
377 397
378 void TaskQueueManager::PumpQueue(size_t queue_index) { 398 void TaskQueueManager::PumpQueue(size_t queue_index) {
379 DCHECK(main_thread_checker_.CalledOnValidThread()); 399 DCHECK(main_thread_checker_.CalledOnValidThread());
380 internal::TaskQueue* queue = Queue(queue_index); 400 internal::TaskQueue* queue = Queue(queue_index);
381 queue->PumpQueue(); 401 queue->PumpQueue();
382 } 402 }
383 403
384 bool TaskQueueManager::UpdateWorkQueues( 404 bool TaskQueueManager::UpdateWorkQueues(
385 base::TimeTicks* next_pending_delayed_task, 405 base::TimeTicks* next_pending_delayed_task,
386 WorkQueueUpdateEventType event_type) { 406 const base::PendingTask* previous_task) {
387 // TODO(skyostil): This is not efficient when the number of queues grows very 407 // TODO(skyostil): This is not efficient when the number of queues grows very
388 // large due to the number of locks taken. Consider optimizing when we get 408 // large due to the number of locks taken. Consider optimizing when we get
389 // there. 409 // there.
390 DCHECK(main_thread_checker_.CalledOnValidThread()); 410 DCHECK(main_thread_checker_.CalledOnValidThread());
391 bool has_work = false; 411 bool has_work = false;
392 for (auto& queue : queues_) { 412 for (auto& queue : queues_) {
393 has_work |= queue->UpdateWorkQueue(next_pending_delayed_task, event_type); 413 has_work |= queue->UpdateWorkQueue(next_pending_delayed_task,
414 previous_task);
394 if (!queue->work_queue().empty()) { 415 if (!queue->work_queue().empty()) {
395 // Currently we should not be getting tasks with delayed run times in any 416 // Currently we should not be getting tasks with delayed run times in any
396 // of the work queues. 417 // of the work queues.
397 DCHECK(queue->work_queue().front().delayed_run_time.is_null()); 418 DCHECK(queue->work_queue().front().delayed_run_time.is_null());
398 } 419 }
399 } 420 }
400 return has_work; 421 return has_work;
401 } 422 }
402 423
403 void TaskQueueManager::MaybePostDoWorkOnMainRunner() { 424 void TaskQueueManager::MaybePostDoWorkOnMainRunner() {
(...skipping 14 matching lines...) Expand all
418 439
419 void TaskQueueManager::DoWork(bool posted_from_main_thread) { 440 void TaskQueueManager::DoWork(bool posted_from_main_thread) {
420 if (posted_from_main_thread) { 441 if (posted_from_main_thread) {
421 pending_dowork_count_--; 442 pending_dowork_count_--;
422 DCHECK_GE(pending_dowork_count_, 0); 443 DCHECK_GE(pending_dowork_count_, 0);
423 } 444 }
424 DCHECK(main_thread_checker_.CalledOnValidThread()); 445 DCHECK(main_thread_checker_.CalledOnValidThread());
425 446
426 base::TimeTicks next_pending_delayed_task( 447 base::TimeTicks next_pending_delayed_task(
427 base::TimeTicks::FromInternalValue(kMaxTimeTicks)); 448 base::TimeTicks::FromInternalValue(kMaxTimeTicks));
449 base::PendingTask previous_task((tracked_objects::Location()),
Sami 2015/03/02 15:55:58 nit: no need to move this here now.
rmcilroy 2015/03/02 16:47:52 Done.
450 (base::Closure()));
428 451
429 if (!UpdateWorkQueues(&next_pending_delayed_task, 452 // Pass nullptr to UpdateWorkQueues here to prevent waking up an
430 WorkQueueUpdateEventType::BEFORE_WAKEUP)) 453 // pump-after-wakeup queue.
454 if (!UpdateWorkQueues(&next_pending_delayed_task, nullptr))
431 return; 455 return;
432 456
433 base::PendingTask previous_task((tracked_objects::Location()),
434 (base::Closure()));
435 for (int i = 0; i < work_batch_size_; i++) { 457 for (int i = 0; i < work_batch_size_; i++) {
436 // Interrupt the work batch if we should run the next delayed task. 458 // Interrupt the work batch if we should run the next delayed task.
437 if (i > 0 && next_pending_delayed_task.ToInternalValue() != kMaxTimeTicks && 459 if (i > 0 && next_pending_delayed_task.ToInternalValue() != kMaxTimeTicks &&
438 Now() >= next_pending_delayed_task) 460 Now() >= next_pending_delayed_task)
439 return; 461 return;
440 462
441 size_t queue_index; 463 size_t queue_index;
442 if (!SelectWorkQueueToService(&queue_index)) 464 if (!SelectWorkQueueToService(&queue_index))
443 return; 465 return;
444 // Note that this function won't post another call to DoWork if one is 466 // Note that this function won't post another call to DoWork if one is
445 // already pending, so it is safe to call it in a loop. 467 // already pending, so it is safe to call it in a loop.
446 MaybePostDoWorkOnMainRunner(); 468 MaybePostDoWorkOnMainRunner();
447 ProcessTaskFromWorkQueue(queue_index, i > 0, &previous_task); 469 ProcessTaskFromWorkQueue(queue_index, i > 0, &previous_task);
448 470
449 if (!UpdateWorkQueues(&next_pending_delayed_task, 471 if (!UpdateWorkQueues(&next_pending_delayed_task, &previous_task))
450 WorkQueueUpdateEventType::AFTER_WAKEUP))
451 return; 472 return;
452 } 473 }
453 } 474 }
454 475
455 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) { 476 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) {
456 bool should_run = selector_->SelectWorkQueueToService(out_queue_index); 477 bool should_run = selector_->SelectWorkQueueToService(out_queue_index);
457 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( 478 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
458 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this, 479 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this,
459 AsValueWithSelectorResult(should_run, *out_queue_index)); 480 AsValueWithSelectorResult(should_run, *out_queue_index));
460 return should_run; 481 return should_run;
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 state->EndArray(); 575 state->EndArray();
555 state->BeginDictionary("selector"); 576 state->BeginDictionary("selector");
556 selector_->AsValueInto(state.get()); 577 selector_->AsValueInto(state.get());
557 state->EndDictionary(); 578 state->EndDictionary();
558 if (should_run) 579 if (should_run)
559 state->SetInteger("selected_queue", selected_queue); 580 state->SetInteger("selected_queue", selected_queue);
560 return state; 581 return state;
561 } 582 }
562 583
563 } // namespace content 584 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698