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

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

Issue 2533603002: [scheduler] Add options to TaskQueue::InsertFence (Closed)
Patch Set: Reupload 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 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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 (!allow_throttling_)
364 if (allow_throttling_) { 324 return;
365 task_queue->SetTimeDomain(time_domain_.get());
366 task_queue->RemoveFence();
367 task_queue->SetQueueEnabled(false);
368 325
369 if (!task_queue->IsEmpty()) { 326 // If ref_count is 1, the task queue is newly throttled.
370 if (task_queue->HasPendingImmediateWork()) { 327 if (insert_result.first->second.throttling_ref_count != 1)
371 OnTimeDomainHasImmediateWork(task_queue); 328 return;
372 } else { 329
373 OnTimeDomainHasDelayedWork(task_queue); 330 task_queue->SetTimeDomain(time_domain_.get());
374 } 331 task_queue->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME);
alex clarke (OOO till 29th) 2016/11/25 16:20:49 Please add a comment explaining that we need to st
altimin 2016/11/25 16:59:26 Done.
375 } 332
333 if (!task_queue->IsEmpty()) {
334 if (task_queue->HasPendingImmediateWork()) {
335 OnTimeDomainHasImmediateWork(task_queue);
336 } else {
337 OnTimeDomainHasDelayedWork(task_queue);
376 } 338 }
377
378 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueThrottled",
379 "task_queue", task_queue);
380 } 339 }
381 340
382 insert_result.first->second.throttling_ref_count++; 341 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueThrottled",
342 "task_queue", task_queue);
383 } 343 }
384 344
385 void TaskQueueThrottler::DecreaseThrottleRefCount(TaskQueue* task_queue) { 345 void TaskQueueThrottler::DecreaseThrottleRefCount(TaskQueue* task_queue) {
386 TaskQueueMap::iterator iter = queue_details_.find(task_queue); 346 TaskQueueMap::iterator iter = queue_details_.find(task_queue);
387 347
388 if (iter != queue_details_.end() && 348 if (iter != queue_details_.end() &&
389 --iter->second.throttling_ref_count == 0) { 349 --iter->second.throttling_ref_count == 0) {
390 bool enabled = iter->second.enabled;
391
392 MaybeDeleteQueueMetadata(iter); 350 MaybeDeleteQueueMetadata(iter);
393 351
394 if (allow_throttling_) { 352 if (allow_throttling_) {
395 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); 353 task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain());
396 task_queue->RemoveFence(); 354 task_queue->RemoveFence();
397 task_queue->SetQueueEnabled(enabled);
398 } 355 }
399 356
400 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueUnthrottled", 357 TRACE_EVENT1(tracing_category_, "TaskQueueThrottler_TaskQueueUnthrottled",
401 "task_queue", task_queue); 358 "task_queue", task_queue);
402 } 359 }
403 } 360 }
404 361
405 bool TaskQueueThrottler::IsThrottled(TaskQueue* task_queue) const { 362 bool TaskQueueThrottler::IsThrottled(TaskQueue* task_queue) const {
406 if (!allow_throttling_) 363 if (!allow_throttling_)
407 return false; 364 return false;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 412
456 void TaskQueueThrottler::PumpThrottledTasks() { 413 void TaskQueueThrottler::PumpThrottledTasks() {
457 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler::PumpThrottledTasks"); 414 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler::PumpThrottledTasks");
458 pending_pump_throttled_tasks_runtime_.reset(); 415 pending_pump_throttled_tasks_runtime_.reset();
459 416
460 LazyNow lazy_now(tick_clock_); 417 LazyNow lazy_now(tick_clock_);
461 base::Optional<base::TimeTicks> next_scheduled_delayed_task; 418 base::Optional<base::TimeTicks> next_scheduled_delayed_task;
462 419
463 for (const TaskQueueMap::value_type& map_entry : queue_details_) { 420 for (const TaskQueueMap::value_type& map_entry : queue_details_) {
464 TaskQueue* task_queue = map_entry.first; 421 TaskQueue* task_queue = map_entry.first;
465 if (!map_entry.second.enabled || task_queue->IsEmpty() || 422 if (task_queue->IsEmpty() || !IsThrottled(task_queue))
466 !IsThrottled(task_queue))
467 continue; 423 continue;
468 424
469 // Don't enable queues whose budget pool doesn't allow them to run now. 425 // Don't enable queues whose budget pool doesn't allow them to run now.
470 base::TimeTicks next_allowed_run_time = 426 base::TimeTicks next_allowed_run_time =
471 GetNextAllowedRunTime(lazy_now.Now(), task_queue); 427 GetNextAllowedRunTime(lazy_now.Now(), task_queue);
472 base::Optional<base::TimeTicks> next_desired_run_time = 428 base::Optional<base::TimeTicks> next_desired_run_time =
473 NextTaskRunTime(&lazy_now, task_queue); 429 NextTaskRunTime(&lazy_now, task_queue);
474 430
475 if (next_desired_run_time && 431 if (next_desired_run_time &&
476 next_allowed_run_time > next_desired_run_time.value()) { 432 next_allowed_run_time > next_desired_run_time.value()) {
477 TRACE_EVENT1( 433 TRACE_EVENT1(
478 tracing_category_, 434 tracing_category_,
479 "TaskQueueThrottler::PumpThrottledTasks_ExpensiveTaskThrottled", 435 "TaskQueueThrottler::PumpThrottledTasks_ExpensiveTaskThrottled",
480 "throttle_time_in_seconds", 436 "throttle_time_in_seconds",
481 (next_allowed_run_time - next_desired_run_time.value()).InSecondsF()); 437 (next_allowed_run_time - next_desired_run_time.value()).InSecondsF());
482 438
483 // Schedule a pump for queue which was disabled because of time budget. 439 // Schedule a pump for queue which was disabled because of time budget.
484 next_scheduled_delayed_task = 440 next_scheduled_delayed_task =
485 Min(next_scheduled_delayed_task, next_allowed_run_time); 441 Min(next_scheduled_delayed_task, next_allowed_run_time);
486 442
487 continue; 443 continue;
488 } 444 }
489 445
490 next_scheduled_delayed_task = 446 next_scheduled_delayed_task =
491 Min(next_scheduled_delayed_task, task_queue->GetNextScheduledWakeUp()); 447 Min(next_scheduled_delayed_task, task_queue->GetNextScheduledWakeUp());
492 448
493 if (next_allowed_run_time > lazy_now.Now()) 449 if (next_allowed_run_time > lazy_now.Now())
494 continue; 450 continue;
495 451
496 task_queue->SetQueueEnabled(true); 452 task_queue->InsertFence(TaskQueue::InsertFencePosition::NOW);
alex clarke (OOO till 29th) 2016/11/25 16:20:49 Please add a comment saying this will allow tasks
altimin 2016/11/25 16:59:26 Done.
497 task_queue->InsertFence();
498 } 453 }
499 454
500 // Maybe schedule a call to TaskQueueThrottler::PumpThrottledTasks if there is 455 // Maybe schedule a call to TaskQueueThrottler::PumpThrottledTasks if there is
501 // a pending delayed task or a throttled task ready to run. 456 // a pending delayed task or a throttled task ready to run.
502 // NOTE: posting a non-delayed task in the future will result in 457 // NOTE: posting a non-delayed task in the future will result in
503 // TaskQueueThrottler::OnTimeDomainHasImmediateWork being called. 458 // TaskQueueThrottler::OnTimeDomainHasImmediateWork being called.
504 if (next_scheduled_delayed_task) { 459 if (next_scheduled_delayed_task) {
505 MaybeSchedulePumpThrottledTasks(FROM_HERE, lazy_now.Now(), 460 MaybeSchedulePumpThrottledTasks(FROM_HERE, lazy_now.Now(),
506 *next_scheduled_delayed_task); 461 *next_scheduled_delayed_task);
507 } 462 }
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
586 pool->AsValueInto(state, now); 541 pool->AsValueInto(state, now);
587 } 542 }
588 state->EndDictionary(); 543 state->EndDictionary();
589 544
590 state->BeginDictionary("queue_details"); 545 state->BeginDictionary("queue_details");
591 for (const auto& map_entry : queue_details_) { 546 for (const auto& map_entry : queue_details_) {
592 state->BeginDictionaryWithCopiedName(PointerToId(map_entry.first)); 547 state->BeginDictionaryWithCopiedName(PointerToId(map_entry.first));
593 548
594 state->SetInteger("throttling_ref_count", 549 state->SetInteger("throttling_ref_count",
595 map_entry.second.throttling_ref_count); 550 map_entry.second.throttling_ref_count);
596 state->SetBoolean("enabled", map_entry.second.enabled);
597 551
598 state->EndDictionary(); 552 state->EndDictionary();
599 } 553 }
600 state->EndDictionary(); 554 state->EndDictionary();
601 } 555 }
602 556
603 TaskQueueThrottler::TimeBudgetPool* 557 TaskQueueThrottler::TimeBudgetPool*
604 TaskQueueThrottler::GetTimeBudgetPoolForQueue(TaskQueue* queue) { 558 TaskQueueThrottler::GetTimeBudgetPoolForQueue(TaskQueue* queue) {
605 auto find_it = queue_details_.find(queue); 559 auto find_it = queue_details_.find(queue);
606 if (find_it == queue_details_.end()) 560 if (find_it == queue_details_.end())
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
643 597
644 for (const auto& map_entry : queue_details_) { 598 for (const auto& map_entry : queue_details_) {
645 if (map_entry.second.throttling_ref_count == 0) 599 if (map_entry.second.throttling_ref_count == 0)
646 continue; 600 continue;
647 601
648 TaskQueue* queue = map_entry.first; 602 TaskQueue* queue = map_entry.first;
649 603
650 queue->SetTimeDomain(renderer_scheduler_->GetActiveTimeDomain()); 604 queue->SetTimeDomain(renderer_scheduler_->GetActiveTimeDomain());
651 605
652 queue->RemoveFence(); 606 queue->RemoveFence();
653 queue->SetQueueEnabled(map_entry.second.enabled);
654 } 607 }
655 608
656 pump_throttled_tasks_closure_.Cancel(); 609 pump_throttled_tasks_closure_.Cancel();
657 pending_pump_throttled_tasks_runtime_ = base::nullopt; 610 pending_pump_throttled_tasks_runtime_ = base::nullopt;
658 611
659 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler_DisableThrottling"); 612 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler_DisableThrottling");
660 } 613 }
661 614
662 void TaskQueueThrottler::EnableThrottling() { 615 void TaskQueueThrottler::EnableThrottling() {
663 if (allow_throttling_) 616 if (allow_throttling_)
664 return; 617 return;
665 618
666 allow_throttling_ = true; 619 allow_throttling_ = true;
667 620
668 LazyNow lazy_now(tick_clock_); 621 LazyNow lazy_now(tick_clock_);
669 622
670 for (const auto& map_entry : queue_details_) { 623 for (const auto& map_entry : queue_details_) {
671 if (map_entry.second.throttling_ref_count == 0) 624 if (map_entry.second.throttling_ref_count == 0)
672 continue; 625 continue;
673 626
674 TaskQueue* queue = map_entry.first; 627 TaskQueue* queue = map_entry.first;
675 628
676 queue->SetQueueEnabled(false); 629 queue->InsertFence(TaskQueue::InsertFencePosition::BEGINNING_OF_TIME);
alex clarke (OOO till 29th) 2016/11/25 16:20:49 Please add a comment explaining that we need to st
altimin 2016/11/25 16:59:26 Done.
677 queue->SetTimeDomain(time_domain_.get()); 630 queue->SetTimeDomain(time_domain_.get());
678 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue, 631 MaybeSchedulePumpQueue(FROM_HERE, lazy_now.Now(), queue,
679 GetNextAllowedRunTime(lazy_now.Now(), queue)); 632 GetNextAllowedRunTime(lazy_now.Now(), queue));
680 } 633 }
681 634
682 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler_EnableThrottling"); 635 TRACE_EVENT0(tracing_category_, "TaskQueueThrottler_EnableThrottling");
683 } 636 }
684 637
685 } // namespace scheduler 638 } // namespace scheduler
686 } // namespace blink 639 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698