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

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

Powered by Google App Engine
This is Rietveld 408576698