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

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

Issue 2523673003: [scheduler] Fix bug in task queue throttler (Closed)
Patch Set: Deleted Metadata::IsThrottled Created 4 years 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"
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 TaskQueue* queue) { 93 TaskQueue* queue) {
94 std::pair<TaskQueueMap::iterator, bool> insert_result = 94 std::pair<TaskQueueMap::iterator, bool> insert_result =
95 task_queue_throttler_->queue_details_.insert( 95 task_queue_throttler_->queue_details_.insert(
96 std::make_pair(queue, Metadata(0, queue->IsQueueEnabled()))); 96 std::make_pair(queue, Metadata(0, queue->IsQueueEnabled())));
97 Metadata& metadata = insert_result.first->second; 97 Metadata& metadata = insert_result.first->second;
98 DCHECK(!metadata.time_budget_pool); 98 DCHECK(!metadata.time_budget_pool);
99 metadata.time_budget_pool = this; 99 metadata.time_budget_pool = this;
100 100
101 associated_task_queues_.insert(queue); 101 associated_task_queues_.insert(queue);
102 102
103 if (!is_enabled_ || !metadata.IsThrottled()) 103 if (!is_enabled_ || !task_queue_throttler_->IsThrottled(queue))
104 return; 104 return;
105 105
106 queue->SetQueueEnabled(false); 106 queue->SetQueueEnabled(false);
107 107
108 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, 108 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue,
109 GetNextAllowedRunTime()); 109 GetNextAllowedRunTime());
110 } 110 }
111 111
112 void TaskQueueThrottler::TimeBudgetPool::RemoveQueue(base::TimeTicks now, 112 void TaskQueueThrottler::TimeBudgetPool::RemoveQueue(base::TimeTicks now,
113 TaskQueue* queue) { 113 TaskQueue* queue) {
114 auto find_it = task_queue_throttler_->queue_details_.find(queue); 114 auto find_it = task_queue_throttler_->queue_details_.find(queue);
115 DCHECK(find_it != task_queue_throttler_->queue_details_.end() && 115 DCHECK(find_it != task_queue_throttler_->queue_details_.end() &&
116 find_it->second.time_budget_pool == this); 116 find_it->second.time_budget_pool == this);
117 find_it->second.time_budget_pool = nullptr; 117 find_it->second.time_budget_pool = nullptr;
118 bool is_throttled = find_it->second.IsThrottled(); 118 bool is_throttled = task_queue_throttler_->IsThrottled(queue);
119 119
120 task_queue_throttler_->MaybeDeleteQueueMetadata(find_it); 120 task_queue_throttler_->MaybeDeleteQueueMetadata(find_it);
121 associated_task_queues_.erase(queue); 121 associated_task_queues_.erase(queue);
122 122
123 if (!is_enabled_ || !is_throttled) 123 if (!is_enabled_ || !is_throttled)
124 return; 124 return;
125 125
126 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, 126 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue,
127 base::nullopt); 127 base::nullopt);
128 } 128 }
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
287 base::Bind(&TaskQueueThrottler::OnTimeDomainHasImmediateWork, 287 base::Bind(&TaskQueueThrottler::OnTimeDomainHasImmediateWork,
288 weak_factory_.GetWeakPtr()); 288 weak_factory_.GetWeakPtr());
289 289
290 renderer_scheduler_->RegisterTimeDomain(time_domain_.get()); 290 renderer_scheduler_->RegisterTimeDomain(time_domain_.get());
291 } 291 }
292 292
293 TaskQueueThrottler::~TaskQueueThrottler() { 293 TaskQueueThrottler::~TaskQueueThrottler() {
294 // It's possible for queues to be still throttled, so we need to tidy up 294 // It's possible for queues to be still throttled, so we need to tidy up
295 // before unregistering the time domain. 295 // before unregistering the time domain.
296 for (const TaskQueueMap::value_type& map_entry : queue_details_) { 296 for (const TaskQueueMap::value_type& map_entry : queue_details_) {
297 if (map_entry.second.IsThrottled()) { 297 TaskQueue* task_queue = map_entry.first;
298 TaskQueue* task_queue = map_entry.first; 298 if (IsThrottled(task_queue)) {
Sami 2016/11/23 16:47:18 Hmm, this could end badly if the throttler is shut
altimin 2016/11/23 16:56:08 If throttling is disabled then all queues are enab
Sami 2016/11/23 17:00:59 I see, okay.
299 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); 299 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain());
300 task_queue->RemoveFence(); 300 task_queue->RemoveFence();
301 } 301 }
302 } 302 }
303 303
304 renderer_scheduler_->UnregisterTimeDomain(time_domain_.get()); 304 renderer_scheduler_->UnregisterTimeDomain(time_domain_.get());
305 } 305 }
306 306
307 void TaskQueueThrottler::SetQueueEnabled(TaskQueue* task_queue, bool enabled) { 307 void TaskQueueThrottler::SetQueueEnabled(TaskQueue* task_queue, bool enabled) {
308 TaskQueueMap::iterator find_it = queue_details_.find(task_queue); 308 TaskQueueMap::iterator find_it = queue_details_.find(task_queue);
309 309
310 if (find_it == queue_details_.end()) { 310 if (find_it == queue_details_.end()) {
311 task_queue->SetQueueEnabled(enabled); 311 task_queue->SetQueueEnabled(enabled);
312 return; 312 return;
313 } 313 }
314 314
315 find_it->second.enabled = enabled; 315 find_it->second.enabled = enabled;
316 316
317 if (!find_it->second.IsThrottled()) { 317 if (!IsThrottled(task_queue)) {
318 task_queue->SetQueueEnabled(enabled); 318 task_queue->SetQueueEnabled(enabled);
319 return; 319 return;
320 } 320 }
321 321
322 // We don't enable the queue here because it's throttled and there might be 322 // We don't enable the queue here because it's throttled and there might be
323 // tasks in it's work queue that would execute immediatly rather than after 323 // tasks in it's work queue that would execute immediatly rather than after
324 // PumpThrottledTasks runs. 324 // PumpThrottledTasks runs.
325 if (!enabled) { 325 if (!enabled) {
326 task_queue->SetQueueEnabled(false); 326 task_queue->SetQueueEnabled(false);
327 MaybeSchedulePumpQueue(FROM_HERE, tick_clock_->NowTicks(), task_queue, 327 MaybeSchedulePumpQueue(FROM_HERE, tick_clock_->NowTicks(), task_queue,
328 base::nullopt); 328 base::nullopt);
329 } 329 }
330 } 330 }
331 331
332 void TaskQueueThrottler::IncreaseThrottleRefCount(TaskQueue* task_queue) { 332 void TaskQueueThrottler::IncreaseThrottleRefCount(TaskQueue* task_queue) {
333 DCHECK_NE(task_queue, task_runner_.get()); 333 DCHECK_NE(task_queue, task_runner_.get());
334 334
335 std::pair<TaskQueueMap::iterator, bool> insert_result = 335 std::pair<TaskQueueMap::iterator, bool> insert_result = queue_details_.insert(
336 queue_details_.insert(std::make_pair(task_queue, Metadata())); 336 std::make_pair(task_queue, Metadata(0 /* ref_count */,
337 task_queue->IsQueueEnabled())));
337 338
338 if (!insert_result.first->second.IsThrottled()) { 339 if (insert_result.first->second.throttling_ref_count == 0) {
339 // The insert was successful so we need to throttle the queue.
340 insert_result.first->second.enabled = task_queue->IsQueueEnabled();
341
342 if (allow_throttling_) { 340 if (allow_throttling_) {
343 task_queue->SetTimeDomain(time_domain_.get()); 341 task_queue->SetTimeDomain(time_domain_.get());
344 task_queue->RemoveFence(); 342 task_queue->RemoveFence();
345 task_queue->SetQueueEnabled(false); 343 task_queue->SetQueueEnabled(false);
346 344
347 if (!task_queue->IsEmpty()) { 345 if (!task_queue->IsEmpty()) {
348 if (task_queue->HasPendingImmediateWork()) { 346 if (task_queue->HasPendingImmediateWork()) {
349 OnTimeDomainHasImmediateWork(task_queue); 347 OnTimeDomainHasImmediateWork(task_queue);
350 } else { 348 } else {
351 OnTimeDomainHasDelayedWork(task_queue); 349 OnTimeDomainHasDelayedWork(task_queue);
(...skipping 22 matching lines...) Expand all
374 task_queue->RemoveFence(); 372 task_queue->RemoveFence();
375 task_queue->SetQueueEnabled(enabled); 373 task_queue->SetQueueEnabled(enabled);
376 } 374 }
377 375
378 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueUntrottled", 376 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueUntrottled",
379 "task_queue", task_queue); 377 "task_queue", task_queue);
380 } 378 }
381 } 379 }
382 380
383 bool TaskQueueThrottler::IsThrottled(TaskQueue* task_queue) const { 381 bool TaskQueueThrottler::IsThrottled(TaskQueue* task_queue) const {
382 if (!allow_throttling_)
383 return false;
384
384 auto find_it = queue_details_.find(task_queue); 385 auto find_it = queue_details_.find(task_queue);
385 if (find_it == queue_details_.end()) 386 if (find_it == queue_details_.end())
386 return false; 387 return false;
387 return find_it->second.IsThrottled(); 388 return find_it->second.throttling_ref_count > 0;
388 } 389 }
389 390
390 void TaskQueueThrottler::UnregisterTaskQueue(TaskQueue* task_queue) { 391 void TaskQueueThrottler::UnregisterTaskQueue(TaskQueue* task_queue) {
391 LazyNow lazy_now(tick_clock_); 392 LazyNow lazy_now(tick_clock_);
392 auto find_it = queue_details_.find(task_queue); 393 auto find_it = queue_details_.find(task_queue);
393 394
394 if (find_it == queue_details_.end()) 395 if (find_it == queue_details_.end())
395 return; 396 return;
396 397
397 if (find_it->second.time_budget_pool) 398 if (find_it->second.time_budget_pool)
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 void TaskQueueThrottler::PumpThrottledTasks() { 432 void TaskQueueThrottler::PumpThrottledTasks() {
432 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler::PumpThrottledTasks"); 433 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler::PumpThrottledTasks");
433 pending_pump_throttled_tasks_runtime_.reset(); 434 pending_pump_throttled_tasks_runtime_.reset();
434 435
435 LazyNow lazy_now(tick_clock_); 436 LazyNow lazy_now(tick_clock_);
436 base::Optional<base::TimeTicks> next_scheduled_delayed_task; 437 base::Optional<base::TimeTicks> next_scheduled_delayed_task;
437 438
438 for (const TaskQueueMap::value_type& map_entry : queue_details_) { 439 for (const TaskQueueMap::value_type& map_entry : queue_details_) {
439 TaskQueue* task_queue = map_entry.first; 440 TaskQueue* task_queue = map_entry.first;
440 if (!map_entry.second.enabled || task_queue->IsEmpty() || 441 if (!map_entry.second.enabled || task_queue->IsEmpty() ||
441 !map_entry.second.IsThrottled()) 442 !IsThrottled(task_queue))
442 continue; 443 continue;
443 444
444 // Don't enable queues whose budget pool doesn't allow them to run now. 445 // Don't enable queues whose budget pool doesn't allow them to run now.
445 base::TimeTicks next_allowed_run_time = 446 base::TimeTicks next_allowed_run_time =
446 GetNextAllowedRunTime(lazy_now.Now(), task_queue); 447 GetNextAllowedRunTime(lazy_now.Now(), task_queue);
447 base::Optional<base::TimeTicks> next_desired_run_time = 448 base::Optional<base::TimeTicks> next_desired_run_time =
448 NextTaskRunTime(&lazy_now, task_queue); 449 NextTaskRunTime(&lazy_now, task_queue);
449 450
450 if (next_desired_run_time && 451 if (next_desired_run_time &&
451 next_allowed_run_time > next_desired_run_time.value()) { 452 next_allowed_run_time > next_desired_run_time.value()) {
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
587 588
588 base::TimeTicks TaskQueueThrottler::GetNextAllowedRunTime(base::TimeTicks now, 589 base::TimeTicks TaskQueueThrottler::GetNextAllowedRunTime(base::TimeTicks now,
589 TaskQueue* queue) { 590 TaskQueue* queue) {
590 TimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(queue); 591 TimeBudgetPool* time_budget_pool = GetTimeBudgetPoolForQueue(queue);
591 if (!time_budget_pool) 592 if (!time_budget_pool)
592 return now; 593 return now;
593 return std::max(now, time_budget_pool->GetNextAllowedRunTime()); 594 return std::max(now, time_budget_pool->GetNextAllowedRunTime());
594 } 595 }
595 596
596 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) { 597 void TaskQueueThrottler::MaybeDeleteQueueMetadata(TaskQueueMap::iterator it) {
597 if (!it->second.IsThrottled() && !it->second.time_budget_pool) 598 if (it->second.throttling_ref_count == 0 && !it->second.time_budget_pool)
598 queue_details_.erase(it); 599 queue_details_.erase(it);
599 } 600 }
600 601
601 void TaskQueueThrottler::DisableThrottling() { 602 void TaskQueueThrottler::DisableThrottling() {
602 if (!allow_throttling_) 603 if (!allow_throttling_)
603 return; 604 return;
604 605
605 allow_throttling_ = false; 606 allow_throttling_ = false;
606 607
607 for (const auto& map_entry : queue_details_) { 608 for (const auto& map_entry : queue_details_) {
608 if (!map_entry.second.IsThrottled()) 609 if (map_entry.second.throttling_ref_count == 0)
609 continue; 610 continue;
610 611
611 TaskQueue* queue = map_entry.first; 612 TaskQueue* queue = map_entry.first;
612 613
613 queue->SetTimeDomain(renderer_scheduler_->GetActiveTimeDomain()); 614 queue->SetTimeDomain(renderer_scheduler_->GetActiveTimeDomain());
614 615
615 queue->RemoveFence(); 616 queue->RemoveFence();
616 queue->SetQueueEnabled(map_entry.second.enabled); 617 queue->SetQueueEnabled(map_entry.second.enabled);
617 } 618 }
618 619
619 pump_throttled_tasks_closure_.Cancel(); 620 pump_throttled_tasks_closure_.Cancel();
620 pending_pump_throttled_tasks_runtime_ = base::nullopt; 621 pending_pump_throttled_tasks_runtime_ = base::nullopt;
621 } 622 }
622 623
623 void TaskQueueThrottler::EnableThrottling() { 624 void TaskQueueThrottler::EnableThrottling() {
624 if (allow_throttling_) 625 if (allow_throttling_)
625 return; 626 return;
626 627
627 allow_throttling_ = true; 628 allow_throttling_ = true;
628 629
629 LazyNow lazy_now(tick_clock_); 630 LazyNow lazy_now(tick_clock_);
630 631
631 for (const auto& map_entry : queue_details_) { 632 for (const auto& map_entry : queue_details_) {
632 if (!map_entry.second.IsThrottled()) 633 if (map_entry.second.throttling_ref_count == 0)
633 continue; 634 continue;
634 635
635 TaskQueue* queue = map_entry.first; 636 TaskQueue* queue = map_entry.first;
636 637
637 queue->SetQueueEnabled(false); 638 queue->SetQueueEnabled(false);
638 queue->SetTimeDomain(time_domain_.get()); 639 queue->SetTimeDomain(time_domain_.get());
639 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue, 640 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue,
640 GetNextAllowedRunTime(lazy_now.Now(), queue)); 641 GetNextAllowedRunTime(lazy_now.Now(), queue));
641 } 642 }
642 } 643 }
643 644
644 } // namespace scheduler 645 } // namespace scheduler
645 } // namespace blink 646 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698