| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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/budget_pool.h" | 5 #include "platform/scheduler/renderer/budget_pool.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 18 matching lines...) Expand all Loading... |
| 29 "0x%" PRIx64, | 29 "0x%" PRIx64, |
| 30 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pointer))); | 30 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pointer))); |
| 31 } | 31 } |
| 32 | 32 |
| 33 } // namespace | 33 } // namespace |
| 34 | 34 |
| 35 BudgetPool::~BudgetPool() {} | 35 BudgetPool::~BudgetPool() {} |
| 36 | 36 |
| 37 CPUTimeBudgetPool::CPUTimeBudgetPool( | 37 CPUTimeBudgetPool::CPUTimeBudgetPool( |
| 38 const char* name, | 38 const char* name, |
| 39 TaskQueueThrottler* task_queue_throttler, | 39 BudgetPoolController* budget_pool_controller, |
| 40 base::TimeTicks now, | 40 base::TimeTicks now, |
| 41 base::Optional<base::TimeDelta> max_budget_level, | 41 base::Optional<base::TimeDelta> max_budget_level, |
| 42 base::Optional<base::TimeDelta> max_throttling_duration) | 42 base::Optional<base::TimeDelta> max_throttling_duration) |
| 43 : name_(name), | 43 : name_(name), |
| 44 task_queue_throttler_(task_queue_throttler), | 44 budget_pool_controller_(budget_pool_controller), |
| 45 max_budget_level_(max_budget_level), | 45 max_budget_level_(max_budget_level), |
| 46 max_throttling_duration_(max_throttling_duration), | 46 max_throttling_duration_(max_throttling_duration), |
| 47 last_checkpoint_(now), | 47 last_checkpoint_(now), |
| 48 cpu_percentage_(1), | 48 cpu_percentage_(1), |
| 49 is_enabled_(true) {} | 49 is_enabled_(true) {} |
| 50 | 50 |
| 51 CPUTimeBudgetPool::~CPUTimeBudgetPool() {} | 51 CPUTimeBudgetPool::~CPUTimeBudgetPool() {} |
| 52 | 52 |
| 53 void CPUTimeBudgetPool::SetTimeBudgetRecoveryRate(base::TimeTicks now, | 53 void CPUTimeBudgetPool::SetTimeBudgetRecoveryRate(base::TimeTicks now, |
| 54 double cpu_percentage) { | 54 double cpu_percentage) { |
| 55 Advance(now); | 55 Advance(now); |
| 56 cpu_percentage_ = cpu_percentage; | 56 cpu_percentage_ = cpu_percentage; |
| 57 EnforceBudgetLevelRestrictions(); | 57 EnforceBudgetLevelRestrictions(); |
| 58 } | 58 } |
| 59 | 59 |
| 60 void CPUTimeBudgetPool::AddQueue(base::TimeTicks now, TaskQueue* queue) { | 60 void CPUTimeBudgetPool::AddQueue(base::TimeTicks now, TaskQueue* queue) { |
| 61 std::pair<TaskQueueThrottler::TaskQueueMap::iterator, bool> insert_result = | 61 budget_pool_controller_->AddQueueToBudgetPool(queue, this); |
| 62 task_queue_throttler_->queue_details_.insert( | |
| 63 std::make_pair(queue, TaskQueueThrottler::Metadata())); | |
| 64 TaskQueueThrottler::Metadata& metadata = insert_result.first->second; | |
| 65 DCHECK(!metadata.time_budget_pool); | |
| 66 metadata.time_budget_pool = this; | |
| 67 | |
| 68 associated_task_queues_.insert(queue); | 62 associated_task_queues_.insert(queue); |
| 69 | 63 |
| 70 if (!is_enabled_ || !task_queue_throttler_->IsThrottled(queue)) | 64 if (!is_enabled_ || !budget_pool_controller_->IsThrottled(queue)) |
| 71 return; | 65 return; |
| 72 | 66 |
| 73 queue->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME); | 67 budget_pool_controller_->BlockQueue(now, queue); |
| 74 | |
| 75 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, | |
| 76 GetNextAllowedRunTime()); | |
| 77 } | 68 } |
| 78 | 69 |
| 79 void CPUTimeBudgetPool::RemoveQueue(base::TimeTicks now, TaskQueue* queue) { | 70 void CPUTimeBudgetPool::RemoveQueue(base::TimeTicks now, TaskQueue* queue) { |
| 80 auto find_it = task_queue_throttler_->queue_details_.find(queue); | 71 budget_pool_controller_->RemoveQueueFromBudgetPool(queue, this); |
| 81 DCHECK(find_it != task_queue_throttler_->queue_details_.end() && | |
| 82 find_it->second.time_budget_pool == this); | |
| 83 find_it->second.time_budget_pool = nullptr; | |
| 84 bool is_throttled = task_queue_throttler_->IsThrottled(queue); | |
| 85 | |
| 86 task_queue_throttler_->MaybeDeleteQueueMetadata(find_it); | |
| 87 associated_task_queues_.erase(queue); | 72 associated_task_queues_.erase(queue); |
| 88 | 73 |
| 89 if (!is_enabled_ || !is_throttled) | 74 if (!is_enabled_ || !budget_pool_controller_->IsThrottled(queue)) |
| 90 return; | 75 return; |
| 91 | 76 |
| 92 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, | 77 budget_pool_controller_->UnblockQueue(now, queue); |
| 93 base::nullopt); | |
| 94 } | 78 } |
| 95 | 79 |
| 96 void CPUTimeBudgetPool::EnableThrottling(LazyNow* lazy_now) { | 80 void CPUTimeBudgetPool::EnableThrottling(LazyNow* lazy_now) { |
| 97 if (is_enabled_) | 81 if (is_enabled_) |
| 98 return; | 82 return; |
| 99 is_enabled_ = true; | 83 is_enabled_ = true; |
| 100 | 84 |
| 101 TRACE_EVENT0(task_queue_throttler_->tracing_category_, | 85 TRACE_EVENT0("renderer.scheduler", "CPUTimeBudgetPool_EnableThrottling"); |
| 102 "CPUTimeBudgetPool_EnableThrottling"); | |
| 103 | 86 |
| 104 BlockThrottledQueues(lazy_now->Now()); | 87 BlockThrottledQueues(lazy_now->Now()); |
| 105 } | 88 } |
| 106 | 89 |
| 107 void CPUTimeBudgetPool::DisableThrottling(LazyNow* lazy_now) { | 90 void CPUTimeBudgetPool::DisableThrottling(LazyNow* lazy_now) { |
| 108 if (!is_enabled_) | 91 if (!is_enabled_) |
| 109 return; | 92 return; |
| 110 is_enabled_ = false; | 93 is_enabled_ = false; |
| 111 | 94 |
| 112 TRACE_EVENT0(task_queue_throttler_->tracing_category_, | 95 TRACE_EVENT0("renderer.scheduler", "CPUTimeBudgetPool_DisableThrottling"); |
| 113 "CPUTimeBudgetPool_DisableThrottling"); | |
| 114 | 96 |
| 115 for (TaskQueue* queue : associated_task_queues_) { | 97 for (TaskQueue* queue : associated_task_queues_) { |
| 116 if (!task_queue_throttler_->IsThrottled(queue)) | 98 if (!budget_pool_controller_->IsThrottled(queue)) |
| 117 continue; | 99 continue; |
| 118 | 100 |
| 119 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, lazy_now->Now(), | 101 budget_pool_controller_->UnblockQueue(lazy_now->Now(), queue); |
| 120 queue, base::nullopt); | |
| 121 } | 102 } |
| 122 | 103 |
| 123 // TODO(altimin): We need to disable TimeBudgetQueues here or they will | 104 // TODO(altimin): We need to disable TimeBudgetQueues here or they will |
| 124 // regenerate extra time budget when they are disabled. | 105 // regenerate extra time budget when they are disabled. |
| 125 } | 106 } |
| 126 | 107 |
| 127 bool CPUTimeBudgetPool::IsThrottlingEnabled() const { | 108 bool CPUTimeBudgetPool::IsThrottlingEnabled() const { |
| 128 return is_enabled_; | 109 return is_enabled_; |
| 129 } | 110 } |
| 130 | 111 |
| 131 void CPUTimeBudgetPool::GrantAdditionalBudget(base::TimeTicks now, | 112 void CPUTimeBudgetPool::GrantAdditionalBudget(base::TimeTicks now, |
| 132 base::TimeDelta budget_level) { | 113 base::TimeDelta budget_level) { |
| 133 Advance(now); | 114 Advance(now); |
| 134 current_budget_level_ += budget_level; | 115 current_budget_level_ += budget_level; |
| 135 EnforceBudgetLevelRestrictions(); | 116 EnforceBudgetLevelRestrictions(); |
| 136 } | 117 } |
| 137 | 118 |
| 138 void CPUTimeBudgetPool::SetReportingCallback( | 119 void CPUTimeBudgetPool::SetReportingCallback( |
| 139 base::Callback<void(base::TimeDelta)> reporting_callback) { | 120 base::Callback<void(base::TimeDelta)> reporting_callback) { |
| 140 reporting_callback_ = reporting_callback; | 121 reporting_callback_ = reporting_callback; |
| 141 } | 122 } |
| 142 | 123 |
| 143 void CPUTimeBudgetPool::Close() { | 124 void CPUTimeBudgetPool::Close() { |
| 144 DCHECK_EQ(0u, associated_task_queues_.size()); | 125 DCHECK_EQ(0u, associated_task_queues_.size()); |
| 145 | 126 |
| 146 task_queue_throttler_->time_budget_pools_.erase(this); | 127 budget_pool_controller_->UnregisterBudgetPool(this); |
| 147 } | 128 } |
| 148 | 129 |
| 149 bool CPUTimeBudgetPool::HasEnoughBudgetToRun(base::TimeTicks now) { | 130 bool CPUTimeBudgetPool::HasEnoughBudgetToRun(base::TimeTicks now) { |
| 150 Advance(now); | 131 Advance(now); |
| 151 return !is_enabled_ || current_budget_level_.InMicroseconds() >= 0; | 132 return !is_enabled_ || current_budget_level_.InMicroseconds() >= 0; |
| 152 } | 133 } |
| 153 | 134 |
| 154 base::TimeTicks CPUTimeBudgetPool::GetNextAllowedRunTime() { | 135 base::TimeTicks CPUTimeBudgetPool::GetNextAllowedRunTime() { |
| 155 if (!is_enabled_ || current_budget_level_.InMicroseconds() >= 0) { | 136 if (!is_enabled_ || current_budget_level_.InMicroseconds() >= 0) { |
| 156 return last_checkpoint_; | 137 return last_checkpoint_; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 if (now > last_checkpoint_) { | 186 if (now > last_checkpoint_) { |
| 206 if (is_enabled_) { | 187 if (is_enabled_) { |
| 207 current_budget_level_ += cpu_percentage_ * (now - last_checkpoint_); | 188 current_budget_level_ += cpu_percentage_ * (now - last_checkpoint_); |
| 208 EnforceBudgetLevelRestrictions(); | 189 EnforceBudgetLevelRestrictions(); |
| 209 } | 190 } |
| 210 last_checkpoint_ = now; | 191 last_checkpoint_ = now; |
| 211 } | 192 } |
| 212 } | 193 } |
| 213 | 194 |
| 214 void CPUTimeBudgetPool::BlockThrottledQueues(base::TimeTicks now) { | 195 void CPUTimeBudgetPool::BlockThrottledQueues(base::TimeTicks now) { |
| 215 for (TaskQueue* queue : associated_task_queues_) { | 196 for (TaskQueue* queue : associated_task_queues_) |
| 216 if (!task_queue_throttler_->IsThrottled(queue)) | 197 budget_pool_controller_->BlockQueue(now, queue); |
| 217 continue; | |
| 218 | |
| 219 queue->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME); | |
| 220 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, | |
| 221 base::nullopt); | |
| 222 } | |
| 223 } | 198 } |
| 224 | 199 |
| 225 void CPUTimeBudgetPool::EnforceBudgetLevelRestrictions() { | 200 void CPUTimeBudgetPool::EnforceBudgetLevelRestrictions() { |
| 226 if (max_budget_level_) { | 201 if (max_budget_level_) { |
| 227 current_budget_level_ = | 202 current_budget_level_ = |
| 228 std::min(current_budget_level_, max_budget_level_.value()); | 203 std::min(current_budget_level_, max_budget_level_.value()); |
| 229 } | 204 } |
| 230 if (max_throttling_duration_) { | 205 if (max_throttling_duration_) { |
| 231 // Current budget level may be negative. | 206 // Current budget level may be negative. |
| 232 current_budget_level_ = | 207 current_budget_level_ = |
| 233 std::max(current_budget_level_, | 208 std::max(current_budget_level_, |
| 234 -max_throttling_duration_.value() * cpu_percentage_); | 209 -max_throttling_duration_.value() * cpu_percentage_); |
| 235 } | 210 } |
| 236 } | 211 } |
| 237 | 212 |
| 238 } // namespace scheduler | 213 } // namespace scheduler |
| 239 } // namespace blink | 214 } // namespace blink |
| OLD | NEW |