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

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

Issue 2383473002: [scheduler] Teach scheduler about audio state (Closed)
Patch Set: Rebased 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"
17 #include "platform/scheduler/renderer/renderer_scheduler_impl.h" 16 #include "platform/scheduler/renderer/renderer_scheduler_impl.h"
18 #include "platform/scheduler/renderer/throttled_time_domain.h" 17 #include "platform/scheduler/renderer/throttled_time_domain.h"
19 #include "platform/scheduler/renderer/web_frame_scheduler_impl.h" 18 #include "platform/scheduler/renderer/web_frame_scheduler_impl.h"
20 #include "public/platform/WebFrameScheduler.h" 19 #include "public/platform/WebFrameScheduler.h"
21 20
22 namespace blink { 21 namespace blink {
23 namespace scheduler { 22 namespace scheduler {
24 23
25 namespace { 24 namespace {
26 constexpr base::TimeDelta kMaxBudgetLevel = base::TimeDelta::FromSeconds(1); 25 constexpr base::TimeDelta kMaxBudgetLevel = base::TimeDelta::FromSeconds(1);
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 return; 142 return;
144 is_enabled_ = false; 143 is_enabled_ = false;
145 144
146 for (TaskQueue* queue : associated_task_queues_) { 145 for (TaskQueue* queue : associated_task_queues_) {
147 if (!task_queue_throttler_->IsThrottled(queue)) 146 if (!task_queue_throttler_->IsThrottled(queue))
148 continue; 147 continue;
149 148
150 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, lazy_now->Now(), 149 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, lazy_now->Now(),
151 queue, base::nullopt); 150 queue, base::nullopt);
152 } 151 }
152
153 // TODO(altimin): We need to disable TimeBudgetQueues here or they will
154 // regenerate extra time budget when they are disabled.
153 } 155 }
154 156
155 bool TaskQueueThrottler::TimeBudgetPool::IsThrottlingEnabled() const { 157 bool TaskQueueThrottler::TimeBudgetPool::IsThrottlingEnabled() const {
156 return is_enabled_; 158 return is_enabled_;
157 } 159 }
158 160
159 void TaskQueueThrottler::TimeBudgetPool::Close() { 161 void TaskQueueThrottler::TimeBudgetPool::Close() {
160 DCHECK_EQ(0u, associated_task_queues_.size()); 162 DCHECK_EQ(0u, associated_task_queues_.size());
161 163
162 task_queue_throttler_->time_budget_pools_.erase(this); 164 task_queue_throttler_->time_budget_pools_.erase(this);
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 TaskQueueThrottler::TaskQueueThrottler( 256 TaskQueueThrottler::TaskQueueThrottler(
255 RendererSchedulerImpl* renderer_scheduler, 257 RendererSchedulerImpl* renderer_scheduler,
256 const char* tracing_category) 258 const char* tracing_category)
257 : task_runner_(renderer_scheduler->ControlTaskRunner()), 259 : task_runner_(renderer_scheduler->ControlTaskRunner()),
258 renderer_scheduler_(renderer_scheduler), 260 renderer_scheduler_(renderer_scheduler),
259 tick_clock_(renderer_scheduler->tick_clock()), 261 tick_clock_(renderer_scheduler->tick_clock()),
260 tracing_category_(tracing_category), 262 tracing_category_(tracing_category),
261 time_domain_(new ThrottledTimeDomain(this, tracing_category)), 263 time_domain_(new ThrottledTimeDomain(this, tracing_category)),
262 max_budget_level_(kMaxBudgetLevel), 264 max_budget_level_(kMaxBudgetLevel),
263 max_throttling_duration_(kMaxThrottlingDuration), 265 max_throttling_duration_(kMaxThrottlingDuration),
264 virtual_time_(false), 266 allow_throttling_(true),
265 weak_factory_(this) { 267 weak_factory_(this) {
266 pump_throttled_tasks_closure_.Reset(base::Bind( 268 pump_throttled_tasks_closure_.Reset(base::Bind(
267 &TaskQueueThrottler::PumpThrottledTasks, weak_factory_.GetWeakPtr())); 269 &TaskQueueThrottler::PumpThrottledTasks, weak_factory_.GetWeakPtr()));
268 forward_immediate_work_callback_ = 270 forward_immediate_work_callback_ =
269 base::Bind(&TaskQueueThrottler::OnTimeDomainHasImmediateWork, 271 base::Bind(&TaskQueueThrottler::OnTimeDomainHasImmediateWork,
270 weak_factory_.GetWeakPtr()); 272 weak_factory_.GetWeakPtr());
271 273
272 renderer_scheduler_->RegisterTimeDomain(time_domain_.get()); 274 renderer_scheduler_->RegisterTimeDomain(time_domain_.get());
273 } 275 }
274 276
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 if (!enabled) { 309 if (!enabled) {
308 task_queue->SetQueueEnabled(false); 310 task_queue->SetQueueEnabled(false);
309 MaybeSchedulePumpQueue(FROM_HERE, tick_clock_->NowTicks(), task_queue, 311 MaybeSchedulePumpQueue(FROM_HERE, tick_clock_->NowTicks(), task_queue,
310 base::nullopt); 312 base::nullopt);
311 } 313 }
312 } 314 }
313 315
314 void TaskQueueThrottler::IncreaseThrottleRefCount(TaskQueue* task_queue) { 316 void TaskQueueThrottler::IncreaseThrottleRefCount(TaskQueue* task_queue) {
315 DCHECK_NE(task_queue, task_runner_.get()); 317 DCHECK_NE(task_queue, task_runner_.get());
316 318
317 if (virtual_time_)
318 return;
319
320 std::pair<TaskQueueMap::iterator, bool> insert_result = 319 std::pair<TaskQueueMap::iterator, bool> insert_result =
321 queue_details_.insert(std::make_pair(task_queue, Metadata())); 320 queue_details_.insert(std::make_pair(task_queue, Metadata()));
322 321
323 if (!insert_result.first->second.IsThrottled()) { 322 if (!insert_result.first->second.IsThrottled()) {
324 // The insert was successful so we need to throttle the queue. 323 // The insert was successful so we need to throttle the queue.
325 insert_result.first->second.enabled = task_queue->IsQueueEnabled(); 324 insert_result.first->second.enabled = task_queue->IsQueueEnabled();
326 325
327 task_queue->SetTimeDomain(time_domain_.get()); 326 if (allow_throttling_) {
328 task_queue->RemoveFence(); 327 task_queue->SetTimeDomain(time_domain_.get());
329 task_queue->SetQueueEnabled(false); 328 task_queue->RemoveFence();
329 task_queue->SetQueueEnabled(false);
330 330
331 if (!task_queue->IsEmpty()) { 331 if (!task_queue->IsEmpty()) {
332 if (task_queue->HasPendingImmediateWork()) { 332 if (task_queue->HasPendingImmediateWork()) {
333 OnTimeDomainHasImmediateWork(task_queue); 333 OnTimeDomainHasImmediateWork(task_queue);
334 } else { 334 } else {
335 OnTimeDomainHasDelayedWork(task_queue); 335 OnTimeDomainHasDelayedWork(task_queue);
336 }
336 } 337 }
337 } 338 }
338 339
339 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueThrottled", 340 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueThrottled",
340 "task_queue", task_queue); 341 "task_queue", task_queue);
341 } 342 }
342 343
343 insert_result.first->second.throttling_ref_count++; 344 insert_result.first->second.throttling_ref_count++;
344 } 345 }
345 346
346 void TaskQueueThrottler::DecreaseThrottleRefCount(TaskQueue* task_queue) { 347 void TaskQueueThrottler::DecreaseThrottleRefCount(TaskQueue* task_queue) {
347 if (virtual_time_)
348 return;
349
350 TaskQueueMap::iterator iter = queue_details_.find(task_queue); 348 TaskQueueMap::iterator iter = queue_details_.find(task_queue);
351 349
352 if (iter != queue_details_.end() && 350 if (iter != queue_details_.end() &&
353 --iter->second.throttling_ref_count == 0) { 351 --iter->second.throttling_ref_count == 0) {
354 bool enabled = iter->second.enabled; 352 bool enabled = iter->second.enabled;
355 353
356 MaybeDeleteQueueMetadata(iter); 354 MaybeDeleteQueueMetadata(iter);
357 355
358 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); 356 if (allow_throttling_) {
359 task_queue->RemoveFence(); 357 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain());
360 task_queue->SetQueueEnabled(enabled); 358 task_queue->RemoveFence();
359 task_queue->SetQueueEnabled(enabled);
360 }
361 361
362 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueUntrottled", 362 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueUntrottled",
363 "task_queue", task_queue); 363 "task_queue", task_queue);
364 } 364 }
365 } 365 }
366 366
367 bool TaskQueueThrottler::IsThrottled(TaskQueue* task_queue) const { 367 bool TaskQueueThrottler::IsThrottled(TaskQueue* task_queue) const {
368 auto find_it = queue_details_.find(task_queue); 368 auto find_it = queue_details_.find(task_queue);
369 if (find_it == queue_details_.end()) 369 if (find_it == queue_details_.end())
370 return false; 370 return false;
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
471 base::TimeTicks unthrottled_runtime) { 471 base::TimeTicks unthrottled_runtime) {
472 const base::TimeDelta one_second = base::TimeDelta::FromSeconds(1); 472 const base::TimeDelta one_second = base::TimeDelta::FromSeconds(1);
473 return unthrottled_runtime + one_second - 473 return unthrottled_runtime + one_second -
474 ((unthrottled_runtime - base::TimeTicks()) % one_second); 474 ((unthrottled_runtime - base::TimeTicks()) % one_second);
475 } 475 }
476 476
477 void TaskQueueThrottler::MaybeSchedulePumpThrottledTasks( 477 void TaskQueueThrottler::MaybeSchedulePumpThrottledTasks(
478 const tracked_objects::Location& from_here, 478 const tracked_objects::Location& from_here,
479 base::TimeTicks now, 479 base::TimeTicks now,
480 base::TimeTicks unaligned_runtime) { 480 base::TimeTicks unaligned_runtime) {
481 if (virtual_time_) 481 if (!allow_throttling_)
482 return; 482 return;
483 483
484 base::TimeTicks runtime = 484 base::TimeTicks runtime =
485 std::max(now, AlignedThrottledRunTime(unaligned_runtime)); 485 std::max(now, AlignedThrottledRunTime(unaligned_runtime));
486 486
487 // If there is a pending call to PumpThrottledTasks and it's sooner than 487 // If there is a pending call to PumpThrottledTasks and it's sooner than
488 // |runtime| then return. 488 // |runtime| then return.
489 if (pending_pump_throttled_tasks_runtime_ && 489 if (pending_pump_throttled_tasks_runtime_ &&
490 runtime >= pending_pump_throttled_tasks_runtime_.value()) { 490 runtime >= pending_pump_throttled_tasks_runtime_.value()) {
491 return; 491 return;
492 } 492 }
493 493
494 pending_pump_throttled_tasks_runtime_ = runtime; 494 pending_pump_throttled_tasks_runtime_ = runtime;
495 495
496 pump_throttled_tasks_closure_.Cancel(); 496 pump_throttled_tasks_closure_.Cancel();
497 497
498 base::TimeDelta delay = pending_pump_throttled_tasks_runtime_.value() - now; 498 base::TimeDelta delay = pending_pump_throttled_tasks_runtime_.value() - now;
499 TRACE_EVENT1(tracing_category_, 499 TRACE_EVENT1(tracing_category_,
500 "TaskQueueThrottler::MaybeSchedulePumpThrottledTasks", 500 "TaskQueueThrottler::MaybeSchedulePumpThrottledTasks",
501 "delay_till_next_pump_ms", delay.InMilliseconds()); 501 "delay_till_next_pump_ms", delay.InMilliseconds());
502 task_runner_->PostDelayedTask( 502 task_runner_->PostDelayedTask(
503 from_here, pump_throttled_tasks_closure_.callback(), delay); 503 from_here, pump_throttled_tasks_closure_.callback(), delay);
504 } 504 }
505 505
506 void TaskQueueThrottler::EnableVirtualTime() {
507 virtual_time_ = true;
508
509 pump_throttled_tasks_closure_.Cancel();
510
511 for (auto it = queue_details_.begin(); it != queue_details_.end();) {
512 TaskQueue* task_queue = it->first;
513 bool enabled = it->second.enabled;
514
515 if (!it->second.time_budget_pool) {
516 it = queue_details_.erase(it);
517 } else {
518 // Fall back to default values.
519 it->second.throttling_ref_count = 0;
520 it->second.enabled = false;
521 it++;
522 }
523
524 task_queue->SetTimeDomain(renderer_scheduler_->GetVirtualTimeDomain());
525 task_queue->RemoveFence();
526 task_queue->SetQueueEnabled(enabled);
527 }
528 }
529
530 TaskQueueThrottler::TimeBudgetPool* TaskQueueThrottler::CreateTimeBudgetPool( 506 TaskQueueThrottler::TimeBudgetPool* TaskQueueThrottler::CreateTimeBudgetPool(
531 const char* name) { 507 const char* name) {
532 TimeBudgetPool* time_budget_pool = 508 TimeBudgetPool* time_budget_pool =
533 new TimeBudgetPool(name, this, tick_clock_->NowTicks(), max_budget_level_, 509 new TimeBudgetPool(name, this, tick_clock_->NowTicks(), max_budget_level_,
534 max_throttling_duration_); 510 max_throttling_duration_);
535 time_budget_pools_[time_budget_pool] = base::WrapUnique(time_budget_pool); 511 time_budget_pools_[time_budget_pool] = base::WrapUnique(time_budget_pool);
536 return time_budget_pool; 512 return time_budget_pool;
537 } 513 }
538 514
539 void TaskQueueThrottler::OnTaskRunTimeReported(TaskQueue* task_queue, 515 void TaskQueueThrottler::OnTaskRunTimeReported(TaskQueue* task_queue,
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 if (!time_budget_pool) 573 if (!time_budget_pool)
598 return now; 574 return now;
599 return std::max(now, time_budget_pool->GetNextAllowedRunTime()); 575 return std::max(now, time_budget_pool->GetNextAllowedRunTime());
600 } 576 }
601 577
602 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) { 578 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) {
603 if (!it->second.IsThrottled() && !it->second.time_budget_pool) 579 if (!it->second.IsThrottled() && !it->second.time_budget_pool)
604 queue_details_.erase(it); 580 queue_details_.erase(it);
605 } 581 }
606 582
583 void TaskQueueThrottler::DisableThrottling() {
584 if (!allow_throttling_)
585 return;
586
587 allow_throttling_ = false;
588
589 for (const auto& map_entry : queue_details_) {
590 if (!map_entry.second.IsThrottled())
591 continue;
592
593 TaskQueue* queue = map_entry.first;
594
595 queue->SetTimeDomain(renderer_scheduler_->GetActiveTimeDomain());
596
597 queue->RemoveFence();
598 queue->SetQueueEnabled(map_entry.second.enabled);
599 }
600 }
601
602 void TaskQueueThrottler::EnableThrottling() {
603 if (allow_throttling_)
604 return;
605
606 allow_throttling_ = true;
607
608 LazyNow lazy_now(tick_clock_);
609
610 for (const auto& map_entry : queue_details_) {
611 if (!map_entry.second.IsThrottled())
612 continue;
613
614 TaskQueue* queue = map_entry.first;
615
616 queue->SetQueueEnabled(false);
617 queue->SetTimeDomain(time_domain_.get());
618 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue,
619 GetNextAllowedRunTime(lazy_now.Now(), queue));
620 }
621 }
622
607 } // namespace scheduler 623 } // namespace scheduler
608 } // namespace blink 624 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698