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

Side by Side Diff: components/scheduler/base/task_queue_selector.cc

Issue 1685093002: Fix bug with TaskQueueSelector and blocked queues (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Improve the dcheck Created 4 years, 10 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 "components/scheduler/base/task_queue_selector.h" 5 #include "components/scheduler/base/task_queue_selector.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/trace_event/trace_event_argument.h" 8 #include "base/trace_event/trace_event_argument.h"
9 #include "components/scheduler/base/task_queue_impl.h" 9 #include "components/scheduler/base/task_queue_impl.h"
10 #include "components/scheduler/base/work_queue.h" 10 #include "components/scheduler/base/work_queue.h"
11 11
12 namespace scheduler { 12 namespace scheduler {
13 namespace internal { 13 namespace internal {
14 14
15 TaskQueueSelector::TaskQueueSelector() 15 TaskQueueSelector::TaskQueueSelector()
16 : enabled_selector_(this), 16 : enabled_selector_(this, "enabled"),
17 blocked_selector_(this), 17 blocked_selector_(this, "blocked"),
18 immediate_starvation_count_(0), 18 immediate_starvation_count_(0),
19 high_priority_starvation_count_(0), 19 high_priority_starvation_count_(0),
20 num_blocked_queues_to_report_(0), 20 num_blocked_queues_to_report_(0),
21 task_queue_selector_observer_(nullptr) {} 21 task_queue_selector_observer_(nullptr) {}
22 22
23 TaskQueueSelector::~TaskQueueSelector() {} 23 TaskQueueSelector::~TaskQueueSelector() {}
24 24
25 void TaskQueueSelector::AddQueue(internal::TaskQueueImpl* queue) { 25 void TaskQueueSelector::AddQueue(internal::TaskQueueImpl* queue) {
26 DCHECK(main_thread_checker_.CalledOnValidThread()); 26 DCHECK(main_thread_checker_.CalledOnValidThread());
27 DCHECK(queue->IsQueueEnabled()); 27 DCHECK(queue->IsQueueEnabled());
28 SetQueuePriority(queue, TaskQueue::NORMAL_PRIORITY); 28 enabled_selector_.AddQueue(queue, TaskQueue::NORMAL_PRIORITY);
29 } 29 }
30 30
31 void TaskQueueSelector::RemoveQueue(internal::TaskQueueImpl* queue) { 31 void TaskQueueSelector::RemoveQueue(internal::TaskQueueImpl* queue) {
32 DCHECK(main_thread_checker_.CalledOnValidThread()); 32 DCHECK(main_thread_checker_.CalledOnValidThread());
33 if (queue->IsQueueEnabled()) { 33 if (queue->IsQueueEnabled()) {
34 enabled_selector_.RemoveQueue(queue); 34 enabled_selector_.RemoveQueue(queue);
35 DCHECK(!blocked_selector_.immediate_work_queue_sets()
Sami 2016/02/10 13:15:47 How about a helper on the selector that combines t
alex clarke (OOO till 29th) 2016/02/10 14:37:12 Done.
36 ->ContainsWorkQueueForTest(queue->immediate_work_queue()));
37 DCHECK(
38 !blocked_selector_.delayed_work_queue_sets()->ContainsWorkQueueForTest(
39 queue->delayed_work_queue()));
35 } else if (queue->should_report_when_execution_blocked()) { 40 } else if (queue->should_report_when_execution_blocked()) {
36 DCHECK_GT(num_blocked_queues_to_report_, 0u); 41 DCHECK_GT(num_blocked_queues_to_report_, 0u);
37 num_blocked_queues_to_report_--; 42 num_blocked_queues_to_report_--;
38 blocked_selector_.RemoveQueue(queue); 43 blocked_selector_.RemoveQueue(queue);
44 DCHECK(!enabled_selector_.immediate_work_queue_sets()
45 ->ContainsWorkQueueForTest(queue->immediate_work_queue()));
46 DCHECK(
47 !enabled_selector_.delayed_work_queue_sets()->ContainsWorkQueueForTest(
48 queue->delayed_work_queue()));
39 } 49 }
40 } 50 }
41 51
42 void TaskQueueSelector::EnableQueue(internal::TaskQueueImpl* queue) { 52 void TaskQueueSelector::EnableQueue(internal::TaskQueueImpl* queue) {
43 DCHECK(main_thread_checker_.CalledOnValidThread()); 53 DCHECK(main_thread_checker_.CalledOnValidThread());
44 DCHECK(queue->IsQueueEnabled()); 54 DCHECK(queue->IsQueueEnabled());
45 if (queue->should_report_when_execution_blocked()) { 55 if (queue->should_report_when_execution_blocked()) {
46 DCHECK_GT(num_blocked_queues_to_report_, 0u); 56 DCHECK_GT(num_blocked_queues_to_report_, 0u);
47 num_blocked_queues_to_report_--; 57 num_blocked_queues_to_report_--;
58 blocked_selector_.RemoveQueue(queue);
48 } 59 }
49 blocked_selector_.RemoveQueue(queue); 60 enabled_selector_.AddQueue(queue, queue->GetQueuePriority());
50 enabled_selector_.AssignQueueToSet(queue, queue->GetQueuePriority());
51 if (task_queue_selector_observer_) 61 if (task_queue_selector_observer_)
52 task_queue_selector_observer_->OnTaskQueueEnabled(queue); 62 task_queue_selector_observer_->OnTaskQueueEnabled(queue);
53 } 63 }
54 64
55 void TaskQueueSelector::DisableQueue(internal::TaskQueueImpl* queue) { 65 void TaskQueueSelector::DisableQueue(internal::TaskQueueImpl* queue) {
56 DCHECK(main_thread_checker_.CalledOnValidThread()); 66 DCHECK(main_thread_checker_.CalledOnValidThread());
57 DCHECK(!queue->IsQueueEnabled()); 67 DCHECK(!queue->IsQueueEnabled());
58 enabled_selector_.RemoveQueue(queue); 68 enabled_selector_.RemoveQueue(queue);
59 blocked_selector_.AssignQueueToSet(queue, queue->GetQueuePriority()); 69 if (queue->should_report_when_execution_blocked()) {
60 if (queue->should_report_when_execution_blocked()) 70 blocked_selector_.AddQueue(queue, queue->GetQueuePriority());
61 num_blocked_queues_to_report_++; 71 num_blocked_queues_to_report_++;
72 }
62 } 73 }
63 74
64 void TaskQueueSelector::SetQueuePriority(internal::TaskQueueImpl* queue, 75 void TaskQueueSelector::SetQueuePriority(internal::TaskQueueImpl* queue,
65 TaskQueue::QueuePriority priority) { 76 TaskQueue::QueuePriority priority) {
66 DCHECK_LT(priority, TaskQueue::QUEUE_PRIORITY_COUNT); 77 DCHECK_LT(priority, TaskQueue::QUEUE_PRIORITY_COUNT);
67 DCHECK(main_thread_checker_.CalledOnValidThread()); 78 DCHECK(main_thread_checker_.CalledOnValidThread());
68 if (queue->IsQueueEnabled()) { 79 if (queue->IsQueueEnabled()) {
69 enabled_selector_.AssignQueueToSet(queue, priority); 80 enabled_selector_.ChangeSetIndex(queue, priority);
81 } else if (queue->should_report_when_execution_blocked()) {
82 blocked_selector_.ChangeSetIndex(queue, priority);
70 } else { 83 } else {
71 blocked_selector_.AssignQueueToSet(queue, priority); 84 queue->delayed_work_queue()->AssignSetIndex(priority);
Sami 2016/02/10 13:15:47 Mind adding a comment here why we need to do this
alex clarke (OOO till 29th) 2016/02/10 14:37:12 Done.
85 queue->immediate_work_queue()->AssignSetIndex(priority);
72 } 86 }
73 DCHECK_EQ(priority, queue->GetQueuePriority()); 87 DCHECK_EQ(priority, queue->GetQueuePriority());
74 } 88 }
75 89
76 TaskQueue::QueuePriority TaskQueueSelector::NextPriority( 90 TaskQueue::QueuePriority TaskQueueSelector::NextPriority(
77 TaskQueue::QueuePriority priority) { 91 TaskQueue::QueuePriority priority) {
78 DCHECK(priority < TaskQueue::QUEUE_PRIORITY_COUNT); 92 DCHECK(priority < TaskQueue::QUEUE_PRIORITY_COUNT);
79 return static_cast<TaskQueue::QueuePriority>(static_cast<int>(priority) + 1); 93 return static_cast<TaskQueue::QueuePriority>(static_cast<int>(priority) + 1);
80 } 94 }
81 95
82 TaskQueueSelector::PrioritizingSelector::PrioritizingSelector( 96 TaskQueueSelector::PrioritizingSelector::PrioritizingSelector(
83 TaskQueueSelector* task_queue_selector) 97 TaskQueueSelector* task_queue_selector,
98 const char* name)
84 : task_queue_selector_(task_queue_selector), 99 : task_queue_selector_(task_queue_selector),
85 delayed_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT), 100 delayed_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT, name),
86 immediate_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT) {} 101 immediate_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT, name) {}
87 102
88 void TaskQueueSelector::PrioritizingSelector::AssignQueueToSet( 103 void TaskQueueSelector::PrioritizingSelector::AddQueue(
89 internal::TaskQueueImpl* queue, 104 internal::TaskQueueImpl* queue,
90 TaskQueue::QueuePriority priority) { 105 TaskQueue::QueuePriority priority) {
91 delayed_work_queue_sets_.AssignQueueToSet(queue->delayed_work_queue(), 106 // The #if DCHECK_IS_ON() shouldn't be necessary but this doesn't compile on
107 // chromeos bots without it :(
108 #if DCHECK_IS_ON()
109 DCHECK(!delayed_work_queue_sets_.ContainsWorkQueueForTest(
110 queue->delayed_work_queue()));
111 DCHECK(!immediate_work_queue_sets_.ContainsWorkQueueForTest(
112 queue->immediate_work_queue()));
113 #endif
114 delayed_work_queue_sets_.AddQueue(queue->delayed_work_queue(), priority);
115 immediate_work_queue_sets_.AddQueue(queue->immediate_work_queue(), priority);
116 #if DCHECK_IS_ON()
117 DCHECK(delayed_work_queue_sets_.ContainsWorkQueueForTest(
118 queue->delayed_work_queue()));
119 DCHECK(immediate_work_queue_sets_.ContainsWorkQueueForTest(
120 queue->immediate_work_queue()));
121 #endif
122 }
123
124 void TaskQueueSelector::PrioritizingSelector::ChangeSetIndex(
125 internal::TaskQueueImpl* queue,
126 TaskQueue::QueuePriority priority) {
127 // The #if DCHECK_IS_ON() shouldn't be necessary but this doesn't compile on
Sami 2016/02/10 13:15:47 nit: might not need to repeat this comment since i
128 // chromeos bots without it :(
129 #if DCHECK_IS_ON()
130 DCHECK(delayed_work_queue_sets_.ContainsWorkQueueForTest(
131 queue->delayed_work_queue()));
132 DCHECK(immediate_work_queue_sets_.ContainsWorkQueueForTest(
133 queue->immediate_work_queue()));
134 #endif
135 delayed_work_queue_sets_.ChangeSetIndex(queue->delayed_work_queue(),
136 priority);
137 immediate_work_queue_sets_.ChangeSetIndex(queue->immediate_work_queue(),
92 priority); 138 priority);
93 immediate_work_queue_sets_.AssignQueueToSet(queue->immediate_work_queue(),
94 priority);
95 // The #if DCHECK_IS_ON() shouldn't be necessary but this doesn't compile on
96 // chromeos bots without it :(
97 #if DCHECK_IS_ON() 139 #if DCHECK_IS_ON()
98 DCHECK_EQ(queue->delayed_work_queue()->Empty(), 140 DCHECK(delayed_work_queue_sets_.ContainsWorkQueueForTest(
99 !delayed_work_queue_sets_.ContainsWorkQueueForTest( 141 queue->delayed_work_queue()));
100 queue->delayed_work_queue())); 142 DCHECK(immediate_work_queue_sets_.ContainsWorkQueueForTest(
101 DCHECK_EQ(queue->immediate_work_queue()->Empty(), 143 queue->immediate_work_queue()));
102 !immediate_work_queue_sets_.ContainsWorkQueueForTest(
103 queue->immediate_work_queue()));
104 #endif 144 #endif
105 } 145 }
106 146
107 void TaskQueueSelector::PrioritizingSelector::RemoveQueue( 147 void TaskQueueSelector::PrioritizingSelector::RemoveQueue(
108 internal::TaskQueueImpl* queue) { 148 internal::TaskQueueImpl* queue) {
109 #if DCHECK_IS_ON() 149 #if DCHECK_IS_ON()
110 DCHECK_EQ(queue->delayed_work_queue()->Empty(), 150 DCHECK(delayed_work_queue_sets_.ContainsWorkQueueForTest(
111 !delayed_work_queue_sets_.ContainsWorkQueueForTest( 151 queue->delayed_work_queue()));
112 queue->delayed_work_queue())) 152 DCHECK(immediate_work_queue_sets_.ContainsWorkQueueForTest(
113 << " Did you try to RemoveQueue twice? Thats not supported!"; 153 queue->immediate_work_queue()));
114 DCHECK_EQ(queue->immediate_work_queue()->Empty(),
115 !immediate_work_queue_sets_.ContainsWorkQueueForTest(
116 queue->immediate_work_queue()))
117 << " Did you try to RemoveQueue twice? Thats not supported!";
118 #endif 154 #endif
119 delayed_work_queue_sets_.RemoveQueue(queue->delayed_work_queue()); 155 delayed_work_queue_sets_.RemoveQueue(queue->delayed_work_queue());
120 immediate_work_queue_sets_.RemoveQueue(queue->immediate_work_queue()); 156 immediate_work_queue_sets_.RemoveQueue(queue->immediate_work_queue());
121 157
122 #if DCHECK_IS_ON() 158 #if DCHECK_IS_ON()
123 DCHECK(!delayed_work_queue_sets_.ContainsWorkQueueForTest( 159 DCHECK(!delayed_work_queue_sets_.ContainsWorkQueueForTest(
124 queue->delayed_work_queue())); 160 queue->delayed_work_queue()));
125 DCHECK(!immediate_work_queue_sets_.ContainsWorkQueueForTest( 161 DCHECK(!immediate_work_queue_sets_.ContainsWorkQueueForTest(
126 queue->delayed_work_queue())); 162 queue->immediate_work_queue()));
127 #endif 163 #endif
128 } 164 }
129 165
130 bool TaskQueueSelector::PrioritizingSelector:: 166 bool TaskQueueSelector::PrioritizingSelector::
131 ChooseOldestImmediateTaskWithPriority(TaskQueue::QueuePriority priority, 167 ChooseOldestImmediateTaskWithPriority(TaskQueue::QueuePriority priority,
132 WorkQueue** out_work_queue) const { 168 WorkQueue** out_work_queue) const {
133 return immediate_work_queue_sets_.GetOldestQueueInSet(priority, 169 return immediate_work_queue_sets_.GetOldestQueueInSet(priority,
134 out_work_queue); 170 out_work_queue);
135 } 171 }
136 172
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 } 268 }
233 269
234 TrySelectingBlockedQueueOverEnabledQueue(**out_work_queue); 270 TrySelectingBlockedQueueOverEnabledQueue(**out_work_queue);
235 DidSelectQueueWithPriority( 271 DidSelectQueueWithPriority(
236 (*out_work_queue)->task_queue()->GetQueuePriority(), 272 (*out_work_queue)->task_queue()->GetQueuePriority(),
237 chose_delayed_over_immediate); 273 chose_delayed_over_immediate);
238 return true; 274 return true;
239 } 275 }
240 276
241 void TaskQueueSelector::TrySelectingBlockedQueue() { 277 void TaskQueueSelector::TrySelectingBlockedQueue() {
278 DCHECK(main_thread_checker_.CalledOnValidThread());
242 if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_) 279 if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_)
243 return; 280 return;
244 WorkQueue* chosen_blocked_queue; 281 WorkQueue* chosen_blocked_queue;
245 bool chose_delayed_over_immediate = false; 282 bool chose_delayed_over_immediate = false;
246 // There was nothing unblocked to run, see if we could have run a blocked 283 // There was nothing unblocked to run, see if we could have run a blocked
247 // task. 284 // task.
248 if (blocked_selector_.SelectWorkQueueToService( 285 if (blocked_selector_.SelectWorkQueueToService(
249 TaskQueue::QUEUE_PRIORITY_COUNT, &chosen_blocked_queue, 286 TaskQueue::QUEUE_PRIORITY_COUNT, &chosen_blocked_queue,
250 &chose_delayed_over_immediate)) { 287 &chose_delayed_over_immediate)) {
251 task_queue_selector_observer_->OnTriedToSelectBlockedWorkQueue( 288 task_queue_selector_observer_->OnTriedToSelectBlockedWorkQueue(
252 chosen_blocked_queue); 289 chosen_blocked_queue);
253 } 290 }
254 } 291 }
255 292
256 void TaskQueueSelector::TrySelectingBlockedQueueOverEnabledQueue( 293 void TaskQueueSelector::TrySelectingBlockedQueueOverEnabledQueue(
257 const WorkQueue& chosen_enabled_queue) { 294 const WorkQueue& chosen_enabled_queue) {
295 DCHECK(main_thread_checker_.CalledOnValidThread());
258 if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_) 296 if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_)
259 return; 297 return;
260 298
261 TaskQueue::QueuePriority max_priority = 299 TaskQueue::QueuePriority max_priority =
262 NextPriority(chosen_enabled_queue.task_queue()->GetQueuePriority()); 300 NextPriority(chosen_enabled_queue.task_queue()->GetQueuePriority());
263 301
264 WorkQueue* chosen_blocked_queue; 302 WorkQueue* chosen_blocked_queue;
265 bool chose_delayed_over_immediate = false; 303 bool chose_delayed_over_immediate = false;
266 bool found_queue = blocked_selector_.SelectWorkQueueToService( 304 bool found_queue = blocked_selector_.SelectWorkQueueToService(
267 max_priority, &chosen_blocked_queue, &chose_delayed_over_immediate); 305 max_priority, &chosen_blocked_queue, &chose_delayed_over_immediate);
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 state->SetInteger("immediate_starvation_count", immediate_starvation_count_); 356 state->SetInteger("immediate_starvation_count", immediate_starvation_count_);
319 state->SetInteger("num_blocked_queues_to_report", 357 state->SetInteger("num_blocked_queues_to_report",
320 num_blocked_queues_to_report_); 358 num_blocked_queues_to_report_);
321 } 359 }
322 360
323 void TaskQueueSelector::SetTaskQueueSelectorObserver(Observer* observer) { 361 void TaskQueueSelector::SetTaskQueueSelectorObserver(Observer* observer) {
324 task_queue_selector_observer_ = observer; 362 task_queue_selector_observer_ = observer;
325 } 363 }
326 364
327 bool TaskQueueSelector::EnabledWorkQueuesEmpty() const { 365 bool TaskQueueSelector::EnabledWorkQueuesEmpty() const {
366 DCHECK(main_thread_checker_.CalledOnValidThread());
328 for (TaskQueue::QueuePriority priority = TaskQueue::CONTROL_PRIORITY; 367 for (TaskQueue::QueuePriority priority = TaskQueue::CONTROL_PRIORITY;
329 priority < TaskQueue::QUEUE_PRIORITY_COUNT; 368 priority < TaskQueue::QUEUE_PRIORITY_COUNT;
330 priority = NextPriority(priority)) { 369 priority = NextPriority(priority)) {
331 if (!enabled_selector_.delayed_work_queue_sets()->IsSetEmpty(priority) || 370 if (!enabled_selector_.delayed_work_queue_sets()->IsSetEmpty(priority) ||
332 !enabled_selector_.immediate_work_queue_sets()->IsSetEmpty(priority)) { 371 !enabled_selector_.immediate_work_queue_sets()->IsSetEmpty(priority)) {
333 return false; 372 return false;
334 } 373 }
335 } 374 }
336 return true; 375 return true;
337 } 376 }
338 377
339 void TaskQueueSelector::SetImmediateStarvationCountForTest( 378 void TaskQueueSelector::SetImmediateStarvationCountForTest(
340 size_t immediate_starvation_count) { 379 size_t immediate_starvation_count) {
341 immediate_starvation_count_ = immediate_starvation_count; 380 immediate_starvation_count_ = immediate_starvation_count;
342 } 381 }
343 382
344 } // namespace internal 383 } // namespace internal
345 } // namespace scheduler 384 } // namespace scheduler
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698