Chromium Code Reviews| Index: third_party/WebKit/Source/platform/scheduler/renderer/budget_pool.cc |
| diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool.cc b/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool.cc |
| index 0c68389330d7536300990bcd877a32a3f2acf551..dc7c0d2c5144241e8dbdfc6852511359feaea21c 100644 |
| --- a/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool.cc |
| +++ b/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool.cc |
| @@ -48,20 +48,27 @@ void BudgetPool::AddQueue(base::TimeTicks now, TaskQueue* queue) { |
| budget_pool_controller_->AddQueueToBudgetPool(queue, this); |
| associated_task_queues_.insert(queue); |
| - if (!is_enabled_ || !budget_pool_controller_->IsThrottled(queue)) |
| + if (!is_enabled_) |
| return; |
| + budget_pool_controller_->UpdateQueueThrottlingState(now, queue); |
| +} |
| - budget_pool_controller_->BlockQueue(now, queue); |
| +void BudgetPool::UnregisterQueue(TaskQueue* queue) { |
| + DissociateQueue(queue); |
| } |
| void BudgetPool::RemoveQueue(base::TimeTicks now, TaskQueue* queue) { |
| - budget_pool_controller_->RemoveQueueFromBudgetPool(queue, this); |
| - associated_task_queues_.erase(queue); |
| + DissociateQueue(queue); |
| - if (!is_enabled_ || !budget_pool_controller_->IsThrottled(queue)) |
| + if (!is_enabled_) |
| return; |
| - budget_pool_controller_->UnblockQueue(now, queue); |
| + budget_pool_controller_->UpdateQueueThrottlingState(now, queue); |
| +} |
| + |
| +void BudgetPool::DissociateQueue(TaskQueue* queue) { |
| + budget_pool_controller_->RemoveQueueFromBudgetPool(queue, this); |
| + associated_task_queues_.erase(queue); |
| } |
| void BudgetPool::EnableThrottling(LazyNow* lazy_now) { |
| @@ -82,10 +89,7 @@ void BudgetPool::DisableThrottling(LazyNow* lazy_now) { |
| TRACE_EVENT0("renderer.scheduler", "BudgetPool_DisableThrottling"); |
| for (TaskQueue* queue : associated_task_queues_) { |
| - if (!budget_pool_controller_->IsThrottled(queue)) |
| - continue; |
| - |
| - budget_pool_controller_->UnblockQueue(lazy_now->Now(), queue); |
| + budget_pool_controller_->UpdateQueueThrottlingState(lazy_now->Now(), queue); |
| } |
| // TODO(altimin): We need to disable TimeBudgetQueues here or they will |
| @@ -104,7 +108,7 @@ void BudgetPool::Close() { |
| void BudgetPool::BlockThrottledQueues(base::TimeTicks now) { |
| for (TaskQueue* queue : associated_task_queues_) |
| - budget_pool_controller_->BlockQueue(now, queue); |
| + budget_pool_controller_->UpdateQueueThrottlingState(now, queue); |
| } |
| CPUTimeBudgetPool::CPUTimeBudgetPool( |
| @@ -117,6 +121,10 @@ CPUTimeBudgetPool::CPUTimeBudgetPool( |
| CPUTimeBudgetPool::~CPUTimeBudgetPool() {} |
| +QueueBlockType CPUTimeBudgetPool::GetBlockType() const { |
| + return QueueBlockType::kAllTasks; |
| +} |
| + |
| void CPUTimeBudgetPool::SetMaxBudgetLevel( |
| base::TimeTicks now, |
| base::Optional<base::TimeDelta> max_budget_level) { |
| @@ -159,11 +167,18 @@ void CPUTimeBudgetPool::SetReportingCallback( |
| reporting_callback_ = reporting_callback; |
| } |
| -bool CPUTimeBudgetPool::HasEnoughBudgetToRun(base::TimeTicks now) { |
| - return now >= GetNextAllowedRunTime(); |
| +bool CPUTimeBudgetPool::CanRunTasksAt(base::TimeTicks now, |
| + bool is_wake_up) const { |
| + return now >= GetNextAllowedRunTime(now); |
| +} |
| + |
| +bool CPUTimeBudgetPool::CanRunTasksUntil(base::TimeTicks now, |
| + base::TimeTicks moment) const { |
| + return CanRunTasksAt(now, false); |
| } |
| -base::TimeTicks CPUTimeBudgetPool::GetNextAllowedRunTime() { |
| +base::TimeTicks CPUTimeBudgetPool::GetNextAllowedRunTime( |
| + base::TimeTicks desired_run_time) const { |
| if (!is_enabled_ || current_budget_level_.InMicroseconds() >= 0) { |
| return last_checkpoint_; |
| } else { |
| @@ -174,7 +189,8 @@ base::TimeTicks CPUTimeBudgetPool::GetNextAllowedRunTime() { |
| } |
| } |
| -void CPUTimeBudgetPool::RecordTaskRunTime(base::TimeTicks start_time, |
| +void CPUTimeBudgetPool::RecordTaskRunTime(TaskQueue* queue, |
| + base::TimeTicks start_time, |
| base::TimeTicks end_time) { |
| DCHECK_LE(start_time, end_time); |
| Advance(end_time); |
| @@ -188,8 +204,20 @@ void CPUTimeBudgetPool::RecordTaskRunTime(base::TimeTicks start_time, |
| reporting_callback_.Run(-current_budget_level_ / cpu_percentage_); |
| } |
| } |
| + |
| + if (current_budget_level_.InSecondsF() < 0) { |
| + BlockThrottledQueues(end_time); |
| + } |
| +} |
| + |
| +void CPUTimeBudgetPool::OnTaskQueueHasWork(TaskQueue* queue, |
| + base::TimeTicks now, |
| + base::TimeTicks desired_run_time) { |
| + budget_pool_controller_->UpdateQueueThrottlingState(now, queue); |
| } |
| +void CPUTimeBudgetPool::OnWakeUp(base::TimeTicks now) {} |
| + |
| void CPUTimeBudgetPool::AsValueInto(base::trace_event::TracedValue* state, |
| base::TimeTicks now) const { |
| state->BeginDictionary(name_); |
| @@ -245,5 +273,102 @@ void CPUTimeBudgetPool::EnforceBudgetLevelRestrictions() { |
| } |
| } |
| +WakeUpBudgetPool::WakeUpBudgetPool(const char* name, |
| + BudgetPoolController* budget_pool_controller, |
| + base::TimeTicks now) |
| + : BudgetPool(name, budget_pool_controller), wakeups_per_second_(1) {} |
| + |
| +WakeUpBudgetPool::~WakeUpBudgetPool() {} |
| + |
| +QueueBlockType WakeUpBudgetPool::GetBlockType() const { |
| + return QueueBlockType::kNewTasksOnly; |
| +} |
| + |
| +void WakeUpBudgetPool::SetWakeUpRate(double wakeups_per_second) { |
| + wakeups_per_second_ = wakeups_per_second; |
| +} |
| + |
| +void WakeUpBudgetPool::SetWakeUpDuration(base::TimeDelta duration) { |
| + wakeup_duration_ = duration; |
| +} |
| + |
| +void WakeUpBudgetPool::RecordTaskRunTime(TaskQueue* queue, |
| + base::TimeTicks start_time, |
| + base::TimeTicks end_time) { |
| + budget_pool_controller_->UpdateQueueThrottlingState(end_time, queue); |
| +} |
| + |
| +base::Optional<base::TimeTicks> WakeUpBudgetPool::NextWakeUp() const { |
| + if (!last_wakeup_) |
| + return base::nullopt; |
| + // Subtract 1 microsecond to work with time alignment in task queue throttler. |
| + // This is needed due to alignment mechanism in task queue throttler -- |
| + // whole seconds need to be aligned to the next second to deal with immediate |
| + // tasks correctly. By subtracting 1 microsecond we ensure that next wakeup |
| + // gets aligned to a correct time. |
| + return last_wakeup_.value() + |
| + base::TimeDelta::FromSeconds(1 / wakeups_per_second_) - |
| + base::TimeDelta::FromMicroseconds(1); |
|
Sami
2017/04/26 13:09:08
Would it be less arbitrary to subtract base::TimeD
altimin
2017/04/26 14:31:29
The current approach is easier to test.
|
| +} |
| + |
| +bool WakeUpBudgetPool::CanRunTasksAt(base::TimeTicks now, |
| + bool is_wake_up) const { |
| + if (!last_wakeup_) |
|
Sami
2017/04/26 13:09:08
If we haven't had a wake up, should we allow every
altimin
2017/04/26 14:31:29
No, if we're throttled we should wait for a wake-u
Sami
2017/04/27 12:12:30
Okay, could you add a comment about that here plea
|
| + return false; |
| + if (last_wakeup_ == now && is_wake_up) |
| + return true; |
| + return now < last_wakeup_.value() + wakeup_duration_; |
| +} |
| + |
| +bool WakeUpBudgetPool::CanRunTasksUntil(base::TimeTicks now, |
| + base::TimeTicks moment) const { |
| + if (!last_wakeup_) |
| + return false; |
| + DCHECK_LE(now, moment); |
| + return now < last_wakeup_.value() + wakeup_duration_ && |
| + moment < last_wakeup_.value() + wakeup_duration_; |
| +} |
| + |
| +base::TimeTicks WakeUpBudgetPool::GetNextAllowedRunTime( |
| + base::TimeTicks desired_run_time) const { |
| + if (!last_wakeup_) |
| + return desired_run_time; |
| + if (desired_run_time < last_wakeup_.value() + wakeup_duration_) |
| + return desired_run_time; |
| + return std::max(desired_run_time, NextWakeUp().value()); |
| +} |
| + |
| +void WakeUpBudgetPool::OnTaskQueueHasWork(TaskQueue* queue, |
| + base::TimeTicks now, |
| + base::TimeTicks desired_run_time) { |
| + budget_pool_controller_->UpdateQueueThrottlingState(now, queue); |
| +} |
| + |
| +void WakeUpBudgetPool::OnWakeUp(base::TimeTicks now) { |
| + last_wakeup_ = now; |
| +} |
| + |
| +void WakeUpBudgetPool::AsValueInto(base::trace_event::TracedValue* state, |
| + base::TimeTicks now) const { |
| + state->BeginDictionary(name_); |
| + |
| + state->SetString("name", name_); |
| + state->SetDouble("wakeups_per_second_rate", wakeups_per_second_); |
| + state->SetDouble("wakeup_duration_in_seconds", wakeup_duration_.InSecondsF()); |
| + if (last_wakeup_) { |
| + state->SetDouble("last_wakeup_seconds_ago", |
| + (now - last_wakeup_.value()).InSecondsF()); |
| + } |
| + state->SetBoolean("is_enabled", is_enabled_); |
| + |
| + state->BeginArray("task_queues"); |
| + for (TaskQueue* queue : associated_task_queues_) { |
| + state->AppendString(PointerToId(queue)); |
| + } |
| + state->EndArray(); |
| + |
| + state->EndDictionary(); |
| +} |
| + |
| } // namespace scheduler |
| } // namespace blink |