Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/scheduler/renderer_scheduler_impl.h" | 5 #include "content/child/scheduler/scheduler_helper.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | |
| 8 #include "base/message_loop/message_loop_proxy.h" | |
| 9 #include "base/trace_event/trace_event.h" | 7 #include "base/trace_event/trace_event.h" |
| 10 #include "base/trace_event/trace_event_argument.h" | 8 #include "base/trace_event/trace_event_argument.h" |
| 11 #include "cc/output/begin_frame_args.h" | 9 #include "content/child/scheduler/nestable_single_thread_task_runner.h" |
| 12 #include "content/renderer/scheduler/nestable_single_thread_task_runner.h" | 10 #include "content/child/scheduler/prioritizing_task_queue_selector.h" |
| 13 #include "content/renderer/scheduler/renderer_task_queue_selector.h" | |
| 14 #include "ui/gfx/frame_time.h" | |
| 15 | 11 |
| 16 namespace content { | 12 namespace content { |
| 17 | 13 |
| 18 RendererSchedulerImpl::RendererSchedulerImpl( | 14 SchedulerHelper::SchedulerHelper( |
| 19 scoped_refptr<NestableSingleThreadTaskRunner> main_task_runner) | 15 scoped_refptr<NestableSingleThreadTaskRunner> main_task_runner, |
| 20 : renderer_task_queue_selector_(new RendererTaskQueueSelector()), | 16 SchedulerHelperDelegate* scheduler_helper_delegate, |
| 17 const char* tracing_category, | |
| 18 const char* disabled_by_default_tracing_category, | |
| 19 size_t total_task_queue_count) | |
| 20 : task_queue_selector_(new PrioritizingTaskQueueSelector()), | |
| 21 task_queue_manager_( | 21 task_queue_manager_( |
| 22 new TaskQueueManager(TASK_QUEUE_COUNT, | 22 new TaskQueueManager(total_task_queue_count, |
| 23 main_task_runner, | 23 main_task_runner, |
| 24 renderer_task_queue_selector_.get())), | 24 task_queue_selector_.get(), |
| 25 disabled_by_default_tracing_category)), | |
| 26 idle_period_state_(IdlePeriodState::NOT_IN_IDLE_PERIOD), | |
| 27 scheduler_helper_delegate_(scheduler_helper_delegate), | |
| 25 control_task_runner_( | 28 control_task_runner_( |
| 26 task_queue_manager_->TaskRunnerForQueue(CONTROL_TASK_QUEUE)), | 29 task_queue_manager_->TaskRunnerForQueue(QueueId::CONTROL_TASK_QUEUE)), |
| 27 control_task_after_wakeup_runner_(task_queue_manager_->TaskRunnerForQueue( | 30 control_task_after_wakeup_runner_(task_queue_manager_->TaskRunnerForQueue( |
| 28 CONTROL_TASK_AFTER_WAKEUP_QUEUE)), | 31 QueueId::CONTROL_TASK_AFTER_WAKEUP_QUEUE)), |
| 29 default_task_runner_( | 32 default_task_runner_( |
| 30 task_queue_manager_->TaskRunnerForQueue(DEFAULT_TASK_QUEUE)), | 33 task_queue_manager_->TaskRunnerForQueue(QueueId::DEFAULT_TASK_QUEUE)), |
| 31 compositor_task_runner_( | 34 tracing_category_(tracing_category), |
| 32 task_queue_manager_->TaskRunnerForQueue(COMPOSITOR_TASK_QUEUE)), | 35 disabled_by_default_tracing_category_( |
| 33 loading_task_runner_( | 36 disabled_by_default_tracing_category), |
| 34 task_queue_manager_->TaskRunnerForQueue(LOADING_TASK_QUEUE)), | |
| 35 delayed_update_policy_runner_( | |
| 36 base::Bind(&RendererSchedulerImpl::UpdatePolicy, | |
| 37 base::Unretained(this)), | |
| 38 control_task_runner_), | |
| 39 current_policy_(Policy::NORMAL), | |
| 40 idle_period_state_(IdlePeriodState::NOT_IN_IDLE_PERIOD), | |
| 41 last_input_type_(blink::WebInputEvent::Undefined), | |
| 42 input_stream_state_(InputStreamState::INACTIVE), | |
| 43 policy_may_need_update_(&incoming_signals_lock_), | |
| 44 weak_factory_(this) { | 37 weak_factory_(this) { |
| 45 weak_renderer_scheduler_ptr_ = weak_factory_.GetWeakPtr(); | 38 DCHECK_GE(total_task_queue_count, QueueId::TASK_QUEUE_COUNT); |
| 46 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, | 39 weak_scheduler_ptr_ = weak_factory_.GetWeakPtr(); |
| 47 weak_renderer_scheduler_ptr_); | 40 end_idle_period_closure_.Reset( |
| 48 end_idle_period_closure_.Reset(base::Bind( | 41 base::Bind(&SchedulerHelper::EndIdlePeriod, weak_scheduler_ptr_)); |
| 49 &RendererSchedulerImpl::EndIdlePeriod, weak_renderer_scheduler_ptr_)); | |
| 50 initiate_next_long_idle_period_closure_.Reset(base::Bind( | 42 initiate_next_long_idle_period_closure_.Reset(base::Bind( |
| 51 &RendererSchedulerImpl::InitiateLongIdlePeriod, | 43 &SchedulerHelper::InitiateLongIdlePeriod, weak_scheduler_ptr_)); |
| 52 weak_renderer_scheduler_ptr_)); | 44 initiate_next_long_idle_period_after_wakeup_closure_.Reset( |
| 53 initiate_next_long_idle_period_after_wakeup_closure_.Reset(base::Bind( | 45 base::Bind(&SchedulerHelper::InitiateLongIdlePeriodAfterWakeup, |
| 54 &RendererSchedulerImpl::InitiateLongIdlePeriodAfterWakeup, | 46 weak_scheduler_ptr_)); |
| 55 weak_renderer_scheduler_ptr_)); | |
| 56 | 47 |
| 57 idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner( | 48 idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner( |
| 58 task_queue_manager_->TaskRunnerForQueue(IDLE_TASK_QUEUE), | 49 task_queue_manager_->TaskRunnerForQueue(QueueId::IDLE_TASK_QUEUE), |
| 59 control_task_after_wakeup_runner_, | 50 control_task_after_wakeup_runner_, |
| 60 base::Bind(&RendererSchedulerImpl::CurrentIdleTaskDeadlineCallback, | 51 base::Bind(&SchedulerHelper::CurrentIdleTaskDeadlineCallback, |
| 61 weak_renderer_scheduler_ptr_))); | 52 weak_scheduler_ptr_), |
| 53 tracing_category)); | |
| 62 | 54 |
| 63 renderer_task_queue_selector_->SetQueuePriority( | 55 task_queue_selector_->SetQueuePriority( |
| 64 CONTROL_TASK_QUEUE, RendererTaskQueueSelector::CONTROL_PRIORITY); | 56 QueueId::CONTROL_TASK_QUEUE, |
| 57 PrioritizingTaskQueueSelector::CONTROL_PRIORITY); | |
| 65 | 58 |
| 66 renderer_task_queue_selector_->SetQueuePriority( | 59 task_queue_selector_->SetQueuePriority( |
| 67 CONTROL_TASK_AFTER_WAKEUP_QUEUE, | 60 QueueId::CONTROL_TASK_AFTER_WAKEUP_QUEUE, |
| 68 RendererTaskQueueSelector::CONTROL_PRIORITY); | 61 PrioritizingTaskQueueSelector::CONTROL_PRIORITY); |
| 69 task_queue_manager_->SetPumpPolicy( | 62 task_queue_manager_->SetPumpPolicy( |
| 70 CONTROL_TASK_AFTER_WAKEUP_QUEUE, | 63 QueueId::CONTROL_TASK_AFTER_WAKEUP_QUEUE, |
| 71 TaskQueueManager::PumpPolicy::AFTER_WAKEUP); | 64 TaskQueueManager::PumpPolicy::AFTER_WAKEUP); |
| 72 | 65 |
| 73 renderer_task_queue_selector_->DisableQueue(IDLE_TASK_QUEUE); | 66 task_queue_selector_->DisableQueue(QueueId::IDLE_TASK_QUEUE); |
| 74 task_queue_manager_->SetPumpPolicy(IDLE_TASK_QUEUE, | 67 task_queue_manager_->SetPumpPolicy(QueueId::IDLE_TASK_QUEUE, |
| 75 TaskQueueManager::PumpPolicy::MANUAL); | 68 TaskQueueManager::PumpPolicy::MANUAL); |
| 76 | 69 |
| 77 // TODO(skyostil): Increase this to 4 (crbug.com/444764). | 70 // TODO(skyostil): Increase this to 4 (crbug.com/444764). |
| 78 task_queue_manager_->SetWorkBatchSize(1); | 71 task_queue_manager_->SetWorkBatchSize(1); |
| 79 | |
| 80 for (size_t i = 0; i < TASK_QUEUE_COUNT; i++) { | |
| 81 task_queue_manager_->SetQueueName( | |
| 82 i, TaskQueueIdToString(static_cast<QueueId>(i))); | |
| 83 } | |
| 84 TRACE_EVENT_OBJECT_CREATED_WITH_ID( | |
| 85 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", | |
| 86 this); | |
| 87 } | 72 } |
| 88 | 73 |
| 89 RendererSchedulerImpl::~RendererSchedulerImpl() { | 74 SchedulerHelper::~SchedulerHelper() { |
| 90 TRACE_EVENT_OBJECT_DELETED_WITH_ID( | |
| 91 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", | |
| 92 this); | |
| 93 } | 75 } |
| 94 | 76 |
| 95 void RendererSchedulerImpl::Shutdown() { | 77 SchedulerHelper::SchedulerHelperDelegate::SchedulerHelperDelegate() { |
| 96 DCHECK(main_thread_checker_.CalledOnValidThread()); | 78 } |
| 79 | |
| 80 SchedulerHelper::SchedulerHelperDelegate::~SchedulerHelperDelegate() { | |
| 81 } | |
| 82 | |
| 83 void SchedulerHelper::Shutdown() { | |
| 84 CheckOnValidThread(); | |
| 97 task_queue_manager_.reset(); | 85 task_queue_manager_.reset(); |
| 98 } | 86 } |
| 99 | 87 |
| 100 scoped_refptr<base::SingleThreadTaskRunner> | 88 scoped_refptr<base::SingleThreadTaskRunner> |
| 101 RendererSchedulerImpl::DefaultTaskRunner() { | 89 SchedulerHelper::DefaultTaskRunner() { |
| 102 DCHECK(main_thread_checker_.CalledOnValidThread()); | 90 CheckOnValidThread(); |
| 103 return default_task_runner_; | 91 return default_task_runner_; |
| 104 } | 92 } |
| 105 | 93 |
| 106 scoped_refptr<base::SingleThreadTaskRunner> | 94 scoped_refptr<SingleThreadIdleTaskRunner> SchedulerHelper::IdleTaskRunner() { |
| 107 RendererSchedulerImpl::CompositorTaskRunner() { | 95 CheckOnValidThread(); |
| 108 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 109 return compositor_task_runner_; | |
| 110 } | |
| 111 | |
| 112 scoped_refptr<SingleThreadIdleTaskRunner> | |
| 113 RendererSchedulerImpl::IdleTaskRunner() { | |
| 114 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 115 return idle_task_runner_; | 96 return idle_task_runner_; |
| 116 } | 97 } |
| 117 | 98 |
| 118 scoped_refptr<base::SingleThreadTaskRunner> | 99 scoped_refptr<base::SingleThreadTaskRunner> |
| 119 RendererSchedulerImpl::LoadingTaskRunner() { | 100 SchedulerHelper::ControlTaskRunner() { |
| 120 DCHECK(main_thread_checker_.CalledOnValidThread()); | 101 return control_task_runner_; |
| 121 return loading_task_runner_; | |
| 122 } | 102 } |
| 123 | 103 |
| 124 void RendererSchedulerImpl::WillBeginFrame(const cc::BeginFrameArgs& args) { | 104 void SchedulerHelper::CurrentIdleTaskDeadlineCallback( |
| 125 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 105 base::TimeTicks* deadline_out) const { |
| 126 "RendererSchedulerImpl::WillBeginFrame", "args", args.AsValue()); | 106 CheckOnValidThread(); |
| 127 DCHECK(main_thread_checker_.CalledOnValidThread()); | 107 *deadline_out = estimated_end_of_idle_; |
| 128 if (!task_queue_manager_) | |
| 129 return; | |
| 130 | |
| 131 EndIdlePeriod(); | |
| 132 estimated_next_frame_begin_ = args.frame_time + args.interval; | |
| 133 // TODO(skyostil): Wire up real notification of input events processing | |
| 134 // instead of this approximation. | |
| 135 DidProcessInputEvent(args.frame_time); | |
| 136 } | 108 } |
| 137 | 109 |
| 138 void RendererSchedulerImpl::DidCommitFrameToCompositor() { | 110 SchedulerHelper::IdlePeriodState SchedulerHelper::ComputeNewLongIdlePeriodState( |
| 139 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | |
| 140 "RendererSchedulerImpl::DidCommitFrameToCompositor"); | |
| 141 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 142 if (!task_queue_manager_) | |
| 143 return; | |
| 144 | |
| 145 base::TimeTicks now(Now()); | |
| 146 if (now < estimated_next_frame_begin_) { | |
| 147 // TODO(rmcilroy): Consider reducing the idle period based on the runtime of | |
| 148 // the next pending delayed tasks (as currently done in for long idle times) | |
| 149 StartIdlePeriod(IdlePeriodState::IN_SHORT_IDLE_PERIOD); | |
| 150 control_task_runner_->PostDelayedTask(FROM_HERE, | |
| 151 end_idle_period_closure_.callback(), | |
| 152 estimated_next_frame_begin_ - now); | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() { | |
| 157 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | |
| 158 "RendererSchedulerImpl::BeginFrameNotExpectedSoon"); | |
| 159 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 160 if (!task_queue_manager_) | |
| 161 return; | |
| 162 | |
| 163 // TODO(skyostil): Wire up real notification of input events processing | |
| 164 // instead of this approximation. | |
| 165 DidProcessInputEvent(base::TimeTicks()); | |
| 166 | |
| 167 InitiateLongIdlePeriod(); | |
| 168 } | |
| 169 | |
| 170 void RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread( | |
| 171 const blink::WebInputEvent& web_input_event) { | |
| 172 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | |
| 173 "RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread"); | |
| 174 // We regard MouseMove events with the left mouse button down as a signal | |
| 175 // that the user is doing something requiring a smooth frame rate. | |
| 176 if (web_input_event.type == blink::WebInputEvent::MouseMove && | |
| 177 (web_input_event.modifiers & blink::WebInputEvent::LeftButtonDown)) { | |
| 178 UpdateForInputEvent(web_input_event.type); | |
| 179 return; | |
| 180 } | |
| 181 // Ignore all other mouse events because they probably don't signal user | |
| 182 // interaction needing a smooth framerate. NOTE isMouseEventType returns false | |
| 183 // for mouse wheel events, hence we regard them as user input. | |
| 184 // Ignore keyboard events because it doesn't really make sense to enter | |
| 185 // compositor priority for them. | |
| 186 if (blink::WebInputEvent::isMouseEventType(web_input_event.type) || | |
| 187 blink::WebInputEvent::isKeyboardEventType(web_input_event.type)) { | |
| 188 return; | |
| 189 } | |
| 190 UpdateForInputEvent(web_input_event.type); | |
| 191 } | |
| 192 | |
| 193 void RendererSchedulerImpl::DidAnimateForInputOnCompositorThread() { | |
| 194 UpdateForInputEvent(blink::WebInputEvent::Undefined); | |
| 195 } | |
| 196 | |
| 197 void RendererSchedulerImpl::UpdateForInputEvent( | |
| 198 blink::WebInputEvent::Type type) { | |
| 199 base::AutoLock lock(incoming_signals_lock_); | |
| 200 | |
| 201 InputStreamState new_input_stream_state = | |
| 202 ComputeNewInputStreamState(input_stream_state_, type, last_input_type_); | |
| 203 | |
| 204 if (input_stream_state_ != new_input_stream_state) { | |
| 205 // Update scheduler policy if we should start a new policy mode. | |
| 206 input_stream_state_ = new_input_stream_state; | |
| 207 EnsureUrgentPolicyUpdatePostedOnMainThread(FROM_HERE); | |
| 208 } | |
| 209 last_input_receipt_time_on_compositor_ = Now(); | |
| 210 // Clear the last known input processing time so that we know an input event | |
| 211 // is still queued up. This timestamp will be updated the next time the | |
| 212 // compositor commits or becomes quiescent. Note that this function is always | |
| 213 // called before the input event is processed either on the compositor or | |
| 214 // main threads. | |
| 215 last_input_process_time_on_main_ = base::TimeTicks(); | |
| 216 last_input_type_ = type; | |
| 217 } | |
| 218 | |
| 219 void RendererSchedulerImpl::DidProcessInputEvent( | |
| 220 base::TimeTicks begin_frame_time) { | |
| 221 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 222 base::AutoLock lock(incoming_signals_lock_); | |
| 223 if (input_stream_state_ == InputStreamState::INACTIVE) | |
| 224 return; | |
| 225 // Avoid marking input that arrived after the BeginFrame as processed. | |
| 226 if (!begin_frame_time.is_null() && | |
| 227 begin_frame_time < last_input_receipt_time_on_compositor_) | |
| 228 return; | |
| 229 last_input_process_time_on_main_ = Now(); | |
| 230 UpdatePolicyLocked(); | |
| 231 } | |
| 232 | |
| 233 bool RendererSchedulerImpl::IsHighPriorityWorkAnticipated() { | |
| 234 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 235 if (!task_queue_manager_) | |
| 236 return false; | |
| 237 | |
| 238 MaybeUpdatePolicy(); | |
| 239 // The touchstart and compositor policies indicate a strong likelihood of | |
| 240 // high-priority work in the near future. | |
| 241 return SchedulerPolicy() == Policy::COMPOSITOR_PRIORITY || | |
| 242 SchedulerPolicy() == Policy::TOUCHSTART_PRIORITY; | |
| 243 } | |
| 244 | |
| 245 bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() { | |
| 246 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 247 if (!task_queue_manager_) | |
| 248 return false; | |
| 249 | |
| 250 MaybeUpdatePolicy(); | |
| 251 // We only yield if we are in the compositor priority and there is compositor | |
| 252 // work outstanding, or if we are in the touchstart response priority. | |
| 253 // Note: even though the control queue is higher priority we don't yield for | |
| 254 // it since these tasks are not user-provided work and they are only intended | |
| 255 // to run before the next task, not interrupt the tasks. | |
| 256 switch (SchedulerPolicy()) { | |
| 257 case Policy::NORMAL: | |
| 258 return false; | |
| 259 | |
| 260 case Policy::COMPOSITOR_PRIORITY: | |
| 261 return !task_queue_manager_->IsQueueEmpty(COMPOSITOR_TASK_QUEUE); | |
| 262 | |
| 263 case Policy::TOUCHSTART_PRIORITY: | |
| 264 return true; | |
| 265 | |
| 266 default: | |
| 267 NOTREACHED(); | |
| 268 return false; | |
| 269 } | |
| 270 } | |
| 271 | |
| 272 void RendererSchedulerImpl::CurrentIdleTaskDeadlineCallback( | |
| 273 base::TimeTicks* deadline_out) const { | |
| 274 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 275 *deadline_out = estimated_next_frame_begin_; | |
| 276 } | |
| 277 | |
| 278 RendererSchedulerImpl::Policy RendererSchedulerImpl::SchedulerPolicy() const { | |
| 279 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 280 return current_policy_; | |
| 281 } | |
| 282 | |
| 283 void RendererSchedulerImpl::MaybeUpdatePolicy() { | |
| 284 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 285 if (policy_may_need_update_.IsSet()) { | |
| 286 UpdatePolicy(); | |
| 287 } | |
| 288 } | |
| 289 | |
| 290 void RendererSchedulerImpl::EnsureUrgentPolicyUpdatePostedOnMainThread( | |
| 291 const tracked_objects::Location& from_here) { | |
| 292 // TODO(scheduler-dev): Check that this method isn't called from the main | |
| 293 // thread. | |
| 294 incoming_signals_lock_.AssertAcquired(); | |
| 295 if (!policy_may_need_update_.IsSet()) { | |
| 296 policy_may_need_update_.SetWhileLocked(true); | |
| 297 control_task_runner_->PostTask(from_here, update_policy_closure_); | |
| 298 } | |
| 299 } | |
| 300 | |
| 301 void RendererSchedulerImpl::UpdatePolicy() { | |
| 302 base::AutoLock lock(incoming_signals_lock_); | |
| 303 UpdatePolicyLocked(); | |
| 304 } | |
| 305 | |
| 306 void RendererSchedulerImpl::UpdatePolicyLocked() { | |
| 307 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 308 incoming_signals_lock_.AssertAcquired(); | |
| 309 if (!task_queue_manager_) | |
| 310 return; | |
| 311 | |
| 312 base::TimeTicks now = Now(); | |
| 313 policy_may_need_update_.SetWhileLocked(false); | |
| 314 | |
| 315 base::TimeDelta new_policy_duration; | |
| 316 Policy new_policy = ComputeNewPolicy(now, &new_policy_duration); | |
| 317 if (new_policy_duration > base::TimeDelta()) { | |
| 318 current_policy_expiration_time_ = now + new_policy_duration; | |
| 319 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, | |
| 320 now); | |
| 321 } else { | |
| 322 current_policy_expiration_time_ = base::TimeTicks(); | |
| 323 } | |
| 324 | |
| 325 if (new_policy == current_policy_) | |
| 326 return; | |
| 327 | |
| 328 switch (new_policy) { | |
| 329 case Policy::COMPOSITOR_PRIORITY: | |
| 330 renderer_task_queue_selector_->SetQueuePriority( | |
| 331 COMPOSITOR_TASK_QUEUE, RendererTaskQueueSelector::HIGH_PRIORITY); | |
| 332 // TODO(scheduler-dev): Add a task priority between HIGH and BEST_EFFORT | |
| 333 // that still has some guarantee of running. | |
| 334 renderer_task_queue_selector_->SetQueuePriority( | |
| 335 LOADING_TASK_QUEUE, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY); | |
| 336 break; | |
| 337 case Policy::TOUCHSTART_PRIORITY: | |
| 338 renderer_task_queue_selector_->SetQueuePriority( | |
| 339 COMPOSITOR_TASK_QUEUE, RendererTaskQueueSelector::HIGH_PRIORITY); | |
| 340 renderer_task_queue_selector_->DisableQueue(LOADING_TASK_QUEUE); | |
| 341 break; | |
| 342 case Policy::NORMAL: | |
| 343 renderer_task_queue_selector_->SetQueuePriority( | |
| 344 COMPOSITOR_TASK_QUEUE, RendererTaskQueueSelector::NORMAL_PRIORITY); | |
| 345 renderer_task_queue_selector_->SetQueuePriority( | |
| 346 LOADING_TASK_QUEUE, RendererTaskQueueSelector::NORMAL_PRIORITY); | |
| 347 break; | |
| 348 } | |
| 349 DCHECK(renderer_task_queue_selector_->IsQueueEnabled(COMPOSITOR_TASK_QUEUE)); | |
| 350 if (new_policy != Policy::TOUCHSTART_PRIORITY) | |
| 351 DCHECK(renderer_task_queue_selector_->IsQueueEnabled(LOADING_TASK_QUEUE)); | |
| 352 | |
| 353 current_policy_ = new_policy; | |
| 354 | |
| 355 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( | |
| 356 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", | |
| 357 this, AsValueLocked(now)); | |
| 358 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | |
| 359 "RendererScheduler.policy", current_policy_); | |
| 360 } | |
| 361 | |
| 362 RendererSchedulerImpl::Policy RendererSchedulerImpl::ComputeNewPolicy( | |
| 363 base::TimeTicks now, | |
| 364 base::TimeDelta* new_policy_duration) { | |
| 365 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 366 incoming_signals_lock_.AssertAcquired(); | |
| 367 | |
| 368 Policy new_policy = Policy::NORMAL; | |
| 369 *new_policy_duration = base::TimeDelta(); | |
| 370 | |
| 371 if (input_stream_state_ == InputStreamState::INACTIVE) | |
| 372 return new_policy; | |
| 373 | |
| 374 Policy input_priority_policy = | |
| 375 input_stream_state_ == | |
| 376 InputStreamState::ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE | |
| 377 ? Policy::TOUCHSTART_PRIORITY | |
| 378 : Policy::COMPOSITOR_PRIORITY; | |
| 379 base::TimeDelta time_left_in_policy = TimeLeftInInputEscalatedPolicy(now); | |
| 380 if (time_left_in_policy > base::TimeDelta()) { | |
| 381 new_policy = input_priority_policy; | |
| 382 *new_policy_duration = time_left_in_policy; | |
| 383 } else { | |
| 384 // Reset |input_stream_state_| to ensure | |
| 385 // DidReceiveInputEventOnCompositorThread will post an UpdatePolicy task | |
| 386 // when it's next called. | |
| 387 input_stream_state_ = InputStreamState::INACTIVE; | |
| 388 } | |
| 389 return new_policy; | |
| 390 } | |
| 391 | |
| 392 base::TimeDelta RendererSchedulerImpl::TimeLeftInInputEscalatedPolicy( | |
| 393 base::TimeTicks now) const { | |
| 394 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 395 // TODO(rmcilroy): Change this to DCHECK_EQ when crbug.com/463869 is fixed. | |
| 396 DCHECK(input_stream_state_ != InputStreamState::INACTIVE); | |
| 397 incoming_signals_lock_.AssertAcquired(); | |
| 398 | |
| 399 base::TimeDelta escalated_priority_duration = | |
| 400 base::TimeDelta::FromMilliseconds(kPriorityEscalationAfterInputMillis); | |
| 401 base::TimeDelta time_left_in_policy; | |
| 402 if (last_input_process_time_on_main_.is_null() && | |
| 403 !task_queue_manager_->IsQueueEmpty(COMPOSITOR_TASK_QUEUE)) { | |
| 404 // If the input event is still pending, go into input prioritized policy | |
| 405 // and check again later. | |
| 406 time_left_in_policy = escalated_priority_duration; | |
| 407 } else { | |
| 408 // Otherwise make sure the input prioritization policy ends on time. | |
| 409 base::TimeTicks new_priority_end( | |
| 410 std::max(last_input_receipt_time_on_compositor_, | |
| 411 last_input_process_time_on_main_) + | |
| 412 escalated_priority_duration); | |
| 413 time_left_in_policy = new_priority_end - now; | |
| 414 } | |
| 415 return time_left_in_policy; | |
| 416 } | |
| 417 | |
| 418 RendererSchedulerImpl::IdlePeriodState | |
| 419 RendererSchedulerImpl::ComputeNewLongIdlePeriodState( | |
| 420 const base::TimeTicks now, | 111 const base::TimeTicks now, |
| 421 base::TimeDelta* next_long_idle_period_delay_out) { | 112 base::TimeDelta* next_long_idle_period_delay_out) { |
| 422 DCHECK(main_thread_checker_.CalledOnValidThread()); | 113 CheckOnValidThread(); |
| 423 | 114 |
| 424 MaybeUpdatePolicy(); | 115 if (!scheduler_helper_delegate_->CanEnterLongIdlePeriod( |
| 425 if (SchedulerPolicy() == Policy::TOUCHSTART_PRIORITY) { | 116 now, next_long_idle_period_delay_out)) { |
| 426 // Don't start a long idle task in touch start priority, try again when | |
| 427 // the policy is scheduled to end. | |
| 428 *next_long_idle_period_delay_out = current_policy_expiration_time_ - now; | |
| 429 return IdlePeriodState::NOT_IN_IDLE_PERIOD; | 117 return IdlePeriodState::NOT_IN_IDLE_PERIOD; |
| 430 } | 118 } |
| 431 | 119 |
| 432 base::TimeTicks next_pending_delayed_task = | 120 base::TimeTicks next_pending_delayed_task = |
| 433 task_queue_manager_->NextPendingDelayedTaskRunTime(); | 121 task_queue_manager_->NextPendingDelayedTaskRunTime(); |
| 434 base::TimeDelta max_long_idle_period_duration = | 122 base::TimeDelta max_long_idle_period_duration = |
| 435 base::TimeDelta::FromMilliseconds(kMaximumIdlePeriodMillis); | 123 base::TimeDelta::FromMilliseconds(kMaximumIdlePeriodMillis); |
| 436 base::TimeDelta long_idle_period_duration; | 124 base::TimeDelta long_idle_period_duration; |
| 437 if (next_pending_delayed_task.is_null()) { | 125 if (next_pending_delayed_task.is_null()) { |
| 438 long_idle_period_duration = max_long_idle_period_duration; | 126 long_idle_period_duration = max_long_idle_period_duration; |
| 439 } else { | 127 } else { |
| 440 // Limit the idle period duration to be before the next pending task. | 128 // Limit the idle period duration to be before the next pending task. |
| 441 long_idle_period_duration = std::min(next_pending_delayed_task - now, | 129 long_idle_period_duration = std::min(next_pending_delayed_task - now, |
| 442 max_long_idle_period_duration); | 130 max_long_idle_period_duration); |
| 443 } | 131 } |
| 444 | 132 |
| 445 if (long_idle_period_duration > base::TimeDelta()) { | 133 if (long_idle_period_duration > base::TimeDelta()) { |
| 446 *next_long_idle_period_delay_out = long_idle_period_duration; | 134 *next_long_idle_period_delay_out = long_idle_period_duration; |
| 447 return long_idle_period_duration == max_long_idle_period_duration | 135 return long_idle_period_duration == max_long_idle_period_duration |
| 448 ? IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE | 136 ? IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE |
| 449 : IdlePeriodState::IN_LONG_IDLE_PERIOD; | 137 : IdlePeriodState::IN_LONG_IDLE_PERIOD; |
| 450 } else { | 138 } else { |
| 451 // If we can't start the idle period yet then try again after wakeup. | 139 // If we can't start the idle period yet then try again after wakeup. |
| 452 *next_long_idle_period_delay_out = base::TimeDelta::FromMilliseconds( | 140 *next_long_idle_period_delay_out = base::TimeDelta::FromMilliseconds( |
| 453 kRetryInitiateLongIdlePeriodDelayMillis); | 141 kRetryInitiateLongIdlePeriodDelayMillis); |
| 454 return IdlePeriodState::NOT_IN_IDLE_PERIOD; | 142 return IdlePeriodState::NOT_IN_IDLE_PERIOD; |
| 455 } | 143 } |
| 456 } | 144 } |
| 457 | 145 |
| 458 void RendererSchedulerImpl::InitiateLongIdlePeriod() { | 146 void SchedulerHelper::InitiateLongIdlePeriod() { |
| 459 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 147 TRACE_EVENT0(disabled_by_default_tracing_category_, "InitiateLongIdlePeriod"); |
| 460 "InitiateLongIdlePeriod"); | 148 CheckOnValidThread(); |
| 461 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 462 | 149 |
| 463 // End any previous idle period. | 150 // End any previous idle period. |
| 464 EndIdlePeriod(); | 151 EndIdlePeriod(); |
| 465 | 152 |
| 466 base::TimeTicks now(Now()); | 153 base::TimeTicks now(Now()); |
| 467 base::TimeDelta next_long_idle_period_delay; | 154 base::TimeDelta next_long_idle_period_delay; |
| 468 IdlePeriodState new_idle_period_state = | 155 IdlePeriodState new_idle_period_state = |
| 469 ComputeNewLongIdlePeriodState(now, &next_long_idle_period_delay); | 156 ComputeNewLongIdlePeriodState(now, &next_long_idle_period_delay); |
| 470 if (IsInIdlePeriod(new_idle_period_state)) { | 157 if (IsInIdlePeriod(new_idle_period_state)) { |
| 471 estimated_next_frame_begin_ = now + next_long_idle_period_delay; | 158 StartIdlePeriod(new_idle_period_state, |
| 472 StartIdlePeriod(new_idle_period_state); | 159 now, |
| 160 now + next_long_idle_period_delay); | |
| 473 } | 161 } |
| 474 | 162 |
| 475 if (task_queue_manager_->IsQueueEmpty(IDLE_TASK_QUEUE)) { | 163 if (task_queue_manager_->IsQueueEmpty(QueueId::IDLE_TASK_QUEUE)) { |
| 476 // If there are no current idle tasks then post the call to initiate the | 164 // If there are no current idle tasks then post the call to initiate the |
| 477 // next idle for execution after wakeup (at which point after-wakeup idle | 165 // next idle for execution after wakeup (at which point after-wakeup idle |
| 478 // tasks might be eligible to run or more idle tasks posted). | 166 // tasks might be eligible to run or more idle tasks posted). |
| 479 control_task_after_wakeup_runner_->PostDelayedTask( | 167 control_task_after_wakeup_runner_->PostDelayedTask( |
| 480 FROM_HERE, | 168 FROM_HERE, |
| 481 initiate_next_long_idle_period_after_wakeup_closure_.callback(), | 169 initiate_next_long_idle_period_after_wakeup_closure_.callback(), |
| 482 next_long_idle_period_delay); | 170 next_long_idle_period_delay); |
| 483 } else { | 171 } else { |
| 484 // Otherwise post on the normal control task queue. | 172 // Otherwise post on the normal control task queue. |
| 485 control_task_runner_->PostDelayedTask( | 173 control_task_runner_->PostDelayedTask( |
| 486 FROM_HERE, | 174 FROM_HERE, initiate_next_long_idle_period_closure_.callback(), |
| 487 initiate_next_long_idle_period_closure_.callback(), | |
| 488 next_long_idle_period_delay); | 175 next_long_idle_period_delay); |
| 489 } | 176 } |
| 490 } | 177 } |
| 491 | 178 |
| 492 void RendererSchedulerImpl::InitiateLongIdlePeriodAfterWakeup() { | 179 void SchedulerHelper::InitiateLongIdlePeriodAfterWakeup() { |
| 493 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 180 TRACE_EVENT0(disabled_by_default_tracing_category_, |
| 494 "InitiateLongIdlePeriodAfterWakeup"); | 181 "InitiateLongIdlePeriodAfterWakeup"); |
| 495 DCHECK(main_thread_checker_.CalledOnValidThread()); | 182 CheckOnValidThread(); |
| 496 | 183 |
| 497 if (IsInIdlePeriod(idle_period_state_)) { | 184 if (IsInIdlePeriod(idle_period_state_)) { |
| 498 // Since we were asleep until now, end the async idle period trace event at | 185 // Since we were asleep until now, end the async idle period trace event at |
| 499 // the time when it would have ended were we awake. | 186 // the time when it would have ended were we awake. |
| 500 TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0( | 187 TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0( |
| 501 "renderer.scheduler", "RendererSchedulerIdlePeriod", this, | 188 tracing_category_, "RendererSchedulerIdlePeriod", this, |
| 502 std::min(estimated_next_frame_begin_, Now()).ToInternalValue()); | 189 std::min(estimated_end_of_idle_, Now()).ToInternalValue()); |
| 503 idle_period_state_ = IdlePeriodState::ENDING_LONG_IDLE_PERIOD; | 190 idle_period_state_ = IdlePeriodState::ENDING_LONG_IDLE_PERIOD; |
| 504 EndIdlePeriod(); | 191 EndIdlePeriod(); |
| 505 } | 192 } |
| 506 | 193 |
| 507 // Post a task to initiate the next long idle period rather than calling it | 194 // Post a task to initiate the next long idle period rather than calling it |
| 508 // directly to allow all pending PostIdleTaskAfterWakeup tasks to get enqueued | 195 // directly to allow all pending PostIdleTaskAfterWakeup tasks to get enqueued |
| 509 // on the idle task queue before the next idle period starts so they are | 196 // on the idle task queue before the next idle period starts so they are |
| 510 // eligible to be run during the new idle period. | 197 // eligible to be run during the new idle period. |
| 511 control_task_runner_->PostTask( | 198 control_task_runner_->PostTask( |
| 512 FROM_HERE, | 199 FROM_HERE, initiate_next_long_idle_period_closure_.callback()); |
| 513 initiate_next_long_idle_period_closure_.callback()); | |
| 514 } | 200 } |
| 515 | 201 |
| 516 void RendererSchedulerImpl::StartIdlePeriod(IdlePeriodState new_state) { | 202 void SchedulerHelper::StartIdlePeriod(IdlePeriodState new_state, |
| 517 TRACE_EVENT_ASYNC_BEGIN0("renderer.scheduler", | 203 base::TimeTicks now, |
| 518 "RendererSchedulerIdlePeriod", this); | 204 base::TimeTicks estimated_end_of_idle) { |
| 519 DCHECK(main_thread_checker_.CalledOnValidThread()); | 205 DCHECK_GT(estimated_end_of_idle, now); |
| 206 TRACE_EVENT_ASYNC_BEGIN0(tracing_category_, "RendererSchedulerIdlePeriod", | |
| 207 this); | |
| 208 CheckOnValidThread(); | |
| 520 DCHECK(IsInIdlePeriod(new_state)); | 209 DCHECK(IsInIdlePeriod(new_state)); |
| 521 | 210 |
| 522 renderer_task_queue_selector_->EnableQueue( | 211 task_queue_selector_->EnableQueue( |
| 523 IDLE_TASK_QUEUE, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY); | 212 QueueId::IDLE_TASK_QUEUE, |
| 524 task_queue_manager_->PumpQueue(IDLE_TASK_QUEUE); | 213 PrioritizingTaskQueueSelector::BEST_EFFORT_PRIORITY); |
| 214 task_queue_manager_->PumpQueue(QueueId::IDLE_TASK_QUEUE); | |
| 525 idle_period_state_ = new_state; | 215 idle_period_state_ = new_state; |
| 216 | |
| 217 estimated_end_of_idle_ = estimated_end_of_idle; | |
| 218 if (new_state == IdlePeriodState::IN_SHORT_IDLE_PERIOD) { | |
|
rmcilroy
2015/03/30 17:53:57
I don't like making this dependent on the state -
alex clarke (OOO till 29th)
2015/03/31 10:18:34
Done.
| |
| 219 control_task_runner_->PostDelayedTask( | |
| 220 FROM_HERE, | |
| 221 end_idle_period_closure_.callback(), | |
| 222 estimated_end_of_idle_ - now); | |
| 223 } | |
| 526 } | 224 } |
| 527 | 225 |
| 528 void RendererSchedulerImpl::EndIdlePeriod() { | 226 void SchedulerHelper::EndIdlePeriod() { |
| 529 DCHECK(main_thread_checker_.CalledOnValidThread()); | 227 CheckOnValidThread(); |
| 530 | 228 |
| 531 end_idle_period_closure_.Cancel(); | 229 end_idle_period_closure_.Cancel(); |
| 532 initiate_next_long_idle_period_closure_.Cancel(); | 230 initiate_next_long_idle_period_closure_.Cancel(); |
| 533 initiate_next_long_idle_period_after_wakeup_closure_.Cancel(); | 231 initiate_next_long_idle_period_after_wakeup_closure_.Cancel(); |
| 534 | 232 |
| 535 // If we weren't already within an idle period then early-out. | 233 // If we weren't already within an idle period then early-out. |
| 536 if (!IsInIdlePeriod(idle_period_state_)) | 234 if (!IsInIdlePeriod(idle_period_state_)) |
| 537 return; | 235 return; |
| 538 | 236 |
| 539 // If we are in the ENDING_LONG_IDLE_PERIOD state we have already logged the | 237 // If we are in the ENDING_LONG_IDLE_PERIOD state we have already logged the |
| 540 // trace event. | 238 // trace event. |
| 541 if (idle_period_state_ != IdlePeriodState::ENDING_LONG_IDLE_PERIOD) { | 239 if (idle_period_state_ != IdlePeriodState::ENDING_LONG_IDLE_PERIOD) { |
| 542 bool is_tracing; | 240 bool is_tracing; |
| 543 TRACE_EVENT_CATEGORY_GROUP_ENABLED("renderer.scheduler", &is_tracing); | 241 TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing); |
| 544 if (is_tracing && !estimated_next_frame_begin_.is_null() && | 242 if (is_tracing && !estimated_end_of_idle_.is_null() && |
| 545 base::TimeTicks::Now() > estimated_next_frame_begin_) { | 243 base::TimeTicks::Now() > estimated_end_of_idle_) { |
| 546 TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0( | 244 TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0( |
| 547 "renderer.scheduler", | 245 tracing_category_, "RendererSchedulerIdlePeriod", this, |
| 548 "RendererSchedulerIdlePeriod", | 246 "DeadlineOverrun", estimated_end_of_idle_.ToInternalValue()); |
| 549 this, | |
| 550 "DeadlineOverrun", | |
| 551 estimated_next_frame_begin_.ToInternalValue()); | |
| 552 } | 247 } |
| 553 TRACE_EVENT_ASYNC_END0("renderer.scheduler", | 248 TRACE_EVENT_ASYNC_END0(tracing_category_, "RendererSchedulerIdlePeriod", |
| 554 "RendererSchedulerIdlePeriod", this); | 249 this); |
| 555 } | 250 } |
| 556 | 251 |
| 557 renderer_task_queue_selector_->DisableQueue(IDLE_TASK_QUEUE); | 252 task_queue_selector_->DisableQueue(QueueId::IDLE_TASK_QUEUE); |
| 558 idle_period_state_ = IdlePeriodState::NOT_IN_IDLE_PERIOD; | 253 idle_period_state_ = IdlePeriodState::NOT_IN_IDLE_PERIOD; |
| 559 } | 254 } |
| 560 | 255 |
| 561 // static | 256 // static |
| 562 bool RendererSchedulerImpl::IsInIdlePeriod(IdlePeriodState state) { | 257 bool SchedulerHelper::IsInIdlePeriod(IdlePeriodState state) { |
| 563 return state != IdlePeriodState::NOT_IN_IDLE_PERIOD; | 258 return state != IdlePeriodState::NOT_IN_IDLE_PERIOD; |
| 564 } | 259 } |
| 565 | 260 |
| 566 bool RendererSchedulerImpl::CanExceedIdleDeadlineIfRequired() const { | 261 bool SchedulerHelper::CanExceedIdleDeadlineIfRequired() const { |
| 567 TRACE_EVENT_BEGIN0("renderer.scheduler", "CanExceedIdleDeadlineIfRequired"); | 262 TRACE_EVENT_BEGIN0(tracing_category_, "CanExceedIdleDeadlineIfRequired"); |
| 568 DCHECK(main_thread_checker_.CalledOnValidThread()); | 263 CheckOnValidThread(); |
| 569 return idle_period_state_ == | 264 return idle_period_state_ == |
| 570 IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE; | 265 IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE; |
| 571 } | 266 } |
| 572 | 267 |
| 573 void RendererSchedulerImpl::SetTimeSourceForTesting( | 268 void SchedulerHelper::SetTimeSourceForTesting( |
| 574 scoped_refptr<cc::TestNowSource> time_source) { | 269 scoped_refptr<cc::TestNowSource> time_source) { |
| 575 DCHECK(main_thread_checker_.CalledOnValidThread()); | 270 CheckOnValidThread(); |
| 576 time_source_ = time_source; | 271 time_source_ = time_source; |
| 577 task_queue_manager_->SetTimeSourceForTesting(time_source); | 272 task_queue_manager_->SetTimeSourceForTesting(time_source); |
| 578 } | 273 } |
| 579 | 274 |
| 580 void RendererSchedulerImpl::SetWorkBatchSizeForTesting(size_t work_batch_size) { | 275 void SchedulerHelper::SetWorkBatchSizeForTesting(size_t work_batch_size) { |
| 581 DCHECK(main_thread_checker_.CalledOnValidThread()); | 276 CheckOnValidThread(); |
| 582 task_queue_manager_->SetWorkBatchSize(work_batch_size); | 277 task_queue_manager_->SetWorkBatchSize(work_batch_size); |
| 583 } | 278 } |
| 584 | 279 |
| 585 base::TimeTicks RendererSchedulerImpl::Now() const { | 280 base::TimeTicks SchedulerHelper::Now() const { |
| 586 return UNLIKELY(time_source_) ? time_source_->Now() : base::TimeTicks::Now(); | 281 return UNLIKELY(time_source_) ? time_source_->Now() : base::TimeTicks::Now(); |
| 587 } | 282 } |
| 588 | 283 |
| 589 RendererSchedulerImpl::PollableNeedsUpdateFlag::PollableNeedsUpdateFlag( | 284 SchedulerHelper::IdlePeriodState |
| 590 base::Lock* write_lock_) | 285 SchedulerHelper::SchedulerIdlePeriodState() const { |
| 591 : flag_(false), write_lock_(write_lock_) { | 286 return idle_period_state_; |
| 592 } | 287 } |
| 593 | 288 |
| 594 RendererSchedulerImpl::PollableNeedsUpdateFlag::~PollableNeedsUpdateFlag() { | 289 PrioritizingTaskQueueSelector* |
| 290 SchedulerHelper::SchedulerTaskQueueSelector() const { | |
| 291 return task_queue_selector_.get(); | |
| 595 } | 292 } |
| 596 | 293 |
| 597 void RendererSchedulerImpl::PollableNeedsUpdateFlag::SetWhileLocked( | 294 TaskQueueManager* SchedulerHelper::SchedulerTaskQueueManager() const { |
| 598 bool value) { | 295 return task_queue_manager_.get(); |
| 599 write_lock_->AssertAcquired(); | |
| 600 base::subtle::Release_Store(&flag_, value); | |
| 601 } | |
| 602 | |
| 603 bool RendererSchedulerImpl::PollableNeedsUpdateFlag::IsSet() const { | |
| 604 return base::subtle::Acquire_Load(&flag_) != 0; | |
| 605 } | 296 } |
| 606 | 297 |
| 607 // static | 298 // static |
| 608 const char* RendererSchedulerImpl::TaskQueueIdToString(QueueId queue_id) { | 299 const char* SchedulerHelper::TaskQueueIdToString(QueueId queue_id) { |
| 609 switch (queue_id) { | 300 switch (queue_id) { |
| 610 case DEFAULT_TASK_QUEUE: | 301 case DEFAULT_TASK_QUEUE: |
| 611 return "default_tq"; | 302 return "default_tq"; |
| 612 case COMPOSITOR_TASK_QUEUE: | |
| 613 return "compositor_tq"; | |
| 614 case LOADING_TASK_QUEUE: | |
| 615 return "loading_tq"; | |
| 616 case IDLE_TASK_QUEUE: | 303 case IDLE_TASK_QUEUE: |
| 617 return "idle_tq"; | 304 return "idle_tq"; |
| 618 case CONTROL_TASK_QUEUE: | 305 case CONTROL_TASK_QUEUE: |
| 619 return "control_tq"; | 306 return "control_tq"; |
| 620 case CONTROL_TASK_AFTER_WAKEUP_QUEUE: | 307 case CONTROL_TASK_AFTER_WAKEUP_QUEUE: |
| 621 return "control_after_wakeup_tq"; | 308 return "control_after_wakeup_tq"; |
| 622 default: | 309 default: |
| 623 NOTREACHED(); | 310 NOTREACHED(); |
| 624 return nullptr; | 311 return nullptr; |
| 625 } | 312 } |
| 626 } | 313 } |
| 627 | 314 |
| 628 // static | 315 // static |
| 629 const char* RendererSchedulerImpl::PolicyToString(Policy policy) { | 316 const char* SchedulerHelper::IdlePeriodStateToString( |
| 630 switch (policy) { | |
| 631 case Policy::NORMAL: | |
| 632 return "normal"; | |
| 633 case Policy::COMPOSITOR_PRIORITY: | |
| 634 return "compositor"; | |
| 635 case Policy::TOUCHSTART_PRIORITY: | |
| 636 return "touchstart"; | |
| 637 default: | |
| 638 NOTREACHED(); | |
| 639 return nullptr; | |
| 640 } | |
| 641 } | |
| 642 | |
| 643 const char* RendererSchedulerImpl::InputStreamStateToString( | |
| 644 InputStreamState state) { | |
| 645 switch (state) { | |
| 646 case InputStreamState::INACTIVE: | |
| 647 return "inactive"; | |
| 648 case InputStreamState::ACTIVE: | |
| 649 return "active"; | |
| 650 case InputStreamState::ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE: | |
| 651 return "active_and_awaiting_touchstart_response"; | |
| 652 default: | |
| 653 NOTREACHED(); | |
| 654 return nullptr; | |
| 655 } | |
| 656 } | |
| 657 | |
| 658 const char* RendererSchedulerImpl::IdlePeriodStateToString( | |
| 659 IdlePeriodState idle_period_state) { | 317 IdlePeriodState idle_period_state) { |
| 660 switch (idle_period_state) { | 318 switch (idle_period_state) { |
| 661 case IdlePeriodState::NOT_IN_IDLE_PERIOD: | 319 case IdlePeriodState::NOT_IN_IDLE_PERIOD: |
| 662 return "not_in_idle_period"; | 320 return "not_in_idle_period"; |
| 663 case IdlePeriodState::IN_SHORT_IDLE_PERIOD: | 321 case IdlePeriodState::IN_SHORT_IDLE_PERIOD: |
| 664 return "in_short_idle_period"; | 322 return "in_short_idle_period"; |
| 665 case IdlePeriodState::IN_LONG_IDLE_PERIOD: | 323 case IdlePeriodState::IN_LONG_IDLE_PERIOD: |
| 666 return "in_long_idle_period"; | 324 return "in_long_idle_period"; |
| 667 case IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE: | 325 case IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE: |
| 668 return "in_long_idle_period_with_max_deadline"; | 326 return "in_long_idle_period_with_max_deadline"; |
| 669 case IdlePeriodState::ENDING_LONG_IDLE_PERIOD: | 327 case IdlePeriodState::ENDING_LONG_IDLE_PERIOD: |
| 670 return "ending_long_idle_period"; | 328 return "ending_long_idle_period"; |
| 671 default: | 329 default: |
| 672 NOTREACHED(); | 330 NOTREACHED(); |
| 673 return nullptr; | 331 return nullptr; |
| 674 } | 332 } |
| 675 } | 333 } |
| 676 | 334 |
| 677 scoped_refptr<base::trace_event::ConvertableToTraceFormat> | 335 void SchedulerHelper::AddTaskObserver( |
| 678 RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const { | |
| 679 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 680 incoming_signals_lock_.AssertAcquired(); | |
| 681 | |
| 682 if (optional_now.is_null()) | |
| 683 optional_now = Now(); | |
| 684 scoped_refptr<base::trace_event::TracedValue> state = | |
| 685 new base::trace_event::TracedValue(); | |
| 686 | |
| 687 state->SetString("current_policy", PolicyToString(current_policy_)); | |
| 688 state->SetString("idle_period_state", | |
| 689 IdlePeriodStateToString(idle_period_state_)); | |
| 690 state->SetString("input_stream_state", | |
| 691 InputStreamStateToString(input_stream_state_)); | |
| 692 state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF()); | |
| 693 state->SetDouble("last_input_receipt_time_on_compositor_", | |
| 694 (last_input_receipt_time_on_compositor_ - base::TimeTicks()) | |
| 695 .InMillisecondsF()); | |
| 696 state->SetDouble( | |
| 697 "last_input_process_time_on_main_", | |
| 698 (last_input_process_time_on_main_ - base::TimeTicks()).InMillisecondsF()); | |
| 699 state->SetDouble( | |
| 700 "estimated_next_frame_begin", | |
| 701 (estimated_next_frame_begin_ - base::TimeTicks()).InMillisecondsF()); | |
| 702 | |
| 703 return state; | |
| 704 } | |
| 705 | |
| 706 RendererSchedulerImpl::InputStreamState | |
| 707 RendererSchedulerImpl::ComputeNewInputStreamState( | |
| 708 InputStreamState current_state, | |
| 709 blink::WebInputEvent::Type new_input_type, | |
| 710 blink::WebInputEvent::Type last_input_type) { | |
| 711 switch (new_input_type) { | |
| 712 case blink::WebInputEvent::TouchStart: | |
| 713 return InputStreamState::ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE; | |
| 714 | |
| 715 case blink::WebInputEvent::TouchMove: | |
| 716 // Observation of consecutive touchmoves is a strong signal that the page | |
| 717 // is consuming the touch sequence, in which case touchstart response | |
| 718 // prioritization is no longer necessary. Otherwise, the initial touchmove | |
| 719 // should preserve the touchstart response pending state. | |
| 720 if (current_state == | |
| 721 InputStreamState::ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE) { | |
| 722 return last_input_type == blink::WebInputEvent::TouchMove | |
| 723 ? InputStreamState::ACTIVE | |
| 724 : InputStreamState::ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE; | |
| 725 } | |
| 726 break; | |
| 727 | |
| 728 case blink::WebInputEvent::GestureTapDown: | |
| 729 case blink::WebInputEvent::GestureShowPress: | |
| 730 case blink::WebInputEvent::GestureFlingCancel: | |
| 731 case blink::WebInputEvent::GestureScrollEnd: | |
| 732 // With no observable effect, these meta events do not indicate a | |
| 733 // meaningful touchstart response and should not impact task priority. | |
| 734 return current_state; | |
| 735 | |
| 736 default: | |
| 737 break; | |
| 738 } | |
| 739 return InputStreamState::ACTIVE; | |
| 740 } | |
| 741 | |
| 742 void RendererSchedulerImpl::AddTaskObserver( | |
| 743 base::MessageLoop::TaskObserver* task_observer) { | 336 base::MessageLoop::TaskObserver* task_observer) { |
| 744 DCHECK(main_thread_checker_.CalledOnValidThread()); | 337 CheckOnValidThread(); |
| 745 if (task_queue_manager_) | 338 if (task_queue_manager_) |
| 746 task_queue_manager_->AddTaskObserver(task_observer); | 339 task_queue_manager_->AddTaskObserver(task_observer); |
| 747 } | 340 } |
| 748 | 341 |
| 749 void RendererSchedulerImpl::RemoveTaskObserver( | 342 void SchedulerHelper::RemoveTaskObserver( |
| 750 base::MessageLoop::TaskObserver* task_observer) { | 343 base::MessageLoop::TaskObserver* task_observer) { |
| 751 DCHECK(main_thread_checker_.CalledOnValidThread()); | 344 CheckOnValidThread(); |
| 752 if (task_queue_manager_) | 345 if (task_queue_manager_) |
| 753 task_queue_manager_->RemoveTaskObserver(task_observer); | 346 task_queue_manager_->RemoveTaskObserver(task_observer); |
| 754 } | 347 } |
| 755 | 348 |
| 756 } // namespace content | 349 } // namespace content |
| OLD | NEW |