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

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

Issue 2412323003: [scheduler] Support setting maximal throttling duration (Closed)
Patch Set: Addressed comments from skyostil@ Created 4 years, 2 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/task_queue_throttler.h" 5 #include "platform/scheduler/renderer/task_queue_throttler.h"
6 6
7 #include <cstdint> 7 #include <cstdint>
8 8
9 #include <iostream> // FIXME
10
9 #include "base/format_macros.h" 11 #include "base/format_macros.h"
10 #include "base/logging.h" 12 #include "base/logging.h"
11 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
12 #include "base/optional.h" 14 #include "base/optional.h"
13 #include "base/strings/stringprintf.h" 15 #include "base/strings/stringprintf.h"
14 #include "platform/scheduler/base/real_time_domain.h" 16 #include "platform/scheduler/base/real_time_domain.h"
15 #include "platform/scheduler/child/scheduler_tqm_delegate.h" 17 #include "platform/scheduler/child/scheduler_tqm_delegate.h"
16 #include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" 18 #include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h"
17 #include "platform/scheduler/renderer/renderer_scheduler_impl.h" 19 #include "platform/scheduler/renderer/renderer_scheduler_impl.h"
18 #include "platform/scheduler/renderer/throttled_time_domain.h" 20 #include "platform/scheduler/renderer/throttled_time_domain.h"
19 #include "platform/scheduler/renderer/web_frame_scheduler_impl.h" 21 #include "platform/scheduler/renderer/web_frame_scheduler_impl.h"
20 #include "public/platform/WebFrameScheduler.h" 22 #include "public/platform/WebFrameScheduler.h"
21 23
22 namespace blink { 24 namespace blink {
23 namespace scheduler { 25 namespace scheduler {
24 26
25 namespace { 27 namespace {
26 const int kMaxBudgetLevelInSeconds = 1; 28 constexpr base::TimeDelta kMaxBudgetLevel = base::TimeDelta::FromSeconds(1);
29 constexpr base::TimeDelta kMaxThrottlingDuration =
30 base::TimeDelta::FromMinutes(1);
27 31
28 base::Optional<base::TimeTicks> NextTaskRunTime(LazyNow* lazy_now, 32 base::Optional<base::TimeTicks> NextTaskRunTime(LazyNow* lazy_now,
29 TaskQueue* queue) { 33 TaskQueue* queue) {
30 if (queue->HasPendingImmediateWork()) 34 if (queue->HasPendingImmediateWork())
31 return lazy_now->Now(); 35 return lazy_now->Now();
32 return queue->GetNextScheduledWakeUp(); 36 return queue->GetNextScheduledWakeUp();
33 } 37 }
34 38
35 template <class T> 39 template <class T>
36 T Min(const base::Optional<T>& optional, const T& value) { 40 T Min(const base::Optional<T>& optional, const T& value) {
(...skipping 26 matching lines...) Expand all
63 if (!a) 67 if (!a)
64 return b; 68 return b;
65 return std::max(a.value(), b.value()); 69 return std::max(a.value(), b.value());
66 } 70 }
67 71
68 } // namespace 72 } // namespace
69 73
70 TaskQueueThrottler::TimeBudgetPool::TimeBudgetPool( 74 TaskQueueThrottler::TimeBudgetPool::TimeBudgetPool(
71 const char* name, 75 const char* name,
72 TaskQueueThrottler* task_queue_throttler, 76 TaskQueueThrottler* task_queue_throttler,
73 base::TimeTicks now) 77 base::TimeTicks now,
78 base::Optional<base::TimeDelta> max_budget_level,
79 base::Optional<base::TimeDelta> max_throttling_duration)
74 : name_(name), 80 : name_(name),
75 task_queue_throttler_(task_queue_throttler), 81 task_queue_throttler_(task_queue_throttler),
76 max_budget_level_(base::TimeDelta::FromSeconds(kMaxBudgetLevelInSeconds)), 82 max_budget_level_(max_budget_level),
83 max_throttling_duration_(max_throttling_duration),
77 last_checkpoint_(now), 84 last_checkpoint_(now),
78 cpu_percentage_(1), 85 cpu_percentage_(1),
79 is_enabled_(true) {} 86 is_enabled_(true) {}
80 87
81 TaskQueueThrottler::TimeBudgetPool::~TimeBudgetPool() {} 88 TaskQueueThrottler::TimeBudgetPool::~TimeBudgetPool() {}
82 89
83 void TaskQueueThrottler::TimeBudgetPool::SetTimeBudget(base::TimeTicks now, 90 void TaskQueueThrottler::TimeBudgetPool::SetTimeBudget(base::TimeTicks now,
84 double cpu_percentage) { 91 double cpu_percentage) {
85 Advance(now); 92 Advance(now);
86 cpu_percentage_ = cpu_percentage; 93 cpu_percentage_ = cpu_percentage;
94 EnforceMaximalThrottlingDuration();
87 } 95 }
88 96
89 void TaskQueueThrottler::TimeBudgetPool::AddQueue(base::TimeTicks now, 97 void TaskQueueThrottler::TimeBudgetPool::AddQueue(base::TimeTicks now,
90 TaskQueue* queue) { 98 TaskQueue* queue) {
91 std::pair<TaskQueueMap::iterator, bool> insert_result = 99 std::pair<TaskQueueMap::iterator, bool> insert_result =
92 task_queue_throttler_->queue_details_.insert( 100 task_queue_throttler_->queue_details_.insert(
93 std::make_pair(queue, Metadata(0, queue->IsQueueEnabled()))); 101 std::make_pair(queue, Metadata(0, queue->IsQueueEnabled())));
94 Metadata& metadata = insert_result.first->second; 102 Metadata& metadata = insert_result.first->second;
95 DCHECK(!metadata.time_budget_pool); 103 DCHECK(!metadata.time_budget_pool);
96 metadata.time_budget_pool = this; 104 metadata.time_budget_pool = this;
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 base::TimeTicks TaskQueueThrottler::TimeBudgetPool::GetNextAllowedRunTime() { 173 base::TimeTicks TaskQueueThrottler::TimeBudgetPool::GetNextAllowedRunTime() {
166 if (!is_enabled_ || current_budget_level_.InMicroseconds() >= 0) { 174 if (!is_enabled_ || current_budget_level_.InMicroseconds() >= 0) {
167 return last_checkpoint_; 175 return last_checkpoint_;
168 } else { 176 } else {
169 // Subtract because current_budget is negative. 177 // Subtract because current_budget is negative.
170 return last_checkpoint_ - current_budget_level_ / cpu_percentage_; 178 return last_checkpoint_ - current_budget_level_ / cpu_percentage_;
171 } 179 }
172 } 180 }
173 181
174 void TaskQueueThrottler::TimeBudgetPool::RecordTaskRunTime( 182 void TaskQueueThrottler::TimeBudgetPool::RecordTaskRunTime(
175 base::TimeDelta task_run_time) { 183 base::TimeTicks start_time,
176 if (is_enabled_) 184 base::TimeTicks end_time) {
177 current_budget_level_ -= task_run_time; 185 Advance(end_time);
alex clarke (OOO till 29th) 2016/10/14 16:37:22 Maybe DCHECK_LE(start_time, end_time);
altimin 2016/10/17 10:48:37 Done.
186 if (is_enabled_) {
187 current_budget_level_ -= (end_time - start_time);
188 EnforceMaximalThrottlingDuration();
189 }
178 } 190 }
179 191
180 const char* TaskQueueThrottler::TimeBudgetPool::Name() const { 192 const char* TaskQueueThrottler::TimeBudgetPool::Name() const {
181 return name_; 193 return name_;
182 } 194 }
183 195
184 void TaskQueueThrottler::TimeBudgetPool::AsValueInto( 196 void TaskQueueThrottler::TimeBudgetPool::AsValueInto(
185 base::trace_event::TracedValue* state, 197 base::trace_event::TracedValue* state,
186 base::TimeTicks now) const { 198 base::TimeTicks now) const {
187 state->BeginDictionary(); 199 state->BeginDictionary();
(...skipping 11 matching lines...) Expand all
199 "%" PRIx64, static_cast<uint64_t>(reinterpret_cast<uintptr_t>(queue)))); 211 "%" PRIx64, static_cast<uint64_t>(reinterpret_cast<uintptr_t>(queue))));
200 } 212 }
201 state->EndArray(); 213 state->EndArray();
202 214
203 state->EndDictionary(); 215 state->EndDictionary();
204 } 216 }
205 217
206 void TaskQueueThrottler::TimeBudgetPool::Advance(base::TimeTicks now) { 218 void TaskQueueThrottler::TimeBudgetPool::Advance(base::TimeTicks now) {
207 if (now > last_checkpoint_) { 219 if (now > last_checkpoint_) {
208 if (is_enabled_) { 220 if (is_enabled_) {
209 current_budget_level_ = std::min( 221 current_budget_level_ += cpu_percentage_ * (now - last_checkpoint_);
210 current_budget_level_ + cpu_percentage_ * (now - last_checkpoint_), 222 if (max_budget_level_) {
211 max_budget_level_); 223 current_budget_level_ =
224 std::min(current_budget_level_, max_budget_level_.value());
225 }
212 } 226 }
213 last_checkpoint_ = now; 227 last_checkpoint_ = now;
214 } 228 }
215 } 229 }
216 230
217 void TaskQueueThrottler::TimeBudgetPool::BlockThrottledQueues( 231 void TaskQueueThrottler::TimeBudgetPool::BlockThrottledQueues(
218 base::TimeTicks now) { 232 base::TimeTicks now) {
219 for (TaskQueue* queue : associated_task_queues_) { 233 for (TaskQueue* queue : associated_task_queues_) {
220 if (!task_queue_throttler_->IsThrottled(queue)) 234 if (!task_queue_throttler_->IsThrottled(queue))
221 continue; 235 continue;
222 236
223 queue->SetQueueEnabled(false); 237 queue->SetQueueEnabled(false);
224 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, 238 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue,
225 base::nullopt); 239 base::nullopt);
226 } 240 }
227 } 241 }
228 242
243 void TaskQueueThrottler::TimeBudgetPool::EnforceMaximalThrottlingDuration() {
alex clarke (OOO till 29th) 2016/10/14 16:37:22 Out of curiosity would it make sense to enforce ma
altimin 2016/10/17 10:48:37 Thanks! Done.
244 if (max_throttling_duration_) {
245 current_budget_level_ =
246 std::max(current_budget_level_,
alex clarke (OOO till 29th) 2016/10/14 16:37:22 Maybe add a comment pointing out the obvious: curr
altimin 2016/10/17 10:48:37 Done.
247 -max_throttling_duration_.value() * cpu_percentage_);
248 }
249 }
250
229 TaskQueueThrottler::TaskQueueThrottler( 251 TaskQueueThrottler::TaskQueueThrottler(
230 RendererSchedulerImpl* renderer_scheduler, 252 RendererSchedulerImpl* renderer_scheduler,
231 const char* tracing_category) 253 const char* tracing_category)
232 : task_runner_(renderer_scheduler->ControlTaskRunner()), 254 : task_runner_(renderer_scheduler->ControlTaskRunner()),
233 renderer_scheduler_(renderer_scheduler), 255 renderer_scheduler_(renderer_scheduler),
234 tick_clock_(renderer_scheduler->tick_clock()), 256 tick_clock_(renderer_scheduler->tick_clock()),
235 tracing_category_(tracing_category), 257 tracing_category_(tracing_category),
236 time_domain_(new ThrottledTimeDomain(this, tracing_category)), 258 time_domain_(new ThrottledTimeDomain(this, tracing_category)),
259 max_budget_level_(kMaxBudgetLevel),
260 max_throttling_duration_(kMaxThrottlingDuration),
237 virtual_time_(false), 261 virtual_time_(false),
238 weak_factory_(this) { 262 weak_factory_(this) {
239 pump_throttled_tasks_closure_.Reset(base::Bind( 263 pump_throttled_tasks_closure_.Reset(base::Bind(
240 &TaskQueueThrottler::PumpThrottledTasks, weak_factory_.GetWeakPtr())); 264 &TaskQueueThrottler::PumpThrottledTasks, weak_factory_.GetWeakPtr()));
241 forward_immediate_work_callback_ = 265 forward_immediate_work_callback_ =
242 base::Bind(&TaskQueueThrottler::OnTimeDomainHasImmediateWork, 266 base::Bind(&TaskQueueThrottler::OnTimeDomainHasImmediateWork,
243 weak_factory_.GetWeakPtr()); 267 weak_factory_.GetWeakPtr());
244 268
245 renderer_scheduler_->RegisterTimeDomain(time_domain_.get()); 269 renderer_scheduler_->RegisterTimeDomain(time_domain_.get());
246 } 270 }
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
496 520
497 task_queue->SetTimeDomain(renderer_scheduler_->GetVirtualTimeDomain()); 521 task_queue->SetTimeDomain(renderer_scheduler_->GetVirtualTimeDomain());
498 task_queue->RemoveFence(); 522 task_queue->RemoveFence();
499 task_queue->SetQueueEnabled(enabled); 523 task_queue->SetQueueEnabled(enabled);
500 } 524 }
501 } 525 }
502 526
503 TaskQueueThrottler::TimeBudgetPool* TaskQueueThrottler::CreateTimeBudgetPool( 527 TaskQueueThrottler::TimeBudgetPool* TaskQueueThrottler::CreateTimeBudgetPool(
504 const char* name) { 528 const char* name) {
505 TimeBudgetPool* time_budget_pool = 529 TimeBudgetPool* time_budget_pool =
506 new TimeBudgetPool(name, this, tick_clock_->NowTicks()); 530 new TimeBudgetPool(name, this, tick_clock_->NowTicks(), max_budget_level_,
531 max_throttling_duration_);
507 time_budget_pools_[time_budget_pool] = base::WrapUnique(time_budget_pool); 532 time_budget_pools_[time_budget_pool] = base::WrapUnique(time_budget_pool);
508 return time_budget_pool; 533 return time_budget_pool;
509 } 534 }
510 535
511 void TaskQueueThrottler::OnTaskRunTimeReported(TaskQueue* task_queue, 536 void TaskQueueThrottler::OnTaskRunTimeReported(TaskQueue* task_queue,
512 base::TimeTicks start_time, 537 base::TimeTicks start_time,
513 base::TimeTicks end_time) { 538 base::TimeTicks end_time) {
514 if (!IsThrottled(task_queue)) 539 if (!IsThrottled(task_queue))
515 return; 540 return;
516 541
517 TimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(task_queue); 542 TimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(task_queue);
518 if (!time_budget_pool) 543 if (!time_budget_pool)
519 return; 544 return;
520 545
521 time_budget_pool->RecordTaskRunTime(end_time - start_time); 546 time_budget_pool->RecordTaskRunTime(start_time, end_time);
522 if (!time_budget_pool->HasEnoughBudgetToRun(end_time)) 547 if (!time_budget_pool->HasEnoughBudgetToRun(end_time))
523 time_budget_pool->BlockThrottledQueues(end_time); 548 time_budget_pool->BlockThrottledQueues(end_time);
524 } 549 }
525 550
526 void TaskQueueThrottler::AsValueInto(base::trace_event::TracedValue* state, 551 void TaskQueueThrottler::AsValueInto(base::trace_event::TracedValue* state,
527 base::TimeTicks now) const { 552 base::TimeTicks now) const {
528 if (pending_pump_throttled_tasks_runtime_) { 553 if (pending_pump_throttled_tasks_runtime_) {
529 state->SetDouble( 554 state->SetDouble(
530 "next_throttled_tasks_pump_in_seconds", 555 "next_throttled_tasks_pump_in_seconds",
531 (pending_pump_throttled_tasks_runtime_.value() - now).InSecondsF()); 556 (pending_pump_throttled_tasks_runtime_.value() - now).InSecondsF());
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
571 return std::max(now, time_budget_pool->GetNextAllowedRunTime()); 596 return std::max(now, time_budget_pool->GetNextAllowedRunTime());
572 } 597 }
573 598
574 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) { 599 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) {
575 if (!it->second.IsThrottled() && !it->second.time_budget_pool) 600 if (!it->second.IsThrottled() && !it->second.time_budget_pool)
576 queue_details_.erase(it); 601 queue_details_.erase(it);
577 } 602 }
578 603
579 } // namespace scheduler 604 } // namespace scheduler
580 } // namespace blink 605 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698