 Chromium Code Reviews
 Chromium Code Reviews Issue 2778123003:
  [scheduler] Add WakeupBudgetPool.  (Closed)
    
  
    Issue 2778123003:
  [scheduler] Add WakeupBudgetPool.  (Closed) 
  | 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 |