| 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/observer_list.h" |
| 10 #include "base/trace_event/trace_event.h" | 11 #include "base/trace_event/trace_event.h" |
| 11 #include "base/trace_event/trace_event_argument.h" | 12 #include "base/trace_event/trace_event_argument.h" |
| 12 #include "cc/test/test_now_source.h" | 13 #include "cc/test/test_now_source.h" |
| 13 #include "content/renderer/scheduler/task_queue_selector.h" | 14 #include "content/renderer/scheduler/task_queue_selector.h" |
| 14 | 15 |
| 15 namespace { | 16 namespace { |
| 16 const int64_t kMaxTimeTicks = std::numeric_limits<int64>::max(); | 17 const int64_t kMaxTimeTicks = std::numeric_limits<int64>::max(); |
| 17 } | 18 } |
| 18 | 19 |
| 19 namespace content { | 20 namespace content { |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 | 268 |
| 268 TaskQueueManager::TaskQueueManager( | 269 TaskQueueManager::TaskQueueManager( |
| 269 size_t task_queue_count, | 270 size_t task_queue_count, |
| 270 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, | 271 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, |
| 271 TaskQueueSelector* selector) | 272 TaskQueueSelector* selector) |
| 272 : main_task_runner_(main_task_runner), | 273 : main_task_runner_(main_task_runner), |
| 273 selector_(selector), | 274 selector_(selector), |
| 274 pending_dowork_count_(0), | 275 pending_dowork_count_(0), |
| 275 work_batch_size_(1), | 276 work_batch_size_(1), |
| 276 time_source_(nullptr), | 277 time_source_(nullptr), |
| 278 previous_task_(tracked_objects::Location(), base::Closure()), |
| 277 weak_factory_(this) { | 279 weak_factory_(this) { |
| 278 DCHECK(main_task_runner->RunsTasksOnCurrentThread()); | 280 DCHECK(main_task_runner->RunsTasksOnCurrentThread()); |
| 279 TRACE_EVENT_OBJECT_CREATED_WITH_ID( | 281 TRACE_EVENT_OBJECT_CREATED_WITH_ID( |
| 280 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", | 282 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", |
| 281 this); | 283 this); |
| 282 | 284 |
| 283 task_queue_manager_weak_ptr_ = weak_factory_.GetWeakPtr(); | 285 task_queue_manager_weak_ptr_ = weak_factory_.GetWeakPtr(); |
| 284 for (size_t i = 0; i < task_queue_count; i++) { | 286 for (size_t i = 0; i < task_queue_count; i++) { |
| 285 scoped_refptr<internal::TaskQueue> queue( | 287 scoped_refptr<internal::TaskQueue> queue( |
| 286 make_scoped_refptr(new internal::TaskQueue(this))); | 288 make_scoped_refptr(new internal::TaskQueue(this))); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 if (posted_from_main_thread) { | 368 if (posted_from_main_thread) { |
| 367 pending_dowork_count_--; | 369 pending_dowork_count_--; |
| 368 DCHECK_GE(pending_dowork_count_, 0); | 370 DCHECK_GE(pending_dowork_count_, 0); |
| 369 } | 371 } |
| 370 DCHECK(main_thread_checker_.CalledOnValidThread()); | 372 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 371 | 373 |
| 372 base::TimeTicks next_pending_delayed_task( | 374 base::TimeTicks next_pending_delayed_task( |
| 373 base::TimeTicks::FromInternalValue(kMaxTimeTicks)); | 375 base::TimeTicks::FromInternalValue(kMaxTimeTicks)); |
| 374 for (int i = 0; i < work_batch_size_; i++) { | 376 for (int i = 0; i < work_batch_size_; i++) { |
| 375 if (!UpdateWorkQueues(&next_pending_delayed_task)) | 377 if (!UpdateWorkQueues(&next_pending_delayed_task)) |
| 376 return; | 378 break; |
| 377 | 379 |
| 378 // Interrupt the work batch if we should run the next delayed task. | 380 // Interrupt the work batch if we should run the next delayed task. |
| 379 if (i > 0 && next_pending_delayed_task.ToInternalValue() != kMaxTimeTicks && | 381 if (i > 0 && next_pending_delayed_task.ToInternalValue() != kMaxTimeTicks && |
| 380 Now() >= next_pending_delayed_task) | 382 Now() >= next_pending_delayed_task) |
| 381 return; | 383 break; |
| 382 | 384 |
| 383 size_t queue_index; | 385 size_t queue_index; |
| 384 if (!SelectWorkQueueToService(&queue_index)) | 386 if (!SelectWorkQueueToService(&queue_index)) |
| 385 return; | 387 break; |
| 386 // Note that this function won't post another call to DoWork if one is | 388 // Note that this function won't post another call to DoWork if one is |
| 387 // already pending, so it is safe to call it in a loop. | 389 // already pending, so it is safe to call it in a loop. |
| 388 MaybePostDoWorkOnMainRunner(); | 390 MaybePostDoWorkOnMainRunner(); |
| 389 ProcessTaskFromWorkQueue(queue_index); | 391 ProcessTaskFromWorkQueue(queue_index, i == 0); |
| 390 } | 392 } |
| 393 previous_task_.task.Reset(); |
| 391 } | 394 } |
| 392 | 395 |
| 393 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) { | 396 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) { |
| 394 bool should_run = selector_->SelectWorkQueueToService(out_queue_index); | 397 bool should_run = selector_->SelectWorkQueueToService(out_queue_index); |
| 395 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( | 398 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( |
| 396 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this, | 399 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "TaskQueueManager", this, |
| 397 AsValueWithSelectorResult(should_run, *out_queue_index)); | 400 AsValueWithSelectorResult(should_run, *out_queue_index)); |
| 398 return should_run; | 401 return should_run; |
| 399 } | 402 } |
| 400 | 403 |
| 401 void TaskQueueManager::DidQueueTask(base::PendingTask* pending_task) { | 404 void TaskQueueManager::DidQueueTask(base::PendingTask* pending_task) { |
| 402 pending_task->sequence_num = task_sequence_num_.GetNext(); | 405 pending_task->sequence_num = task_sequence_num_.GetNext(); |
| 403 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", *pending_task); | 406 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", *pending_task); |
| 404 } | 407 } |
| 405 | 408 |
| 406 void TaskQueueManager::ProcessTaskFromWorkQueue(size_t queue_index) { | 409 void TaskQueueManager::ProcessTaskFromWorkQueue(size_t queue_index, |
| 410 bool first_task_in_batch) { |
| 407 DCHECK(main_thread_checker_.CalledOnValidThread()); | 411 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 408 internal::TaskQueue* queue = Queue(queue_index); | 412 internal::TaskQueue* queue = Queue(queue_index); |
| 409 base::PendingTask pending_task = queue->TakeTaskFromWorkQueue(); | 413 base::PendingTask pending_task = queue->TakeTaskFromWorkQueue(); |
| 410 if (!pending_task.nestable) { | 414 if (!pending_task.nestable) { |
| 411 // Defer non-nestable work to the main task runner. NOTE these tasks can be | 415 // Defer non-nestable work to the main task runner. NOTE these tasks can be |
| 412 // arbitrarily delayed so the additional delay should not be a problem. | 416 // arbitrarily delayed so the additional delay should not be a problem. |
| 413 main_task_runner_->PostNonNestableTask(pending_task.posted_from, | 417 main_task_runner_->PostNonNestableTask(pending_task.posted_from, |
| 414 pending_task.task); | 418 pending_task.task); |
| 415 } else { | 419 } else { |
| 420 // Supress "will" task observer notifications for the first and "did" |
| 421 // notifications for the last task in the batch to avoid duplicate |
| 422 // notifications. |
| 423 if (!first_task_in_batch) { |
| 424 FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_, |
| 425 DidProcessTask(previous_task_)); |
| 426 FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_, |
| 427 WillProcessTask(pending_task)); |
| 428 } |
| 416 task_annotator_.RunTask("TaskQueueManager::PostTask", | 429 task_annotator_.RunTask("TaskQueueManager::PostTask", |
| 417 "TaskQueueManager::RunTask", pending_task); | 430 "TaskQueueManager::RunTask", pending_task); |
| 431 previous_task_ = pending_task; |
| 418 } | 432 } |
| 419 } | 433 } |
| 420 | 434 |
| 421 bool TaskQueueManager::RunsTasksOnCurrentThread() const { | 435 bool TaskQueueManager::RunsTasksOnCurrentThread() const { |
| 422 return main_task_runner_->RunsTasksOnCurrentThread(); | 436 return main_task_runner_->RunsTasksOnCurrentThread(); |
| 423 } | 437 } |
| 424 | 438 |
| 425 bool TaskQueueManager::PostDelayedTask( | 439 bool TaskQueueManager::PostDelayedTask( |
| 426 const tracked_objects::Location& from_here, | 440 const tracked_objects::Location& from_here, |
| 427 const base::Closure& task, | 441 const base::Closure& task, |
| 428 base::TimeDelta delay) { | 442 base::TimeDelta delay) { |
| 429 DCHECK(delay > base::TimeDelta()); | 443 DCHECK(delay > base::TimeDelta()); |
| 430 return main_task_runner_->PostDelayedTask(from_here, task, delay); | 444 return main_task_runner_->PostDelayedTask(from_here, task, delay); |
| 431 } | 445 } |
| 432 | 446 |
| 433 void TaskQueueManager::SetQueueName(size_t queue_index, const char* name) { | 447 void TaskQueueManager::SetQueueName(size_t queue_index, const char* name) { |
| 434 DCHECK(main_thread_checker_.CalledOnValidThread()); | 448 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 435 internal::TaskQueue* queue = Queue(queue_index); | 449 internal::TaskQueue* queue = Queue(queue_index); |
| 436 queue->set_name(name); | 450 queue->set_name(name); |
| 437 } | 451 } |
| 438 | 452 |
| 439 void TaskQueueManager::SetWorkBatchSize(int work_batch_size) { | 453 void TaskQueueManager::SetWorkBatchSize(int work_batch_size) { |
| 440 DCHECK(main_thread_checker_.CalledOnValidThread()); | 454 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 441 DCHECK_GE(work_batch_size, 1); | 455 DCHECK_GE(work_batch_size, 1); |
| 442 work_batch_size_ = work_batch_size; | 456 work_batch_size_ = work_batch_size; |
| 443 } | 457 } |
| 444 | 458 |
| 459 void TaskQueueManager::AddTaskObserver( |
| 460 base::MessageLoop::TaskObserver* task_observer) { |
| 461 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 462 task_observers_.AddObserver(task_observer); |
| 463 } |
| 464 |
| 465 void TaskQueueManager::RemoveTaskObserver( |
| 466 base::MessageLoop::TaskObserver* task_observer) { |
| 467 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 468 task_observers_.RemoveObserver(task_observer); |
| 469 } |
| 470 |
| 445 void TaskQueueManager::SetTimeSourceForTesting( | 471 void TaskQueueManager::SetTimeSourceForTesting( |
| 446 scoped_refptr<cc::TestNowSource> time_source) { | 472 scoped_refptr<cc::TestNowSource> time_source) { |
| 447 DCHECK(main_thread_checker_.CalledOnValidThread()); | 473 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 448 time_source_ = time_source; | 474 time_source_ = time_source; |
| 449 } | 475 } |
| 450 | 476 |
| 451 base::TimeTicks TaskQueueManager::Now() const { | 477 base::TimeTicks TaskQueueManager::Now() const { |
| 452 return UNLIKELY(time_source_) ? time_source_->Now() : base::TimeTicks::Now(); | 478 return UNLIKELY(time_source_) ? time_source_->Now() : base::TimeTicks::Now(); |
| 453 } | 479 } |
| 454 | 480 |
| 455 scoped_refptr<base::trace_event::ConvertableToTraceFormat> | 481 scoped_refptr<base::trace_event::ConvertableToTraceFormat> |
| 456 TaskQueueManager::AsValueWithSelectorResult(bool should_run, | 482 TaskQueueManager::AsValueWithSelectorResult(bool should_run, |
| 457 size_t selected_queue) const { | 483 size_t selected_queue) const { |
| 458 DCHECK(main_thread_checker_.CalledOnValidThread()); | 484 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 459 scoped_refptr<base::trace_event::TracedValue> state = | 485 scoped_refptr<base::trace_event::TracedValue> state = |
| 460 new base::trace_event::TracedValue(); | 486 new base::trace_event::TracedValue(); |
| 461 state->BeginArray("queues"); | 487 state->BeginArray("queues"); |
| 462 for (auto& queue : queues_) | 488 for (auto& queue : queues_) |
| 463 queue->AsValueInto(state.get()); | 489 queue->AsValueInto(state.get()); |
| 464 state->EndArray(); | 490 state->EndArray(); |
| 465 state->BeginDictionary("selector"); | 491 state->BeginDictionary("selector"); |
| 466 selector_->AsValueInto(state.get()); | 492 selector_->AsValueInto(state.get()); |
| 467 state->EndDictionary(); | 493 state->EndDictionary(); |
| 468 if (should_run) | 494 if (should_run) |
| 469 state->SetInteger("selected_queue", selected_queue); | 495 state->SetInteger("selected_queue", selected_queue); |
| 470 return state; | 496 return state; |
| 471 } | 497 } |
| 472 | 498 |
| 473 } // namespace content | 499 } // namespace content |
| OLD | NEW |