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

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

Issue 2741473002: [scheduler] Move TimeBudgetPool to a separate file. (Closed)
Patch Set: Addressed comments from alexclarke@ Created 3 years, 9 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/WebFrameScheduler.h" 14 #include "platform/WebFrameScheduler.h"
15 #include "platform/scheduler/base/real_time_domain.h" 15 #include "platform/scheduler/base/real_time_domain.h"
16 #include "platform/scheduler/child/scheduler_tqm_delegate.h" 16 #include "platform/scheduler/child/scheduler_tqm_delegate.h"
17 #include "platform/scheduler/renderer/budget_pool.h"
17 #include "platform/scheduler/renderer/renderer_scheduler_impl.h" 18 #include "platform/scheduler/renderer/renderer_scheduler_impl.h"
18 #include "platform/scheduler/renderer/throttled_time_domain.h" 19 #include "platform/scheduler/renderer/throttled_time_domain.h"
19 #include "platform/scheduler/renderer/web_frame_scheduler_impl.h" 20 #include "platform/scheduler/renderer/web_frame_scheduler_impl.h"
20 21
21 namespace blink { 22 namespace blink {
22 namespace scheduler { 23 namespace scheduler {
23 24
24 namespace { 25 namespace {
25 26
26 base::Optional<base::TimeTicks> NextTaskRunTime(LazyNow* lazy_now, 27 base::Optional<base::TimeTicks> NextTaskRunTime(LazyNow* lazy_now,
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 } 65 }
65 66
66 std::string PointerToId(void* pointer) { 67 std::string PointerToId(void* pointer) {
67 return base::StringPrintf( 68 return base::StringPrintf(
68 "0x%" PRIx64, 69 "0x%" PRIx64,
69 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pointer))); 70 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pointer)));
70 } 71 }
71 72
72 } // namespace 73 } // namespace
73 74
74 TaskQueueThrottler::TimeBudgetPool::TimeBudgetPool(
75 const char* name,
76 TaskQueueThrottler* task_queue_throttler,
77 base::TimeTicks now,
78 base::Optional<base::TimeDelta> max_budget_level,
79 base::Optional<base::TimeDelta> max_throttling_duration)
80 : name_(name),
81 task_queue_throttler_(task_queue_throttler),
82 max_budget_level_(max_budget_level),
83 max_throttling_duration_(max_throttling_duration),
84 last_checkpoint_(now),
85 cpu_percentage_(1),
86 is_enabled_(true) {}
87
88 TaskQueueThrottler::TimeBudgetPool::~TimeBudgetPool() {}
89
90 void TaskQueueThrottler::TimeBudgetPool::SetTimeBudgetRecoveryRate(
91 base::TimeTicks now,
92 double cpu_percentage) {
93 Advance(now);
94 cpu_percentage_ = cpu_percentage;
95 EnforceBudgetLevelRestrictions();
96 }
97
98 void TaskQueueThrottler::TimeBudgetPool::AddQueue(base::TimeTicks now,
99 TaskQueue* queue) {
100 std::pair<TaskQueueMap::iterator, bool> insert_result =
101 task_queue_throttler_->queue_details_.insert(
102 std::make_pair(queue, Metadata()));
103 Metadata& metadata = insert_result.first->second;
104 DCHECK(!metadata.time_budget_pool);
105 metadata.time_budget_pool = this;
106
107 associated_task_queues_.insert(queue);
108
109 if (!is_enabled_ || !task_queue_throttler_->IsThrottled(queue))
110 return;
111
112 queue->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME);
113
114 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue,
115 GetNextAllowedRunTime());
116 }
117
118 void TaskQueueThrottler::TimeBudgetPool::RemoveQueue(base::TimeTicks now,
119 TaskQueue* queue) {
120 auto find_it = task_queue_throttler_->queue_details_.find(queue);
121 DCHECK(find_it != task_queue_throttler_->queue_details_.end() &&
122 find_it->second.time_budget_pool == this);
123 find_it->second.time_budget_pool = nullptr;
124 bool is_throttled = task_queue_throttler_->IsThrottled(queue);
125
126 task_queue_throttler_->MaybeDeleteQueueMetadata(find_it);
127 associated_task_queues_.erase(queue);
128
129 if (!is_enabled_ || !is_throttled)
130 return;
131
132 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue,
133 base::nullopt);
134 }
135
136 void TaskQueueThrottler::TimeBudgetPool::EnableThrottling(LazyNow* lazy_now) {
137 if (is_enabled_)
138 return;
139 is_enabled_ = true;
140
141 TRACE_EVENT0(task_queue_throttler_->tracing_category_,
142 "TaskQueueThrottler_TimeBudgetPool_EnableThrottling");
143
144 BlockThrottledQueues(lazy_now->Now());
145 }
146
147 void TaskQueueThrottler::TimeBudgetPool::DisableThrottling(LazyNow* lazy_now) {
148 if (!is_enabled_)
149 return;
150 is_enabled_ = false;
151
152 TRACE_EVENT0(task_queue_throttler_->tracing_category_,
153 "TaskQueueThrottler_TimeBudgetPool_DisableThrottling");
154
155 for (TaskQueue* queue : associated_task_queues_) {
156 if (!task_queue_throttler_->IsThrottled(queue))
157 continue;
158
159 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, lazy_now->Now(),
160 queue, base::nullopt);
161 }
162
163 // TODO(altimin): We need to disable TimeBudgetQueues here or they will
164 // regenerate extra time budget when they are disabled.
165 }
166
167 bool TaskQueueThrottler::TimeBudgetPool::IsThrottlingEnabled() const {
168 return is_enabled_;
169 }
170
171 void TaskQueueThrottler::TimeBudgetPool::GrantAdditionalBudget(
172 base::TimeTicks now,
173 base::TimeDelta budget_level) {
174 Advance(now);
175 current_budget_level_ += budget_level;
176 EnforceBudgetLevelRestrictions();
177 }
178
179 void TaskQueueThrottler::TimeBudgetPool::SetReportingCallback(
180 base::Callback<void(base::TimeDelta)> reporting_callback) {
181 reporting_callback_ = reporting_callback;
182 }
183
184 void TaskQueueThrottler::TimeBudgetPool::Close() {
185 DCHECK_EQ(0u, associated_task_queues_.size());
186
187 task_queue_throttler_->time_budget_pools_.erase(this);
188 }
189
190 bool TaskQueueThrottler::TimeBudgetPool::HasEnoughBudgetToRun(
191 base::TimeTicks now) {
192 Advance(now);
193 return !is_enabled_ || current_budget_level_.InMicroseconds() >= 0;
194 }
195
196 base::TimeTicks TaskQueueThrottler::TimeBudgetPool::GetNextAllowedRunTime() {
197 if (!is_enabled_ || current_budget_level_.InMicroseconds() >= 0) {
198 return last_checkpoint_;
199 } else {
200 // Subtract because current_budget is negative.
201 return last_checkpoint_ - current_budget_level_ / cpu_percentage_;
202 }
203 }
204
205 void TaskQueueThrottler::TimeBudgetPool::RecordTaskRunTime(
206 base::TimeTicks start_time,
207 base::TimeTicks end_time) {
208 DCHECK_LE(start_time, end_time);
209 Advance(end_time);
210 if (is_enabled_) {
211 base::TimeDelta old_budget_level = current_budget_level_;
212 current_budget_level_ -= (end_time - start_time);
213 EnforceBudgetLevelRestrictions();
214
215 if (!reporting_callback_.is_null() && old_budget_level.InSecondsF() > 0 &&
216 current_budget_level_.InSecondsF() < 0) {
217 reporting_callback_.Run(-current_budget_level_ / cpu_percentage_);
218 }
219 }
220 }
221
222 const char* TaskQueueThrottler::TimeBudgetPool::Name() const {
223 return name_;
224 }
225
226 void TaskQueueThrottler::TimeBudgetPool::AsValueInto(
227 base::trace_event::TracedValue* state,
228 base::TimeTicks now) const {
229 state->BeginDictionary(name_);
230
231 state->SetString("name", name_);
232 state->SetDouble("time_budget", cpu_percentage_);
233 state->SetDouble("time_budget_level_in_seconds",
234 current_budget_level_.InSecondsF());
235 state->SetDouble("last_checkpoint_seconds_ago",
236 (now - last_checkpoint_).InSecondsF());
237 state->SetBoolean("is_enabled", is_enabled_);
238
239 state->BeginArray("task_queues");
240 for (TaskQueue* queue : associated_task_queues_) {
241 state->AppendString(PointerToId(queue));
242 }
243 state->EndArray();
244
245 state->EndDictionary();
246 }
247
248 void TaskQueueThrottler::TimeBudgetPool::Advance(base::TimeTicks now) {
249 if (now > last_checkpoint_) {
250 if (is_enabled_) {
251 current_budget_level_ += cpu_percentage_ * (now - last_checkpoint_);
252 EnforceBudgetLevelRestrictions();
253 }
254 last_checkpoint_ = now;
255 }
256 }
257
258 void TaskQueueThrottler::TimeBudgetPool::BlockThrottledQueues(
259 base::TimeTicks now) {
260 for (TaskQueue* queue : associated_task_queues_) {
261 if (!task_queue_throttler_->IsThrottled(queue))
262 continue;
263
264 queue->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME);
265 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue,
266 base::nullopt);
267 }
268 }
269
270 void TaskQueueThrottler::TimeBudgetPool::EnforceBudgetLevelRestrictions() {
271 if (max_budget_level_) {
272 current_budget_level_ =
273 std::min(current_budget_level_, max_budget_level_.value());
274 }
275 if (max_throttling_duration_) {
276 // Current budget level may be negative.
277 current_budget_level_ =
278 std::max(current_budget_level_,
279 -max_throttling_duration_.value() * cpu_percentage_);
280 }
281 }
282
283 TaskQueueThrottler::TaskQueueThrottler( 75 TaskQueueThrottler::TaskQueueThrottler(
284 RendererSchedulerImpl* renderer_scheduler, 76 RendererSchedulerImpl* renderer_scheduler,
285 const char* tracing_category) 77 const char* tracing_category)
286 : task_runner_(renderer_scheduler->ControlTaskRunner()), 78 : task_runner_(renderer_scheduler->ControlTaskRunner()),
287 renderer_scheduler_(renderer_scheduler), 79 renderer_scheduler_(renderer_scheduler),
288 tick_clock_(renderer_scheduler->tick_clock()), 80 tick_clock_(renderer_scheduler->tick_clock()),
289 tracing_category_(tracing_category), 81 tracing_category_(tracing_category),
290 time_domain_(new ThrottledTimeDomain(this, tracing_category)), 82 time_domain_(new ThrottledTimeDomain(this, tracing_category)),
291 allow_throttling_(true), 83 allow_throttling_(true),
292 weak_factory_(this) { 84 weak_factory_(this) {
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 pump_throttled_tasks_closure_.Cancel(); 301 pump_throttled_tasks_closure_.Cancel();
510 302
511 base::TimeDelta delay = pending_pump_throttled_tasks_runtime_.value() - now; 303 base::TimeDelta delay = pending_pump_throttled_tasks_runtime_.value() - now;
512 TRACE_EVENT1(tracing_category_, 304 TRACE_EVENT1(tracing_category_,
513 "TaskQueueThrottler::MaybeSchedulePumpThrottledTasks", 305 "TaskQueueThrottler::MaybeSchedulePumpThrottledTasks",
514 "delay_till_next_pump_ms", delay.InMilliseconds()); 306 "delay_till_next_pump_ms", delay.InMilliseconds());
515 task_runner_->PostDelayedTask( 307 task_runner_->PostDelayedTask(
516 from_here, pump_throttled_tasks_closure_.callback(), delay); 308 from_here, pump_throttled_tasks_closure_.callback(), delay);
517 } 309 }
518 310
519 TaskQueueThrottler::TimeBudgetPool* TaskQueueThrottler::CreateTimeBudgetPool( 311 CPUTimeBudgetPool* TaskQueueThrottler::CreateCPUTimeBudgetPool(
520 const char* name, 312 const char* name,
521 base::Optional<base::TimeDelta> max_budget_level, 313 base::Optional<base::TimeDelta> max_budget_level,
522 base::Optional<base::TimeDelta> max_throttling_duration) { 314 base::Optional<base::TimeDelta> max_throttling_duration) {
523 TimeBudgetPool* time_budget_pool = 315 CPUTimeBudgetPool* time_budget_pool =
524 new TimeBudgetPool(name, this, tick_clock_->NowTicks(), max_budget_level, 316 new CPUTimeBudgetPool(name, this, tick_clock_->NowTicks(),
525 max_throttling_duration); 317 max_budget_level, max_throttling_duration);
526 time_budget_pools_[time_budget_pool] = base::WrapUnique(time_budget_pool); 318 time_budget_pools_[time_budget_pool] = base::WrapUnique(time_budget_pool);
527 return time_budget_pool; 319 return time_budget_pool;
528 } 320 }
529 321
530 void TaskQueueThrottler::OnTaskRunTimeReported(TaskQueue* task_queue, 322 void TaskQueueThrottler::OnTaskRunTimeReported(TaskQueue* task_queue,
531 base::TimeTicks start_time, 323 base::TimeTicks start_time,
532 base::TimeTicks end_time) { 324 base::TimeTicks end_time) {
533 if (!IsThrottled(task_queue)) 325 if (!IsThrottled(task_queue))
534 return; 326 return;
535 327
536 TimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(task_queue); 328 CPUTimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(task_queue);
537 if (!time_budget_pool) 329 if (!time_budget_pool)
538 return; 330 return;
539 331
540 time_budget_pool->RecordTaskRunTime(start_time, end_time); 332 time_budget_pool->RecordTaskRunTime(start_time, end_time);
541 if (!time_budget_pool->HasEnoughBudgetToRun(end_time)) 333 if (!time_budget_pool->HasEnoughBudgetToRun(end_time))
542 time_budget_pool->BlockThrottledQueues(end_time); 334 time_budget_pool->BlockThrottledQueues(end_time);
543 } 335 }
544 336
545 void TaskQueueThrottler::AsValueInto(base::trace_event::TracedValue* state, 337 void TaskQueueThrottler::AsValueInto(base::trace_event::TracedValue* state,
546 base::TimeTicks now) const { 338 base::TimeTicks now) const {
547 if (pending_pump_throttled_tasks_runtime_) { 339 if (pending_pump_throttled_tasks_runtime_) {
548 state->SetDouble( 340 state->SetDouble(
549 "next_throttled_tasks_pump_in_seconds", 341 "next_throttled_tasks_pump_in_seconds",
550 (pending_pump_throttled_tasks_runtime_.value() - now).InSecondsF()); 342 (pending_pump_throttled_tasks_runtime_.value() - now).InSecondsF());
551 } 343 }
552 344
553 state->SetBoolean("allow_throttling", allow_throttling_); 345 state->SetBoolean("allow_throttling", allow_throttling_);
554 346
555 state->BeginDictionary("time_budget_pools"); 347 state->BeginDictionary("time_budget_pools");
556 for (const auto& map_entry : time_budget_pools_) { 348 for (const auto& map_entry : time_budget_pools_) {
557 TaskQueueThrottler::TimeBudgetPool* pool = map_entry.first; 349 BudgetPool* pool = map_entry.first;
558 pool->AsValueInto(state, now); 350 pool->AsValueInto(state, now);
559 } 351 }
560 state->EndDictionary(); 352 state->EndDictionary();
561 353
562 state->BeginDictionary("queue_details"); 354 state->BeginDictionary("queue_details");
563 for (const auto& map_entry : queue_details_) { 355 for (const auto& map_entry : queue_details_) {
564 state->BeginDictionaryWithCopiedName(PointerToId(map_entry.first)); 356 state->BeginDictionaryWithCopiedName(PointerToId(map_entry.first));
565 357
566 state->SetInteger("throttling_ref_count", 358 state->SetInteger("throttling_ref_count",
567 map_entry.second.throttling_ref_count); 359 map_entry.second.throttling_ref_count);
568 360
569 state->EndDictionary(); 361 state->EndDictionary();
570 } 362 }
571 state->EndDictionary(); 363 state->EndDictionary();
572 } 364 }
573 365
574 TaskQueueThrottler::TimeBudgetPool* 366 CPUTimeBudgetPool* TaskQueueThrottler::GetTimeBudgetPoolForQueue(
575 TaskQueueThrottler::GetTimeBudgetPoolForQueue(TaskQueue* queue) { 367 TaskQueue* queue) {
576 auto find_it = queue_details_.find(queue); 368 auto find_it = queue_details_.find(queue);
577 if (find_it == queue_details_.end()) 369 if (find_it == queue_details_.end())
578 return nullptr; 370 return nullptr;
579 return find_it->second.time_budget_pool; 371 return find_it->second.time_budget_pool;
580 } 372 }
581 373
582 void TaskQueueThrottler::MaybeSchedulePumpQueue( 374 void TaskQueueThrottler::MaybeSchedulePumpQueue(
583 const tracked_objects::Location& from_here, 375 const tracked_objects::Location& from_here,
584 base::TimeTicks now, 376 base::TimeTicks now,
585 TaskQueue* queue, 377 TaskQueue* queue,
586 base::Optional<base::TimeTicks> next_possible_run_time) { 378 base::Optional<base::TimeTicks> next_possible_run_time) {
587 LazyNow lazy_now(now); 379 LazyNow lazy_now(now);
588 base::Optional<base::TimeTicks> next_run_time = 380 base::Optional<base::TimeTicks> next_run_time =
589 Max(NextTaskRunTime(&lazy_now, queue), next_possible_run_time); 381 Max(NextTaskRunTime(&lazy_now, queue), next_possible_run_time);
590 382
591 if (next_run_time) { 383 if (next_run_time) {
592 MaybeSchedulePumpThrottledTasks(from_here, now, next_run_time.value()); 384 MaybeSchedulePumpThrottledTasks(from_here, now, next_run_time.value());
593 } 385 }
594 } 386 }
595 387
596 base::TimeTicks TaskQueueThrottler::GetNextAllowedRunTime(base::TimeTicks now, 388 base::TimeTicks TaskQueueThrottler::GetNextAllowedRunTime(base::TimeTicks now,
597 TaskQueue* queue) { 389 TaskQueue* queue) {
598 TimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(queue); 390 CPUTimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(queue);
599 if (!time_budget_pool) 391 if (!time_budget_pool)
600 return now; 392 return now;
601 return std::max(now, time_budget_pool->GetNextAllowedRunTime()); 393 return std::max(now, time_budget_pool->GetNextAllowedRunTime());
602 } 394 }
603 395
604 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) { 396 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) {
605 if (it->second.throttling_ref_count == 0 && !it->second.time_budget_pool) 397 if (it->second.throttling_ref_count == 0 && !it->second.time_budget_pool)
606 queue_details_.erase(it); 398 queue_details_.erase(it);
607 } 399 }
608 400
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
649 queue->SetTimeDomain(time_domain_.get()); 441 queue->SetTimeDomain(time_domain_.get());
650 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue, 442 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue,
651 GetNextAllowedRunTime(lazy_now.Now(), queue)); 443 GetNextAllowedRunTime(lazy_now.Now(), queue));
652 } 444 }
653 445
654 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler_EnableThrottling"); 446 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler_EnableThrottling");
655 } 447 }
656 448
657 } // namespace scheduler 449 } // namespace scheduler
658 } // namespace blink 450 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698