| 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" |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 double cpu_percentage) { | 92 double cpu_percentage) { |
| 93 Advance(now); | 93 Advance(now); |
| 94 cpu_percentage_ = cpu_percentage; | 94 cpu_percentage_ = cpu_percentage; |
| 95 EnforceBudgetLevelRestrictions(); | 95 EnforceBudgetLevelRestrictions(); |
| 96 } | 96 } |
| 97 | 97 |
| 98 void TaskQueueThrottler::TimeBudgetPool::AddQueue(base::TimeTicks now, | 98 void TaskQueueThrottler::TimeBudgetPool::AddQueue(base::TimeTicks now, |
| 99 TaskQueue* queue) { | 99 TaskQueue* queue) { |
| 100 std::pair<TaskQueueMap::iterator, bool> insert_result = | 100 std::pair<TaskQueueMap::iterator, bool> insert_result = |
| 101 task_queue_throttler_->queue_details_.insert( | 101 task_queue_throttler_->queue_details_.insert( |
| 102 std::make_pair(queue, Metadata(0, queue->IsQueueEnabled()))); | 102 std::make_pair(queue, Metadata())); |
| 103 Metadata& metadata = insert_result.first->second; | 103 Metadata& metadata = insert_result.first->second; |
| 104 DCHECK(!metadata.time_budget_pool); | 104 DCHECK(!metadata.time_budget_pool); |
| 105 metadata.time_budget_pool = this; | 105 metadata.time_budget_pool = this; |
| 106 | 106 |
| 107 associated_task_queues_.insert(queue); | 107 associated_task_queues_.insert(queue); |
| 108 | 108 |
| 109 if (!is_enabled_ || !task_queue_throttler_->IsThrottled(queue)) | 109 if (!is_enabled_ || !task_queue_throttler_->IsThrottled(queue)) |
| 110 return; | 110 return; |
| 111 | 111 |
| 112 queue->SetQueueEnabled(false); | 112 queue->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME); |
| 113 | 113 |
| 114 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, | 114 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, |
| 115 GetNextAllowedRunTime()); | 115 GetNextAllowedRunTime()); |
| 116 } | 116 } |
| 117 | 117 |
| 118 void TaskQueueThrottler::TimeBudgetPool::RemoveQueue(base::TimeTicks now, | 118 void TaskQueueThrottler::TimeBudgetPool::RemoveQueue(base::TimeTicks now, |
| 119 TaskQueue* queue) { | 119 TaskQueue* queue) { |
| 120 auto find_it = task_queue_throttler_->queue_details_.find(queue); | 120 auto find_it = task_queue_throttler_->queue_details_.find(queue); |
| 121 DCHECK(find_it != task_queue_throttler_->queue_details_.end() && | 121 DCHECK(find_it != task_queue_throttler_->queue_details_.end() && |
| 122 find_it->second.time_budget_pool == this); | 122 find_it->second.time_budget_pool == this); |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 last_checkpoint_ = now; | 254 last_checkpoint_ = now; |
| 255 } | 255 } |
| 256 } | 256 } |
| 257 | 257 |
| 258 void TaskQueueThrottler::TimeBudgetPool::BlockThrottledQueues( | 258 void TaskQueueThrottler::TimeBudgetPool::BlockThrottledQueues( |
| 259 base::TimeTicks now) { | 259 base::TimeTicks now) { |
| 260 for (TaskQueue* queue : associated_task_queues_) { | 260 for (TaskQueue* queue : associated_task_queues_) { |
| 261 if (!task_queue_throttler_->IsThrottled(queue)) | 261 if (!task_queue_throttler_->IsThrottled(queue)) |
| 262 continue; | 262 continue; |
| 263 | 263 |
| 264 queue->SetQueueEnabled(false); | 264 queue->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME); |
| 265 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, | 265 task_queue_throttler_->MaybeSchedulePumpQueue(FROM_HERE, now, queue, |
| 266 base::nullopt); | 266 base::nullopt); |
| 267 } | 267 } |
| 268 } | 268 } |
| 269 | 269 |
| 270 void TaskQueueThrottler::TimeBudgetPool::EnforceBudgetLevelRestrictions() { | 270 void TaskQueueThrottler::TimeBudgetPool::EnforceBudgetLevelRestrictions() { |
| 271 if (max_budget_level_) { | 271 if (max_budget_level_) { |
| 272 current_budget_level_ = | 272 current_budget_level_ = |
| 273 std::min(current_budget_level_, max_budget_level_.value()); | 273 std::min(current_budget_level_, max_budget_level_.value()); |
| 274 } | 274 } |
| 275 if (max_throttling_duration_) { | 275 if (max_throttling_duration_) { |
| 276 // Current budget level may be negative. | 276 // Current budget level may be negative. |
| 277 current_budget_level_ = | 277 current_budget_level_ = |
| 278 std::max(current_budget_level_, | 278 std::max(current_budget_level_, |
| 279 -max_throttling_duration_.value() * cpu_percentage_); | 279 -max_throttling_duration_.value() * cpu_percentage_); |
| 280 } | 280 } |
| 281 } | 281 } |
| 282 | 282 |
| 283 // TODO(altimin): Control max_budget_level and max_throttling_duration | |
| 284 // from Finch. | |
| 285 TaskQueueThrottler::TaskQueueThrottler( | 283 TaskQueueThrottler::TaskQueueThrottler( |
| 286 RendererSchedulerImpl* renderer_scheduler, | 284 RendererSchedulerImpl* renderer_scheduler, |
| 287 const char* tracing_category) | 285 const char* tracing_category) |
| 288 : task_runner_(renderer_scheduler->ControlTaskRunner()), | 286 : task_runner_(renderer_scheduler->ControlTaskRunner()), |
| 289 renderer_scheduler_(renderer_scheduler), | 287 renderer_scheduler_(renderer_scheduler), |
| 290 tick_clock_(renderer_scheduler->tick_clock()), | 288 tick_clock_(renderer_scheduler->tick_clock()), |
| 291 tracing_category_(tracing_category), | 289 tracing_category_(tracing_category), |
| 292 time_domain_(new ThrottledTimeDomain(this, tracing_category)), | 290 time_domain_(new ThrottledTimeDomain(this, tracing_category)), |
| 293 allow_throttling_(true), | 291 allow_throttling_(true), |
| 294 weak_factory_(this) { | 292 weak_factory_(this) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 308 TaskQueue* task_queue = map_entry.first; | 306 TaskQueue* task_queue = map_entry.first; |
| 309 if (IsThrottled(task_queue)) { | 307 if (IsThrottled(task_queue)) { |
| 310 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); | 308 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); |
| 311 task_queue->RemoveFence(); | 309 task_queue->RemoveFence(); |
| 312 } | 310 } |
| 313 } | 311 } |
| 314 | 312 |
| 315 renderer_scheduler_->UnregisterTimeDomain(time_domain_.get()); | 313 renderer_scheduler_->UnregisterTimeDomain(time_domain_.get()); |
| 316 } | 314 } |
| 317 | 315 |
| 318 void TaskQueueThrottler::SetQueueEnabled(TaskQueue* task_queue, bool enabled) { | |
| 319 // Both the TaskQueueThrottler and other systems want to enable and disable | |
| 320 // task queues. The policy we've adopted to deal with this is: | |
| 321 // | |
| 322 // A task queue is disabled if either the TaskQueueThrottler or the caller | |
| 323 // vote to disable it. | |
| 324 // | |
| 325 // A task queue is enabled only if both the TaskQueueThrottler and the caller | |
| 326 // vote to enable it. | |
| 327 TaskQueueMap::iterator find_it = queue_details_.find(task_queue); | |
| 328 | |
| 329 // If TaskQueueThrottler does not know about this queue, just call | |
| 330 // SetQueueEnabled directly. | |
| 331 if (find_it == queue_details_.end()) { | |
| 332 task_queue->SetQueueEnabled(enabled); | |
| 333 return; | |
| 334 } | |
| 335 | |
| 336 // Remember the caller's preference so we know what to do when the task queue | |
| 337 // isn't throttled, or has budget to run. | |
| 338 find_it->second.enabled = enabled; | |
| 339 | |
| 340 if (!IsThrottled(task_queue)) { | |
| 341 task_queue->SetQueueEnabled(enabled); | |
| 342 return; | |
| 343 } | |
| 344 | |
| 345 if (enabled) { | |
| 346 // If the task queue is throttled and we want to enable it, we can't | |
| 347 // do it immediately due to task alignment requirement and we should | |
| 348 // schedule a call to PumpThrottledTasks. | |
| 349 MaybeSchedulePumpQueue(FROM_HERE, tick_clock_->NowTicks(), task_queue, | |
| 350 base::nullopt); | |
| 351 } else { | |
| 352 task_queue->SetQueueEnabled(false); | |
| 353 } | |
| 354 } | |
| 355 | |
| 356 void TaskQueueThrottler::IncreaseThrottleRefCount(TaskQueue* task_queue) { | 316 void TaskQueueThrottler::IncreaseThrottleRefCount(TaskQueue* task_queue) { |
| 357 DCHECK_NE(task_queue, task_runner_.get()); | 317 DCHECK_NE(task_queue, task_runner_.get()); |
| 358 | 318 |
| 359 std::pair<TaskQueueMap::iterator, bool> insert_result = queue_details_.insert( | 319 std::pair<TaskQueueMap::iterator, bool> insert_result = |
| 360 std::make_pair(task_queue, Metadata(0 /* ref_count */, | 320 queue_details_.insert(std::make_pair(task_queue, Metadata())); |
| 361 task_queue->IsQueueEnabled()))); | 321 insert_result.first->second.throttling_ref_count++; |
| 362 | 322 |
| 363 if (insert_result.first->second.throttling_ref_count == 0) { | 323 // If ref_count is 1, the task queue is newly throttled. |
| 364 if (allow_throttling_) { | 324 if (insert_result.first->second.throttling_ref_count != 1) |
| 365 task_queue->SetTimeDomain(time_domain_.get()); | 325 return; |
| 366 task_queue->RemoveFence(); | |
| 367 task_queue->SetQueueEnabled(false); | |
| 368 | 326 |
| 369 if (!task_queue->IsEmpty()) { | 327 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueThrottled", |
| 370 if (task_queue->HasPendingImmediateWork()) { | 328 "task_queue", task_queue); |
| 371 OnTimeDomainHasImmediateWork(task_queue); | 329 |
| 372 } else { | 330 if (!allow_throttling_) |
| 373 OnTimeDomainHasDelayedWork(task_queue); | 331 return; |
| 374 } | 332 |
| 375 } | 333 task_queue->SetTimeDomain(time_domain_.get()); |
| 334 // This blocks any tasks from |task_queue| until PumpThrottledTasks() to |
| 335 // enforce task alignment. |
| 336 task_queue->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME); |
| 337 |
| 338 if (!task_queue->IsEmpty()) { |
| 339 if (task_queue->HasPendingImmediateWork()) { |
| 340 OnTimeDomainHasImmediateWork(task_queue); |
| 341 } else { |
| 342 OnTimeDomainHasDelayedWork(task_queue); |
| 376 } | 343 } |
| 377 | |
| 378 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueThrottled", | |
| 379 "task_queue", task_queue); | |
| 380 } | 344 } |
| 381 | |
| 382 insert_result.first->second.throttling_ref_count++; | |
| 383 } | 345 } |
| 384 | 346 |
| 385 void TaskQueueThrottler::DecreaseThrottleRefCount(TaskQueue* task_queue) { | 347 void TaskQueueThrottler::DecreaseThrottleRefCount(TaskQueue* task_queue) { |
| 386 TaskQueueMap::iterator iter = queue_details_.find(task_queue); | 348 TaskQueueMap::iterator iter = queue_details_.find(task_queue); |
| 387 | 349 |
| 388 if (iter != queue_details_.end() && | 350 if (iter == queue_details_.end() || |
| 389 --iter->second.throttling_ref_count == 0) { | 351 --iter->second.throttling_ref_count != 0) { |
| 390 bool enabled = iter->second.enabled; | 352 return; |
| 353 } |
| 391 | 354 |
| 392 MaybeDeleteQueueMetadata(iter); | 355 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueUnthrottled", |
| 356 "task_queue", task_queue); |
| 393 | 357 |
| 394 if (allow_throttling_) { | 358 MaybeDeleteQueueMetadata(iter); |
| 395 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); | |
| 396 task_queue->RemoveFence(); | |
| 397 task_queue->SetQueueEnabled(enabled); | |
| 398 } | |
| 399 | 359 |
| 400 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueUnthrottled", | 360 if (!allow_throttling_) |
| 401 "task_queue", task_queue); | 361 return; |
| 402 } | 362 |
| 363 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); |
| 364 task_queue->RemoveFence(); |
| 403 } | 365 } |
| 404 | 366 |
| 405 bool TaskQueueThrottler::IsThrottled(TaskQueue* task_queue) const { | 367 bool TaskQueueThrottler::IsThrottled(TaskQueue* task_queue) const { |
| 406 if (!allow_throttling_) | 368 if (!allow_throttling_) |
| 407 return false; | 369 return false; |
| 408 | 370 |
| 409 auto find_it = queue_details_.find(task_queue); | 371 auto find_it = queue_details_.find(task_queue); |
| 410 if (find_it == queue_details_.end()) | 372 if (find_it == queue_details_.end()) |
| 411 return false; | 373 return false; |
| 412 return find_it->second.throttling_ref_count > 0; | 374 return find_it->second.throttling_ref_count > 0; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 | 417 |
| 456 void TaskQueueThrottler::PumpThrottledTasks() { | 418 void TaskQueueThrottler::PumpThrottledTasks() { |
| 457 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler::PumpThrottledTasks"); | 419 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler::PumpThrottledTasks"); |
| 458 pending_pump_throttled_tasks_runtime_.reset(); | 420 pending_pump_throttled_tasks_runtime_.reset(); |
| 459 | 421 |
| 460 LazyNow lazy_now(tick_clock_); | 422 LazyNow lazy_now(tick_clock_); |
| 461 base::Optional<base::TimeTicks> next_scheduled_delayed_task; | 423 base::Optional<base::TimeTicks> next_scheduled_delayed_task; |
| 462 | 424 |
| 463 for (const TaskQueueMap::value_type& map_entry : queue_details_) { | 425 for (const TaskQueueMap::value_type& map_entry : queue_details_) { |
| 464 TaskQueue* task_queue = map_entry.first; | 426 TaskQueue* task_queue = map_entry.first; |
| 465 if (!map_entry.second.enabled || task_queue->IsEmpty() || | 427 if (task_queue->IsEmpty() || !IsThrottled(task_queue)) |
| 466 !IsThrottled(task_queue)) | |
| 467 continue; | 428 continue; |
| 468 | 429 |
| 469 // Don't enable queues whose budget pool doesn't allow them to run now. | 430 // Don't enable queues whose budget pool doesn't allow them to run now. |
| 470 base::TimeTicks next_allowed_run_time = | 431 base::TimeTicks next_allowed_run_time = |
| 471 GetNextAllowedRunTime(lazy_now.Now(), task_queue); | 432 GetNextAllowedRunTime(lazy_now.Now(), task_queue); |
| 472 base::Optional<base::TimeTicks> next_desired_run_time = | 433 base::Optional<base::TimeTicks> next_desired_run_time = |
| 473 NextTaskRunTime(&lazy_now, task_queue); | 434 NextTaskRunTime(&lazy_now, task_queue); |
| 474 | 435 |
| 475 if (next_desired_run_time && | 436 if (next_desired_run_time && |
| 476 next_allowed_run_time > next_desired_run_time.value()) { | 437 next_allowed_run_time > next_desired_run_time.value()) { |
| 477 TRACE_EVENT1( | 438 TRACE_EVENT1( |
| 478 tracing_category_, | 439 tracing_category_, |
| 479 "TaskQueueThrottler::PumpThrottledTasks_ExpensiveTaskThrottled", | 440 "TaskQueueThrottler::PumpThrottledTasks_ExpensiveTaskThrottled", |
| 480 "throttle_time_in_seconds", | 441 "throttle_time_in_seconds", |
| 481 (next_allowed_run_time - next_desired_run_time.value()).InSecondsF()); | 442 (next_allowed_run_time - next_desired_run_time.value()).InSecondsF()); |
| 482 | 443 |
| 483 // Schedule a pump for queue which was disabled because of time budget. | 444 // Schedule a pump for queue which was disabled because of time budget. |
| 484 next_scheduled_delayed_task = | 445 next_scheduled_delayed_task = |
| 485 Min(next_scheduled_delayed_task, next_allowed_run_time); | 446 Min(next_scheduled_delayed_task, next_allowed_run_time); |
| 486 | 447 |
| 487 continue; | 448 continue; |
| 488 } | 449 } |
| 489 | 450 |
| 490 next_scheduled_delayed_task = | 451 next_scheduled_delayed_task = |
| 491 Min(next_scheduled_delayed_task, task_queue->GetNextScheduledWakeUp()); | 452 Min(next_scheduled_delayed_task, task_queue->GetNextScheduledWakeUp()); |
| 492 | 453 |
| 493 if (next_allowed_run_time > lazy_now.Now()) | 454 if (next_allowed_run_time > lazy_now.Now()) |
| 494 continue; | 455 continue; |
| 495 | 456 |
| 496 task_queue->SetQueueEnabled(true); | 457 // Remove previous fence and install a new one, allowing all tasks posted |
| 497 task_queue->InsertFence(); | 458 // on |task_queue| up until this point to run and block all further tasks. |
| 459 task_queue->InsertFence(TaskQueue::InsertFencePosition::NOW); |
| 498 } | 460 } |
| 499 | 461 |
| 500 // Maybe schedule a call to TaskQueueThrottler::PumpThrottledTasks if there is | 462 // Maybe schedule a call to TaskQueueThrottler::PumpThrottledTasks if there is |
| 501 // a pending delayed task or a throttled task ready to run. | 463 // a pending delayed task or a throttled task ready to run. |
| 502 // NOTE: posting a non-delayed task in the future will result in | 464 // NOTE: posting a non-delayed task in the future will result in |
| 503 // TaskQueueThrottler::OnTimeDomainHasImmediateWork being called. | 465 // TaskQueueThrottler::OnTimeDomainHasImmediateWork being called. |
| 504 if (next_scheduled_delayed_task) { | 466 if (next_scheduled_delayed_task) { |
| 505 MaybeSchedulePumpThrottledTasks(FROM_HERE, lazy_now.Now(), | 467 MaybeSchedulePumpThrottledTasks(FROM_HERE, lazy_now.Now(), |
| 506 *next_scheduled_delayed_task); | 468 *next_scheduled_delayed_task); |
| 507 } | 469 } |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 586 pool->AsValueInto(state, now); | 548 pool->AsValueInto(state, now); |
| 587 } | 549 } |
| 588 state->EndDictionary(); | 550 state->EndDictionary(); |
| 589 | 551 |
| 590 state->BeginDictionary("queue_details"); | 552 state->BeginDictionary("queue_details"); |
| 591 for (const auto& map_entry : queue_details_) { | 553 for (const auto& map_entry : queue_details_) { |
| 592 state->BeginDictionaryWithCopiedName(PointerToId(map_entry.first)); | 554 state->BeginDictionaryWithCopiedName(PointerToId(map_entry.first)); |
| 593 | 555 |
| 594 state->SetInteger("throttling_ref_count", | 556 state->SetInteger("throttling_ref_count", |
| 595 map_entry.second.throttling_ref_count); | 557 map_entry.second.throttling_ref_count); |
| 596 state->SetBoolean("enabled", map_entry.second.enabled); | |
| 597 | 558 |
| 598 state->EndDictionary(); | 559 state->EndDictionary(); |
| 599 } | 560 } |
| 600 state->EndDictionary(); | 561 state->EndDictionary(); |
| 601 } | 562 } |
| 602 | 563 |
| 603 TaskQueueThrottler::TimeBudgetPool* | 564 TaskQueueThrottler::TimeBudgetPool* |
| 604 TaskQueueThrottler::GetTimeBudgetPoolForQueue(TaskQueue* queue) { | 565 TaskQueueThrottler::GetTimeBudgetPoolForQueue(TaskQueue* queue) { |
| 605 auto find_it = queue_details_.find(queue); | 566 auto find_it = queue_details_.find(queue); |
| 606 if (find_it == queue_details_.end()) | 567 if (find_it == queue_details_.end()) |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 643 | 604 |
| 644 for (const auto& map_entry : queue_details_) { | 605 for (const auto& map_entry : queue_details_) { |
| 645 if (map_entry.second.throttling_ref_count == 0) | 606 if (map_entry.second.throttling_ref_count == 0) |
| 646 continue; | 607 continue; |
| 647 | 608 |
| 648 TaskQueue* queue = map_entry.first; | 609 TaskQueue* queue = map_entry.first; |
| 649 | 610 |
| 650 queue->SetTimeDomain(renderer_scheduler_->GetActiveTimeDomain()); | 611 queue->SetTimeDomain(renderer_scheduler_->GetActiveTimeDomain()); |
| 651 | 612 |
| 652 queue->RemoveFence(); | 613 queue->RemoveFence(); |
| 653 queue->SetQueueEnabled(map_entry.second.enabled); | |
| 654 } | 614 } |
| 655 | 615 |
| 656 pump_throttled_tasks_closure_.Cancel(); | 616 pump_throttled_tasks_closure_.Cancel(); |
| 657 pending_pump_throttled_tasks_runtime_ = base::nullopt; | 617 pending_pump_throttled_tasks_runtime_ = base::nullopt; |
| 658 | 618 |
| 659 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler_DisableThrottling"); | 619 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler_DisableThrottling"); |
| 660 } | 620 } |
| 661 | 621 |
| 662 void TaskQueueThrottler::EnableThrottling() { | 622 void TaskQueueThrottler::EnableThrottling() { |
| 663 if (allow_throttling_) | 623 if (allow_throttling_) |
| 664 return; | 624 return; |
| 665 | 625 |
| 666 allow_throttling_ = true; | 626 allow_throttling_ = true; |
| 667 | 627 |
| 668 LazyNow lazy_now(tick_clock_); | 628 LazyNow lazy_now(tick_clock_); |
| 669 | 629 |
| 670 for (const auto& map_entry : queue_details_) { | 630 for (const auto& map_entry : queue_details_) { |
| 671 if (map_entry.second.throttling_ref_count == 0) | 631 if (map_entry.second.throttling_ref_count == 0) |
| 672 continue; | 632 continue; |
| 673 | 633 |
| 674 TaskQueue* queue = map_entry.first; | 634 TaskQueue* queue = map_entry.first; |
| 675 | 635 |
| 676 queue->SetQueueEnabled(false); | 636 // Throttling is enabled and task queue should be blocked immediately |
| 637 // to enforce task alignment. |
| 638 queue->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME); |
| 677 queue->SetTimeDomain(time_domain_.get()); | 639 queue->SetTimeDomain(time_domain_.get()); |
| 678 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue, | 640 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue, |
| 679 GetNextAllowedRunTime(lazy_now.Now(), queue)); | 641 GetNextAllowedRunTime(lazy_now.Now(), queue)); |
| 680 } | 642 } |
| 681 | 643 |
| 682 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler_EnableThrottling"); | 644 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler_EnableThrottling"); |
| 683 } | 645 } |
| 684 | 646 |
| 685 } // namespace scheduler | 647 } // namespace scheduler |
| 686 } // namespace blink | 648 } // namespace blink |
| OLD | NEW |