Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 { | 17 namespace { |
| 18 const int kTimerTaskEstimationSampleCount = 4 * 60; | 18 const int kLoadingTaskEstimationSampleCount = 200; |
| 19 const double kTimerTaskEstimationPercentile = 80; | 19 const double kLoadingTaskEstimationPercentile = 90; |
| 20 const int kTimerTaskEstimationSampleCount = 200; | |
| 21 const double kTimerTaskEstimationPercentile = 90; | |
| 20 const int kShortIdlePeriodDurationSampleCount = 10; | 22 const int kShortIdlePeriodDurationSampleCount = 10; |
| 21 const double kShortIdlePeriodDurationPercentile = 20; | 23 const double kShortIdlePeriodDurationPercentile = 20; |
| 22 } | 24 } |
| 23 | 25 |
| 24 RendererSchedulerImpl::RendererSchedulerImpl( | 26 RendererSchedulerImpl::RendererSchedulerImpl( |
| 25 scoped_refptr<SchedulerTaskRunnerDelegate> main_task_runner) | 27 scoped_refptr<SchedulerTaskRunnerDelegate> main_task_runner) |
| 26 : helper_(main_task_runner, | 28 : helper_(main_task_runner, |
| 27 "renderer.scheduler", | 29 "renderer.scheduler", |
| 28 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 30 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 29 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")), | 31 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")), |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 47 base::Bind(&RendererSchedulerImpl::UpdatePolicy, | 49 base::Bind(&RendererSchedulerImpl::UpdatePolicy, |
| 48 base::Unretained(this)), | 50 base::Unretained(this)), |
| 49 helper_.ControlTaskRunner()), | 51 helper_.ControlTaskRunner()), |
| 50 policy_may_need_update_(&any_thread_lock_), | 52 policy_may_need_update_(&any_thread_lock_), |
| 51 weak_factory_(this) { | 53 weak_factory_(this) { |
| 52 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, | 54 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, |
| 53 weak_factory_.GetWeakPtr()); | 55 weak_factory_.GetWeakPtr()); |
| 54 end_renderer_hidden_idle_period_closure_.Reset(base::Bind( | 56 end_renderer_hidden_idle_period_closure_.Reset(base::Bind( |
| 55 &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr())); | 57 &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr())); |
| 56 | 58 |
| 59 loading_task_runner_->AddTaskObserver( | |
| 60 &MainThreadOnly().loading_task_cost_estimator); | |
| 61 | |
| 57 timer_task_runner_->AddTaskObserver( | 62 timer_task_runner_->AddTaskObserver( |
| 58 &MainThreadOnly().timer_task_cost_estimator_); | 63 &MainThreadOnly().timer_task_cost_estimator); |
| 59 | 64 |
| 60 TRACE_EVENT_OBJECT_CREATED_WITH_ID( | 65 TRACE_EVENT_OBJECT_CREATED_WITH_ID( |
| 61 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", | 66 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", |
| 62 this); | 67 this); |
| 68 | |
| 69 // Make sure that we don't initially assume there is no idle time. | |
| 70 MainThreadOnly().short_idle_period_duration.InsertSample( | |
| 71 cc::BeginFrameArgs::DefaultInterval()); | |
| 63 } | 72 } |
| 64 | 73 |
| 65 RendererSchedulerImpl::~RendererSchedulerImpl() { | 74 RendererSchedulerImpl::~RendererSchedulerImpl() { |
| 66 TRACE_EVENT_OBJECT_DELETED_WITH_ID( | 75 TRACE_EVENT_OBJECT_DELETED_WITH_ID( |
| 67 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", | 76 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", |
| 68 this); | 77 this); |
| 69 timer_task_runner_->RemoveTaskObserver( | 78 timer_task_runner_->RemoveTaskObserver( |
| 70 &MainThreadOnly().timer_task_cost_estimator_); | 79 &MainThreadOnly().timer_task_cost_estimator); |
| 71 // Ensure the renderer scheduler was shut down explicitly, because otherwise | 80 // Ensure the renderer scheduler was shut down explicitly, because otherwise |
| 72 // we could end up having stale pointers to the Blink heap which has been | 81 // we could end up having stale pointers to the Blink heap which has been |
| 73 // terminated by this point. | 82 // terminated by this point. |
| 74 DCHECK(MainThreadOnly().was_shutdown_); | 83 DCHECK(MainThreadOnly().was_shutdown); |
| 75 } | 84 } |
| 76 | 85 |
| 86 RendererSchedulerImpl::Policy::Policy() | |
| 87 : compositor_queue_priority(TaskQueue::NORMAL_PRIORITY), | |
| 88 loading_queue_priority(TaskQueue::NORMAL_PRIORITY), | |
| 89 timer_queue_priority(TaskQueue::NORMAL_PRIORITY) {} | |
| 90 | |
| 77 RendererSchedulerImpl::MainThreadOnly::MainThreadOnly() | 91 RendererSchedulerImpl::MainThreadOnly::MainThreadOnly() |
| 78 : timer_task_cost_estimator_(kTimerTaskEstimationSampleCount, | 92 : loading_task_cost_estimator(kLoadingTaskEstimationSampleCount, |
| 79 kTimerTaskEstimationPercentile), | 93 kLoadingTaskEstimationPercentile), |
| 80 short_idle_period_duration_(kShortIdlePeriodDurationSampleCount), | 94 timer_task_cost_estimator(kTimerTaskEstimationSampleCount, |
| 81 current_policy_(Policy::NORMAL), | 95 kTimerTaskEstimationPercentile), |
| 82 timer_queue_suspend_count_(0), | 96 short_idle_period_duration(kShortIdlePeriodDurationSampleCount), |
| 83 renderer_hidden_(false), | 97 current_use_case(UseCase::NONE), |
| 84 was_shutdown_(false) {} | 98 timer_queue_suspend_count(0), |
| 99 renderer_hidden(false), | |
| 100 was_shutdown(false), | |
| 101 loading_tasks_seem_expensive(false), | |
| 102 timer_tasks_seem_expensive(false), | |
| 103 touchstart_expected_soon(false) {} | |
| 85 | 104 |
| 86 RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {} | 105 RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {} |
| 87 | 106 |
| 88 RendererSchedulerImpl::AnyThread::AnyThread() | 107 RendererSchedulerImpl::AnyThread::AnyThread() |
| 89 : pending_main_thread_input_event_count_(0), | 108 : awaiting_touch_start_response(false), |
| 90 awaiting_touch_start_response_(false), | 109 in_idle_period(false), |
| 91 in_idle_period_(false), | 110 begin_main_frame_on_critical_path(false) {} |
| 92 begin_main_frame_on_critical_path_(false), | |
| 93 timer_tasks_seem_expensive_(false) {} | |
| 94 | 111 |
| 95 RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly() | 112 RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly() |
| 96 : last_input_type_(blink::WebInputEvent::Undefined) { | 113 : last_input_type(blink::WebInputEvent::Undefined) {} |
| 97 } | |
| 98 | 114 |
| 99 RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() { | 115 RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() { |
| 100 } | 116 } |
| 101 | 117 |
| 102 void RendererSchedulerImpl::Shutdown() { | 118 void RendererSchedulerImpl::Shutdown() { |
| 103 helper_.Shutdown(); | 119 helper_.Shutdown(); |
| 104 MainThreadOnly().was_shutdown_ = true; | 120 MainThreadOnly().was_shutdown = true; |
| 105 } | 121 } |
| 106 | 122 |
| 107 scoped_refptr<TaskQueue> RendererSchedulerImpl::DefaultTaskRunner() { | 123 scoped_refptr<TaskQueue> RendererSchedulerImpl::DefaultTaskRunner() { |
| 108 return helper_.DefaultTaskRunner(); | 124 return helper_.DefaultTaskRunner(); |
| 109 } | 125 } |
| 110 | 126 |
| 111 scoped_refptr<base::SingleThreadTaskRunner> | 127 scoped_refptr<base::SingleThreadTaskRunner> |
| 112 RendererSchedulerImpl::CompositorTaskRunner() { | 128 RendererSchedulerImpl::CompositorTaskRunner() { |
| 113 helper_.CheckOnValidThread(); | 129 helper_.CheckOnValidThread(); |
| 114 return compositor_task_runner_; | 130 return compositor_task_runner_; |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 145 } | 161 } |
| 146 | 162 |
| 147 void RendererSchedulerImpl::WillBeginFrame(const cc::BeginFrameArgs& args) { | 163 void RendererSchedulerImpl::WillBeginFrame(const cc::BeginFrameArgs& args) { |
| 148 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 164 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 149 "RendererSchedulerImpl::WillBeginFrame", "args", args.AsValue()); | 165 "RendererSchedulerImpl::WillBeginFrame", "args", args.AsValue()); |
| 150 helper_.CheckOnValidThread(); | 166 helper_.CheckOnValidThread(); |
| 151 if (helper_.IsShutdown()) | 167 if (helper_.IsShutdown()) |
| 152 return; | 168 return; |
| 153 | 169 |
| 154 EndIdlePeriod(); | 170 EndIdlePeriod(); |
| 155 MainThreadOnly().estimated_next_frame_begin_ = | 171 MainThreadOnly().estimated_next_frame_begin = args.frame_time + args.interval; |
| 156 args.frame_time + args.interval; | |
| 157 { | 172 { |
| 158 base::AutoLock lock(any_thread_lock_); | 173 base::AutoLock lock(any_thread_lock_); |
| 159 AnyThread().begin_main_frame_on_critical_path_ = args.on_critical_path; | 174 AnyThread().begin_main_frame_on_critical_path = args.on_critical_path; |
| 160 } | 175 } |
| 161 } | 176 } |
| 162 | 177 |
| 163 void RendererSchedulerImpl::DidCommitFrameToCompositor() { | 178 void RendererSchedulerImpl::DidCommitFrameToCompositor() { |
| 164 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 179 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 165 "RendererSchedulerImpl::DidCommitFrameToCompositor"); | 180 "RendererSchedulerImpl::DidCommitFrameToCompositor"); |
| 166 helper_.CheckOnValidThread(); | 181 helper_.CheckOnValidThread(); |
| 167 if (helper_.IsShutdown()) | 182 if (helper_.IsShutdown()) |
| 168 return; | 183 return; |
| 169 | 184 |
| 170 base::TimeTicks now(helper_.Now()); | 185 base::TimeTicks now(helper_.Now()); |
| 171 if (now < MainThreadOnly().estimated_next_frame_begin_) { | 186 if (now < MainThreadOnly().estimated_next_frame_begin) { |
| 172 // TODO(rmcilroy): Consider reducing the idle period based on the runtime of | 187 // TODO(rmcilroy): Consider reducing the idle period based on the runtime of |
| 173 // the next pending delayed tasks (as currently done in for long idle times) | 188 // the next pending delayed tasks (as currently done in for long idle times) |
| 174 idle_helper_.StartIdlePeriod( | 189 idle_helper_.StartIdlePeriod( |
| 175 IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now, | 190 IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now, |
| 176 MainThreadOnly().estimated_next_frame_begin_); | 191 MainThreadOnly().estimated_next_frame_begin); |
| 177 MainThreadOnly().short_idle_period_duration_.InsertSample( | 192 MainThreadOnly().short_idle_period_duration.InsertSample( |
| 178 MainThreadOnly().estimated_next_frame_begin_ - now); | 193 MainThreadOnly().estimated_next_frame_begin - now); |
| 179 MainThreadOnly().expected_short_idle_period_duration_ = | 194 } else { |
| 180 MainThreadOnly().short_idle_period_duration_.Percentile( | 195 // There was no idle time :( |
| 181 kShortIdlePeriodDurationPercentile); | 196 MainThreadOnly().short_idle_period_duration.InsertSample(base::TimeDelta()); |
| 182 } | 197 } |
| 198 | |
| 199 MainThreadOnly().expected_short_idle_period_duration = | |
| 200 MainThreadOnly().short_idle_period_duration.Percentile( | |
| 201 kShortIdlePeriodDurationPercentile); | |
| 183 } | 202 } |
| 184 | 203 |
| 185 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() { | 204 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() { |
| 186 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 205 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 187 "RendererSchedulerImpl::BeginFrameNotExpectedSoon"); | 206 "RendererSchedulerImpl::BeginFrameNotExpectedSoon"); |
| 188 helper_.CheckOnValidThread(); | 207 helper_.CheckOnValidThread(); |
| 189 if (helper_.IsShutdown()) | 208 if (helper_.IsShutdown()) |
| 190 return; | 209 return; |
| 191 | 210 |
| 192 idle_helper_.EnableLongIdlePeriod(); | 211 idle_helper_.EnableLongIdlePeriod(); |
| 193 } | 212 } |
| 194 | 213 |
| 195 void RendererSchedulerImpl::OnRendererHidden() { | 214 void RendererSchedulerImpl::OnRendererHidden() { |
| 196 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 215 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 197 "RendererSchedulerImpl::OnRendererHidden"); | 216 "RendererSchedulerImpl::OnRendererHidden"); |
| 198 helper_.CheckOnValidThread(); | 217 helper_.CheckOnValidThread(); |
| 199 if (helper_.IsShutdown() || MainThreadOnly().renderer_hidden_) | 218 if (helper_.IsShutdown() || MainThreadOnly().renderer_hidden) |
| 200 return; | 219 return; |
| 201 | 220 |
| 202 idle_helper_.EnableLongIdlePeriod(); | 221 idle_helper_.EnableLongIdlePeriod(); |
| 203 | 222 |
| 204 // Ensure that we stop running idle tasks after a few seconds of being hidden. | 223 // Ensure that we stop running idle tasks after a few seconds of being hidden. |
| 205 end_renderer_hidden_idle_period_closure_.Cancel(); | 224 end_renderer_hidden_idle_period_closure_.Cancel(); |
| 206 base::TimeDelta end_idle_when_hidden_delay = | 225 base::TimeDelta end_idle_when_hidden_delay = |
| 207 base::TimeDelta::FromMilliseconds(kEndIdleWhenHiddenDelayMillis); | 226 base::TimeDelta::FromMilliseconds(kEndIdleWhenHiddenDelayMillis); |
| 208 control_task_runner_->PostDelayedTask( | 227 control_task_runner_->PostDelayedTask( |
| 209 FROM_HERE, end_renderer_hidden_idle_period_closure_.callback(), | 228 FROM_HERE, end_renderer_hidden_idle_period_closure_.callback(), |
| 210 end_idle_when_hidden_delay); | 229 end_idle_when_hidden_delay); |
| 211 MainThreadOnly().renderer_hidden_ = true; | 230 MainThreadOnly().renderer_hidden = true; |
| 212 | 231 |
| 213 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( | 232 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( |
| 214 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", | 233 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", |
| 215 this, AsValue(helper_.Now())); | 234 this, AsValue(helper_.Now())); |
| 216 } | 235 } |
| 217 | 236 |
| 218 void RendererSchedulerImpl::OnRendererVisible() { | 237 void RendererSchedulerImpl::OnRendererVisible() { |
| 219 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 238 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 220 "RendererSchedulerImpl::OnRendererVisible"); | 239 "RendererSchedulerImpl::OnRendererVisible"); |
| 221 helper_.CheckOnValidThread(); | 240 helper_.CheckOnValidThread(); |
| 222 if (helper_.IsShutdown() || !MainThreadOnly().renderer_hidden_) | 241 if (helper_.IsShutdown() || !MainThreadOnly().renderer_hidden) |
| 223 return; | 242 return; |
| 224 | 243 |
| 225 end_renderer_hidden_idle_period_closure_.Cancel(); | 244 end_renderer_hidden_idle_period_closure_.Cancel(); |
| 226 MainThreadOnly().renderer_hidden_ = false; | 245 MainThreadOnly().renderer_hidden = false; |
| 227 EndIdlePeriod(); | 246 EndIdlePeriod(); |
| 228 | 247 |
| 229 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( | 248 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( |
| 230 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", | 249 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", |
| 231 this, AsValue(helper_.Now())); | 250 this, AsValue(helper_.Now())); |
| 232 } | 251 } |
| 233 | 252 |
| 234 void RendererSchedulerImpl::EndIdlePeriod() { | 253 void RendererSchedulerImpl::EndIdlePeriod() { |
| 235 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 254 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 236 "RendererSchedulerImpl::EndIdlePeriod"); | 255 "RendererSchedulerImpl::EndIdlePeriod"); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 276 UpdateForInputEventOnCompositorThread( | 295 UpdateForInputEventOnCompositorThread( |
| 277 blink::WebInputEvent::Undefined, | 296 blink::WebInputEvent::Undefined, |
| 278 InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); | 297 InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); |
| 279 } | 298 } |
| 280 | 299 |
| 281 void RendererSchedulerImpl::UpdateForInputEventOnCompositorThread( | 300 void RendererSchedulerImpl::UpdateForInputEventOnCompositorThread( |
| 282 blink::WebInputEvent::Type type, | 301 blink::WebInputEvent::Type type, |
| 283 InputEventState input_event_state) { | 302 InputEventState input_event_state) { |
| 284 base::AutoLock lock(any_thread_lock_); | 303 base::AutoLock lock(any_thread_lock_); |
| 285 base::TimeTicks now = helper_.Now(); | 304 base::TimeTicks now = helper_.Now(); |
| 286 bool was_in_compositor_priority = InputSignalsSuggestCompositorPriority(now); | 305 |
| 306 // TODO(alexclarke): Move WebInputEventTraits where we can access it from here | |
| 307 // and record the name rather than the integer representation. | |
| 308 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | |
| 309 "RendererSchedulerImpl::UpdateForInputEventOnCompositorThread", | |
| 310 "type", static_cast<int>(type), "input_event_state", | |
| 311 InputEventStateToString(input_event_state)); | |
| 312 | |
| 313 bool gesture_already_in_progress = InputSignalsSuggestGestureInProgress(now); | |
| 287 bool was_awaiting_touch_start_response = | 314 bool was_awaiting_touch_start_response = |
| 288 AnyThread().awaiting_touch_start_response_; | 315 AnyThread().awaiting_touch_start_response; |
| 316 | |
| 317 AnyThread().user_model.DidHandleInputEventOnCompositorThread( | |
| 318 type, input_event_state, now); | |
| 289 | 319 |
| 290 if (type) { | 320 if (type) { |
| 291 switch (type) { | 321 switch (type) { |
| 292 case blink::WebInputEvent::TouchStart: | 322 case blink::WebInputEvent::TouchStart: |
| 293 AnyThread().awaiting_touch_start_response_ = true; | 323 AnyThread().awaiting_touch_start_response = true; |
| 294 break; | 324 break; |
| 295 | 325 |
| 296 case blink::WebInputEvent::TouchMove: | 326 case blink::WebInputEvent::TouchMove: |
| 297 // Observation of consecutive touchmoves is a strong signal that the | 327 // Observation of consecutive touchmoves is a strong signal that the |
| 298 // page is consuming the touch sequence, in which case touchstart | 328 // page is consuming the touch sequence, in which case touchstart |
| 299 // response prioritization is no longer necessary. Otherwise, the | 329 // response prioritization is no longer necessary. Otherwise, the |
| 300 // initial touchmove should preserve the touchstart response pending | 330 // initial touchmove should preserve the touchstart response pending |
| 301 // state. | 331 // state. |
| 302 if (AnyThread().awaiting_touch_start_response_ && | 332 if (AnyThread().awaiting_touch_start_response && |
| 303 CompositorThreadOnly().last_input_type_ == | 333 CompositorThreadOnly().last_input_type == |
| 304 blink::WebInputEvent::TouchMove) { | 334 blink::WebInputEvent::TouchMove) { |
| 305 AnyThread().awaiting_touch_start_response_ = false; | 335 AnyThread().awaiting_touch_start_response = false; |
| 306 } | 336 } |
| 307 break; | 337 break; |
| 308 | 338 |
| 309 case blink::WebInputEvent::Undefined: | 339 case blink::WebInputEvent::Undefined: |
| 310 case blink::WebInputEvent::GestureTapDown: | 340 case blink::WebInputEvent::GestureTapDown: |
| 311 case blink::WebInputEvent::GestureShowPress: | 341 case blink::WebInputEvent::GestureShowPress: |
| 312 case blink::WebInputEvent::GestureFlingCancel: | 342 case blink::WebInputEvent::GestureFlingCancel: |
| 313 case blink::WebInputEvent::GestureScrollEnd: | 343 case blink::WebInputEvent::GestureScrollEnd: |
| 314 // With no observable effect, these meta events do not indicate a | 344 // With no observable effect, these meta events do not indicate a |
| 315 // meaningful touchstart response and should not impact task priority. | 345 // meaningful touchstart response and should not impact task priority. |
| 316 break; | 346 break; |
| 317 | 347 |
| 318 default: | 348 default: |
| 319 AnyThread().awaiting_touch_start_response_ = false; | 349 AnyThread().awaiting_touch_start_response = false; |
| 320 break; | 350 break; |
| 321 } | 351 } |
| 322 } | 352 } |
| 323 | 353 |
| 324 // Avoid unnecessary policy updates, while in compositor priority. | 354 // Avoid unnecessary policy updates, while a gesture is already in progress. |
| 325 if (!was_in_compositor_priority || | 355 if (!gesture_already_in_progress || |
| 326 was_awaiting_touch_start_response != | 356 was_awaiting_touch_start_response != |
| 327 AnyThread().awaiting_touch_start_response_) { | 357 AnyThread().awaiting_touch_start_response) { |
| 328 EnsureUrgentPolicyUpdatePostedOnMainThread(FROM_HERE); | 358 EnsureUrgentPolicyUpdatePostedOnMainThread(FROM_HERE); |
| 329 } | 359 } |
| 330 AnyThread().last_input_signal_time_ = now; | 360 CompositorThreadOnly().last_input_type = type; |
| 331 CompositorThreadOnly().last_input_type_ = type; | |
| 332 | |
| 333 if (input_event_state == InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD) | |
| 334 AnyThread().pending_main_thread_input_event_count_++; | |
| 335 } | 361 } |
| 336 | 362 |
| 337 void RendererSchedulerImpl::DidHandleInputEventOnMainThread( | 363 void RendererSchedulerImpl::DidHandleInputEventOnMainThread( |
| 338 const blink::WebInputEvent& web_input_event) { | 364 const blink::WebInputEvent& web_input_event) { |
| 339 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 365 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 340 "RendererSchedulerImpl::DidHandleInputEventOnMainThread"); | 366 "RendererSchedulerImpl::DidHandleInputEventOnMainThread"); |
| 341 helper_.CheckOnValidThread(); | 367 helper_.CheckOnValidThread(); |
| 342 if (ShouldPrioritizeInputEvent(web_input_event)) { | 368 if (ShouldPrioritizeInputEvent(web_input_event)) { |
| 343 base::AutoLock lock(any_thread_lock_); | 369 base::AutoLock lock(any_thread_lock_); |
| 344 AnyThread().last_input_signal_time_ = helper_.Now(); | 370 AnyThread().user_model.DidHandleInputEventOnMainThread(helper_.Now()); |
| 345 if (AnyThread().pending_main_thread_input_event_count_ > 0) | |
| 346 AnyThread().pending_main_thread_input_event_count_--; | |
| 347 } | 371 } |
| 348 } | 372 } |
| 349 | 373 |
| 350 bool RendererSchedulerImpl::IsHighPriorityWorkAnticipated() { | 374 bool RendererSchedulerImpl::IsHighPriorityWorkAnticipated() { |
| 351 helper_.CheckOnValidThread(); | 375 helper_.CheckOnValidThread(); |
| 352 if (helper_.IsShutdown()) | 376 if (helper_.IsShutdown()) |
| 353 return false; | 377 return false; |
| 354 | 378 |
| 355 MaybeUpdatePolicy(); | 379 MaybeUpdatePolicy(); |
| 356 // The touchstart and compositor policies indicate a strong likelihood of | 380 // The touchstart and main-thread scrolling states indicate a strong |
| 357 // high-priority work in the near future. | 381 // likelihood of high-priority work in the near future. |
| 358 return MainThreadOnly().current_policy_ == Policy::COMPOSITOR_PRIORITY || | 382 UseCase use_case = MainThreadOnly().current_use_case; |
| 359 MainThreadOnly().current_policy_ == | 383 return MainThreadOnly().touchstart_expected_soon || |
| 360 Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY || | 384 use_case == UseCase::TOUCHSTART || |
| 361 MainThreadOnly().current_policy_ == Policy::TOUCHSTART_PRIORITY; | 385 use_case == UseCase::MAIN_THREAD_GESTURE; |
| 362 } | 386 } |
| 363 | 387 |
| 364 bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() { | 388 bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() { |
| 365 helper_.CheckOnValidThread(); | 389 helper_.CheckOnValidThread(); |
| 366 if (helper_.IsShutdown()) | 390 if (helper_.IsShutdown()) |
| 367 return false; | 391 return false; |
| 368 | 392 |
| 369 MaybeUpdatePolicy(); | 393 MaybeUpdatePolicy(); |
| 370 // We only yield if we are in the compositor priority and there is compositor | 394 // We only yield if there's a urgent task to be run now, or we are expecting |
| 371 // work outstanding, or if we are in the touchstart response priority. | 395 // one soon (touch start). |
| 372 // Note: even though the control queue is higher priority we don't yield for | 396 // Note: even though the control queue has the highest priority we don't yield |
| 373 // it since these tasks are not user-provided work and they are only intended | 397 // for it since these tasks are not user-provided work and they are only |
| 374 // to run before the next task, not interrupt the tasks. | 398 // intended to run before the next task, not interrupt the tasks. |
| 375 switch (MainThreadOnly().current_policy_) { | 399 switch (MainThreadOnly().current_use_case) { |
| 376 case Policy::NORMAL: | 400 case UseCase::NONE: |
| 377 return false; | 401 return MainThreadOnly().touchstart_expected_soon; |
| 378 | 402 |
| 379 case Policy::COMPOSITOR_PRIORITY: | 403 case UseCase::COMPOSITOR_GESTURE: |
| 380 return !compositor_task_runner_->IsQueueEmpty(); | 404 return MainThreadOnly().touchstart_expected_soon; |
| 381 | 405 |
| 382 case Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY: | 406 case UseCase::MAIN_THREAD_GESTURE: |
| 383 return !compositor_task_runner_->IsQueueEmpty(); | 407 return !compositor_task_runner_->IsQueueEmpty() || |
| 408 MainThreadOnly().touchstart_expected_soon; | |
| 384 | 409 |
| 385 case Policy::TOUCHSTART_PRIORITY: | 410 case UseCase::TOUCHSTART: |
| 386 return true; | 411 return true; |
| 387 | 412 |
| 388 case Policy::LOADING_PRIORITY: | 413 case UseCase::LOADING: |
| 389 return false; | 414 return false; |
| 390 | 415 |
| 391 default: | 416 default: |
| 392 NOTREACHED(); | 417 NOTREACHED(); |
| 393 return false; | 418 return false; |
| 394 } | 419 } |
| 395 } | 420 } |
| 396 | 421 |
| 397 base::TimeTicks RendererSchedulerImpl::CurrentIdleTaskDeadlineForTesting() | 422 base::TimeTicks RendererSchedulerImpl::CurrentIdleTaskDeadlineForTesting() |
| 398 const { | 423 const { |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 429 | 454 |
| 430 void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { | 455 void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { |
| 431 helper_.CheckOnValidThread(); | 456 helper_.CheckOnValidThread(); |
| 432 any_thread_lock_.AssertAcquired(); | 457 any_thread_lock_.AssertAcquired(); |
| 433 if (helper_.IsShutdown()) | 458 if (helper_.IsShutdown()) |
| 434 return; | 459 return; |
| 435 | 460 |
| 436 base::TimeTicks now = helper_.Now(); | 461 base::TimeTicks now = helper_.Now(); |
| 437 policy_may_need_update_.SetWhileLocked(false); | 462 policy_may_need_update_.SetWhileLocked(false); |
| 438 | 463 |
| 439 AnyThread().timer_tasks_seem_expensive_ = | 464 base::TimeDelta expected_use_case_duration; |
| 440 MainThreadOnly().expected_short_idle_period_duration_ > | 465 UseCase use_case = ComputeCurrentUseCase(now, &expected_use_case_duration); |
| 441 base::TimeDelta() && | 466 MainThreadOnly().current_use_case = use_case; |
| 442 MainThreadOnly().timer_task_cost_estimator_.expected_task_duration() > | |
| 443 MainThreadOnly().expected_short_idle_period_duration_; | |
| 444 | 467 |
| 445 base::TimeDelta new_policy_duration; | 468 // TODO(alexclarke): We should wire up a signal from blink to let us know if |
| 446 Policy new_policy = ComputeNewPolicy(now, &new_policy_duration); | 469 // there are any touch handlers registerd or not, and only call |
| 470 // TouchStartExpectedSoon if there is at least one. | |
| 471 base::TimeDelta scroll_expected_flag_valid_for_duration; | |
| 472 bool touchstart_expected_soon = AnyThread().user_model.TouchStartExpectedSoon( | |
| 473 use_case, now, &scroll_expected_flag_valid_for_duration); | |
| 474 MainThreadOnly().touchstart_expected_soon = touchstart_expected_soon; | |
| 475 | |
| 476 bool loading_tasks_seem_expensive = | |
| 477 MainThreadOnly().loading_task_cost_estimator.expected_task_duration() > | |
| 478 MainThreadOnly().expected_short_idle_period_duration; | |
| 479 MainThreadOnly().loading_tasks_seem_expensive = loading_tasks_seem_expensive; | |
| 480 | |
| 481 bool timer_tasks_seem_expensive = | |
| 482 MainThreadOnly().timer_task_cost_estimator.expected_task_duration() > | |
| 483 MainThreadOnly().expected_short_idle_period_duration; | |
| 484 MainThreadOnly().timer_tasks_seem_expensive = timer_tasks_seem_expensive; | |
| 485 | |
| 486 // The |new_policy_duration| is the minimum of |expected_use_case_duration| | |
| 487 // and |scroll_expected_flag_valid_for_duration| unless one is zero in which | |
| 488 // case we choose the other. | |
| 489 base::TimeDelta new_policy_duration = expected_use_case_duration; | |
| 490 if (new_policy_duration == base::TimeDelta() || | |
| 491 (scroll_expected_flag_valid_for_duration > base::TimeDelta() && | |
| 492 new_policy_duration > scroll_expected_flag_valid_for_duration)) { | |
| 493 new_policy_duration = scroll_expected_flag_valid_for_duration; | |
| 494 } | |
| 495 | |
| 447 if (new_policy_duration > base::TimeDelta()) { | 496 if (new_policy_duration > base::TimeDelta()) { |
| 448 MainThreadOnly().current_policy_expiration_time_ = | 497 MainThreadOnly().current_policy_expiration_time = now + new_policy_duration; |
| 449 now + new_policy_duration; | |
| 450 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, | 498 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, |
| 451 now); | 499 now); |
| 452 } else { | 500 } else { |
| 453 MainThreadOnly().current_policy_expiration_time_ = base::TimeTicks(); | 501 MainThreadOnly().current_policy_expiration_time = base::TimeTicks(); |
| 454 } | 502 } |
| 455 | 503 |
| 456 if (update_type == UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED && | 504 Policy new_policy; |
| 457 new_policy == MainThreadOnly().current_policy_) | 505 bool block_expensive_tasks = false; |
| 458 return; | 506 switch (use_case) { |
| 507 case UseCase::COMPOSITOR_GESTURE: | |
| 508 if (touchstart_expected_soon) | |
| 509 block_expensive_tasks = true; | |
| 510 else | |
| 511 new_policy.loading_queue_priority = TaskQueue::HIGH_PRIORITY; | |
| 512 break; | |
| 459 | 513 |
| 460 TaskQueue::QueuePriority compositor_queue_priority = | 514 case UseCase::MAIN_THREAD_GESTURE: |
| 461 TaskQueue::NORMAL_PRIORITY; | 515 new_policy.compositor_queue_priority = TaskQueue::HIGH_PRIORITY; |
| 462 TaskQueue::QueuePriority loading_queue_priority = TaskQueue::NORMAL_PRIORITY; | 516 block_expensive_tasks = true; |
| 463 TaskQueue::QueuePriority timer_queue_priority = | 517 break; |
| 464 MainThreadOnly().timer_queue_suspend_count_ != 0 | |
| 465 ? TaskQueue::DISABLED_PRIORITY | |
| 466 : TaskQueue::NORMAL_PRIORITY; | |
| 467 | 518 |
| 468 switch (new_policy) { | 519 case UseCase::TOUCHSTART: |
| 469 case Policy::COMPOSITOR_PRIORITY: | 520 new_policy.compositor_queue_priority = TaskQueue::HIGH_PRIORITY; |
| 470 compositor_queue_priority = TaskQueue::HIGH_PRIORITY; | 521 new_policy.loading_queue_priority = TaskQueue::DISABLED_PRIORITY; |
| 522 new_policy.timer_queue_priority = TaskQueue::DISABLED_PRIORITY; | |
| 471 break; | 523 break; |
| 472 case Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY: | 524 |
| 473 compositor_queue_priority = TaskQueue::HIGH_PRIORITY; | 525 case UseCase::NONE: |
| 474 loading_queue_priority = TaskQueue::DISABLED_PRIORITY; | 526 if (touchstart_expected_soon) |
| 475 timer_queue_priority = TaskQueue::DISABLED_PRIORITY; | 527 block_expensive_tasks = true; |
| 528 else | |
| 529 new_policy.loading_queue_priority = TaskQueue::HIGH_PRIORITY; | |
| 476 break; | 530 break; |
| 477 case Policy::TOUCHSTART_PRIORITY: | 531 |
| 478 compositor_queue_priority = TaskQueue::HIGH_PRIORITY; | 532 case UseCase::LOADING: |
| 479 loading_queue_priority = TaskQueue::DISABLED_PRIORITY; | 533 new_policy.loading_queue_priority = TaskQueue::HIGH_PRIORITY; |
| 480 timer_queue_priority = TaskQueue::DISABLED_PRIORITY; | |
| 481 break; | |
| 482 case Policy::NORMAL: | |
| 483 break; | |
| 484 case Policy::LOADING_PRIORITY: | |
| 485 // We prioritize loading tasks by deprioritizing compositing and timers. | |
| 486 compositor_queue_priority = TaskQueue::BEST_EFFORT_PRIORITY; | |
| 487 timer_queue_priority = TaskQueue::BEST_EFFORT_PRIORITY; | |
| 488 // TODO(alexclarke): See if we can safely mark the loading task queue as | |
| 489 // high priority. | |
| 490 break; | 534 break; |
| 491 default: | 535 default: |
| 492 NOTREACHED(); | 536 NOTREACHED(); |
| 493 } | 537 } |
| 494 | 538 |
| 495 compositor_task_runner_->SetQueuePriority(compositor_queue_priority); | 539 if (block_expensive_tasks && loading_tasks_seem_expensive) |
| 496 loading_task_runner_->SetQueuePriority(loading_queue_priority); | 540 new_policy.loading_queue_priority = TaskQueue::DISABLED_PRIORITY; |
| 497 timer_task_runner_->SetQueuePriority(timer_queue_priority); | |
| 498 | 541 |
| 499 DCHECK(compositor_task_runner_->IsQueueEnabled()); | 542 if ((block_expensive_tasks && timer_tasks_seem_expensive) || |
| 500 if (new_policy != Policy::TOUCHSTART_PRIORITY && | 543 MainThreadOnly().timer_queue_suspend_count != 0) |
| 501 new_policy != Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY) { | 544 new_policy.timer_queue_priority = TaskQueue::DISABLED_PRIORITY; |
| 502 DCHECK(loading_task_runner_->IsQueueEnabled()); | |
| 503 } | |
| 504 MainThreadOnly().current_policy_ = new_policy; | |
| 505 | 545 |
| 546 // Tracing is done before the early out check, because it's quite possible we | |
|
Sami
2015/08/27 15:15:59
Should we only do this if the use case or the poli
alex clarke (OOO till 29th)
2015/09/03 10:34:25
I actually think it was way too hard to figure out
| |
| 547 // will otherwise miss this information in traces. | |
| 506 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( | 548 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( |
| 507 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", | 549 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", |
| 508 this, AsValueLocked(now)); | 550 this, AsValueLocked(now)); |
| 551 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case", | |
| 552 use_case); | |
| 509 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 553 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 510 "RendererScheduler.policy", MainThreadOnly().current_policy_); | 554 "RendererScheduler.loading_tasks_seem_expensive", |
| 555 MainThreadOnly().loading_tasks_seem_expensive); | |
| 511 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 556 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 512 "RendererScheduler.timer_tasks_seem_expensive", | 557 "RendererScheduler.timer_tasks_seem_expensive", |
| 513 AnyThread().timer_tasks_seem_expensive_); | 558 MainThreadOnly().timer_tasks_seem_expensive); |
| 559 | |
| 560 if (update_type == UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED && | |
| 561 new_policy == MainThreadOnly().current_policy) { | |
| 562 return; | |
| 563 } | |
| 564 | |
| 565 compositor_task_runner_->SetQueuePriority( | |
| 566 new_policy.compositor_queue_priority); | |
| 567 loading_task_runner_->SetQueuePriority(new_policy.loading_queue_priority); | |
| 568 timer_task_runner_->SetQueuePriority(new_policy.timer_queue_priority); | |
| 569 | |
| 570 DCHECK(compositor_task_runner_->IsQueueEnabled()); | |
| 571 MainThreadOnly().current_policy = new_policy; | |
| 514 } | 572 } |
| 515 | 573 |
| 516 bool RendererSchedulerImpl::InputSignalsSuggestCompositorPriority( | 574 bool RendererSchedulerImpl::InputSignalsSuggestGestureInProgress( |
| 517 base::TimeTicks now) const { | 575 base::TimeTicks now) const { |
| 518 base::TimeDelta unused_policy_duration; | 576 base::TimeDelta unused_policy_duration; |
| 519 switch (ComputeNewPolicy(now, &unused_policy_duration)) { | 577 switch (ComputeCurrentUseCase(now, &unused_policy_duration)) { |
| 520 case Policy::TOUCHSTART_PRIORITY: | 578 case UseCase::COMPOSITOR_GESTURE: |
| 521 case Policy::COMPOSITOR_PRIORITY: | 579 case UseCase::MAIN_THREAD_GESTURE: |
| 522 case Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY: | 580 case UseCase::TOUCHSTART: |
| 523 return true; | 581 return true; |
| 524 | 582 |
| 525 default: | 583 default: |
| 526 break; | 584 break; |
| 527 } | 585 } |
| 528 return false; | 586 return false; |
| 529 } | 587 } |
| 530 | 588 |
| 531 RendererSchedulerImpl::Policy RendererSchedulerImpl::ComputeNewPolicy( | 589 RendererSchedulerImpl::UseCase RendererSchedulerImpl::ComputeCurrentUseCase( |
| 532 base::TimeTicks now, | 590 base::TimeTicks now, |
| 533 base::TimeDelta* new_policy_duration) const { | 591 base::TimeDelta* expected_use_case_duration) const { |
| 534 any_thread_lock_.AssertAcquired(); | 592 any_thread_lock_.AssertAcquired(); |
| 535 // Above all else we want to be responsive to user input. | 593 // Above all else we want to be responsive to user input. |
| 536 *new_policy_duration = TimeLeftInInputEscalatedPolicy(now); | 594 *expected_use_case_duration = |
| 537 if (*new_policy_duration > base::TimeDelta()) { | 595 AnyThread().user_model.TimeLeftInInputEscalatedPolicy(now); |
| 538 if (AnyThread().awaiting_touch_start_response_) | 596 if (*expected_use_case_duration > base::TimeDelta()) { |
| 539 return Policy::TOUCHSTART_PRIORITY; | 597 // Has scrolling been fully established? |
| 540 // If BeginMainFrame is on the critical path, we want to try and prevent | 598 if (AnyThread().awaiting_touch_start_response) { |
| 541 // timers and loading tasks from running if we think they might be | 599 // No, so arrange for compositor tasks to be run at the highest priority. |
| 542 // expensive. | 600 return UseCase::TOUCHSTART; |
| 601 } | |
| 602 // Yes scrolling has been established. If BeginMainFrame is on the critical | |
| 603 // path, compositor tasks need to be prioritized, otherwise now might be a | |
| 604 // good time to run potentially expensive work. | |
| 543 // TODO(skyostil): Consider removing in_idle_period_ and | 605 // TODO(skyostil): Consider removing in_idle_period_ and |
| 544 // HadAnIdlePeriodRecently() unless we need them here. | 606 // HadAnIdlePeriodRecently() unless we need them here. |
| 545 if (AnyThread().timer_tasks_seem_expensive_ && | 607 if (AnyThread().begin_main_frame_on_critical_path) { |
| 546 AnyThread().begin_main_frame_on_critical_path_) { | 608 return UseCase::MAIN_THREAD_GESTURE; |
| 547 return Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY; | 609 } else { |
| 610 return UseCase::COMPOSITOR_GESTURE; | |
| 548 } | 611 } |
| 549 return Policy::COMPOSITOR_PRIORITY; | |
| 550 } | 612 } |
| 551 | 613 |
| 552 if (AnyThread().rails_loading_priority_deadline_ > now) { | 614 if (AnyThread().rails_loading_priority_deadline > now) { |
| 553 *new_policy_duration = AnyThread().rails_loading_priority_deadline_ - now; | 615 *expected_use_case_duration = |
| 554 return Policy::LOADING_PRIORITY; | 616 AnyThread().rails_loading_priority_deadline - now; |
| 617 return UseCase::LOADING; | |
| 555 } | 618 } |
| 556 | 619 |
| 557 return Policy::NORMAL; | 620 return UseCase::NONE; |
| 558 } | |
| 559 | |
| 560 base::TimeDelta RendererSchedulerImpl::TimeLeftInInputEscalatedPolicy( | |
| 561 base::TimeTicks now) const { | |
| 562 any_thread_lock_.AssertAcquired(); | |
| 563 | |
| 564 base::TimeDelta escalated_priority_duration = | |
| 565 base::TimeDelta::FromMilliseconds(kPriorityEscalationAfterInputMillis); | |
| 566 | |
| 567 // If the input event is still pending, go into input prioritized policy | |
| 568 // and check again later. | |
| 569 if (AnyThread().pending_main_thread_input_event_count_ > 0) | |
| 570 return escalated_priority_duration; | |
| 571 if (AnyThread().last_input_signal_time_.is_null() || | |
| 572 AnyThread().last_input_signal_time_ + escalated_priority_duration < now) { | |
| 573 return base::TimeDelta(); | |
| 574 } | |
| 575 return AnyThread().last_input_signal_time_ + escalated_priority_duration - | |
| 576 now; | |
| 577 } | 621 } |
| 578 | 622 |
| 579 bool RendererSchedulerImpl::CanEnterLongIdlePeriod( | 623 bool RendererSchedulerImpl::CanEnterLongIdlePeriod( |
| 580 base::TimeTicks now, | 624 base::TimeTicks now, |
| 581 base::TimeDelta* next_long_idle_period_delay_out) { | 625 base::TimeDelta* next_long_idle_period_delay_out) { |
| 582 helper_.CheckOnValidThread(); | 626 helper_.CheckOnValidThread(); |
| 583 | 627 |
| 584 MaybeUpdatePolicy(); | 628 MaybeUpdatePolicy(); |
| 585 if (MainThreadOnly().current_policy_ == Policy::TOUCHSTART_PRIORITY) { | 629 if (MainThreadOnly().current_use_case == UseCase::TOUCHSTART) { |
| 586 // Don't start a long idle task in touch start priority, try again when | 630 // Don't start a long idle task in touch start priority, try again when |
| 587 // the policy is scheduled to end. | 631 // the policy is scheduled to end. |
| 588 *next_long_idle_period_delay_out = | 632 *next_long_idle_period_delay_out = |
| 589 MainThreadOnly().current_policy_expiration_time_ - now; | 633 MainThreadOnly().current_policy_expiration_time - now; |
| 590 return false; | 634 return false; |
| 591 } | 635 } |
| 592 return true; | 636 return true; |
| 593 } | 637 } |
| 594 | 638 |
| 595 SchedulerHelper* RendererSchedulerImpl::GetSchedulerHelperForTesting() { | 639 SchedulerHelper* RendererSchedulerImpl::GetSchedulerHelperForTesting() { |
| 596 return &helper_; | 640 return &helper_; |
| 597 } | 641 } |
| 598 | 642 |
| 599 void RendererSchedulerImpl::SuspendTimerQueue() { | 643 void RendererSchedulerImpl::SuspendTimerQueue() { |
| 600 MainThreadOnly().timer_queue_suspend_count_++; | 644 MainThreadOnly().timer_queue_suspend_count++; |
| 601 ForceUpdatePolicy(); | 645 ForceUpdatePolicy(); |
| 602 DCHECK(!timer_task_runner_->IsQueueEnabled()); | 646 DCHECK(!timer_task_runner_->IsQueueEnabled()); |
| 603 } | 647 } |
| 604 | 648 |
| 605 void RendererSchedulerImpl::ResumeTimerQueue() { | 649 void RendererSchedulerImpl::ResumeTimerQueue() { |
| 606 MainThreadOnly().timer_queue_suspend_count_--; | 650 MainThreadOnly().timer_queue_suspend_count--; |
| 607 DCHECK_GE(MainThreadOnly().timer_queue_suspend_count_, 0); | 651 DCHECK_GE(MainThreadOnly().timer_queue_suspend_count, 0); |
| 608 ForceUpdatePolicy(); | 652 ForceUpdatePolicy(); |
| 609 } | 653 } |
| 610 | 654 |
| 611 // static | |
| 612 const char* RendererSchedulerImpl::PolicyToString(Policy policy) { | |
| 613 switch (policy) { | |
| 614 case Policy::NORMAL: | |
| 615 return "normal"; | |
| 616 case Policy::COMPOSITOR_PRIORITY: | |
| 617 return "compositor"; | |
| 618 case Policy::COMPOSITOR_CRITICAL_PATH_PRIORITY: | |
| 619 return "compositor_critical_path"; | |
| 620 case Policy::TOUCHSTART_PRIORITY: | |
| 621 return "touchstart"; | |
| 622 case Policy::LOADING_PRIORITY: | |
| 623 return "loading"; | |
| 624 default: | |
| 625 NOTREACHED(); | |
| 626 return nullptr; | |
| 627 } | |
| 628 } | |
| 629 | |
| 630 scoped_refptr<base::trace_event::ConvertableToTraceFormat> | 655 scoped_refptr<base::trace_event::ConvertableToTraceFormat> |
| 631 RendererSchedulerImpl::AsValue(base::TimeTicks optional_now) const { | 656 RendererSchedulerImpl::AsValue(base::TimeTicks optional_now) const { |
| 632 base::AutoLock lock(any_thread_lock_); | 657 base::AutoLock lock(any_thread_lock_); |
| 633 return AsValueLocked(optional_now); | 658 return AsValueLocked(optional_now); |
| 634 } | 659 } |
| 635 | 660 |
| 636 scoped_refptr<base::trace_event::ConvertableToTraceFormat> | 661 scoped_refptr<base::trace_event::ConvertableToTraceFormat> |
| 637 RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const { | 662 RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const { |
| 638 helper_.CheckOnValidThread(); | 663 helper_.CheckOnValidThread(); |
| 639 any_thread_lock_.AssertAcquired(); | 664 any_thread_lock_.AssertAcquired(); |
| 640 | 665 |
| 641 if (optional_now.is_null()) | 666 if (optional_now.is_null()) |
| 642 optional_now = helper_.Now(); | 667 optional_now = helper_.Now(); |
| 643 scoped_refptr<base::trace_event::TracedValue> state = | 668 scoped_refptr<base::trace_event::TracedValue> state = |
| 644 new base::trace_event::TracedValue(); | 669 new base::trace_event::TracedValue(); |
| 645 | 670 |
| 646 state->SetString("current_policy", | 671 state->SetString("current_use_case", |
| 647 PolicyToString(MainThreadOnly().current_policy_)); | 672 UseCaseToString(MainThreadOnly().current_use_case)); |
| 673 state->SetBoolean("loading_tasks_seem_expensive", | |
| 674 MainThreadOnly().loading_tasks_seem_expensive); | |
| 675 state->SetBoolean("timer_tasks_seem_expensive", | |
| 676 MainThreadOnly().timer_tasks_seem_expensive); | |
| 677 state->SetBoolean("touchstart_expected_soon", | |
| 678 MainThreadOnly().touchstart_expected_soon); | |
| 648 state->SetString("idle_period_state", | 679 state->SetString("idle_period_state", |
| 649 IdleHelper::IdlePeriodStateToString( | 680 IdleHelper::IdlePeriodStateToString( |
| 650 idle_helper_.SchedulerIdlePeriodState())); | 681 idle_helper_.SchedulerIdlePeriodState())); |
| 651 state->SetBoolean("renderer_hidden", MainThreadOnly().renderer_hidden_); | 682 state->SetBoolean("renderer_hidden", MainThreadOnly().renderer_hidden); |
| 652 state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF()); | 683 state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF()); |
| 653 state->SetDouble("last_input_signal_time", | 684 state->SetDouble( |
| 654 (AnyThread().last_input_signal_time_ - base::TimeTicks()) | 685 "rails_loading_priority_deadline", |
| 686 (AnyThread().rails_loading_priority_deadline - base::TimeTicks()) | |
| 687 .InMillisecondsF()); | |
| 688 state->SetDouble("last_idle_period_end_time", | |
| 689 (AnyThread().last_idle_period_end_time - base::TimeTicks()) | |
| 655 .InMillisecondsF()); | 690 .InMillisecondsF()); |
| 656 state->SetDouble("rails_loading_priority_deadline", | 691 state->SetBoolean("awaiting_touch_start_response", |
| 657 (AnyThread().rails_loading_priority_deadline_ - | 692 AnyThread().awaiting_touch_start_response); |
| 658 base::TimeTicks()).InMillisecondsF()); | 693 state->SetBoolean("begin_main_frame_on_critical_path", |
| 659 state->SetDouble("last_idle_period_end_time", | 694 AnyThread().begin_main_frame_on_critical_path); |
| 660 (AnyThread().last_idle_period_end_time_ - base::TimeTicks()) | 695 state->SetDouble("expected_loading_task_duration", |
| 696 MainThreadOnly() | |
| 697 .loading_task_cost_estimator.expected_task_duration() | |
| 661 .InMillisecondsF()); | 698 .InMillisecondsF()); |
| 662 state->SetInteger("pending_main_thread_input_event_count", | |
| 663 AnyThread().pending_main_thread_input_event_count_); | |
| 664 state->SetBoolean("awaiting_touch_start_response", | |
| 665 AnyThread().awaiting_touch_start_response_); | |
| 666 state->SetBoolean("begin_main_frame_on_critical_path", | |
| 667 AnyThread().begin_main_frame_on_critical_path_); | |
| 668 state->SetDouble("expected_timer_task_duration", | 699 state->SetDouble("expected_timer_task_duration", |
| 669 MainThreadOnly() | 700 MainThreadOnly() |
| 670 .timer_task_cost_estimator_.expected_task_duration() | 701 .timer_task_cost_estimator.expected_task_duration() |
| 671 .InMillisecondsF()); | 702 .InMillisecondsF()); |
| 672 // TODO(skyostil): Can we somehow trace how accurate these estimates were? | 703 // TODO(skyostil): Can we somehow trace how accurate these estimates were? |
| 673 state->SetDouble( | 704 state->SetDouble( |
| 674 "expected_short_idle_period_duration", | 705 "expected_short_idle_period_duration", |
| 675 MainThreadOnly().expected_short_idle_period_duration_.InMillisecondsF()); | 706 MainThreadOnly().expected_short_idle_period_duration.InMillisecondsF()); |
| 676 state->SetBoolean("timer_tasks_seem_expensive", | 707 state->SetDouble( |
| 677 AnyThread().timer_tasks_seem_expensive_); | 708 "estimated_next_frame_begin", |
| 678 state->SetDouble("estimated_next_frame_begin", | 709 (MainThreadOnly().estimated_next_frame_begin - base::TimeTicks()) |
| 679 (MainThreadOnly().estimated_next_frame_begin_ - | 710 .InMillisecondsF()); |
| 680 base::TimeTicks()).InMillisecondsF()); | 711 state->SetBoolean("in_idle_period", AnyThread().in_idle_period); |
| 681 state->SetBoolean("in_idle_period", AnyThread().in_idle_period_); | 712 AnyThread().user_model.AsValueInto(state.get()); |
| 682 | 713 |
| 683 return state; | 714 return state; |
| 684 } | 715 } |
| 685 | 716 |
| 686 void RendererSchedulerImpl::OnIdlePeriodStarted() { | 717 void RendererSchedulerImpl::OnIdlePeriodStarted() { |
| 687 base::AutoLock lock(any_thread_lock_); | 718 base::AutoLock lock(any_thread_lock_); |
| 688 AnyThread().in_idle_period_ = true; | 719 AnyThread().in_idle_period = true; |
| 689 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); | 720 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); |
| 690 } | 721 } |
| 691 | 722 |
| 692 void RendererSchedulerImpl::OnIdlePeriodEnded() { | 723 void RendererSchedulerImpl::OnIdlePeriodEnded() { |
| 693 base::AutoLock lock(any_thread_lock_); | 724 base::AutoLock lock(any_thread_lock_); |
| 694 AnyThread().last_idle_period_end_time_ = helper_.Now(); | 725 AnyThread().last_idle_period_end_time = helper_.Now(); |
| 695 AnyThread().in_idle_period_ = false; | 726 AnyThread().in_idle_period = false; |
| 696 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); | 727 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); |
| 697 } | 728 } |
| 698 | 729 |
| 699 void RendererSchedulerImpl::OnPageLoadStarted() { | 730 void RendererSchedulerImpl::OnPageLoadStarted() { |
| 700 base::AutoLock lock(any_thread_lock_); | 731 base::AutoLock lock(any_thread_lock_); |
| 701 AnyThread().rails_loading_priority_deadline_ = | 732 AnyThread().rails_loading_priority_deadline = |
| 702 helper_.Now() + base::TimeDelta::FromMilliseconds( | 733 helper_.Now() + base::TimeDelta::FromMilliseconds( |
| 703 kRailsInitialLoadingPrioritizationMillis); | 734 kRailsInitialLoadingPrioritizationMillis); |
| 704 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); | 735 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); |
| 705 } | 736 } |
| 706 | 737 |
| 707 bool RendererSchedulerImpl::HadAnIdlePeriodRecently(base::TimeTicks now) const { | 738 bool RendererSchedulerImpl::HadAnIdlePeriodRecently(base::TimeTicks now) const { |
| 708 return (now - AnyThread().last_idle_period_end_time_) <= | 739 return (now - AnyThread().last_idle_period_end_time) <= |
| 709 base::TimeDelta::FromMilliseconds( | 740 base::TimeDelta::FromMilliseconds( |
| 710 kIdlePeriodStarvationThresholdMillis); | 741 kIdlePeriodStarvationThresholdMillis); |
| 711 } | 742 } |
| 712 | 743 |
| 713 } // namespace scheduler | 744 } // namespace scheduler |
| OLD | NEW |