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

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

Issue 1381273002: A better idle time estimator (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 2 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/base/task_queue_impl.h" 12 #include "components/scheduler/base/task_queue_impl.h"
13 #include "components/scheduler/base/task_queue_selector.h" 13 #include "components/scheduler/base/task_queue_selector.h"
14 #include "components/scheduler/child/scheduler_task_runner_delegate.h" 14 #include "components/scheduler/child/scheduler_task_runner_delegate.h"
15 15
16 namespace scheduler { 16 namespace scheduler {
17 namespace { 17 namespace {
18 const int kLoadingTaskEstimationSampleCount = 200; 18 const int kLoadingTaskEstimationSampleCount = 200;
19 const double kLoadingTaskEstimationPercentile = 90; 19 const double kLoadingTaskEstimationPercentile = 90;
20 const int kTimerTaskEstimationSampleCount = 200; 20 const int kTimerTaskEstimationSampleCount = 200;
21 const double kTimerTaskEstimationPercentile = 90; 21 const double kTimerTaskEstimationPercentile = 90;
22 const int kShortIdlePeriodDurationSampleCount = 10; 22 const int kShortIdlePeriodDurationSampleCount = 10;
23 const double kShortIdlePeriodDurationPercentile = 20; 23 const double kShortIdlePeriodDurationPercentile = 50;
24 } 24 }
25 25
26 RendererSchedulerImpl::RendererSchedulerImpl( 26 RendererSchedulerImpl::RendererSchedulerImpl(
27 scoped_refptr<SchedulerTaskRunnerDelegate> main_task_runner) 27 scoped_refptr<SchedulerTaskRunnerDelegate> main_task_runner)
28 : helper_(main_task_runner, 28 : helper_(main_task_runner,
29 "renderer.scheduler", 29 "renderer.scheduler",
30 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), 30 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
31 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")), 31 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")),
32 idle_helper_(&helper_, 32 idle_helper_(&helper_,
33 this, 33 this,
(...skipping 16 matching lines...) Expand all
50 end_renderer_hidden_idle_period_closure_.Reset(base::Bind( 50 end_renderer_hidden_idle_period_closure_.Reset(base::Bind(
51 &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr())); 51 &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr()));
52 52
53 suspend_timers_when_backgrounded_closure_.Reset( 53 suspend_timers_when_backgrounded_closure_.Reset(
54 base::Bind(&RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded, 54 base::Bind(&RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded,
55 weak_factory_.GetWeakPtr())); 55 weak_factory_.GetWeakPtr()));
56 56
57 default_loading_task_runner_ = NewLoadingTaskRunner("default_loading_tq"); 57 default_loading_task_runner_ = NewLoadingTaskRunner("default_loading_tq");
58 default_timer_task_runner_ = NewTimerTaskRunner("default_timer_tq"); 58 default_timer_task_runner_ = NewTimerTaskRunner("default_timer_tq");
59 59
60 compositor_task_runner_->AddTaskObserver(
61 &MainThreadOnly().idle_time_estimator);
62
60 TRACE_EVENT_OBJECT_CREATED_WITH_ID( 63 TRACE_EVENT_OBJECT_CREATED_WITH_ID(
61 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", 64 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
62 this); 65 this);
63 66
64 // Make sure that we don't initially assume there is no idle time.
65 MainThreadOnly().short_idle_period_duration.InsertSample(
66 cc::BeginFrameArgs::DefaultInterval());
67
68 helper_.SetObserver(this); 67 helper_.SetObserver(this);
69 } 68 }
70 69
71 RendererSchedulerImpl::~RendererSchedulerImpl() { 70 RendererSchedulerImpl::~RendererSchedulerImpl() {
72 TRACE_EVENT_OBJECT_DELETED_WITH_ID( 71 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
73 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", 72 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
74 this); 73 this);
75 74
76 for (const scoped_refptr<TaskQueue>& loading_queue : loading_task_runners_) { 75 for (const scoped_refptr<TaskQueue>& loading_queue : loading_task_runners_) {
77 loading_queue->RemoveTaskObserver( 76 loading_queue->RemoveTaskObserver(
(...skipping 14 matching lines...) Expand all
92 : compositor_queue_priority(TaskQueue::NORMAL_PRIORITY), 91 : compositor_queue_priority(TaskQueue::NORMAL_PRIORITY),
93 loading_queue_priority(TaskQueue::NORMAL_PRIORITY), 92 loading_queue_priority(TaskQueue::NORMAL_PRIORITY),
94 timer_queue_priority(TaskQueue::NORMAL_PRIORITY), 93 timer_queue_priority(TaskQueue::NORMAL_PRIORITY),
95 default_queue_priority(TaskQueue::NORMAL_PRIORITY) {} 94 default_queue_priority(TaskQueue::NORMAL_PRIORITY) {}
96 95
97 RendererSchedulerImpl::MainThreadOnly::MainThreadOnly() 96 RendererSchedulerImpl::MainThreadOnly::MainThreadOnly()
98 : loading_task_cost_estimator(kLoadingTaskEstimationSampleCount, 97 : loading_task_cost_estimator(kLoadingTaskEstimationSampleCount,
99 kLoadingTaskEstimationPercentile), 98 kLoadingTaskEstimationPercentile),
100 timer_task_cost_estimator(kTimerTaskEstimationSampleCount, 99 timer_task_cost_estimator(kTimerTaskEstimationSampleCount,
101 kTimerTaskEstimationPercentile), 100 kTimerTaskEstimationPercentile),
102 short_idle_period_duration(kShortIdlePeriodDurationSampleCount), 101 idle_time_estimator(kShortIdlePeriodDurationSampleCount,
102 kShortIdlePeriodDurationPercentile),
103 current_use_case(UseCase::NONE), 103 current_use_case(UseCase::NONE),
104 timer_queue_suspend_count(0), 104 timer_queue_suspend_count(0),
105 navigation_task_expected_count(0), 105 navigation_task_expected_count(0),
106 renderer_hidden(false), 106 renderer_hidden(false),
107 renderer_backgrounded(false), 107 renderer_backgrounded(false),
108 timer_queue_suspension_when_backgrounded_enabled(false), 108 timer_queue_suspension_when_backgrounded_enabled(false),
109 timer_queue_suspended_when_backgrounded(false), 109 timer_queue_suspended_when_backgrounded(false),
110 was_shutdown(false), 110 was_shutdown(false),
111 loading_tasks_seem_expensive(false), 111 loading_tasks_seem_expensive(false),
112 timer_tasks_seem_expensive(false), 112 timer_tasks_seem_expensive(false),
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 if (helper_.IsShutdown()) 233 if (helper_.IsShutdown())
234 return; 234 return;
235 235
236 base::TimeTicks now(helper_.Now()); 236 base::TimeTicks now(helper_.Now());
237 if (now < MainThreadOnly().estimated_next_frame_begin) { 237 if (now < MainThreadOnly().estimated_next_frame_begin) {
238 // TODO(rmcilroy): Consider reducing the idle period based on the runtime of 238 // TODO(rmcilroy): Consider reducing the idle period based on the runtime of
239 // the next pending delayed tasks (as currently done in for long idle times) 239 // the next pending delayed tasks (as currently done in for long idle times)
240 idle_helper_.StartIdlePeriod( 240 idle_helper_.StartIdlePeriod(
241 IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now, 241 IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now,
242 MainThreadOnly().estimated_next_frame_begin); 242 MainThreadOnly().estimated_next_frame_begin);
243 MainThreadOnly().short_idle_period_duration.InsertSample(
244 MainThreadOnly().estimated_next_frame_begin - now);
245 } else {
246 // There was no idle time :(
247 MainThreadOnly().short_idle_period_duration.InsertSample(base::TimeDelta());
248 } 243 }
249 244
250 MainThreadOnly().expected_short_idle_period_duration = 245 MainThreadOnly().idle_time_estimator.DidCommitFrameToCompositor();
251 MainThreadOnly().short_idle_period_duration.Percentile(
252 kShortIdlePeriodDurationPercentile);
253 } 246 }
254 247
255 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() { 248 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() {
256 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), 249 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
257 "RendererSchedulerImpl::BeginFrameNotExpectedSoon"); 250 "RendererSchedulerImpl::BeginFrameNotExpectedSoon");
258 helper_.CheckOnValidThread(); 251 helper_.CheckOnValidThread();
259 if (helper_.IsShutdown()) 252 if (helper_.IsShutdown())
260 return; 253 return;
261 254
262 idle_helper_.EnableLongIdlePeriod(); 255 idle_helper_.EnableLongIdlePeriod();
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 // there are any touch handlers registerd or not, and only call 547 // there are any touch handlers registerd or not, and only call
555 // TouchStartExpectedSoon if there is at least one. NOTE a TouchStart will 548 // TouchStartExpectedSoon if there is at least one. NOTE a TouchStart will
556 // only actually get sent if there is a touch handler. 549 // only actually get sent if there is a touch handler.
557 base::TimeDelta touchstart_expected_flag_valid_for_duration; 550 base::TimeDelta touchstart_expected_flag_valid_for_duration;
558 bool touchstart_expected_soon = AnyThread().user_model.IsGestureExpectedSoon( 551 bool touchstart_expected_soon = AnyThread().user_model.IsGestureExpectedSoon(
559 use_case, now, &touchstart_expected_flag_valid_for_duration); 552 use_case, now, &touchstart_expected_flag_valid_for_duration);
560 MainThreadOnly().touchstart_expected_soon = touchstart_expected_soon; 553 MainThreadOnly().touchstart_expected_soon = touchstart_expected_soon;
561 554
562 bool loading_tasks_seem_expensive = 555 bool loading_tasks_seem_expensive =
563 MainThreadOnly().loading_task_cost_estimator.expected_task_duration() > 556 MainThreadOnly().loading_task_cost_estimator.expected_task_duration() >
564 MainThreadOnly().expected_short_idle_period_duration; 557 MainThreadOnly().idle_time_estimator.expected_idle_duration();
565 MainThreadOnly().loading_tasks_seem_expensive = loading_tasks_seem_expensive; 558 MainThreadOnly().loading_tasks_seem_expensive = loading_tasks_seem_expensive;
566 559
567 bool timer_tasks_seem_expensive = 560 bool timer_tasks_seem_expensive =
568 MainThreadOnly().timer_task_cost_estimator.expected_task_duration() > 561 MainThreadOnly().timer_task_cost_estimator.expected_task_duration() >
569 MainThreadOnly().expected_short_idle_period_duration; 562 MainThreadOnly().idle_time_estimator.expected_idle_duration();
570 MainThreadOnly().timer_tasks_seem_expensive = timer_tasks_seem_expensive; 563 MainThreadOnly().timer_tasks_seem_expensive = timer_tasks_seem_expensive;
571 564
572 // The |new_policy_duration| is the minimum of |expected_use_case_duration| 565 // The |new_policy_duration| is the minimum of |expected_use_case_duration|
573 // and |touchstart_expected_flag_valid_for_duration| unless one is zero in 566 // and |touchstart_expected_flag_valid_for_duration| unless one is zero in
574 // which case we choose the other. 567 // which case we choose the other.
575 base::TimeDelta new_policy_duration = expected_use_case_duration; 568 base::TimeDelta new_policy_duration = expected_use_case_duration;
576 if (new_policy_duration == base::TimeDelta() || 569 if (new_policy_duration == base::TimeDelta() ||
577 (touchstart_expected_flag_valid_for_duration > base::TimeDelta() && 570 (touchstart_expected_flag_valid_for_duration > base::TimeDelta() &&
578 new_policy_duration > touchstart_expected_flag_valid_for_duration)) { 571 new_policy_duration > touchstart_expected_flag_valid_for_duration)) {
579 new_policy_duration = touchstart_expected_flag_valid_for_duration; 572 new_policy_duration = touchstart_expected_flag_valid_for_duration;
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
632 if (!MainThreadOnly().have_seen_a_begin_main_frame) 625 if (!MainThreadOnly().have_seen_a_begin_main_frame)
633 block_expensive_tasks = false; 626 block_expensive_tasks = false;
634 627
635 // Don't block expensive tasks if we are expecting a navigation. 628 // Don't block expensive tasks if we are expecting a navigation.
636 if (MainThreadOnly().navigation_task_expected_count > 0) 629 if (MainThreadOnly().navigation_task_expected_count > 0)
637 block_expensive_tasks = false; 630 block_expensive_tasks = false;
638 631
639 if (block_expensive_tasks && loading_tasks_seem_expensive) 632 if (block_expensive_tasks && loading_tasks_seem_expensive)
640 new_policy.loading_queue_priority = TaskQueue::DISABLED_PRIORITY; 633 new_policy.loading_queue_priority = TaskQueue::DISABLED_PRIORITY;
641 634
642 if (MainThreadOnly().timer_queue_suspend_count != 0 || 635 if ((block_expensive_tasks && timer_tasks_seem_expensive) ||
636 MainThreadOnly().timer_queue_suspend_count != 0 ||
643 MainThreadOnly().timer_queue_suspended_when_backgrounded) { 637 MainThreadOnly().timer_queue_suspended_when_backgrounded) {
644 new_policy.timer_queue_priority = TaskQueue::DISABLED_PRIORITY; 638 new_policy.timer_queue_priority = TaskQueue::DISABLED_PRIORITY;
645 } 639 }
646 640
647 // Tracing is done before the early out check, because it's quite possible we 641 // Tracing is done before the early out check, because it's quite possible we
648 // will otherwise miss this information in traces. 642 // will otherwise miss this information in traces.
649 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( 643 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
650 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", 644 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
651 this, AsValueLocked(now)); 645 this, AsValueLocked(now));
652 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case", 646 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case",
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
831 AnyThread().begin_main_frame_on_critical_path); 825 AnyThread().begin_main_frame_on_critical_path);
832 state->SetDouble("expected_loading_task_duration", 826 state->SetDouble("expected_loading_task_duration",
833 MainThreadOnly() 827 MainThreadOnly()
834 .loading_task_cost_estimator.expected_task_duration() 828 .loading_task_cost_estimator.expected_task_duration()
835 .InMillisecondsF()); 829 .InMillisecondsF());
836 state->SetDouble("expected_timer_task_duration", 830 state->SetDouble("expected_timer_task_duration",
837 MainThreadOnly() 831 MainThreadOnly()
838 .timer_task_cost_estimator.expected_task_duration() 832 .timer_task_cost_estimator.expected_task_duration()
839 .InMillisecondsF()); 833 .InMillisecondsF());
840 // TODO(skyostil): Can we somehow trace how accurate these estimates were? 834 // TODO(skyostil): Can we somehow trace how accurate these estimates were?
841 state->SetDouble( 835 state->SetDouble("idle_time_estimator",
Sami 2015/10/03 00:56:15 nit: expected_idle_duration instead of idle_time_e
alex clarke (OOO till 29th) 2015/10/05 17:32:19 Done.
842 "expected_short_idle_period_duration", 836 MainThreadOnly()
843 MainThreadOnly().expected_short_idle_period_duration.InMillisecondsF()); 837 .idle_time_estimator.expected_idle_duration()
838 .InMillisecondsF());
844 state->SetDouble( 839 state->SetDouble(
845 "estimated_next_frame_begin", 840 "estimated_next_frame_begin",
846 (MainThreadOnly().estimated_next_frame_begin - base::TimeTicks()) 841 (MainThreadOnly().estimated_next_frame_begin - base::TimeTicks())
847 .InMillisecondsF()); 842 .InMillisecondsF());
848 state->SetBoolean("in_idle_period", AnyThread().in_idle_period); 843 state->SetBoolean("in_idle_period", AnyThread().in_idle_period);
849 AnyThread().user_model.AsValueInto(state.get()); 844 AnyThread().user_model.AsValueInto(state.get());
850 845
851 return state; 846 return state;
852 } 847 }
853 848
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
910 905
911 MainThreadOnly().timer_queue_suspended_when_backgrounded = false; 906 MainThreadOnly().timer_queue_suspended_when_backgrounded = false;
912 ForceUpdatePolicy(); 907 ForceUpdatePolicy();
913 } 908 }
914 909
915 void RendererSchedulerImpl::ResetForNavigationLocked() { 910 void RendererSchedulerImpl::ResetForNavigationLocked() {
916 helper_.CheckOnValidThread(); 911 helper_.CheckOnValidThread();
917 any_thread_lock_.AssertAcquired(); 912 any_thread_lock_.AssertAcquired();
918 MainThreadOnly().loading_task_cost_estimator.Clear(); 913 MainThreadOnly().loading_task_cost_estimator.Clear();
919 MainThreadOnly().timer_task_cost_estimator.Clear(); 914 MainThreadOnly().timer_task_cost_estimator.Clear();
920 MainThreadOnly().short_idle_period_duration.Clear(); 915 MainThreadOnly().idle_time_estimator.Clear();
921 // Make sure that we don't initially assume there is no idle time.
922 MainThreadOnly().short_idle_period_duration.InsertSample(
923 cc::BeginFrameArgs::DefaultInterval());
924 AnyThread().user_model.Reset(); 916 AnyThread().user_model.Reset();
925 MainThreadOnly().have_seen_a_begin_main_frame = false; 917 MainThreadOnly().have_seen_a_begin_main_frame = false;
926 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); 918 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
927 } 919 }
928 920
929 } // namespace scheduler 921 } // namespace scheduler
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698