| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/renderer/task_queue_throttler.h" | 5 #include "platform/scheduler/renderer/task_queue_throttler.h" |
| 6 | 6 |
| 7 #include <cstdint> | 7 #include <cstdint> |
| 8 | 8 |
| 9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 TaskQueue* queue) { | 93 TaskQueue* queue) { |
| 94 std::pair<TaskQueueMap::iterator, bool> insert_result = | 94 std::pair<TaskQueueMap::iterator, bool> insert_result = |
| 95 task_queue_throttler_->queue_details_.insert( | 95 task_queue_throttler_->queue_details_.insert( |
| 96 std::make_pair(queue, Metadata(0, queue->IsQueueEnabled()))); | 96 std::make_pair(queue, Metadata(0, queue->IsQueueEnabled()))); |
| 97 Metadata& metadata = insert_result.first->second; | 97 Metadata& metadata = insert_result.first->second; |
| 98 DCHECK(!metadata.time_budget_pool); | 98 DCHECK(!metadata.time_budget_pool); |
| 99 metadata.time_budget_pool = this; | 99 metadata.time_budget_pool = this; |
| 100 | 100 |
| 101 associated_task_queues_.insert(queue); | 101 associated_task_queues_.insert(queue); |
| 102 | 102 |
| 103 if (!is_enabled_ || !metadata.IsThrottled()) | 103 if (!is_enabled_ || !task_queue_throttler_->IsThrottled(queue)) |
| 104 return; | 104 return; |
| 105 | 105 |
| 106 queue->SetQueueEnabled(false); | 106 queue->SetQueueEnabled(false); |
| 107 | 107 |
| 108 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, | 108 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, |
| 109 GetNextAllowedRunTime()); | 109 GetNextAllowedRunTime()); |
| 110 } | 110 } |
| 111 | 111 |
| 112 void TaskQueueThrottler::TimeBudgetPool::RemoveQueue(base::TimeTicks now, | 112 void TaskQueueThrottler::TimeBudgetPool::RemoveQueue(base::TimeTicks now, |
| 113 TaskQueue* queue) { | 113 TaskQueue* queue) { |
| 114 auto find_it = task_queue_throttler_->queue_details_.find(queue); | 114 auto find_it = task_queue_throttler_->queue_details_.find(queue); |
| 115 DCHECK(find_it != task_queue_throttler_->queue_details_.end() && | 115 DCHECK(find_it != task_queue_throttler_->queue_details_.end() && |
| 116 find_it->second.time_budget_pool == this); | 116 find_it->second.time_budget_pool == this); |
| 117 find_it->second.time_budget_pool = nullptr; | 117 find_it->second.time_budget_pool = nullptr; |
| 118 bool is_throttled = find_it->second.IsThrottled(); | 118 bool is_throttled = task_queue_throttler_->IsThrottled(queue); |
| 119 | 119 |
| 120 task_queue_throttler_->MaybeDeleteQueueMetadata(find_it); | 120 task_queue_throttler_->MaybeDeleteQueueMetadata(find_it); |
| 121 associated_task_queues_.erase(queue); | 121 associated_task_queues_.erase(queue); |
| 122 | 122 |
| 123 if (!is_enabled_ || !is_throttled) | 123 if (!is_enabled_ || !is_throttled) |
| 124 return; | 124 return; |
| 125 | 125 |
| 126 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, | 126 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, |
| 127 base::nullopt); | 127 base::nullopt); |
| 128 } | 128 } |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 base::Bind(&TaskQueueThrottler::OnTimeDomainHasImmediateWork, | 286 base::Bind(&TaskQueueThrottler::OnTimeDomainHasImmediateWork, |
| 287 weak_factory_.GetWeakPtr()); | 287 weak_factory_.GetWeakPtr()); |
| 288 | 288 |
| 289 renderer_scheduler_->RegisterTimeDomain(time_domain_.get()); | 289 renderer_scheduler_->RegisterTimeDomain(time_domain_.get()); |
| 290 } | 290 } |
| 291 | 291 |
| 292 TaskQueueThrottler::~TaskQueueThrottler() { | 292 TaskQueueThrottler::~TaskQueueThrottler() { |
| 293 // It's possible for queues to be still throttled, so we need to tidy up | 293 // It's possible for queues to be still throttled, so we need to tidy up |
| 294 // before unregistering the time domain. | 294 // before unregistering the time domain. |
| 295 for (const TaskQueueMap::value_type& map_entry : queue_details_) { | 295 for (const TaskQueueMap::value_type& map_entry : queue_details_) { |
| 296 if (map_entry.second.IsThrottled()) { | 296 TaskQueue* task_queue = map_entry.first; |
| 297 TaskQueue* task_queue = map_entry.first; | 297 if (IsThrottled(task_queue)) { |
| 298 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); | 298 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); |
| 299 task_queue->RemoveFence(); | 299 task_queue->RemoveFence(); |
| 300 } | 300 } |
| 301 } | 301 } |
| 302 | 302 |
| 303 renderer_scheduler_->UnregisterTimeDomain(time_domain_.get()); | 303 renderer_scheduler_->UnregisterTimeDomain(time_domain_.get()); |
| 304 } | 304 } |
| 305 | 305 |
| 306 void TaskQueueThrottler::SetQueueEnabled(TaskQueue* task_queue, bool enabled) { | 306 void TaskQueueThrottler::SetQueueEnabled(TaskQueue* task_queue, bool enabled) { |
| 307 TaskQueueMap::iterator find_it = queue_details_.find(task_queue); | 307 TaskQueueMap::iterator find_it = queue_details_.find(task_queue); |
| 308 | 308 |
| 309 if (find_it == queue_details_.end()) { | 309 if (find_it == queue_details_.end()) { |
| 310 task_queue->SetQueueEnabled(enabled); | 310 task_queue->SetQueueEnabled(enabled); |
| 311 return; | 311 return; |
| 312 } | 312 } |
| 313 | 313 |
| 314 find_it->second.enabled = enabled; | 314 find_it->second.enabled = enabled; |
| 315 | 315 |
| 316 if (!find_it->second.IsThrottled()) { | 316 if (!IsThrottled(task_queue)) { |
| 317 task_queue->SetQueueEnabled(enabled); | 317 task_queue->SetQueueEnabled(enabled); |
| 318 return; | 318 return; |
| 319 } | 319 } |
| 320 | 320 |
| 321 // We don't enable the queue here because it's throttled and there might be | 321 // We don't enable the queue here because it's throttled and there might be |
| 322 // tasks in it's work queue that would execute immediatly rather than after | 322 // tasks in it's work queue that would execute immediatly rather than after |
| 323 // PumpThrottledTasks runs. | 323 // PumpThrottledTasks runs. |
| 324 if (!enabled) { | 324 if (!enabled) { |
| 325 task_queue->SetQueueEnabled(false); | 325 task_queue->SetQueueEnabled(false); |
| 326 MaybeSchedulePumpQueue(FROM_HERE, tick_clock_->NowTicks(), task_queue, | 326 MaybeSchedulePumpQueue(FROM_HERE, tick_clock_->NowTicks(), task_queue, |
| 327 base::nullopt); | 327 base::nullopt); |
| 328 } | 328 } |
| 329 } | 329 } |
| 330 | 330 |
| 331 void TaskQueueThrottler::IncreaseThrottleRefCount(TaskQueue* task_queue) { | 331 void TaskQueueThrottler::IncreaseThrottleRefCount(TaskQueue* task_queue) { |
| 332 DCHECK_NE(task_queue, task_runner_.get()); | 332 DCHECK_NE(task_queue, task_runner_.get()); |
| 333 | 333 |
| 334 std::pair<TaskQueueMap::iterator, bool> insert_result = | 334 std::pair<TaskQueueMap::iterator, bool> insert_result = queue_details_.insert( |
| 335 queue_details_.insert(std::make_pair(task_queue, Metadata())); | 335 std::make_pair(task_queue, Metadata(0 /* ref_count */, |
| 336 task_queue->IsQueueEnabled()))); |
| 336 | 337 |
| 337 if (!insert_result.first->second.IsThrottled()) { | 338 if (insert_result.first->second.throttling_ref_count == 0) { |
| 338 // The insert was successful so we need to throttle the queue. | |
| 339 insert_result.first->second.enabled = task_queue->IsQueueEnabled(); | |
| 340 | |
| 341 if (allow_throttling_) { | 339 if (allow_throttling_) { |
| 342 task_queue->SetTimeDomain(time_domain_.get()); | 340 task_queue->SetTimeDomain(time_domain_.get()); |
| 343 task_queue->RemoveFence(); | 341 task_queue->RemoveFence(); |
| 344 task_queue->SetQueueEnabled(false); | 342 task_queue->SetQueueEnabled(false); |
| 345 | 343 |
| 346 if (!task_queue->IsEmpty()) { | 344 if (!task_queue->IsEmpty()) { |
| 347 if (task_queue->HasPendingImmediateWork()) { | 345 if (task_queue->HasPendingImmediateWork()) { |
| 348 OnTimeDomainHasImmediateWork(task_queue); | 346 OnTimeDomainHasImmediateWork(task_queue); |
| 349 } else { | 347 } else { |
| 350 OnTimeDomainHasDelayedWork(task_queue); | 348 OnTimeDomainHasDelayedWork(task_queue); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 373 task_queue->RemoveFence(); | 371 task_queue->RemoveFence(); |
| 374 task_queue->SetQueueEnabled(enabled); | 372 task_queue->SetQueueEnabled(enabled); |
| 375 } | 373 } |
| 376 | 374 |
| 377 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueUntrottled", | 375 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueUntrottled", |
| 378 "task_queue", task_queue); | 376 "task_queue", task_queue); |
| 379 } | 377 } |
| 380 } | 378 } |
| 381 | 379 |
| 382 bool TaskQueueThrottler::IsThrottled(TaskQueue* task_queue) const { | 380 bool TaskQueueThrottler::IsThrottled(TaskQueue* task_queue) const { |
| 381 if (!allow_throttling_) |
| 382 return false; |
| 383 |
| 383 auto find_it = queue_details_.find(task_queue); | 384 auto find_it = queue_details_.find(task_queue); |
| 384 if (find_it == queue_details_.end()) | 385 if (find_it == queue_details_.end()) |
| 385 return false; | 386 return false; |
| 386 return find_it->second.IsThrottled(); | 387 return find_it->second.throttling_ref_count > 0; |
| 387 } | 388 } |
| 388 | 389 |
| 389 void TaskQueueThrottler::UnregisterTaskQueue(TaskQueue* task_queue) { | 390 void TaskQueueThrottler::UnregisterTaskQueue(TaskQueue* task_queue) { |
| 390 LazyNow lazy_now(tick_clock_); | 391 LazyNow lazy_now(tick_clock_); |
| 391 auto find_it = queue_details_.find(task_queue); | 392 auto find_it = queue_details_.find(task_queue); |
| 392 | 393 |
| 393 if (find_it == queue_details_.end()) | 394 if (find_it == queue_details_.end()) |
| 394 return; | 395 return; |
| 395 | 396 |
| 396 if (find_it->second.time_budget_pool) | 397 if (find_it->second.time_budget_pool) |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 void TaskQueueThrottler::PumpThrottledTasks() { | 431 void TaskQueueThrottler::PumpThrottledTasks() { |
| 431 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler::PumpThrottledTasks"); | 432 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler::PumpThrottledTasks"); |
| 432 pending_pump_throttled_tasks_runtime_.reset(); | 433 pending_pump_throttled_tasks_runtime_.reset(); |
| 433 | 434 |
| 434 LazyNow lazy_now(tick_clock_); | 435 LazyNow lazy_now(tick_clock_); |
| 435 base::Optional<base::TimeTicks> next_scheduled_delayed_task; | 436 base::Optional<base::TimeTicks> next_scheduled_delayed_task; |
| 436 | 437 |
| 437 for (const TaskQueueMap::value_type& map_entry : queue_details_) { | 438 for (const TaskQueueMap::value_type& map_entry : queue_details_) { |
| 438 TaskQueue* task_queue = map_entry.first; | 439 TaskQueue* task_queue = map_entry.first; |
| 439 if (!map_entry.second.enabled || task_queue->IsEmpty() || | 440 if (!map_entry.second.enabled || task_queue->IsEmpty() || |
| 440 !map_entry.second.IsThrottled()) | 441 !IsThrottled(task_queue)) |
| 441 continue; | 442 continue; |
| 442 | 443 |
| 443 // Don't enable queues whose budget pool doesn't allow them to run now. | 444 // Don't enable queues whose budget pool doesn't allow them to run now. |
| 444 base::TimeTicks next_allowed_run_time = | 445 base::TimeTicks next_allowed_run_time = |
| 445 GetNextAllowedRunTime(lazy_now.Now(), task_queue); | 446 GetNextAllowedRunTime(lazy_now.Now(), task_queue); |
| 446 base::Optional<base::TimeTicks> next_desired_run_time = | 447 base::Optional<base::TimeTicks> next_desired_run_time = |
| 447 NextTaskRunTime(&lazy_now, task_queue); | 448 NextTaskRunTime(&lazy_now, task_queue); |
| 448 | 449 |
| 449 if (next_desired_run_time && | 450 if (next_desired_run_time && |
| 450 next_allowed_run_time > next_desired_run_time.value()) { | 451 next_allowed_run_time > next_desired_run_time.value()) { |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 586 | 587 |
| 587 base::TimeTicks TaskQueueThrottler::GetNextAllowedRunTime(base::TimeTicks now, | 588 base::TimeTicks TaskQueueThrottler::GetNextAllowedRunTime(base::TimeTicks now, |
| 588 TaskQueue* queue) { | 589 TaskQueue* queue) { |
| 589 TimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(queue); | 590 TimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(queue); |
| 590 if (!time_budget_pool) | 591 if (!time_budget_pool) |
| 591 return now; | 592 return now; |
| 592 return std::max(now, time_budget_pool->GetNextAllowedRunTime()); | 593 return std::max(now, time_budget_pool->GetNextAllowedRunTime()); |
| 593 } | 594 } |
| 594 | 595 |
| 595 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) { | 596 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) { |
| 596 if (!it->second.IsThrottled() && !it->second.time_budget_pool) | 597 if (it->second.throttling_ref_count == 0 && !it->second.time_budget_pool) |
| 597 queue_details_.erase(it); | 598 queue_details_.erase(it); |
| 598 } | 599 } |
| 599 | 600 |
| 600 void TaskQueueThrottler::DisableThrottling() { | 601 void TaskQueueThrottler::DisableThrottling() { |
| 601 if (!allow_throttling_) | 602 if (!allow_throttling_) |
| 602 return; | 603 return; |
| 603 | 604 |
| 604 allow_throttling_ = false; | 605 allow_throttling_ = false; |
| 605 | 606 |
| 606 for (const auto& map_entry : queue_details_) { | 607 for (const auto& map_entry : queue_details_) { |
| 607 if (!map_entry.second.IsThrottled()) | 608 if (map_entry.second.throttling_ref_count == 0) |
| 608 continue; | 609 continue; |
| 609 | 610 |
| 610 TaskQueue* queue = map_entry.first; | 611 TaskQueue* queue = map_entry.first; |
| 611 | 612 |
| 612 queue->SetTimeDomain(renderer_scheduler_->GetActiveTimeDomain()); | 613 queue->SetTimeDomain(renderer_scheduler_->GetActiveTimeDomain()); |
| 613 | 614 |
| 614 queue->RemoveFence(); | 615 queue->RemoveFence(); |
| 615 queue->SetQueueEnabled(map_entry.second.enabled); | 616 queue->SetQueueEnabled(map_entry.second.enabled); |
| 616 } | 617 } |
| 617 | 618 |
| 618 pump_throttled_tasks_closure_.Cancel(); | 619 pump_throttled_tasks_closure_.Cancel(); |
| 619 pending_pump_throttled_tasks_runtime_ = base::nullopt; | 620 pending_pump_throttled_tasks_runtime_ = base::nullopt; |
| 620 } | 621 } |
| 621 | 622 |
| 622 void TaskQueueThrottler::EnableThrottling() { | 623 void TaskQueueThrottler::EnableThrottling() { |
| 623 if (allow_throttling_) | 624 if (allow_throttling_) |
| 624 return; | 625 return; |
| 625 | 626 |
| 626 allow_throttling_ = true; | 627 allow_throttling_ = true; |
| 627 | 628 |
| 628 LazyNow lazy_now(tick_clock_); | 629 LazyNow lazy_now(tick_clock_); |
| 629 | 630 |
| 630 for (const auto& map_entry : queue_details_) { | 631 for (const auto& map_entry : queue_details_) { |
| 631 if (!map_entry.second.IsThrottled()) | 632 if (map_entry.second.throttling_ref_count == 0) |
| 632 continue; | 633 continue; |
| 633 | 634 |
| 634 TaskQueue* queue = map_entry.first; | 635 TaskQueue* queue = map_entry.first; |
| 635 | 636 |
| 636 queue->SetQueueEnabled(false); | 637 queue->SetQueueEnabled(false); |
| 637 queue->SetTimeDomain(time_domain_.get()); | 638 queue->SetTimeDomain(time_domain_.get()); |
| 638 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue, | 639 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue, |
| 639 GetNextAllowedRunTime(lazy_now.Now(), queue)); | 640 GetNextAllowedRunTime(lazy_now.Now(), queue)); |
| 640 } | 641 } |
| 641 } | 642 } |
| 642 | 643 |
| 643 } // namespace scheduler | 644 } // namespace scheduler |
| 644 } // namespace blink | 645 } // namespace blink |
| OLD | NEW |