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

Side by Side Diff: third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc

Issue 2276353002: Remove after wakeup logic and replace PumpTask with Fences (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased Created 4 years, 3 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 "platform/scheduler/base/task_queue_manager.h" 5 #include "platform/scheduler/base/task_queue_manager.h"
6 6
7 #include <queue> 7 #include <queue>
8 #include <set> 8 #include <set>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 if (observer_) 121 if (observer_)
122 observer_->OnUnregisterTaskQueue(task_queue); 122 observer_->OnUnregisterTaskQueue(task_queue);
123 123
124 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being 124 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being
125 // freed while any of our structures hold hold a raw pointer to it. 125 // freed while any of our structures hold hold a raw pointer to it.
126 queues_to_delete_.insert(task_queue); 126 queues_to_delete_.insert(task_queue);
127 queues_.erase(task_queue); 127 queues_.erase(task_queue);
128 selector_.RemoveQueue(task_queue.get()); 128 selector_.RemoveQueue(task_queue.get());
129 } 129 }
130 130
131 void TaskQueueManager::UpdateWorkQueues( 131 void TaskQueueManager::UpdateWorkQueues(LazyNow lazy_now) {
132 bool should_trigger_wakeup,
133 const internal::TaskQueueImpl::Task* previous_task,
134 LazyNow lazy_now) {
135 TRACE_EVENT0(disabled_by_default_tracing_category_, 132 TRACE_EVENT0(disabled_by_default_tracing_category_,
136 "TaskQueueManager::UpdateWorkQueues"); 133 "TaskQueueManager::UpdateWorkQueues");
137 134
138 for (TimeDomain* time_domain : time_domains_) { 135 for (TimeDomain* time_domain : time_domains_) {
139 LazyNow lazy_now_in_domain = time_domain == real_time_domain_.get() 136 LazyNow lazy_now_in_domain = time_domain == real_time_domain_.get()
140 ? lazy_now 137 ? lazy_now
141 : time_domain->CreateLazyNow(); 138 : time_domain->CreateLazyNow();
142 time_domain->UpdateWorkQueues(should_trigger_wakeup, previous_task, 139 time_domain->UpdateWorkQueues(lazy_now_in_domain);
143 lazy_now_in_domain);
144 } 140 }
145 } 141 }
146 142
147 void TaskQueueManager::MaybeScheduleImmediateWork( 143 void TaskQueueManager::MaybeScheduleImmediateWork(
148 const tracked_objects::Location& from_here) { 144 const tracked_objects::Location& from_here) {
149 bool on_main_thread = delegate_->BelongsToCurrentThread(); 145 bool on_main_thread = delegate_->BelongsToCurrentThread();
150 // De-duplicate DoWork posts. 146 // De-duplicate DoWork posts.
151 if (on_main_thread) { 147 if (on_main_thread) {
152 if (!main_thread_pending_wakeups_.insert(base::TimeTicks()).second) { 148 if (!main_thread_pending_wakeups_.insert(base::TimeTicks()).second) {
153 return; 149 return;
(...skipping 30 matching lines...) Expand all
184 DCHECK(main_thread_checker_.CalledOnValidThread()); 180 DCHECK(main_thread_checker_.CalledOnValidThread());
185 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", 181 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork",
186 "from_main_thread", from_main_thread); 182 "from_main_thread", from_main_thread);
187 if (from_main_thread) { 183 if (from_main_thread) {
188 main_thread_pending_wakeups_.erase(run_time); 184 main_thread_pending_wakeups_.erase(run_time);
189 } else { 185 } else {
190 base::AutoLock lock(other_thread_lock_); 186 base::AutoLock lock(other_thread_lock_);
191 other_thread_pending_wakeups_.erase(run_time); 187 other_thread_pending_wakeups_.erase(run_time);
192 } 188 }
193 189
190 // TODO(alexclarke): Add a base::RunLoop observer and prevent
191 // MaybeScheduleImmediateWork posting MaybeScheduleImmediateWork while DoWork
192 // is running. We'll need to post a DoWork on entering and leaving a nested
193 // run loop.
194
194 if (!delegate_->IsNested()) 195 if (!delegate_->IsNested())
195 queues_to_delete_.clear(); 196 queues_to_delete_.clear();
196 197
197 LazyNow lazy_now(real_time_domain()->CreateLazyNow()); 198 LazyNow lazy_now(real_time_domain()->CreateLazyNow());
198 base::TimeTicks task_start_time; 199 base::TimeTicks task_start_time;
199 200
200 if (!delegate_->IsNested() && task_time_tracker_) 201 if (!delegate_->IsNested() && task_time_tracker_)
201 task_start_time = lazy_now.Now(); 202 task_start_time = lazy_now.Now();
202 203
203 // Pass false and nullptr to UpdateWorkQueues here to prevent waking up a 204 // TODO(alexclarke): Get rid of this and call once per loop iteration.
204 // pump-after-wakeup queue. 205 UpdateWorkQueues(lazy_now);
205 UpdateWorkQueues(false, nullptr, lazy_now);
206
207 internal::TaskQueueImpl::Task previous_task;
208 206
209 for (int i = 0; i < work_batch_size_; i++) { 207 for (int i = 0; i < work_batch_size_; i++) {
210 internal::WorkQueue* work_queue; 208 internal::WorkQueue* work_queue;
211 if (!SelectWorkQueueToService(&work_queue)) { 209 if (!SelectWorkQueueToService(&work_queue))
212 break; 210 break;
213 }
214 211
215 bool should_trigger_wakeup = work_queue->task_queue()->wakeup_policy() == 212 switch (ProcessTaskFromWorkQueue(work_queue)) {
216 TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES;
217
218 switch (ProcessTaskFromWorkQueue(work_queue, &previous_task)) {
219 case ProcessTaskResult::DEFERRED: 213 case ProcessTaskResult::DEFERRED:
220 // If a task was deferred, try again with another task. Note that this 214 // If a task was deferred, try again with another task.
221 // means deferred tasks (i.e. non-nestable tasks) will never trigger
222 // queue wake-ups.
223 continue; 215 continue;
224 case ProcessTaskResult::EXECUTED: 216 case ProcessTaskResult::EXECUTED:
225 break; 217 break;
226 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: 218 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED:
227 return; // The TaskQueueManager got deleted, we must bail out. 219 return; // The TaskQueueManager got deleted, we must bail out.
228 } 220 }
229 221
230 lazy_now = real_time_domain()->CreateLazyNow(); 222 lazy_now = real_time_domain()->CreateLazyNow();
231 if (!delegate_->IsNested() && task_time_tracker_) { 223 if (!delegate_->IsNested() && task_time_tracker_) {
232 // Only report top level task durations. 224 // Only report top level task durations.
233 base::TimeTicks task_end_time = lazy_now.Now(); 225 base::TimeTicks task_end_time = lazy_now.Now();
234 task_time_tracker_->ReportTaskTime(task_start_time, task_end_time); 226 task_time_tracker_->ReportTaskTime(task_start_time, task_end_time);
235 task_start_time = task_end_time; 227 task_start_time = task_end_time;
236 } 228 }
237 229
238 work_queue = nullptr; // The queue may have been unregistered. 230 work_queue = nullptr; // The queue may have been unregistered.
239 231
240 UpdateWorkQueues(should_trigger_wakeup, &previous_task, lazy_now); 232 UpdateWorkQueues(lazy_now);
241 233
242 // Only run a single task per batch in nested run loops so that we can 234 // Only run a single task per batch in nested run loops so that we can
243 // properly exit the nested loop when someone calls RunLoop::Quit(). 235 // properly exit the nested loop when someone calls RunLoop::Quit().
244 if (delegate_->IsNested()) 236 if (delegate_->IsNested())
245 break; 237 break;
246 } 238 }
247 239
248 // TODO(alexclarke): Consider refactoring the above loop to terminate only 240 // TODO(alexclarke): Consider refactoring the above loop to terminate only
249 // when there's no more work left to be done, rather than posting a 241 // when there's no more work left to be done, rather than posting a
250 // continuation task. 242 // continuation task.
(...skipping 17 matching lines...) Expand all
268 AsValueWithSelectorResult(should_run, *out_work_queue)); 260 AsValueWithSelectorResult(should_run, *out_work_queue));
269 return should_run; 261 return should_run;
270 } 262 }
271 263
272 void TaskQueueManager::DidQueueTask( 264 void TaskQueueManager::DidQueueTask(
273 const internal::TaskQueueImpl::Task& pending_task) { 265 const internal::TaskQueueImpl::Task& pending_task) {
274 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task); 266 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task);
275 } 267 }
276 268
277 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue( 269 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue(
278 internal::WorkQueue* work_queue, 270 internal::WorkQueue* work_queue) {
279 internal::TaskQueueImpl::Task* out_previous_task) {
280 DCHECK(main_thread_checker_.CalledOnValidThread()); 271 DCHECK(main_thread_checker_.CalledOnValidThread());
281 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_); 272 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_);
282 internal::TaskQueueImpl* queue = work_queue->task_queue(); 273 internal::TaskQueueImpl* queue = work_queue->task_queue();
283 274
284 if (queue->GetQuiescenceMonitored()) 275 if (queue->GetQuiescenceMonitored())
285 task_was_run_on_quiescence_monitored_queue_ = true; 276 task_was_run_on_quiescence_monitored_queue_ = true;
286 277
287 internal::TaskQueueImpl::Task pending_task = 278 internal::TaskQueueImpl::Task pending_task =
288 work_queue->TakeTaskFromWorkQueue(); 279 work_queue->TakeTaskFromWorkQueue();
289 if (!pending_task.nestable && delegate_->IsNested()) { 280 if (!pending_task.nestable && delegate_->IsNested()) {
(...skipping 16 matching lines...) Expand all
306 } 297 }
307 TRACE_EVENT1(tracing_category_, "TaskQueueManager::RunTask", "queue", 298 TRACE_EVENT1(tracing_category_, "TaskQueueManager::RunTask", "queue",
308 queue->GetName()); 299 queue->GetName());
309 // NOTE when TaskQueues get unregistered a reference ends up getting retained 300 // NOTE when TaskQueues get unregistered a reference ends up getting retained
310 // by |queues_to_delete_| which is cleared at the top of |DoWork|. This means 301 // by |queues_to_delete_| which is cleared at the top of |DoWork|. This means
311 // we are OK to use raw pointers here. 302 // we are OK to use raw pointers here.
312 internal::TaskQueueImpl* prev_executing_task_queue = 303 internal::TaskQueueImpl* prev_executing_task_queue =
313 currently_executing_task_queue_; 304 currently_executing_task_queue_;
314 currently_executing_task_queue_ = queue; 305 currently_executing_task_queue_ = queue;
315 task_annotator_.RunTask("TaskQueueManager::PostTask", pending_task); 306 task_annotator_.RunTask("TaskQueueManager::PostTask", pending_task);
316
317 // Detect if the TaskQueueManager just got deleted. If this happens we must 307 // Detect if the TaskQueueManager just got deleted. If this happens we must
318 // not access any member variables after this point. 308 // not access any member variables after this point.
319 if (protect->HasOneRef()) 309 if (protect->HasOneRef())
320 return ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED; 310 return ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED;
321 311
322 currently_executing_task_queue_ = prev_executing_task_queue; 312 currently_executing_task_queue_ = prev_executing_task_queue;
323 313
324 if (queue->GetShouldNotifyObservers()) { 314 if (queue->GetShouldNotifyObservers()) {
325 FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_, 315 FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_,
326 DidProcessTask(pending_task)); 316 DidProcessTask(pending_task));
327 queue->NotifyDidProcessTask(pending_task); 317 queue->NotifyDidProcessTask(pending_task);
328 } 318 }
329 319
330 pending_task.task.Reset();
331 *out_previous_task = std::move(pending_task);
332 return ProcessTaskResult::EXECUTED; 320 return ProcessTaskResult::EXECUTED;
333 } 321 }
334 322
335 void TaskQueueManager::MaybeRecordTaskDelayHistograms( 323 void TaskQueueManager::MaybeRecordTaskDelayHistograms(
336 const internal::TaskQueueImpl::Task& pending_task, 324 const internal::TaskQueueImpl::Task& pending_task,
337 const internal::TaskQueueImpl* queue) { 325 const internal::TaskQueueImpl* queue) {
338 if ((task_count_++ % kRecordRecordTaskDelayHistogramsEveryNTasks) != 0) 326 if ((task_count_++ % kRecordRecordTaskDelayHistogramsEveryNTasks) != 0)
339 return; 327 return;
340 328
341 // Record delayed task lateness and immediate task queueing durations, but 329 // Record delayed task lateness and immediate task queuing durations.
342 // only for auto-pumped queues. Manually pumped and after wakeup queues can 330 if (!pending_task.delayed_run_time.is_null()) {
343 // have arbitarially large delayes, which would cloud any analysis. 331 RecordDelayedTaskLateness(delegate_->NowTicks() -
344 if (queue->GetPumpPolicy() == TaskQueue::PumpPolicy::AUTO) { 332 pending_task.delayed_run_time);
345 if (!pending_task.delayed_run_time.is_null()) { 333 } else if (!pending_task.time_posted.is_null()) {
346 RecordDelayedTaskLateness(delegate_->NowTicks() - 334 RecordImmediateTaskQueueingDuration(tracked_objects::TrackedTime::Now() -
347 pending_task.delayed_run_time); 335 pending_task.time_posted);
348 } else if (!pending_task.time_posted.is_null()) {
349 RecordImmediateTaskQueueingDuration(tracked_objects::TrackedTime::Now() -
350 pending_task.time_posted);
351 }
352 } 336 }
353 } 337 }
354 338
355 bool TaskQueueManager::RunsTasksOnCurrentThread() const { 339 bool TaskQueueManager::RunsTasksOnCurrentThread() const {
356 return delegate_->RunsTasksOnCurrentThread(); 340 return delegate_->RunsTasksOnCurrentThread();
357 } 341 }
358 342
359 void TaskQueueManager::SetWorkBatchSize(int work_batch_size) { 343 void TaskQueueManager::SetWorkBatchSize(int work_batch_size) {
360 DCHECK(main_thread_checker_.CalledOnValidThread()); 344 DCHECK(main_thread_checker_.CalledOnValidThread());
361 DCHECK_GE(work_batch_size, 1); 345 DCHECK_GE(work_batch_size, 1);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 state->BeginArray("time_domains"); 400 state->BeginArray("time_domains");
417 for (auto* time_domain : time_domains_) 401 for (auto* time_domain : time_domains_)
418 time_domain->AsValueInto(state.get()); 402 time_domain->AsValueInto(state.get());
419 state->EndArray(); 403 state->EndArray();
420 return std::move(state); 404 return std::move(state);
421 } 405 }
422 406
423 void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) { 407 void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) {
424 DCHECK(main_thread_checker_.CalledOnValidThread()); 408 DCHECK(main_thread_checker_.CalledOnValidThread());
425 // Only schedule DoWork if there's something to do. 409 // Only schedule DoWork if there's something to do.
426 if (!queue->immediate_work_queue()->Empty() || 410 if (queue->HasPendingImmediateWork())
427 !queue->delayed_work_queue()->Empty()) {
428 MaybeScheduleImmediateWork(FROM_HERE); 411 MaybeScheduleImmediateWork(FROM_HERE);
429 }
430 } 412 }
431 413
432 void TaskQueueManager::OnTriedToSelectBlockedWorkQueue( 414 void TaskQueueManager::OnTriedToSelectBlockedWorkQueue(
433 internal::WorkQueue* work_queue) { 415 internal::WorkQueue* work_queue) {
434 DCHECK(main_thread_checker_.CalledOnValidThread()); 416 DCHECK(main_thread_checker_.CalledOnValidThread());
435 DCHECK(!work_queue->Empty()); 417 DCHECK(!work_queue->Empty());
436 if (observer_) { 418 if (observer_) {
437 observer_->OnTriedToExecuteBlockedTask(*work_queue->task_queue(), 419 observer_->OnTriedToExecuteBlockedTask(*work_queue->task_queue(),
438 *work_queue->GetFrontTask()); 420 *work_queue->GetFrontTask());
439 } 421 }
440 } 422 }
441 423
442 } // namespace scheduler 424 } // namespace scheduler
443 } // namespace blink 425 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698