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

Side by Side Diff: components/scheduler/renderer/renderer_scheduler_impl.cc

Issue 1303353003: scheduler: Disable expensive timers during main thread user input (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review comments. Created 5 years, 4 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "components/scheduler/renderer/renderer_scheduler_impl.h" 5 #include "components/scheduler/renderer/renderer_scheduler_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/debug/stack_trace.h" 8 #include "base/debug/stack_trace.h"
9 #include "base/trace_event/trace_event.h" 9 #include "base/trace_event/trace_event.h"
10 #include "base/trace_event/trace_event_argument.h" 10 #include "base/trace_event/trace_event_argument.h"
11 #include "cc/output/begin_frame_args.h" 11 #include "cc/output/begin_frame_args.h"
12 #include "components/scheduler/child/scheduler_task_runner_delegate.h" 12 #include "components/scheduler/child/scheduler_task_runner_delegate.h"
13 #include "components/scheduler/child/task_queue_impl.h" 13 #include "components/scheduler/child/task_queue_impl.h"
14 #include "components/scheduler/child/task_queue_selector.h" 14 #include "components/scheduler/child/task_queue_selector.h"
15 15
16 namespace scheduler { 16 namespace scheduler {
17 namespace {
18 const int kTimerTaskEstimationSampleCount = 4 * 60;
19 const double kTimerTaskEstimationPercentile = 80;
20 const int kShortIdlePeriodDurationSampleCount = 10;
21 const double kShortIdlePeriodDurationPercentile = 20;
22 }
17 23
18 RendererSchedulerImpl::RendererSchedulerImpl( 24 RendererSchedulerImpl::RendererSchedulerImpl(
19 scoped_refptr<SchedulerTaskRunnerDelegate> main_task_runner) 25 scoped_refptr<SchedulerTaskRunnerDelegate> main_task_runner)
20 : helper_(main_task_runner, 26 : helper_(main_task_runner,
21 "renderer.scheduler", 27 "renderer.scheduler",
22 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), 28 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
23 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")), 29 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")),
24 idle_helper_(&helper_, 30 idle_helper_(&helper_,
25 this, 31 this,
26 "renderer.scheduler", 32 "renderer.scheduler",
(...skipping 14 matching lines...) Expand all
41 base::Bind(&RendererSchedulerImpl::UpdatePolicy, 47 base::Bind(&RendererSchedulerImpl::UpdatePolicy,
42 base::Unretained(this)), 48 base::Unretained(this)),
43 helper_.ControlTaskRunner()), 49 helper_.ControlTaskRunner()),
44 policy_may_need_update_(&any_thread_lock_), 50 policy_may_need_update_(&any_thread_lock_),
45 weak_factory_(this) { 51 weak_factory_(this) {
46 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, 52 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy,
47 weak_factory_.GetWeakPtr()); 53 weak_factory_.GetWeakPtr());
48 end_renderer_hidden_idle_period_closure_.Reset(base::Bind( 54 end_renderer_hidden_idle_period_closure_.Reset(base::Bind(
49 &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr())); 55 &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr()));
50 56
57 timer_task_runner_->AddTaskObserver(
58 &MainThreadOnly().timer_task_cost_estimator_);
59
51 TRACE_EVENT_OBJECT_CREATED_WITH_ID( 60 TRACE_EVENT_OBJECT_CREATED_WITH_ID(
52 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", 61 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
53 this); 62 this);
54 } 63 }
55 64
56 RendererSchedulerImpl::~RendererSchedulerImpl() { 65 RendererSchedulerImpl::~RendererSchedulerImpl() {
57 TRACE_EVENT_OBJECT_DELETED_WITH_ID( 66 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
58 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", 67 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
59 this); 68 this);
69 timer_task_runner_->RemoveTaskObserver(
70 &MainThreadOnly().timer_task_cost_estimator_);
60 // Ensure the renderer scheduler was shut down explicitly, because otherwise 71 // Ensure the renderer scheduler was shut down explicitly, because otherwise
61 // we could end up having stale pointers to the Blink heap which has been 72 // we could end up having stale pointers to the Blink heap which has been
62 // terminated by this point. 73 // terminated by this point.
63 DCHECK(MainThreadOnly().was_shutdown_); 74 DCHECK(MainThreadOnly().was_shutdown_);
64 } 75 }
65 76
66 RendererSchedulerImpl::MainThreadOnly::MainThreadOnly() 77 RendererSchedulerImpl::MainThreadOnly::MainThreadOnly()
67 : current_policy_(Policy::NORMAL), 78 : timer_task_cost_estimator_(kTimerTaskEstimationSampleCount,
79 kTimerTaskEstimationPercentile),
80 short_idle_period_duration_(kShortIdlePeriodDurationSampleCount),
81 current_policy_(Policy::NORMAL),
68 timer_queue_suspend_count_(0), 82 timer_queue_suspend_count_(0),
69 renderer_hidden_(false), 83 renderer_hidden_(false),
70 was_shutdown_(false) { 84 was_shutdown_(false) {}
71 } 85
86 RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {}
72 87
73 RendererSchedulerImpl::AnyThread::AnyThread() 88 RendererSchedulerImpl::AnyThread::AnyThread()
74 : pending_main_thread_input_event_count_(0), 89 : pending_main_thread_input_event_count_(0),
75 awaiting_touch_start_response_(false), 90 awaiting_touch_start_response_(false),
76 in_idle_period_(false), 91 in_idle_period_(false),
77 begin_main_frame_on_critical_path_(false) { 92 begin_main_frame_on_critical_path_(false),
78 } 93 timer_tasks_seem_expensive_(false) {}
79 94
80 RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly() 95 RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly()
81 : last_input_type_(blink::WebInputEvent::Undefined) { 96 : last_input_type_(blink::WebInputEvent::Undefined) {
82 } 97 }
83 98
84 RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() { 99 RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() {
85 } 100 }
86 101
87 void RendererSchedulerImpl::Shutdown() { 102 void RendererSchedulerImpl::Shutdown() {
88 helper_.Shutdown(); 103 helper_.Shutdown();
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 if (helper_.IsShutdown()) 167 if (helper_.IsShutdown())
153 return; 168 return;
154 169
155 base::TimeTicks now(helper_.Now()); 170 base::TimeTicks now(helper_.Now());
156 if (now < MainThreadOnly().estimated_next_frame_begin_) { 171 if (now < MainThreadOnly().estimated_next_frame_begin_) {
157 // TODO(rmcilroy): Consider reducing the idle period based on the runtime of 172 // TODO(rmcilroy): Consider reducing the idle period based on the runtime of
158 // the next pending delayed tasks (as currently done in for long idle times) 173 // the next pending delayed tasks (as currently done in for long idle times)
159 idle_helper_.StartIdlePeriod( 174 idle_helper_.StartIdlePeriod(
160 IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now, 175 IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now,
161 MainThreadOnly().estimated_next_frame_begin_); 176 MainThreadOnly().estimated_next_frame_begin_);
177 MainThreadOnly().short_idle_period_duration_.InsertSample(
178 MainThreadOnly().estimated_next_frame_begin_ - now);
179 MainThreadOnly().expected_short_idle_period_duration_ =
180 MainThreadOnly().short_idle_period_duration_.Percentile(
181 kShortIdlePeriodDurationPercentile);
162 } 182 }
163 } 183 }
164 184
165 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() { 185 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() {
166 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), 186 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
167 "RendererSchedulerImpl::BeginFrameNotExpectedSoon"); 187 "RendererSchedulerImpl::BeginFrameNotExpectedSoon");
168 helper_.CheckOnValidThread(); 188 helper_.CheckOnValidThread();
169 if (helper_.IsShutdown()) 189 if (helper_.IsShutdown())
170 return; 190 return;
171 191
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 428
409 void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { 429 void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
410 helper_.CheckOnValidThread(); 430 helper_.CheckOnValidThread();
411 any_thread_lock_.AssertAcquired(); 431 any_thread_lock_.AssertAcquired();
412 if (helper_.IsShutdown()) 432 if (helper_.IsShutdown())
413 return; 433 return;
414 434
415 base::TimeTicks now = helper_.Now(); 435 base::TimeTicks now = helper_.Now();
416 policy_may_need_update_.SetWhileLocked(false); 436 policy_may_need_update_.SetWhileLocked(false);
417 437
438 AnyThread().timer_tasks_seem_expensive_ =
439 MainThreadOnly().expected_short_idle_period_duration_ >
440 base::TimeDelta() &&
441 MainThreadOnly().timer_task_cost_estimator_.expected_task_duration() >
442 MainThreadOnly().expected_short_idle_period_duration_;
443
418 base::TimeDelta new_policy_duration; 444 base::TimeDelta new_policy_duration;
419 Policy new_policy = ComputeNewPolicy(now, &new_policy_duration); 445 Policy new_policy = ComputeNewPolicy(now, &new_policy_duration);
420 if (new_policy_duration > base::TimeDelta()) { 446 if (new_policy_duration > base::TimeDelta()) {
421 MainThreadOnly().current_policy_expiration_time_ = 447 MainThreadOnly().current_policy_expiration_time_ =
422 now + new_policy_duration; 448 now + new_policy_duration;
423 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, 449 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration,
424 now); 450 now);
425 } else { 451 } else {
426 MainThreadOnly().current_policy_expiration_time_ = base::TimeTicks(); 452 MainThreadOnly().current_policy_expiration_time_ = base::TimeTicks();
427 } 453 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 new_policy != Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY) { 500 new_policy != Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY) {
475 DCHECK(loading_task_runner_->IsQueueEnabled()); 501 DCHECK(loading_task_runner_->IsQueueEnabled());
476 } 502 }
477 MainThreadOnly().current_policy_ = new_policy; 503 MainThreadOnly().current_policy_ = new_policy;
478 504
479 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( 505 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
480 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", 506 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
481 this, AsValueLocked(now)); 507 this, AsValueLocked(now));
482 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), 508 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
483 "RendererScheduler.policy", MainThreadOnly().current_policy_); 509 "RendererScheduler.policy", MainThreadOnly().current_policy_);
510 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
511 "RendererScheduler.timer_tasks_seem_expensive",
512 AnyThread().timer_tasks_seem_expensive_);
484 } 513 }
485 514
486 bool RendererSchedulerImpl::InputSignalsSuggestCompositorPriority( 515 bool RendererSchedulerImpl::InputSignalsSuggestCompositorPriority(
487 base::TimeTicks now) const { 516 base::TimeTicks now) const {
488 base::TimeDelta unused_policy_duration; 517 base::TimeDelta unused_policy_duration;
489 switch (ComputeNewPolicy(now, &unused_policy_duration)) { 518 switch (ComputeNewPolicy(now, &unused_policy_duration)) {
490 case Policy::TOUCHSTART_PRIORITY: 519 case Policy::TOUCHSTART_PRIORITY:
491 case Policy::COMPOSITOR_PRIORITY: 520 case Policy::COMPOSITOR_PRIORITY:
492 case Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY: 521 case Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY:
493 return true; 522 return true;
494 523
495 default: 524 default:
496 break; 525 break;
497 } 526 }
498 return false; 527 return false;
499 } 528 }
500 529
501 RendererSchedulerImpl::Policy RendererSchedulerImpl::ComputeNewPolicy( 530 RendererSchedulerImpl::Policy RendererSchedulerImpl::ComputeNewPolicy(
502 base::TimeTicks now, 531 base::TimeTicks now,
503 base::TimeDelta* new_policy_duration) const { 532 base::TimeDelta* new_policy_duration) const {
504 any_thread_lock_.AssertAcquired(); 533 any_thread_lock_.AssertAcquired();
505 // Above all else we want to be responsive to user input. 534 // Above all else we want to be responsive to user input.
506 *new_policy_duration = TimeLeftInInputEscalatedPolicy(now); 535 *new_policy_duration = TimeLeftInInputEscalatedPolicy(now);
507 if (*new_policy_duration > base::TimeDelta()) { 536 if (*new_policy_duration > base::TimeDelta()) {
508 if (AnyThread().awaiting_touch_start_response_) 537 if (AnyThread().awaiting_touch_start_response_)
509 return Policy::TOUCHSTART_PRIORITY; 538 return Policy::TOUCHSTART_PRIORITY;
510 // If BeginMainFrame is on the critical path, we want to try and prevent 539 // If BeginMainFrame is on the critical path, we want to try and prevent
511 // timers and loading tasks from running shortly before BeginMainFrame is 540 // timers and loading tasks from running if we think they might be
512 // due to be posted from the compositor, because they can delay 541 // expensive.
513 // BeginMainFrame's execution. We do this by limiting execution of timers to 542 // TODO(skyostil): Consider removing in_idle_period_ and
514 // idle periods, provided there has been at least one idle period recently. 543 // HadAnIdlePeriodRecently() unless we need them here.
515 // 544 if (AnyThread().timer_tasks_seem_expensive_ &&
516 // TODO(alexclarke): It's a shame in_idle_period_, 545 AnyThread().begin_main_frame_on_critical_path_) {
517 // begin_main_frame_on_critical_path_ and last_idle_period_end_time_ are in
518 // the AnyThread struct. Find a way to migrate them to MainThreadOnly.
519 if (!AnyThread().in_idle_period_ &&
520 AnyThread().begin_main_frame_on_critical_path_ &&
521 HadAnIdlePeriodRecently(now)) {
522 return Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY; 546 return Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY;
523 } 547 }
524 return Policy::COMPOSITOR_PRIORITY; 548 return Policy::COMPOSITOR_PRIORITY;
525 } 549 }
526 550
527 if (AnyThread().rails_loading_priority_deadline_ > now) { 551 if (AnyThread().rails_loading_priority_deadline_ > now) {
528 *new_policy_duration = AnyThread().rails_loading_priority_deadline_ - now; 552 *new_policy_duration = AnyThread().rails_loading_priority_deadline_ - now;
529 return Policy::LOADING_PRIORITY; 553 return Policy::LOADING_PRIORITY;
530 } 554 }
531 555
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
633 base::TimeTicks()).InMillisecondsF()); 657 base::TimeTicks()).InMillisecondsF());
634 state->SetDouble("last_idle_period_end_time", 658 state->SetDouble("last_idle_period_end_time",
635 (AnyThread().last_idle_period_end_time_ - base::TimeTicks()) 659 (AnyThread().last_idle_period_end_time_ - base::TimeTicks())
636 .InMillisecondsF()); 660 .InMillisecondsF());
637 state->SetInteger("pending_main_thread_input_event_count", 661 state->SetInteger("pending_main_thread_input_event_count",
638 AnyThread().pending_main_thread_input_event_count_); 662 AnyThread().pending_main_thread_input_event_count_);
639 state->SetBoolean("awaiting_touch_start_response", 663 state->SetBoolean("awaiting_touch_start_response",
640 AnyThread().awaiting_touch_start_response_); 664 AnyThread().awaiting_touch_start_response_);
641 state->SetBoolean("begin_main_frame_on_critical_path", 665 state->SetBoolean("begin_main_frame_on_critical_path",
642 AnyThread().begin_main_frame_on_critical_path_); 666 AnyThread().begin_main_frame_on_critical_path_);
667 state->SetDouble("expected_timer_task_duration",
668 MainThreadOnly()
669 .timer_task_cost_estimator_.expected_task_duration()
670 .InMillisecondsF());
671 // TODO(skyostil): Can we somehow trace how accurate these estimates were?
672 state->SetDouble(
673 "expected_short_idle_period_duration",
674 MainThreadOnly().expected_short_idle_period_duration_.InMillisecondsF());
675 state->SetBoolean("timer_tasks_seem_expensive",
676 AnyThread().timer_tasks_seem_expensive_);
643 state->SetDouble("estimated_next_frame_begin", 677 state->SetDouble("estimated_next_frame_begin",
644 (MainThreadOnly().estimated_next_frame_begin_ - 678 (MainThreadOnly().estimated_next_frame_begin_ -
645 base::TimeTicks()).InMillisecondsF()); 679 base::TimeTicks()).InMillisecondsF());
646 state->SetBoolean("in_idle_period", AnyThread().in_idle_period_); 680 state->SetBoolean("in_idle_period", AnyThread().in_idle_period_);
647 681
648 return state; 682 return state;
649 } 683 }
650 684
651 void RendererSchedulerImpl::OnIdlePeriodStarted() { 685 void RendererSchedulerImpl::OnIdlePeriodStarted() {
652 base::AutoLock lock(any_thread_lock_); 686 base::AutoLock lock(any_thread_lock_);
(...skipping 16 matching lines...) Expand all
669 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); 703 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
670 } 704 }
671 705
672 bool RendererSchedulerImpl::HadAnIdlePeriodRecently(base::TimeTicks now) const { 706 bool RendererSchedulerImpl::HadAnIdlePeriodRecently(base::TimeTicks now) const {
673 return (now - AnyThread().last_idle_period_end_time_) <= 707 return (now - AnyThread().last_idle_period_end_time_) <=
674 base::TimeDelta::FromMilliseconds( 708 base::TimeDelta::FromMilliseconds(
675 kIdlePeriodStarvationThresholdMillis); 709 kIdlePeriodStarvationThresholdMillis);
676 } 710 }
677 711
678 } // namespace scheduler 712 } // namespace scheduler
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698