OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |