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

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

Issue 2778123003: [scheduler] Add WakeupBudgetPool. (Closed)
Patch Set: addressed comments Created 3 years, 7 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) {
alex clarke (OOO till 29th) 2017/04/27 10:28:14 I wonder if this and DissociateQueue and TaskQueu
altimin 2017/04/27 11:07:41 I'll look into it, but it may be non-trivial due t
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) {
alex clarke (OOO till 29th) 2017/04/27 10:28:14 nit: Elsewhere we tend not to use curly braces for
altimin 2017/04/27 11:07:41 Done.
209 BlockThrottledQueues(end_time);
210 }
191 } 211 }
192 212
213 void CPUTimeBudgetPool::OnQueueNextWakeUpChanged(
214 TaskQueue* queue,
215 base::TimeTicks now,
216 base::TimeTicks desired_run_time) {
217 budget_pool_controller_->UpdateQueueThrottlingState(now, queue);
218 }
219
220 void CPUTimeBudgetPool::OnWakeUp(base::TimeTicks now) {}
221
193 void CPUTimeBudgetPool::AsValueInto(base::trace_event::TracedValue* state, 222 void CPUTimeBudgetPool::AsValueInto(base::trace_event::TracedValue* state,
194 base::TimeTicks now) const { 223 base::TimeTicks now) const {
195 state->BeginDictionary(name_); 224 state->BeginDictionary(name_);
196 225
197 state->SetString("name", name_); 226 state->SetString("name", name_);
198 state->SetDouble("time_budget", cpu_percentage_); 227 state->SetDouble("time_budget", cpu_percentage_);
199 state->SetDouble("time_budget_level_in_seconds", 228 state->SetDouble("time_budget_level_in_seconds",
200 current_budget_level_.InSecondsF()); 229 current_budget_level_.InSecondsF());
201 state->SetDouble("last_checkpoint_seconds_ago", 230 state->SetDouble("last_checkpoint_seconds_ago",
202 (now - last_checkpoint_).InSecondsF()); 231 (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()); 267 std::min(current_budget_level_, max_budget_level_.value());
239 } 268 }
240 if (max_throttling_delay_) { 269 if (max_throttling_delay_) {
241 // Current budget level may be negative. 270 // Current budget level may be negative.
242 current_budget_level_ = 271 current_budget_level_ =
243 std::max(current_budget_level_, 272 std::max(current_budget_level_,
244 -max_throttling_delay_.value() * cpu_percentage_); 273 -max_throttling_delay_.value() * cpu_percentage_);
245 } 274 }
246 } 275 }
247 276
277 WakeUpBudgetPool::WakeUpBudgetPool(const char* name,
278 BudgetPoolController* budget_pool_controller,
279 base::TimeTicks now)
280 : BudgetPool(name, budget_pool_controller), wakeups_per_second_(1) {}
281
282 WakeUpBudgetPool::~WakeUpBudgetPool() {}
283
284 QueueBlockType WakeUpBudgetPool::GetBlockType() const {
285 return QueueBlockType::kNewTasksOnly;
286 }
287
288 void WakeUpBudgetPool::SetWakeUpRate(double wakeups_per_second) {
289 wakeups_per_second_ = wakeups_per_second;
290 }
291
292 void WakeUpBudgetPool::SetWakeUpDuration(base::TimeDelta duration) {
293 wakeup_duration_ = duration;
294 }
295
296 void WakeUpBudgetPool::RecordTaskRunTime(TaskQueue* queue,
297 base::TimeTicks start_time,
298 base::TimeTicks end_time) {
299 budget_pool_controller_->UpdateQueueThrottlingState(end_time, queue);
300 }
301
302 base::Optional<base::TimeTicks> WakeUpBudgetPool::NextWakeUp() const {
303 if (!last_wakeup_)
304 return base::nullopt;
305 // Subtract 1 microsecond to work with time alignment in task queue throttler.
306 // This is needed due to alignment mechanism in task queue throttler --
307 // whole seconds need to be aligned to the next second to deal with immediate
308 // tasks correctly. By subtracting 1 microsecond we ensure that next wakeup
309 // gets aligned to a correct time.
310 return last_wakeup_.value() +
311 base::TimeDelta::FromSeconds(1 / wakeups_per_second_) -
312 base::TimeDelta::FromMicroseconds(1);
313 }
314
315 bool WakeUpBudgetPool::CanRunTasksAt(base::TimeTicks now,
316 bool is_wake_up) const {
317 if (!last_wakeup_)
318 return false;
319 if (last_wakeup_ == now && is_wake_up)
320 return true;
321 return now < last_wakeup_.value() + wakeup_duration_;
322 }
323
324 bool WakeUpBudgetPool::CanRunTasksUntil(base::TimeTicks now,
325 base::TimeTicks moment) const {
326 if (!last_wakeup_)
327 return false;
328 DCHECK_LE(now, moment);
329 return now < last_wakeup_.value() + wakeup_duration_ &&
330 moment < last_wakeup_.value() + wakeup_duration_;
331 }
332
333 base::TimeTicks WakeUpBudgetPool::GetNextAllowedRunTime(
334 base::TimeTicks desired_run_time) const {
335 if (!last_wakeup_)
336 return desired_run_time;
337 if (desired_run_time < last_wakeup_.value() + wakeup_duration_)
338 return desired_run_time;
339 return std::max(desired_run_time, NextWakeUp().value());
340 }
341
342 void WakeUpBudgetPool::OnQueueNextWakeUpChanged(
343 TaskQueue* queue,
344 base::TimeTicks now,
345 base::TimeTicks desired_run_time) {
346 budget_pool_controller_->UpdateQueueThrottlingState(now, queue);
347 }
348
349 void WakeUpBudgetPool::OnWakeUp(base::TimeTicks now) {
350 last_wakeup_ = now;
351 }
352
353 void WakeUpBudgetPool::AsValueInto(base::trace_event::TracedValue* state,
354 base::TimeTicks now) const {
355 state->BeginDictionary(name_);
356
357 state->SetString("name", name_);
358 state->SetDouble("wakeups_per_second_rate", wakeups_per_second_);
359 state->SetDouble("wakeup_duration_in_seconds", wakeup_duration_.InSecondsF());
360 if (last_wakeup_) {
361 state->SetDouble("last_wakeup_seconds_ago",
362 (now - last_wakeup_.value()).InSecondsF());
363 }
364 state->SetBoolean("is_enabled", is_enabled_);
365
366 state->BeginArray("task_queues");
367 for (TaskQueue* queue : associated_task_queues_) {
368 state->AppendString(PointerToId(queue));
369 }
370 state->EndArray();
371
372 state->EndDictionary();
373 }
374
248 } // namespace scheduler 375 } // namespace scheduler
249 } // namespace blink 376 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698