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