Chromium Code Reviews| 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 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 287 base::Bind(&TaskQueueThrottler::OnTimeDomainHasImmediateWork, | 287 base::Bind(&TaskQueueThrottler::OnTimeDomainHasImmediateWork, |
| 288 weak_factory_.GetWeakPtr()); | 288 weak_factory_.GetWeakPtr()); |
| 289 | 289 |
| 290 renderer_scheduler_->RegisterTimeDomain(time_domain_.get()); | 290 renderer_scheduler_->RegisterTimeDomain(time_domain_.get()); |
| 291 } | 291 } |
| 292 | 292 |
| 293 TaskQueueThrottler::~TaskQueueThrottler() { | 293 TaskQueueThrottler::~TaskQueueThrottler() { |
| 294 // It's possible for queues to be still throttled, so we need to tidy up | 294 // It's possible for queues to be still throttled, so we need to tidy up |
| 295 // before unregistering the time domain. | 295 // before unregistering the time domain. |
| 296 for (const TaskQueueMap::value_type& map_entry : queue_details_) { | 296 for (const TaskQueueMap::value_type& map_entry : queue_details_) { |
| 297 if (map_entry.second.IsThrottled()) { | 297 TaskQueue* task_queue = map_entry.first; |
| 298 TaskQueue* task_queue = map_entry.first; | 298 if (IsThrottled(task_queue)) { |
|
Sami
2016/11/23 16:47:18
Hmm, this could end badly if the throttler is shut
altimin
2016/11/23 16:56:08
If throttling is disabled then all queues are enab
Sami
2016/11/23 17:00:59
I see, okay.
| |
| 299 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); | 299 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); |
| 300 task_queue->RemoveFence(); | 300 task_queue->RemoveFence(); |
| 301 } | 301 } |
| 302 } | 302 } |
| 303 | 303 |
| 304 renderer_scheduler_->UnregisterTimeDomain(time_domain_.get()); | 304 renderer_scheduler_->UnregisterTimeDomain(time_domain_.get()); |
| 305 } | 305 } |
| 306 | 306 |
| 307 void TaskQueueThrottler::SetQueueEnabled(TaskQueue* task_queue, bool enabled) { | 307 void TaskQueueThrottler::SetQueueEnabled(TaskQueue* task_queue, bool enabled) { |
| 308 TaskQueueMap::iterator find_it = queue_details_.find(task_queue); | 308 TaskQueueMap::iterator find_it = queue_details_.find(task_queue); |
| 309 | 309 |
| 310 if (find_it == queue_details_.end()) { | 310 if (find_it == queue_details_.end()) { |
| 311 task_queue->SetQueueEnabled(enabled); | 311 task_queue->SetQueueEnabled(enabled); |
| 312 return; | 312 return; |
| 313 } | 313 } |
| 314 | 314 |
| 315 find_it->second.enabled = enabled; | 315 find_it->second.enabled = enabled; |
| 316 | 316 |
| 317 if (!find_it->second.IsThrottled()) { | 317 if (!IsThrottled(task_queue)) { |
| 318 task_queue->SetQueueEnabled(enabled); | 318 task_queue->SetQueueEnabled(enabled); |
| 319 return; | 319 return; |
| 320 } | 320 } |
| 321 | 321 |
| 322 // We don't enable the queue here because it's throttled and there might be | 322 // We don't enable the queue here because it's throttled and there might be |
| 323 // tasks in it's work queue that would execute immediatly rather than after | 323 // tasks in it's work queue that would execute immediatly rather than after |
| 324 // PumpThrottledTasks runs. | 324 // PumpThrottledTasks runs. |
| 325 if (!enabled) { | 325 if (!enabled) { |
| 326 task_queue->SetQueueEnabled(false); | 326 task_queue->SetQueueEnabled(false); |
| 327 MaybeSchedulePumpQueue(FROM_HERE, tick_clock_->NowTicks(), task_queue, | 327 MaybeSchedulePumpQueue(FROM_HERE, tick_clock_->NowTicks(), task_queue, |
| 328 base::nullopt); | 328 base::nullopt); |
| 329 } | 329 } |
| 330 } | 330 } |
| 331 | 331 |
| 332 void TaskQueueThrottler::IncreaseThrottleRefCount(TaskQueue* task_queue) { | 332 void TaskQueueThrottler::IncreaseThrottleRefCount(TaskQueue* task_queue) { |
| 333 DCHECK_NE(task_queue, task_runner_.get()); | 333 DCHECK_NE(task_queue, task_runner_.get()); |
| 334 | 334 |
| 335 std::pair<TaskQueueMap::iterator, bool> insert_result = | 335 std::pair<TaskQueueMap::iterator, bool> insert_result = queue_details_.insert( |
| 336 queue_details_.insert(std::make_pair(task_queue, Metadata())); | 336 std::make_pair(task_queue, Metadata(0 /* ref_count */, |
| 337 task_queue->IsQueueEnabled()))); | |
| 337 | 338 |
| 338 if (!insert_result.first->second.IsThrottled()) { | 339 if (insert_result.first->second.throttling_ref_count == 0) { |
| 339 // The insert was successful so we need to throttle the queue. | |
| 340 insert_result.first->second.enabled = task_queue->IsQueueEnabled(); | |
| 341 | |
| 342 if (allow_throttling_) { | 340 if (allow_throttling_) { |
| 343 task_queue->SetTimeDomain(time_domain_.get()); | 341 task_queue->SetTimeDomain(time_domain_.get()); |
| 344 task_queue->RemoveFence(); | 342 task_queue->RemoveFence(); |
| 345 task_queue->SetQueueEnabled(false); | 343 task_queue->SetQueueEnabled(false); |
| 346 | 344 |
| 347 if (!task_queue->IsEmpty()) { | 345 if (!task_queue->IsEmpty()) { |
| 348 if (task_queue->HasPendingImmediateWork()) { | 346 if (task_queue->HasPendingImmediateWork()) { |
| 349 OnTimeDomainHasImmediateWork(task_queue); | 347 OnTimeDomainHasImmediateWork(task_queue); |
| 350 } else { | 348 } else { |
| 351 OnTimeDomainHasDelayedWork(task_queue); | 349 OnTimeDomainHasDelayedWork(task_queue); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 374 task_queue->RemoveFence(); | 372 task_queue->RemoveFence(); |
| 375 task_queue->SetQueueEnabled(enabled); | 373 task_queue->SetQueueEnabled(enabled); |
| 376 } | 374 } |
| 377 | 375 |
| 378 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueUntrottled", | 376 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueUntrottled", |
| 379 "task_queue", task_queue); | 377 "task_queue", task_queue); |
| 380 } | 378 } |
| 381 } | 379 } |
| 382 | 380 |
| 383 bool TaskQueueThrottler::IsThrottled(TaskQueue* task_queue) const { | 381 bool TaskQueueThrottler::IsThrottled(TaskQueue* task_queue) const { |
| 382 if (!allow_throttling_) | |
| 383 return false; | |
| 384 | |
| 384 auto find_it = queue_details_.find(task_queue); | 385 auto find_it = queue_details_.find(task_queue); |
| 385 if (find_it == queue_details_.end()) | 386 if (find_it == queue_details_.end()) |
| 386 return false; | 387 return false; |
| 387 return find_it->second.IsThrottled(); | 388 return find_it->second.throttling_ref_count > 0; |
| 388 } | 389 } |
| 389 | 390 |
| 390 void TaskQueueThrottler::UnregisterTaskQueue(TaskQueue* task_queue) { | 391 void TaskQueueThrottler::UnregisterTaskQueue(TaskQueue* task_queue) { |
| 391 LazyNow lazy_now(tick_clock_); | 392 LazyNow lazy_now(tick_clock_); |
| 392 auto find_it = queue_details_.find(task_queue); | 393 auto find_it = queue_details_.find(task_queue); |
| 393 | 394 |
| 394 if (find_it == queue_details_.end()) | 395 if (find_it == queue_details_.end()) |
| 395 return; | 396 return; |
| 396 | 397 |
| 397 if (find_it->second.time_budget_pool) | 398 if (find_it->second.time_budget_pool) |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 431 void TaskQueueThrottler::PumpThrottledTasks() { | 432 void TaskQueueThrottler::PumpThrottledTasks() { |
| 432 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler::PumpThrottledTasks"); | 433 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler::PumpThrottledTasks"); |
| 433 pending_pump_throttled_tasks_runtime_.reset(); | 434 pending_pump_throttled_tasks_runtime_.reset(); |
| 434 | 435 |
| 435 LazyNow lazy_now(tick_clock_); | 436 LazyNow lazy_now(tick_clock_); |
| 436 base::Optional<base::TimeTicks> next_scheduled_delayed_task; | 437 base::Optional<base::TimeTicks> next_scheduled_delayed_task; |
| 437 | 438 |
| 438 for (const TaskQueueMap::value_type& map_entry : queue_details_) { | 439 for (const TaskQueueMap::value_type& map_entry : queue_details_) { |
| 439 TaskQueue* task_queue = map_entry.first; | 440 TaskQueue* task_queue = map_entry.first; |
| 440 if (!map_entry.second.enabled || task_queue->IsEmpty() || | 441 if (!map_entry.second.enabled || task_queue->IsEmpty() || |
| 441 !map_entry.second.IsThrottled()) | 442 !IsThrottled(task_queue)) |
| 442 continue; | 443 continue; |
| 443 | 444 |
| 444 // Don't enable queues whose budget pool doesn't allow them to run now. | 445 // Don't enable queues whose budget pool doesn't allow them to run now. |
| 445 base::TimeTicks next_allowed_run_time = | 446 base::TimeTicks next_allowed_run_time = |
| 446 GetNextAllowedRunTime(lazy_now.Now(), task_queue); | 447 GetNextAllowedRunTime(lazy_now.Now(), task_queue); |
| 447 base::Optional<base::TimeTicks> next_desired_run_time = | 448 base::Optional<base::TimeTicks> next_desired_run_time = |
| 448 NextTaskRunTime(&lazy_now, task_queue); | 449 NextTaskRunTime(&lazy_now, task_queue); |
| 449 | 450 |
| 450 if (next_desired_run_time && | 451 if (next_desired_run_time && |
| 451 next_allowed_run_time > next_desired_run_time.value()) { | 452 next_allowed_run_time > next_desired_run_time.value()) { |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 587 | 588 |
| 588 base::TimeTicks TaskQueueThrottler::GetNextAllowedRunTime(base::TimeTicks now, | 589 base::TimeTicks TaskQueueThrottler::GetNextAllowedRunTime(base::TimeTicks now, |
| 589 TaskQueue* queue) { | 590 TaskQueue* queue) { |
| 590 TimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(queue); | 591 TimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(queue); |
| 591 if (!time_budget_pool) | 592 if (!time_budget_pool) |
| 592 return now; | 593 return now; |
| 593 return std::max(now, time_budget_pool->GetNextAllowedRunTime()); | 594 return std::max(now, time_budget_pool->GetNextAllowedRunTime()); |
| 594 } | 595 } |
| 595 | 596 |
| 596 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) { | 597 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) { |
| 597 if (!it->second.IsThrottled() && !it->second.time_budget_pool) | 598 if (it->second.throttling_ref_count == 0 && !it->second.time_budget_pool) |
| 598 queue_details_.erase(it); | 599 queue_details_.erase(it); |
| 599 } | 600 } |
| 600 | 601 |
| 601 void TaskQueueThrottler::DisableThrottling() { | 602 void TaskQueueThrottler::DisableThrottling() { |
| 602 if (!allow_throttling_) | 603 if (!allow_throttling_) |
| 603 return; | 604 return; |
| 604 | 605 |
| 605 allow_throttling_ = false; | 606 allow_throttling_ = false; |
| 606 | 607 |
| 607 for (const auto& map_entry : queue_details_) { | 608 for (const auto& map_entry : queue_details_) { |
| 608 if (!map_entry.second.IsThrottled()) | 609 if (map_entry.second.throttling_ref_count == 0) |
| 609 continue; | 610 continue; |
| 610 | 611 |
| 611 TaskQueue* queue = map_entry.first; | 612 TaskQueue* queue = map_entry.first; |
| 612 | 613 |
| 613 queue->SetTimeDomain(renderer_scheduler_->GetActiveTimeDomain()); | 614 queue->SetTimeDomain(renderer_scheduler_->GetActiveTimeDomain()); |
| 614 | 615 |
| 615 queue->RemoveFence(); | 616 queue->RemoveFence(); |
| 616 queue->SetQueueEnabled(map_entry.second.enabled); | 617 queue->SetQueueEnabled(map_entry.second.enabled); |
| 617 } | 618 } |
| 618 | 619 |
| 619 pump_throttled_tasks_closure_.Cancel(); | 620 pump_throttled_tasks_closure_.Cancel(); |
| 620 pending_pump_throttled_tasks_runtime_ = base::nullopt; | 621 pending_pump_throttled_tasks_runtime_ = base::nullopt; |
| 621 } | 622 } |
| 622 | 623 |
| 623 void TaskQueueThrottler::EnableThrottling() { | 624 void TaskQueueThrottler::EnableThrottling() { |
| 624 if (allow_throttling_) | 625 if (allow_throttling_) |
| 625 return; | 626 return; |
| 626 | 627 |
| 627 allow_throttling_ = true; | 628 allow_throttling_ = true; |
| 628 | 629 |
| 629 LazyNow lazy_now(tick_clock_); | 630 LazyNow lazy_now(tick_clock_); |
| 630 | 631 |
| 631 for (const auto& map_entry : queue_details_) { | 632 for (const auto& map_entry : queue_details_) { |
| 632 if (!map_entry.second.IsThrottled()) | 633 if (map_entry.second.throttling_ref_count == 0) |
| 633 continue; | 634 continue; |
| 634 | 635 |
| 635 TaskQueue* queue = map_entry.first; | 636 TaskQueue* queue = map_entry.first; |
| 636 | 637 |
| 637 queue->SetQueueEnabled(false); | 638 queue->SetQueueEnabled(false); |
| 638 queue->SetTimeDomain(time_domain_.get()); | 639 queue->SetTimeDomain(time_domain_.get()); |
| 639 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue, | 640 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue, |
| 640 GetNextAllowedRunTime(lazy_now.Now(), queue)); | 641 GetNextAllowedRunTime(lazy_now.Now(), queue)); |
| 641 } | 642 } |
| 642 } | 643 } |
| 643 | 644 |
| 644 } // namespace scheduler | 645 } // namespace scheduler |
| 645 } // namespace blink | 646 } // namespace blink |
| OLD | NEW |