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 | 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 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
412 DCHECK_GE(pending_dowork_count_, 0); | 412 DCHECK_GE(pending_dowork_count_, 0); |
413 } | 413 } |
414 DCHECK(main_thread_checker_.CalledOnValidThread()); | 414 DCHECK(main_thread_checker_.CalledOnValidThread()); |
415 | 415 |
416 base::TimeTicks next_pending_delayed_task( | 416 base::TimeTicks next_pending_delayed_task( |
417 base::TimeTicks::FromInternalValue(kMaxTimeTicks)); | 417 base::TimeTicks::FromInternalValue(kMaxTimeTicks)); |
418 | 418 |
419 if (!UpdateWorkQueues(&next_pending_delayed_task, BEFORE_WAKEUP_EVENT_TYPE)) | 419 if (!UpdateWorkQueues(&next_pending_delayed_task, BEFORE_WAKEUP_EVENT_TYPE)) |
420 return; | 420 return; |
421 | 421 |
| 422 base::PendingTask previous_task((tracked_objects::Location()), |
| 423 (base::Closure())); |
422 for (int i = 0; i < work_batch_size_; i++) { | 424 for (int i = 0; i < work_batch_size_; i++) { |
423 // Interrupt the work batch if we should run the next delayed task. | 425 // Interrupt the work batch if we should run the next delayed task. |
424 if (i > 0 && next_pending_delayed_task.ToInternalValue() != kMaxTimeTicks && | 426 if (i > 0 && next_pending_delayed_task.ToInternalValue() != kMaxTimeTicks && |
425 Now() >= next_pending_delayed_task) | 427 Now() >= next_pending_delayed_task) |
426 return; | 428 return; |
427 | 429 |
428 size_t queue_index; | 430 size_t queue_index; |
429 if (!SelectWorkQueueToService(&queue_index)) | 431 if (!SelectWorkQueueToService(&queue_index)) |
430 return; | 432 return; |
431 // Note that this function won't post another call to DoWork if one is | 433 // Note that this function won't post another call to DoWork if one is |
432 // already pending, so it is safe to call it in a loop. | 434 // already pending, so it is safe to call it in a loop. |
433 MaybePostDoWorkOnMainRunner(); | 435 MaybePostDoWorkOnMainRunner(); |
434 ProcessTaskFromWorkQueue(queue_index); | 436 ProcessTaskFromWorkQueue(queue_index, i > 0, &previous_task); |
435 | 437 |
436 if (!UpdateWorkQueues(&next_pending_delayed_task, AFTER_WAKEUP_EVENT_TYPE)) | 438 if (!UpdateWorkQueues(&next_pending_delayed_task, AFTER_WAKEUP_EVENT_TYPE)) |
437 return; | 439 return; |
438 } | 440 } |
439 } | 441 } |
440 | 442 |
441 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) { | 443 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) { |
442 bool should_run = selector_->SelectWorkQueueToService(out_queue_index); | 444 bool should_run = selector_->SelectWorkQueueToService(out_queue_index); |
443 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( | 445 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( |
444 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this, | 446 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this, |
445 AsValueWithSelectorResult(should_run, *out_queue_index)); | 447 AsValueWithSelectorResult(should_run, *out_queue_index)); |
446 return should_run; | 448 return should_run; |
447 } | 449 } |
448 | 450 |
449 void TaskQueueManager::DidQueueTask(base::PendingTask* pending_task) { | 451 void TaskQueueManager::DidQueueTask(base::PendingTask* pending_task) { |
450 pending_task->sequence_num = task_sequence_num_.GetNext(); | 452 pending_task->sequence_num = task_sequence_num_.GetNext(); |
451 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", *pending_task); | 453 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", *pending_task); |
452 } | 454 } |
453 | 455 |
454 void TaskQueueManager::ProcessTaskFromWorkQueue(size_t queue_index) { | 456 void TaskQueueManager::ProcessTaskFromWorkQueue( |
| 457 size_t queue_index, |
| 458 bool has_previous_task, |
| 459 base::PendingTask* previous_task) { |
455 DCHECK(main_thread_checker_.CalledOnValidThread()); | 460 DCHECK(main_thread_checker_.CalledOnValidThread()); |
456 internal::TaskQueue* queue = Queue(queue_index); | 461 internal::TaskQueue* queue = Queue(queue_index); |
457 base::PendingTask pending_task = queue->TakeTaskFromWorkQueue(); | 462 base::PendingTask pending_task = queue->TakeTaskFromWorkQueue(); |
458 if (!pending_task.nestable) { | 463 if (!pending_task.nestable) { |
459 // Defer non-nestable work to the main task runner. NOTE these tasks can be | 464 // Defer non-nestable work to the main task runner. NOTE these tasks can be |
460 // arbitrarily delayed so the additional delay should not be a problem. | 465 // arbitrarily delayed so the additional delay should not be a problem. |
461 main_task_runner_->PostNonNestableTask(pending_task.posted_from, | 466 main_task_runner_->PostNonNestableTask(pending_task.posted_from, |
462 pending_task.task); | 467 pending_task.task); |
463 } else { | 468 } else { |
| 469 // Suppress "will" task observer notifications for the first and "did" |
| 470 // notifications for the last task in the batch to avoid duplicate |
| 471 // notifications. |
| 472 if (has_previous_task) { |
| 473 FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_, |
| 474 DidProcessTask(*previous_task)); |
| 475 FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_, |
| 476 WillProcessTask(pending_task)); |
| 477 } |
464 task_annotator_.RunTask("TaskQueueManager::PostTask", | 478 task_annotator_.RunTask("TaskQueueManager::PostTask", |
465 "TaskQueueManager::RunTask", pending_task); | 479 "TaskQueueManager::RunTask", pending_task); |
| 480 pending_task.task.Reset(); |
| 481 *previous_task = pending_task; |
466 } | 482 } |
467 } | 483 } |
468 | 484 |
469 bool TaskQueueManager::RunsTasksOnCurrentThread() const { | 485 bool TaskQueueManager::RunsTasksOnCurrentThread() const { |
470 return main_task_runner_->RunsTasksOnCurrentThread(); | 486 return main_task_runner_->RunsTasksOnCurrentThread(); |
471 } | 487 } |
472 | 488 |
473 bool TaskQueueManager::PostDelayedTask( | 489 bool TaskQueueManager::PostDelayedTask( |
474 const tracked_objects::Location& from_here, | 490 const tracked_objects::Location& from_here, |
475 const base::Closure& task, | 491 const base::Closure& task, |
476 base::TimeDelta delay) { | 492 base::TimeDelta delay) { |
477 DCHECK(delay > base::TimeDelta()); | 493 DCHECK(delay > base::TimeDelta()); |
478 return main_task_runner_->PostDelayedTask(from_here, task, delay); | 494 return main_task_runner_->PostDelayedTask(from_here, task, delay); |
479 } | 495 } |
480 | 496 |
481 void TaskQueueManager::SetQueueName(size_t queue_index, const char* name) { | 497 void TaskQueueManager::SetQueueName(size_t queue_index, const char* name) { |
482 DCHECK(main_thread_checker_.CalledOnValidThread()); | 498 DCHECK(main_thread_checker_.CalledOnValidThread()); |
483 internal::TaskQueue* queue = Queue(queue_index); | 499 internal::TaskQueue* queue = Queue(queue_index); |
484 queue->set_name(name); | 500 queue->set_name(name); |
485 } | 501 } |
486 | 502 |
487 void TaskQueueManager::SetWorkBatchSize(int work_batch_size) { | 503 void TaskQueueManager::SetWorkBatchSize(int work_batch_size) { |
488 DCHECK(main_thread_checker_.CalledOnValidThread()); | 504 DCHECK(main_thread_checker_.CalledOnValidThread()); |
489 DCHECK_GE(work_batch_size, 1); | 505 DCHECK_GE(work_batch_size, 1); |
490 work_batch_size_ = work_batch_size; | 506 work_batch_size_ = work_batch_size; |
491 } | 507 } |
492 | 508 |
| 509 void TaskQueueManager::AddTaskObserver( |
| 510 base::MessageLoop::TaskObserver* task_observer) { |
| 511 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 512 base::MessageLoop::current()->AddTaskObserver(task_observer); |
| 513 task_observers_.AddObserver(task_observer); |
| 514 } |
| 515 |
| 516 void TaskQueueManager::RemoveTaskObserver( |
| 517 base::MessageLoop::TaskObserver* task_observer) { |
| 518 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 519 base::MessageLoop::current()->RemoveTaskObserver(task_observer); |
| 520 task_observers_.RemoveObserver(task_observer); |
| 521 } |
| 522 |
493 void TaskQueueManager::SetTimeSourceForTesting( | 523 void TaskQueueManager::SetTimeSourceForTesting( |
494 scoped_refptr<cc::TestNowSource> time_source) { | 524 scoped_refptr<cc::TestNowSource> time_source) { |
495 DCHECK(main_thread_checker_.CalledOnValidThread()); | 525 DCHECK(main_thread_checker_.CalledOnValidThread()); |
496 time_source_ = time_source; | 526 time_source_ = time_source; |
497 } | 527 } |
498 | 528 |
499 base::TimeTicks TaskQueueManager::Now() const { | 529 base::TimeTicks TaskQueueManager::Now() const { |
500 return UNLIKELY(time_source_) ? time_source_->Now() : base::TimeTicks::Now(); | 530 return UNLIKELY(time_source_) ? time_source_->Now() : base::TimeTicks::Now(); |
501 } | 531 } |
502 | 532 |
503 scoped_refptr<base::trace_event::ConvertableToTraceFormat> | 533 scoped_refptr<base::trace_event::ConvertableToTraceFormat> |
504 TaskQueueManager::AsValueWithSelectorResult(bool should_run, | 534 TaskQueueManager::AsValueWithSelectorResult(bool should_run, |
505 size_t selected_queue) const { | 535 size_t selected_queue) const { |
506 DCHECK(main_thread_checker_.CalledOnValidThread()); | 536 DCHECK(main_thread_checker_.CalledOnValidThread()); |
507 scoped_refptr<base::trace_event::TracedValue> state = | 537 scoped_refptr<base::trace_event::TracedValue> state = |
508 new base::trace_event::TracedValue(); | 538 new base::trace_event::TracedValue(); |
509 state->BeginArray("queues"); | 539 state->BeginArray("queues"); |
510 for (auto& queue : queues_) | 540 for (auto& queue : queues_) |
511 queue->AsValueInto(state.get()); | 541 queue->AsValueInto(state.get()); |
512 state->EndArray(); | 542 state->EndArray(); |
513 state->BeginDictionary("selector"); | 543 state->BeginDictionary("selector"); |
514 selector_->AsValueInto(state.get()); | 544 selector_->AsValueInto(state.get()); |
515 state->EndDictionary(); | 545 state->EndDictionary(); |
516 if (should_run) | 546 if (should_run) |
517 state->SetInteger("selected_queue", selected_queue); | 547 state->SetInteger("selected_queue", selected_queue); |
518 return state; | 548 return state; |
519 } | 549 } |
520 | 550 |
521 } // namespace content | 551 } // namespace content |
OLD | NEW |