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
3 // found in the LICENSE file.
5 #include "content/renderer/scheduler/renderer_scheduler_impl.h"
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "base/trace_event/trace_event.h"
10 #include "base/trace_event/trace_event_argument.h"
11 #include "cc/output/begin_frame_args.h"
12 #include "content/renderer/scheduler/nestable_single_thread_task_runner.h"
13 #include "content/renderer/scheduler/renderer_task_queue_selector.h"
14 #include "ui/gfx/frame_time.h"
18 RendererSchedulerImpl::RendererSchedulerImpl(
19 scoped_refptr
<NestableSingleThreadTaskRunner
> main_task_runner
)
20 : renderer_task_queue_selector_(new RendererTaskQueueSelector()),
22 new TaskQueueManager(TASK_QUEUE_COUNT
,
24 renderer_task_queue_selector_
.get())),
26 task_queue_manager_
->TaskRunnerForQueue(CONTROL_TASK_QUEUE
)),
27 control_task_after_wakeup_runner_(task_queue_manager_
->TaskRunnerForQueue(
28 CONTROL_TASK_AFTER_WAKEUP_QUEUE
)),
30 task_queue_manager_
->TaskRunnerForQueue(DEFAULT_TASK_QUEUE
)),
31 compositor_task_runner_(
32 task_queue_manager_
->TaskRunnerForQueue(COMPOSITOR_TASK_QUEUE
)),
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_
),
45 weak_renderer_scheduler_ptr_
= weak_factory_
.GetWeakPtr();
46 update_policy_closure_
= base::Bind(&RendererSchedulerImpl::UpdatePolicy
,
47 weak_renderer_scheduler_ptr_
);
48 end_idle_period_closure_
.Reset(base::Bind(
49 &RendererSchedulerImpl::EndIdlePeriod
, weak_renderer_scheduler_ptr_
));
50 initiate_next_long_idle_period_closure_
.Reset(base::Bind(
51 &RendererSchedulerImpl::InitiateLongIdlePeriod
,
52 weak_renderer_scheduler_ptr_
));
53 initiate_next_long_idle_period_after_wakeup_closure_
.Reset(base::Bind(
54 &RendererSchedulerImpl::InitiateLongIdlePeriodAfterWakeup
,
55 weak_renderer_scheduler_ptr_
));
57 idle_task_runner_
= make_scoped_refptr(new SingleThreadIdleTaskRunner(
58 task_queue_manager_
->TaskRunnerForQueue(IDLE_TASK_QUEUE
),
59 control_task_after_wakeup_runner_
,
60 base::Bind(&RendererSchedulerImpl::CurrentIdleTaskDeadlineCallback
,
61 weak_renderer_scheduler_ptr_
)));
63 renderer_task_queue_selector_
->SetQueuePriority(
64 CONTROL_TASK_QUEUE
, RendererTaskQueueSelector::CONTROL_PRIORITY
);
66 renderer_task_queue_selector_
->SetQueuePriority(
67 CONTROL_TASK_AFTER_WAKEUP_QUEUE
,
68 RendererTaskQueueSelector::CONTROL_PRIORITY
);
69 task_queue_manager_
->SetPumpPolicy(
70 CONTROL_TASK_AFTER_WAKEUP_QUEUE
,
71 TaskQueueManager::PumpPolicy::AFTER_WAKEUP
);
73 renderer_task_queue_selector_
->DisableQueue(IDLE_TASK_QUEUE
);
74 task_queue_manager_
->SetPumpPolicy(IDLE_TASK_QUEUE
,
75 TaskQueueManager::PumpPolicy::MANUAL
);
77 // TODO(skyostil): Increase this to 4 (crbug.com/444764).
78 task_queue_manager_
->SetWorkBatchSize(1);
80 for (size_t i
= 0; i
< TASK_QUEUE_COUNT
; i
++) {
81 task_queue_manager_
->SetQueueName(
82 i
, TaskQueueIdToString(static_cast<QueueId
>(i
)));
84 TRACE_EVENT_OBJECT_CREATED_WITH_ID(
85 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
89 RendererSchedulerImpl::~RendererSchedulerImpl() {
90 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
91 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
95 void RendererSchedulerImpl::Shutdown() {
96 DCHECK(main_thread_checker_
.CalledOnValidThread());
97 task_queue_manager_
.reset();
100 scoped_refptr
<base::SingleThreadTaskRunner
>
101 RendererSchedulerImpl::DefaultTaskRunner() {
102 DCHECK(main_thread_checker_
.CalledOnValidThread());
103 return default_task_runner_
;
106 scoped_refptr
<base::SingleThreadTaskRunner
>
107 RendererSchedulerImpl::CompositorTaskRunner() {
108 DCHECK(main_thread_checker_
.CalledOnValidThread());
109 return compositor_task_runner_
;
112 scoped_refptr
<SingleThreadIdleTaskRunner
>
113 RendererSchedulerImpl::IdleTaskRunner() {
114 DCHECK(main_thread_checker_
.CalledOnValidThread());
115 return idle_task_runner_
;
118 scoped_refptr
<base::SingleThreadTaskRunner
>
119 RendererSchedulerImpl::LoadingTaskRunner() {
120 DCHECK(main_thread_checker_
.CalledOnValidThread());
121 return loading_task_runner_
;
124 void RendererSchedulerImpl::WillBeginFrame(const cc::BeginFrameArgs
& args
) {
125 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
126 "RendererSchedulerImpl::WillBeginFrame", "args", args
.AsValue());
127 DCHECK(main_thread_checker_
.CalledOnValidThread());
128 if (!task_queue_manager_
)
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
);
138 void RendererSchedulerImpl::DidCommitFrameToCompositor() {
139 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
140 "RendererSchedulerImpl::DidCommitFrameToCompositor");
141 DCHECK(main_thread_checker_
.CalledOnValidThread());
142 if (!task_queue_manager_
)
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
);
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_
)
163 // TODO(skyostil): Wire up real notification of input events processing
164 // instead of this approximation.
165 DidProcessInputEvent(base::TimeTicks());
167 InitiateLongIdlePeriod();
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
);
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
)) {
190 UpdateForInputEvent(web_input_event
.type
);
193 void RendererSchedulerImpl::DidAnimateForInputOnCompositorThread() {
194 UpdateForInputEvent(blink::WebInputEvent::Undefined
);
197 void RendererSchedulerImpl::UpdateForInputEvent(
198 blink::WebInputEvent::Type type
) {
199 base::AutoLock
lock(incoming_signals_lock_
);
201 InputStreamState new_input_stream_state
=
202 ComputeNewInputStreamState(input_stream_state_
, type
, last_input_type_
);
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
);
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
215 last_input_process_time_on_main_
= base::TimeTicks();
216 last_input_type_
= type
;
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
)
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_
)
229 last_input_process_time_on_main_
= Now();
230 UpdatePolicyLocked();
233 bool RendererSchedulerImpl::IsHighPriorityWorkAnticipated() {
234 DCHECK(main_thread_checker_
.CalledOnValidThread());
235 if (!task_queue_manager_
)
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
;
245 bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() {
246 DCHECK(main_thread_checker_
.CalledOnValidThread());
247 if (!task_queue_manager_
)
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()) {
260 case Policy::COMPOSITOR_PRIORITY
:
261 return !task_queue_manager_
->IsQueueEmpty(COMPOSITOR_TASK_QUEUE
);
263 case Policy::TOUCHSTART_PRIORITY
:
272 void RendererSchedulerImpl::CurrentIdleTaskDeadlineCallback(
273 base::TimeTicks
* deadline_out
) const {
274 DCHECK(main_thread_checker_
.CalledOnValidThread());
275 *deadline_out
= estimated_next_frame_begin_
;
278 RendererSchedulerImpl::Policy
RendererSchedulerImpl::SchedulerPolicy() const {
279 DCHECK(main_thread_checker_
.CalledOnValidThread());
280 return current_policy_
;
283 void RendererSchedulerImpl::MaybeUpdatePolicy() {
284 DCHECK(main_thread_checker_
.CalledOnValidThread());
285 if (policy_may_need_update_
.IsSet()) {
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
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_
);
301 void RendererSchedulerImpl::UpdatePolicy() {
302 base::AutoLock
lock(incoming_signals_lock_
);
303 UpdatePolicyLocked();
306 void RendererSchedulerImpl::UpdatePolicyLocked() {
307 DCHECK(main_thread_checker_
.CalledOnValidThread());
308 incoming_signals_lock_
.AssertAcquired();
309 if (!task_queue_manager_
)
312 base::TimeTicks now
= Now();
313 policy_may_need_update_
.SetWhileLocked(false);
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
,
322 current_policy_expiration_time_
= base::TimeTicks();
325 if (new_policy
== current_policy_
)
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
);
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
);
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
);
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
));
353 current_policy_
= new_policy
;
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_
);
362 RendererSchedulerImpl::Policy
RendererSchedulerImpl::ComputeNewPolicy(
364 base::TimeDelta
* new_policy_duration
) {
365 DCHECK(main_thread_checker_
.CalledOnValidThread());
366 incoming_signals_lock_
.AssertAcquired();
368 Policy new_policy
= Policy::NORMAL
;
369 *new_policy_duration
= base::TimeDelta();
371 if (input_stream_state_
== InputStreamState::INACTIVE
)
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
;
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
;
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();
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
;
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
;
415 return time_left_in_policy
;
418 RendererSchedulerImpl::IdlePeriodState
419 RendererSchedulerImpl::ComputeNewLongIdlePeriodState(
420 const base::TimeTicks now
,
421 base::TimeDelta
* next_long_idle_period_delay_out
) {
422 DCHECK(main_thread_checker_
.CalledOnValidThread());
425 if (SchedulerPolicy() == Policy::TOUCHSTART_PRIORITY
) {
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
;
432 base::TimeTicks next_pending_delayed_task
=
433 task_queue_manager_
->NextPendingDelayedTaskRunTime();
434 base::TimeDelta max_long_idle_period_duration
=
435 base::TimeDelta::FromMilliseconds(kMaximumIdlePeriodMillis
);
436 base::TimeDelta long_idle_period_duration
;
437 if (next_pending_delayed_task
.is_null()) {
438 long_idle_period_duration
= max_long_idle_period_duration
;
440 // Limit the idle period duration to be before the next pending task.
441 long_idle_period_duration
= std::min(next_pending_delayed_task
- now
,
442 max_long_idle_period_duration
);
445 if (long_idle_period_duration
> base::TimeDelta()) {
446 *next_long_idle_period_delay_out
= long_idle_period_duration
;
447 return long_idle_period_duration
== max_long_idle_period_duration
448 ? IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE
449 : IdlePeriodState::IN_LONG_IDLE_PERIOD
;
451 // If we can't start the idle period yet then try again after wakeup.
452 *next_long_idle_period_delay_out
= base::TimeDelta::FromMilliseconds(
453 kRetryInitiateLongIdlePeriodDelayMillis
);
454 return IdlePeriodState::NOT_IN_IDLE_PERIOD
;
458 void RendererSchedulerImpl::InitiateLongIdlePeriod() {
459 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
460 "InitiateLongIdlePeriod");
461 DCHECK(main_thread_checker_
.CalledOnValidThread());
463 // End any previous idle period.
466 base::TimeTicks
now(Now());
467 base::TimeDelta next_long_idle_period_delay
;
468 IdlePeriodState new_idle_period_state
=
469 ComputeNewLongIdlePeriodState(now
, &next_long_idle_period_delay
);
470 if (IsInIdlePeriod(new_idle_period_state
)) {
471 estimated_next_frame_begin_
= now
+ next_long_idle_period_delay
;
472 StartIdlePeriod(new_idle_period_state
);
475 if (task_queue_manager_
->IsQueueEmpty(IDLE_TASK_QUEUE
)) {
476 // 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
478 // tasks might be eligible to run or more idle tasks posted).
479 control_task_after_wakeup_runner_
->PostDelayedTask(
481 initiate_next_long_idle_period_after_wakeup_closure_
.callback(),
482 next_long_idle_period_delay
);
484 // Otherwise post on the normal control task queue.
485 control_task_runner_
->PostDelayedTask(
487 initiate_next_long_idle_period_closure_
.callback(),
488 next_long_idle_period_delay
);
492 void RendererSchedulerImpl::InitiateLongIdlePeriodAfterWakeup() {
493 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
494 "InitiateLongIdlePeriodAfterWakeup");
495 DCHECK(main_thread_checker_
.CalledOnValidThread());
497 if (IsInIdlePeriod(idle_period_state_
)) {
498 // 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.
500 TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(
501 "renderer.scheduler", "RendererSchedulerIdlePeriod", this,
502 std::min(estimated_next_frame_begin_
, Now()).ToInternalValue());
503 idle_period_state_
= IdlePeriodState::ENDING_LONG_IDLE_PERIOD
;
507 // 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
509 // on the idle task queue before the next idle period starts so they are
510 // eligible to be run during the new idle period.
511 control_task_runner_
->PostTask(
513 initiate_next_long_idle_period_closure_
.callback());
516 void RendererSchedulerImpl::StartIdlePeriod(IdlePeriodState new_state
) {
517 TRACE_EVENT_ASYNC_BEGIN0("renderer.scheduler",
518 "RendererSchedulerIdlePeriod", this);
519 DCHECK(main_thread_checker_
.CalledOnValidThread());
520 DCHECK(IsInIdlePeriod(new_state
));
522 renderer_task_queue_selector_
->EnableQueue(
523 IDLE_TASK_QUEUE
, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY
);
524 task_queue_manager_
->PumpQueue(IDLE_TASK_QUEUE
);
525 idle_period_state_
= new_state
;
528 void RendererSchedulerImpl::EndIdlePeriod() {
529 DCHECK(main_thread_checker_
.CalledOnValidThread());
531 end_idle_period_closure_
.Cancel();
532 initiate_next_long_idle_period_closure_
.Cancel();
533 initiate_next_long_idle_period_after_wakeup_closure_
.Cancel();
535 // If we weren't already within an idle period then early-out.
536 if (!IsInIdlePeriod(idle_period_state_
))
539 // If we are in the ENDING_LONG_IDLE_PERIOD state we have already logged the
541 if (idle_period_state_
!= IdlePeriodState::ENDING_LONG_IDLE_PERIOD
) {
543 TRACE_EVENT_CATEGORY_GROUP_ENABLED("renderer.scheduler", &is_tracing
);
544 if (is_tracing
&& !estimated_next_frame_begin_
.is_null() &&
545 base::TimeTicks::Now() > estimated_next_frame_begin_
) {
546 TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(
547 "renderer.scheduler",
548 "RendererSchedulerIdlePeriod",
551 estimated_next_frame_begin_
.ToInternalValue());
553 TRACE_EVENT_ASYNC_END0("renderer.scheduler",
554 "RendererSchedulerIdlePeriod", this);
557 renderer_task_queue_selector_
->DisableQueue(IDLE_TASK_QUEUE
);
558 idle_period_state_
= IdlePeriodState::NOT_IN_IDLE_PERIOD
;
562 bool RendererSchedulerImpl::IsInIdlePeriod(IdlePeriodState state
) {
563 return state
!= IdlePeriodState::NOT_IN_IDLE_PERIOD
;
566 bool RendererSchedulerImpl::CanExceedIdleDeadlineIfRequired() const {
567 TRACE_EVENT_BEGIN0("renderer.scheduler", "CanExceedIdleDeadlineIfRequired");
568 DCHECK(main_thread_checker_
.CalledOnValidThread());
569 return idle_period_state_
==
570 IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE
;
573 void RendererSchedulerImpl::SetTimeSourceForTesting(
574 scoped_refptr
<cc::TestNowSource
> time_source
) {
575 DCHECK(main_thread_checker_
.CalledOnValidThread());
576 time_source_
= time_source
;
577 task_queue_manager_
->SetTimeSourceForTesting(time_source
);
580 void RendererSchedulerImpl::SetWorkBatchSizeForTesting(size_t work_batch_size
) {
581 DCHECK(main_thread_checker_
.CalledOnValidThread());
582 task_queue_manager_
->SetWorkBatchSize(work_batch_size
);
585 base::TimeTicks
RendererSchedulerImpl::Now() const {
586 return UNLIKELY(time_source_
) ? time_source_
->Now() : base::TimeTicks::Now();
589 RendererSchedulerImpl::PollableNeedsUpdateFlag::PollableNeedsUpdateFlag(
590 base::Lock
* write_lock_
)
591 : flag_(false), write_lock_(write_lock_
) {
594 RendererSchedulerImpl::PollableNeedsUpdateFlag::~PollableNeedsUpdateFlag() {
597 void RendererSchedulerImpl::PollableNeedsUpdateFlag::SetWhileLocked(
599 write_lock_
->AssertAcquired();
600 base::subtle::Release_Store(&flag_
, value
);
603 bool RendererSchedulerImpl::PollableNeedsUpdateFlag::IsSet() const {
604 return base::subtle::Acquire_Load(&flag_
) != 0;
608 const char* RendererSchedulerImpl::TaskQueueIdToString(QueueId queue_id
) {
610 case DEFAULT_TASK_QUEUE
:
612 case COMPOSITOR_TASK_QUEUE
:
613 return "compositor_tq";
614 case LOADING_TASK_QUEUE
:
616 case IDLE_TASK_QUEUE
:
618 case CONTROL_TASK_QUEUE
:
620 case CONTROL_TASK_AFTER_WAKEUP_QUEUE
:
621 return "control_after_wakeup_tq";
629 const char* RendererSchedulerImpl::PolicyToString(Policy policy
) {
633 case Policy::COMPOSITOR_PRIORITY
:
635 case Policy::TOUCHSTART_PRIORITY
:
643 const char* RendererSchedulerImpl::InputStreamStateToString(
644 InputStreamState state
) {
646 case InputStreamState::INACTIVE
:
648 case InputStreamState::ACTIVE
:
650 case InputStreamState::ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE
:
651 return "active_and_awaiting_touchstart_response";
658 const char* RendererSchedulerImpl::IdlePeriodStateToString(
659 IdlePeriodState idle_period_state
) {
660 switch (idle_period_state
) {
661 case IdlePeriodState::NOT_IN_IDLE_PERIOD
:
662 return "not_in_idle_period";
663 case IdlePeriodState::IN_SHORT_IDLE_PERIOD
:
664 return "in_short_idle_period";
665 case IdlePeriodState::IN_LONG_IDLE_PERIOD
:
666 return "in_long_idle_period";
667 case IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE
:
668 return "in_long_idle_period_with_max_deadline";
669 case IdlePeriodState::ENDING_LONG_IDLE_PERIOD
:
670 return "ending_long_idle_period";
677 scoped_refptr
<base::trace_event::ConvertableToTraceFormat
>
678 RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now
) const {
679 DCHECK(main_thread_checker_
.CalledOnValidThread());
680 incoming_signals_lock_
.AssertAcquired();
682 if (optional_now
.is_null())
683 optional_now
= Now();
684 scoped_refptr
<base::trace_event::TracedValue
> state
=
685 new base::trace_event::TracedValue();
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())
697 "last_input_process_time_on_main_",
698 (last_input_process_time_on_main_
- base::TimeTicks()).InMillisecondsF());
700 "estimated_next_frame_begin",
701 (estimated_next_frame_begin_
- base::TimeTicks()).InMillisecondsF());
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
;
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.
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
;
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
;
739 return InputStreamState::ACTIVE
;
742 void RendererSchedulerImpl::AddTaskObserver(
743 base::MessageLoop::TaskObserver
* task_observer
) {
744 DCHECK(main_thread_checker_
.CalledOnValidThread());
745 if (task_queue_manager_
)
746 task_queue_manager_
->AddTaskObserver(task_observer
);
749 void RendererSchedulerImpl::RemoveTaskObserver(
750 base::MessageLoop::TaskObserver
* task_observer
) {
751 DCHECK(main_thread_checker_
.CalledOnValidThread());
752 if (task_queue_manager_
)
753 task_queue_manager_
->RemoveTaskObserver(task_observer
);
756 } // namespace content