Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(266)

Side by Side Diff: third_party/WebKit/Source/platform/scheduler/renderer/budget_pool.cc

Issue 2778123003: [scheduler] Add WakeupBudgetPool. (Closed)
Patch Set: Second iteration. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 30 matching lines...) Expand all
41 BudgetPool::~BudgetPool() {} 41 BudgetPool::~BudgetPool() {}
42 42
43 const char* BudgetPool::Name() const { 43 const char* BudgetPool::Name() const {
44 return name_; 44 return name_;
45 } 45 }
46 46
47 void BudgetPool::AddQueue(base::TimeTicks now, TaskQueue* queue) { 47 void BudgetPool::AddQueue(base::TimeTicks now, TaskQueue* queue) {
48 budget_pool_controller_->AddQueueToBudgetPool(queue, this); 48 budget_pool_controller_->AddQueueToBudgetPool(queue, this);
49 associated_task_queues_.insert(queue); 49 associated_task_queues_.insert(queue);
50 50
51 if (!is_enabled_ || !budget_pool_controller_->IsThrottled(queue)) 51 if (!is_enabled_)
52 return; 52 return;
53 budget_pool_controller_->UpdateQueueThrottlingState(now, queue);
54 }
53 55
54 budget_pool_controller_->BlockQueue(now, queue); 56 void BudgetPool::UnregisterQueue(TaskQueue* queue) {
57 DissociateQueue(queue);
55 } 58 }
56 59
57 void BudgetPool::RemoveQueue(base::TimeTicks now, TaskQueue* queue) { 60 void BudgetPool::RemoveQueue(base::TimeTicks now, TaskQueue* queue) {
61 DissociateQueue(queue);
62
63 if (!is_enabled_)
64 return;
65
66 budget_pool_controller_->UpdateQueueThrottlingState(now, queue);
67 }
68
69 void BudgetPool::DissociateQueue(TaskQueue* queue) {
58 budget_pool_controller_->RemoveQueueFromBudgetPool(queue, this); 70 budget_pool_controller_->RemoveQueueFromBudgetPool(queue, this);
59 associated_task_queues_.erase(queue); 71 associated_task_queues_.erase(queue);
60
61 if (!is_enabled_ || !budget_pool_controller_->IsThrottled(queue))
62 return;
63
64 budget_pool_controller_->UnblockQueue(now, queue);
65 } 72 }
66 73
67 void BudgetPool::EnableThrottling(LazyNow* lazy_now) { 74 void BudgetPool::EnableThrottling(LazyNow* lazy_now) {
68 if (is_enabled_) 75 if (is_enabled_)
69 return; 76 return;
70 is_enabled_ = true; 77 is_enabled_ = true;
71 78
72 TRACE_EVENT0("renderer.scheduler", "BudgetPool_EnableThrottling"); 79 TRACE_EVENT0("renderer.scheduler", "BudgetPool_EnableThrottling");
73 80
74 BlockThrottledQueues(lazy_now->Now()); 81 BlockThrottledQueues(lazy_now->Now());
75 } 82 }
76 83
77 void BudgetPool::DisableThrottling(LazyNow* lazy_now) { 84 void BudgetPool::DisableThrottling(LazyNow* lazy_now) {
78 if (!is_enabled_) 85 if (!is_enabled_)
79 return; 86 return;
80 is_enabled_ = false; 87 is_enabled_ = false;
81 88
82 TRACE_EVENT0("renderer.scheduler", "BudgetPool_DisableThrottling"); 89 TRACE_EVENT0("renderer.scheduler", "BudgetPool_DisableThrottling");
83 90
84 for (TaskQueue* queue : associated_task_queues_) { 91 for (TaskQueue* queue : associated_task_queues_) {
85 if (!budget_pool_controller_->IsThrottled(queue)) 92 budget_pool_controller_->UpdateQueueThrottlingState(lazy_now->Now(), queue);
86 continue;
87
88 budget_pool_controller_->UnblockQueue(lazy_now->Now(), queue);
89 } 93 }
90 94
91 // TODO(altimin): We need to disable TimeBudgetQueues here or they will 95 // TODO(altimin): We need to disable TimeBudgetQueues here or they will
92 // regenerate extra time budget when they are disabled. 96 // regenerate extra time budget when they are disabled.
93 } 97 }
94 98
95 bool BudgetPool::IsThrottlingEnabled() const { 99 bool BudgetPool::IsThrottlingEnabled() const {
96 return is_enabled_; 100 return is_enabled_;
97 } 101 }
98 102
99 void BudgetPool::Close() { 103 void BudgetPool::Close() {
100 DCHECK_EQ(0u, associated_task_queues_.size()); 104 DCHECK_EQ(0u, associated_task_queues_.size());
101 105
102 budget_pool_controller_->UnregisterBudgetPool(this); 106 budget_pool_controller_->UnregisterBudgetPool(this);
103 } 107 }
104 108
105 void BudgetPool::BlockThrottledQueues(base::TimeTicks now) { 109 void BudgetPool::BlockThrottledQueues(base::TimeTicks now) {
106 for (TaskQueue* queue : associated_task_queues_) 110 for (TaskQueue* queue : associated_task_queues_)
107 budget_pool_controller_->BlockQueue(now, queue); 111 budget_pool_controller_->UpdateQueueThrottlingState(now, queue);
108 } 112 }
109 113
110 CPUTimeBudgetPool::CPUTimeBudgetPool( 114 CPUTimeBudgetPool::CPUTimeBudgetPool(
111 const char* name, 115 const char* name,
112 BudgetPoolController* budget_pool_controller, 116 BudgetPoolController* budget_pool_controller,
113 base::TimeTicks now) 117 base::TimeTicks now)
114 : BudgetPool(name, budget_pool_controller), 118 : BudgetPool(name, budget_pool_controller),
115 last_checkpoint_(now), 119 last_checkpoint_(now),
116 cpu_percentage_(1) {} 120 cpu_percentage_(1) {}
117 121
118 CPUTimeBudgetPool::~CPUTimeBudgetPool() {} 122 CPUTimeBudgetPool::~CPUTimeBudgetPool() {}
119 123
124 QueueBlockType CPUTimeBudgetPool::GetBlockType() const {
125 return QueueBlockType::kAllTasks;
126 }
127
120 void CPUTimeBudgetPool::SetMaxBudgetLevel( 128 void CPUTimeBudgetPool::SetMaxBudgetLevel(
121 base::TimeTicks now, 129 base::TimeTicks now,
122 base::Optional<base::TimeDelta> max_budget_level) { 130 base::Optional<base::TimeDelta> max_budget_level) {
123 Advance(now); 131 Advance(now);
124 max_budget_level_ = max_budget_level; 132 max_budget_level_ = max_budget_level;
125 EnforceBudgetLevelRestrictions(); 133 EnforceBudgetLevelRestrictions();
126 } 134 }
127 135
128 void CPUTimeBudgetPool::SetMaxThrottlingDelay( 136 void CPUTimeBudgetPool::SetMaxThrottlingDelay(
129 base::TimeTicks now, 137 base::TimeTicks now,
(...skipping 22 matching lines...) Expand all
152 Advance(now); 160 Advance(now);
153 current_budget_level_ += budget_level; 161 current_budget_level_ += budget_level;
154 EnforceBudgetLevelRestrictions(); 162 EnforceBudgetLevelRestrictions();
155 } 163 }
156 164
157 void CPUTimeBudgetPool::SetReportingCallback( 165 void CPUTimeBudgetPool::SetReportingCallback(
158 base::Callback<void(base::TimeDelta)> reporting_callback) { 166 base::Callback<void(base::TimeDelta)> reporting_callback) {
159 reporting_callback_ = reporting_callback; 167 reporting_callback_ = reporting_callback;
160 } 168 }
161 169
162 bool CPUTimeBudgetPool::HasEnoughBudgetToRun(base::TimeTicks now) { 170 bool CPUTimeBudgetPool::CanRunTasksAt(base::TimeTicks now,
163 return now >= GetNextAllowedRunTime(); 171 bool is_wake_up) const {
172 return now >= GetNextAllowedRunTime(now);
164 } 173 }
165 174
166 base::TimeTicks CPUTimeBudgetPool::GetNextAllowedRunTime() { 175 bool CPUTimeBudgetPool::CanRunTasksUntil(base::TimeTicks now,
176 base::TimeTicks moment) const {
177 return CanRunTasksAt(now, false);
178 }
179
180 base::TimeTicks CPUTimeBudgetPool::GetNextAllowedRunTime(
181 base::TimeTicks desired_run_time) const {
167 if (!is_enabled_ || current_budget_level_.InMicroseconds() >= 0) { 182 if (!is_enabled_ || current_budget_level_.InMicroseconds() >= 0) {
168 return last_checkpoint_; 183 return last_checkpoint_;
169 } else { 184 } else {
170 // Subtract because current_budget is negative. 185 // Subtract because current_budget is negative.
171 return last_checkpoint_ + 186 return last_checkpoint_ +
172 (-current_budget_level_ + min_budget_level_to_run_) / 187 (-current_budget_level_ + min_budget_level_to_run_) /
173 cpu_percentage_; 188 cpu_percentage_;
174 } 189 }
175 } 190 }
176 191
177 void CPUTimeBudgetPool::RecordTaskRunTime(base::TimeTicks start_time, 192 void CPUTimeBudgetPool::RecordTaskRunTime(TaskQueue* queue,
193 base::TimeTicks start_time,
178 base::TimeTicks end_time) { 194 base::TimeTicks end_time) {
179 DCHECK_LE(start_time, end_time); 195 DCHECK_LE(start_time, end_time);
180 Advance(end_time); 196 Advance(end_time);
181 if (is_enabled_) { 197 if (is_enabled_) {
182 base::TimeDelta old_budget_level = current_budget_level_; 198 base::TimeDelta old_budget_level = current_budget_level_;
183 current_budget_level_ -= (end_time - start_time); 199 current_budget_level_ -= (end_time - start_time);
184 EnforceBudgetLevelRestrictions(); 200 EnforceBudgetLevelRestrictions();
185 201
186 if (!reporting_callback_.is_null() && old_budget_level.InSecondsF() > 0 && 202 if (!reporting_callback_.is_null() && old_budget_level.InSecondsF() > 0 &&
187 current_budget_level_.InSecondsF() < 0) { 203 current_budget_level_.InSecondsF() < 0) {
188 reporting_callback_.Run(-current_budget_level_ / cpu_percentage_); 204 reporting_callback_.Run(-current_budget_level_ / cpu_percentage_);
189 } 205 }
190 } 206 }
207
208 if (current_budget_level_.InSecondsF() < 0) {
209 BlockThrottledQueues(end_time);
210 }
191 } 211 }
192 212
213 void CPUTimeBudgetPool::OnTaskQueueHasWork(TaskQueue* queue,
214 base::TimeTicks now,
215 base::TimeTicks desired_run_time) {
216 budget_pool_controller_->UpdateQueueThrottlingState(now, queue);
217 }
218
219 void CPUTimeBudgetPool::OnWakeUp(base::TimeTicks now) {}
220
193 void CPUTimeBudgetPool::AsValueInto(base::trace_event::TracedValue* state, 221 void CPUTimeBudgetPool::AsValueInto(base::trace_event::TracedValue* state,
194 base::TimeTicks now) const { 222 base::TimeTicks now) const {
195 state->BeginDictionary(name_); 223 state->BeginDictionary(name_);
196 224
197 state->SetString("name", name_); 225 state->SetString("name", name_);
198 state->SetDouble("time_budget", cpu_percentage_); 226 state->SetDouble("time_budget", cpu_percentage_);
199 state->SetDouble("time_budget_level_in_seconds", 227 state->SetDouble("time_budget_level_in_seconds",
200 current_budget_level_.InSecondsF()); 228 current_budget_level_.InSecondsF());
201 state->SetDouble("last_checkpoint_seconds_ago", 229 state->SetDouble("last_checkpoint_seconds_ago",
202 (now - last_checkpoint_).InSecondsF()); 230 (now - last_checkpoint_).InSecondsF());
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 std::min(current_budget_level_, max_budget_level_.value()); 266 std::min(current_budget_level_, max_budget_level_.value());
239 } 267 }
240 if (max_throttling_delay_) { 268 if (max_throttling_delay_) {
241 // Current budget level may be negative. 269 // Current budget level may be negative.
242 current_budget_level_ = 270 current_budget_level_ =
243 std::max(current_budget_level_, 271 std::max(current_budget_level_,
244 -max_throttling_delay_.value() * cpu_percentage_); 272 -max_throttling_delay_.value() * cpu_percentage_);
245 } 273 }
246 } 274 }
247 275
276 WakeUpBudgetPool::WakeUpBudgetPool(const char* name,
277 BudgetPoolController* budget_pool_controller,
278 base::TimeTicks now)
279 : BudgetPool(name, budget_pool_controller), wakeups_per_second_(1) {}
280
281 WakeUpBudgetPool::~WakeUpBudgetPool() {}
282
283 QueueBlockType WakeUpBudgetPool::GetBlockType() const {
284 return QueueBlockType::kNewTasksOnly;
285 }
286
287 void WakeUpBudgetPool::SetWakeUpRate(double wakeups_per_second) {
288 wakeups_per_second_ = wakeups_per_second;
289 }
290
291 void WakeUpBudgetPool::SetWakeUpDuration(base::TimeDelta duration) {
292 wakeup_duration_ = duration;
293 }
294
295 void WakeUpBudgetPool::RecordTaskRunTime(TaskQueue* queue,
296 base::TimeTicks start_time,
297 base::TimeTicks end_time) {
298 budget_pool_controller_->UpdateQueueThrottlingState(end_time, queue);
299 }
300
301 base::Optional<base::TimeTicks> WakeUpBudgetPool::NextWakeUp() const {
302 if (!last_wakeup_)
303 return base::nullopt;
304 // Subtract 1 microsecond to work with time alignment in task queue throttler.
305 // This is needed due to alignment mechanism in task queue throttler --
306 // whole seconds need to be aligned to the next second to deal with immediate
307 // tasks correctly. By subtracting 1 microsecond we ensure that next wakeup
308 // gets aligned to a correct time.
309 return last_wakeup_.value() +
310 base::TimeDelta::FromSeconds(1 / wakeups_per_second_) -
311 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.
312 }
313
314 bool WakeUpBudgetPool::CanRunTasksAt(base::TimeTicks now,
315 bool is_wake_up) const {
316 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
317 return false;
318 if (last_wakeup_ == now && is_wake_up)
319 return true;
320 return now < last_wakeup_.value() + wakeup_duration_;
321 }
322
323 bool WakeUpBudgetPool::CanRunTasksUntil(base::TimeTicks now,
324 base::TimeTicks moment) const {
325 if (!last_wakeup_)
326 return false;
327 DCHECK_LE(now, moment);
328 return now < last_wakeup_.value() + wakeup_duration_ &&
329 moment < last_wakeup_.value() + wakeup_duration_;
330 }
331
332 base::TimeTicks WakeUpBudgetPool::GetNextAllowedRunTime(
333 base::TimeTicks desired_run_time) const {
334 if (!last_wakeup_)
335 return desired_run_time;
336 if (desired_run_time < last_wakeup_.value() + wakeup_duration_)
337 return desired_run_time;
338 return std::max(desired_run_time, NextWakeUp().value());
339 }
340
341 void WakeUpBudgetPool::OnTaskQueueHasWork(TaskQueue* queue,
342 base::TimeTicks now,
343 base::TimeTicks desired_run_time) {
344 budget_pool_controller_->UpdateQueueThrottlingState(now, queue);
345 }
346
347 void WakeUpBudgetPool::OnWakeUp(base::TimeTicks now) {
348 last_wakeup_ = now;
349 }
350
351 void WakeUpBudgetPool::AsValueInto(base::trace_event::TracedValue* state,
352 base::TimeTicks now) const {
353 state->BeginDictionary(name_);
354
355 state->SetString("name", name_);
356 state->SetDouble("wakeups_per_second_rate", wakeups_per_second_);
357 state->SetDouble("wakeup_duration_in_seconds", wakeup_duration_.InSecondsF());
358 if (last_wakeup_) {
359 state->SetDouble("last_wakeup_seconds_ago",
360 (now - last_wakeup_.value()).InSecondsF());
361 }
362 state->SetBoolean("is_enabled", is_enabled_);
363
364 state->BeginArray("task_queues");
365 for (TaskQueue* queue : associated_task_queues_) {
366 state->AppendString(PointerToId(queue));
367 }
368 state->EndArray();
369
370 state->EndDictionary();
371 }
372
248 } // namespace scheduler 373 } // namespace scheduler
249 } // namespace blink 374 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698