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

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

Issue 2644553002: Refactor TimeDomain::MaybeAdvanceTime in preparation for DoWork deduping (Closed)
Patch Set: Rebased Created 3 years, 11 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 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 observer_->OnUnregisterTaskQueue(task_queue); 140 observer_->OnUnregisterTaskQueue(task_queue);
141 141
142 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being 142 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being
143 // freed while any of our structures hold hold a raw pointer to it. 143 // freed while any of our structures hold hold a raw pointer to it.
144 queues_to_delete_.insert(task_queue); 144 queues_to_delete_.insert(task_queue);
145 queues_.erase(task_queue); 145 queues_.erase(task_queue);
146 146
147 selector_.RemoveQueue(task_queue.get()); 147 selector_.RemoveQueue(task_queue.get());
148 } 148 }
149 149
150 void TaskQueueManager::UpdateWorkQueues(LazyNow lazy_now) { 150 void TaskQueueManager::UpdateWorkQueues(LazyNow* lazy_now) {
151 TRACE_EVENT0(disabled_by_default_tracing_category_, 151 TRACE_EVENT0(disabled_by_default_tracing_category_,
152 "TaskQueueManager::UpdateWorkQueues"); 152 "TaskQueueManager::UpdateWorkQueues");
153 153
154 for (TimeDomain* time_domain : time_domains_) { 154 for (TimeDomain* time_domain : time_domains_) {
155 LazyNow lazy_now_in_domain = time_domain == real_time_domain_.get() 155 if (time_domain == real_time_domain_.get()) {
156 ? lazy_now 156 time_domain->UpdateWorkQueues(lazy_now);
157 : time_domain->CreateLazyNow(); 157 } else {
158 time_domain->UpdateWorkQueues(lazy_now_in_domain); 158 LazyNow time_domain_lazy_now = time_domain->CreateLazyNow();
159 time_domain->UpdateWorkQueues(&time_domain_lazy_now);
160 }
159 } 161 }
160 } 162 }
161 163
162 void TaskQueueManager::OnBeginNestedMessageLoop() { 164 void TaskQueueManager::OnBeginNestedMessageLoop() {
163 // We just entered a nested message loop, make sure there's a DoWork posted or 165 // We just entered a nested message loop, make sure there's a DoWork posted or
164 // the system will grind to a halt. 166 // the system will grind to a halt.
165 delegate_->PostTask(FROM_HERE, from_main_thread_immediate_do_work_closure_); 167 delegate_->PostTask(FROM_HERE, from_main_thread_immediate_do_work_closure_);
166 } 168 }
167 169
168 void TaskQueueManager::MaybeScheduleImmediateWork( 170 void TaskQueueManager::MaybeScheduleImmediateWork(
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 other_thread_pending_wakeup_ = false; 227 other_thread_pending_wakeup_ = false;
226 } 228 }
227 229
228 // Posting a DoWork while a DoWork is running leads to spurious DoWorks. 230 // Posting a DoWork while a DoWork is running leads to spurious DoWorks.
229 main_thread_pending_wakeups_.insert(base::TimeTicks()); 231 main_thread_pending_wakeups_.insert(base::TimeTicks());
230 232
231 if (!delegate_->IsNested()) 233 if (!delegate_->IsNested())
232 queues_to_delete_.clear(); 234 queues_to_delete_.clear();
233 235
234 LazyNow lazy_now(real_time_domain()->CreateLazyNow()); 236 LazyNow lazy_now(real_time_domain()->CreateLazyNow());
235 UpdateWorkQueues(lazy_now); 237 UpdateWorkQueues(&lazy_now);
236 238
237 for (int i = 0; i < work_batch_size_; i++) { 239 for (int i = 0; i < work_batch_size_; i++) {
238 internal::WorkQueue* work_queue; 240 internal::WorkQueue* work_queue;
239 if (!SelectWorkQueueToService(&work_queue)) 241 if (!SelectWorkQueueToService(&work_queue))
240 break; 242 break;
241 243
242 switch (ProcessTaskFromWorkQueue(work_queue, &lazy_now)) { 244 base::TimeTicks time_after_task;
245 switch (ProcessTaskFromWorkQueue(work_queue, lazy_now, &time_after_task)) {
243 case ProcessTaskResult::DEFERRED: 246 case ProcessTaskResult::DEFERRED:
244 // If a task was deferred, try again with another task. 247 // If a task was deferred, try again with another task.
245 continue; 248 continue;
246 case ProcessTaskResult::EXECUTED: 249 case ProcessTaskResult::EXECUTED:
247 break; 250 break;
248 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: 251 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED:
249 return; // The TaskQueueManager got deleted, we must bail out. 252 return; // The TaskQueueManager got deleted, we must bail out.
250 } 253 }
251 254
252 work_queue = nullptr; // The queue may have been unregistered. 255 work_queue = nullptr; // The queue may have been unregistered.
253 256
254 UpdateWorkQueues(lazy_now); 257 lazy_now = time_after_task.is_null() ? real_time_domain()->CreateLazyNow()
258 : LazyNow(time_after_task);
259 UpdateWorkQueues(&lazy_now);
255 260
256 // Only run a single task per batch in nested run loops so that we can 261 // Only run a single task per batch in nested run loops so that we can
257 // properly exit the nested loop when someone calls RunLoop::Quit(). 262 // properly exit the nested loop when someone calls RunLoop::Quit().
258 if (delegate_->IsNested()) 263 if (delegate_->IsNested())
259 break; 264 break;
260 } 265 }
261 266
262 main_thread_pending_wakeups_.erase(base::TimeTicks()); 267 main_thread_pending_wakeups_.erase(base::TimeTicks());
263 268
264 // TODO(alexclarke): Consider refactoring the above loop to terminate only 269 // TODO(alexclarke): Consider refactoring the above loop to terminate only
265 // when there's no more work left to be done, rather than posting a 270 // when there's no more work left to be done, rather than posting a
266 // continuation task. 271 // continuation task.
267 if (!selector_.EnabledWorkQueuesEmpty() || TryAdvanceTimeDomains()) 272 base::Optional<base::TimeDelta> next_delay =
273 ComputeDelayTillNextTask(&lazy_now);
274
275 if (!next_delay)
276 return;
277
278 base::TimeDelta delay = next_delay.value();
279 if (delay.is_zero()) {
268 MaybeScheduleImmediateWork(FROM_HERE); 280 MaybeScheduleImmediateWork(FROM_HERE);
281 } else {
282 MaybeScheduleDelayedWork(FROM_HERE, lazy_now.Now(), delay);
283 }
269 } 284 }
270 285
271 bool TaskQueueManager::TryAdvanceTimeDomains() { 286 base::Optional<base::TimeDelta> TaskQueueManager::ComputeDelayTillNextTask(
272 bool can_advance = false; 287 LazyNow* lazy_now) {
288 // If the selector has non-empty queues we trivially know there is immediate
289 // work to be done.
290 if (!selector_.EnabledWorkQueuesEmpty())
291 return base::TimeDelta();
292
293 // Otherwise we need to find the shortest delay, if any.
294 base::Optional<base::TimeDelta> next_continuation;
273 for (TimeDomain* time_domain : time_domains_) { 295 for (TimeDomain* time_domain : time_domains_) {
274 can_advance |= time_domain->MaybeAdvanceTime(); 296 base::Optional<base::TimeDelta> continuation =
297 time_domain->DelayTillNextTask(lazy_now);
298 if (!continuation)
299 continue;
300 if (!next_continuation || next_continuation.value() > continuation.value())
301 next_continuation = continuation;
275 } 302 }
276 return can_advance; 303 return next_continuation;
277 } 304 }
278 305
279 bool TaskQueueManager::SelectWorkQueueToService( 306 bool TaskQueueManager::SelectWorkQueueToService(
280 internal::WorkQueue** out_work_queue) { 307 internal::WorkQueue** out_work_queue) {
281 bool should_run = selector_.SelectWorkQueueToService(out_work_queue); 308 bool should_run = selector_.SelectWorkQueueToService(out_work_queue);
282 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( 309 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
283 disabled_by_default_tracing_category_, "TaskQueueManager", this, 310 disabled_by_default_tracing_category_, "TaskQueueManager", this,
284 AsValueWithSelectorResult(should_run, *out_work_queue)); 311 AsValueWithSelectorResult(should_run, *out_work_queue));
285 return should_run; 312 return should_run;
286 } 313 }
287 314
288 void TaskQueueManager::DidQueueTask( 315 void TaskQueueManager::DidQueueTask(
289 const internal::TaskQueueImpl::Task& pending_task) { 316 const internal::TaskQueueImpl::Task& pending_task) {
290 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task); 317 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task);
291 } 318 }
292 319
293 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue( 320 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue(
294 internal::WorkQueue* work_queue, 321 internal::WorkQueue* work_queue,
295 LazyNow* lazy_now) { 322 LazyNow time_before_task,
323 base::TimeTicks* time_after_task) {
296 DCHECK(main_thread_checker_.CalledOnValidThread()); 324 DCHECK(main_thread_checker_.CalledOnValidThread());
297 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_); 325 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_);
298 internal::TaskQueueImpl::Task pending_task = 326 internal::TaskQueueImpl::Task pending_task =
299 work_queue->TakeTaskFromWorkQueue(); 327 work_queue->TakeTaskFromWorkQueue();
300 328
301 // It's possible the task was canceled, if so bail out. 329 // It's possible the task was canceled, if so bail out.
302 if (pending_task.task.IsCancelled()) 330 if (pending_task.task.IsCancelled())
303 return ProcessTaskResult::EXECUTED; 331 return ProcessTaskResult::EXECUTED;
304 332
305 internal::TaskQueueImpl* queue = work_queue->task_queue(); 333 internal::TaskQueueImpl* queue = work_queue->task_queue();
(...skipping 19 matching lines...) Expand all
325 TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue", 353 TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue",
326 pending_task); 354 pending_task);
327 if (queue->GetShouldNotifyObservers()) { 355 if (queue->GetShouldNotifyObservers()) {
328 for (auto& observer : task_observers_) 356 for (auto& observer : task_observers_)
329 observer.WillProcessTask(pending_task); 357 observer.WillProcessTask(pending_task);
330 queue->NotifyWillProcessTask(pending_task); 358 queue->NotifyWillProcessTask(pending_task);
331 359
332 bool notify_time_observers = 360 bool notify_time_observers =
333 !delegate_->IsNested() && task_time_observers_.might_have_observers(); 361 !delegate_->IsNested() && task_time_observers_.might_have_observers();
334 if (notify_time_observers) { 362 if (notify_time_observers) {
335 task_start_time = MonotonicTimeInSeconds(lazy_now->Now()); 363 task_start_time = MonotonicTimeInSeconds(time_before_task.Now());
336 for (auto& observer : task_time_observers_) 364 for (auto& observer : task_time_observers_)
337 observer.willProcessTask(queue, task_start_time); 365 observer.willProcessTask(queue, task_start_time);
338 } 366 }
339 } 367 }
340 368
341 TRACE_EVENT1(tracing_category_, "TaskQueueManager::RunTask", "queue", 369 TRACE_EVENT1(tracing_category_, "TaskQueueManager::RunTask", "queue",
342 queue->GetName()); 370 queue->GetName());
343 // NOTE when TaskQueues get unregistered a reference ends up getting retained 371 // NOTE when TaskQueues get unregistered a reference ends up getting retained
344 // by |queues_to_delete_| which is cleared at the top of |DoWork|. This means 372 // by |queues_to_delete_| which is cleared at the top of |DoWork|. This means
345 // we are OK to use raw pointers here. 373 // we are OK to use raw pointers here.
346 internal::TaskQueueImpl* prev_executing_task_queue = 374 internal::TaskQueueImpl* prev_executing_task_queue =
347 currently_executing_task_queue_; 375 currently_executing_task_queue_;
348 currently_executing_task_queue_ = queue; 376 currently_executing_task_queue_ = queue;
349 task_annotator_.RunTask("TaskQueueManager::PostTask", &pending_task); 377 task_annotator_.RunTask("TaskQueueManager::PostTask", &pending_task);
350 // Detect if the TaskQueueManager just got deleted. If this happens we must 378 // Detect if the TaskQueueManager just got deleted. If this happens we must
351 // not access any member variables after this point. 379 // not access any member variables after this point.
352 if (protect->HasOneRef()) 380 if (protect->HasOneRef())
353 return ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED; 381 return ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED;
354 382
355 currently_executing_task_queue_ = prev_executing_task_queue; 383 currently_executing_task_queue_ = prev_executing_task_queue;
356 384
357 *lazy_now = real_time_domain()->CreateLazyNow();
358 385
359 if (queue->GetShouldNotifyObservers()) { 386 if (queue->GetShouldNotifyObservers()) {
360 if (task_start_time) { 387 if (task_start_time) {
361 double task_end_time = MonotonicTimeInSeconds(lazy_now->Now()); 388 *time_after_task = real_time_domain()->Now();
389 double task_end_time = MonotonicTimeInSeconds(*time_after_task);
362 for (auto& observer : task_time_observers_) 390 for (auto& observer : task_time_observers_)
363 observer.didProcessTask(queue, task_start_time, task_end_time); 391 observer.didProcessTask(queue, task_start_time, task_end_time);
364 } 392 }
365 393
366 for (auto& observer : task_observers_) 394 for (auto& observer : task_observers_)
367 observer.DidProcessTask(pending_task); 395 observer.DidProcessTask(pending_task);
368 queue->NotifyDidProcessTask(pending_task); 396 queue->NotifyDidProcessTask(pending_task);
369 } 397 }
370 398
371 return ProcessTaskResult::EXECUTED; 399 return ProcessTaskResult::EXECUTED;
(...skipping 30 matching lines...) Expand all
402 DCHECK(main_thread_checker_.CalledOnValidThread()); 430 DCHECK(main_thread_checker_.CalledOnValidThread());
403 task_observers_.AddObserver(task_observer); 431 task_observers_.AddObserver(task_observer);
404 } 432 }
405 433
406 void TaskQueueManager::RemoveTaskObserver( 434 void TaskQueueManager::RemoveTaskObserver(
407 base::MessageLoop::TaskObserver* task_observer) { 435 base::MessageLoop::TaskObserver* task_observer) {
408 DCHECK(main_thread_checker_.CalledOnValidThread()); 436 DCHECK(main_thread_checker_.CalledOnValidThread());
409 task_observers_.RemoveObserver(task_observer); 437 task_observers_.RemoveObserver(task_observer);
410 } 438 }
411 439
412 void TaskQueueManager::AddTaskTimeObserver(TaskTimeObserver* task_time_observer) { 440 void TaskQueueManager::AddTaskTimeObserver(
441 TaskTimeObserver* task_time_observer) {
413 DCHECK(main_thread_checker_.CalledOnValidThread()); 442 DCHECK(main_thread_checker_.CalledOnValidThread());
414 task_time_observers_.AddObserver(task_time_observer); 443 task_time_observers_.AddObserver(task_time_observer);
415 } 444 }
416 445
417 void TaskQueueManager::RemoveTaskTimeObserver( 446 void TaskQueueManager::RemoveTaskTimeObserver(
418 TaskTimeObserver* task_time_observer) { 447 TaskTimeObserver* task_time_observer) {
419 DCHECK(main_thread_checker_.CalledOnValidThread()); 448 DCHECK(main_thread_checker_.CalledOnValidThread());
420 task_time_observers_.RemoveObserver(task_time_observer); 449 task_time_observers_.RemoveObserver(task_time_observer);
421 } 450 }
422 451
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
499 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) { 528 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) {
500 TimeDomain* time_domain = queue->GetTimeDomain(); 529 TimeDomain* time_domain = queue->GetTimeDomain();
501 if (time_domain_now.find(time_domain) == time_domain_now.end()) 530 if (time_domain_now.find(time_domain) == time_domain_now.end())
502 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now())); 531 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now()));
503 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]); 532 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]);
504 } 533 }
505 } 534 }
506 535
507 } // namespace scheduler 536 } // namespace scheduler
508 } // namespace blink 537 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698