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

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

Issue 2118903002: scheduler: Move the Blink scheduler into Blink (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "components/scheduler/renderer/renderer_scheduler_impl.h"
6
7 #include "base/bind.h"
8 #include "base/debug/stack_trace.h"
9 #include "base/logging.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/trace_event/trace_event.h"
13 #include "base/trace_event/trace_event_argument.h"
14 #include "cc/output/begin_frame_args.h"
15 #include "components/scheduler/base/task_queue_impl.h"
16 #include "components/scheduler/base/task_queue_selector.h"
17 #include "components/scheduler/base/virtual_time_domain.h"
18 #include "components/scheduler/child/scheduler_tqm_delegate.h"
19 #include "components/scheduler/renderer/auto_advancing_virtual_time_domain.h"
20 #include "components/scheduler/renderer/web_view_scheduler_impl.h"
21 #include "components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h"
22
23 namespace scheduler {
24 namespace {
25 // The run time of loading tasks is strongly bimodal. The vast majority are
26 // very cheap, but there are usually a handful of very expensive tasks (e.g ~1
27 // second on a mobile device) so we take a very pessimistic view when estimating
28 // the cost of loading tasks.
29 const int kLoadingTaskEstimationSampleCount = 1000;
30 const double kLoadingTaskEstimationPercentile = 99;
31 const int kTimerTaskEstimationSampleCount = 1000;
32 const double kTimerTaskEstimationPercentile = 99;
33 const int kShortIdlePeriodDurationSampleCount = 10;
34 const double kShortIdlePeriodDurationPercentile = 50;
35 // Amount of idle time left in a frame (as a ratio of the vsync interval) above
36 // which main thread compositing can be considered fast.
37 const double kFastCompositingIdleTimeThreshold = .2;
38 } // namespace
39
40 RendererSchedulerImpl::RendererSchedulerImpl(
41 scoped_refptr<SchedulerTqmDelegate> main_task_runner)
42 : helper_(main_task_runner,
43 "renderer.scheduler",
44 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
45 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")),
46 idle_helper_(&helper_,
47 this,
48 "renderer.scheduler",
49 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
50 "RendererSchedulerIdlePeriod",
51 base::TimeDelta()),
52 render_widget_scheduler_signals_(this),
53 control_task_runner_(helper_.ControlTaskRunner()),
54 compositor_task_runner_(helper_.NewTaskQueue(
55 TaskQueue::Spec("compositor_tq").SetShouldMonitorQuiescence(true))),
56 delayed_update_policy_runner_(
57 base::Bind(&RendererSchedulerImpl::UpdatePolicy,
58 base::Unretained(this)),
59 helper_.ControlTaskRunner()),
60 main_thread_only_(this,
61 compositor_task_runner_,
62 helper_.scheduler_tqm_delegate().get()),
63 policy_may_need_update_(&any_thread_lock_),
64 weak_factory_(this) {
65 throttling_helper_.reset(new ThrottlingHelper(this, "renderer.scheduler"));
66 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy,
67 weak_factory_.GetWeakPtr());
68 end_renderer_hidden_idle_period_closure_.Reset(base::Bind(
69 &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr()));
70
71 suspend_timers_when_backgrounded_closure_.Reset(
72 base::Bind(&RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded,
73 weak_factory_.GetWeakPtr()));
74
75 default_loading_task_runner_ = NewLoadingTaskRunner("default_loading_tq");
76 default_timer_task_runner_ = NewTimerTaskRunner("default_timer_tq");
77
78 TRACE_EVENT_OBJECT_CREATED_WITH_ID(
79 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
80 this);
81
82 helper_.SetObserver(this);
83 helper_.SetTaskTimeTracker(this);
84 }
85
86 RendererSchedulerImpl::~RendererSchedulerImpl() {
87 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
88 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
89 this);
90
91 for (const scoped_refptr<TaskQueue>& loading_queue : loading_task_runners_) {
92 loading_queue->RemoveTaskObserver(
93 &MainThreadOnly().loading_task_cost_estimator);
94 }
95 for (const scoped_refptr<TaskQueue>& timer_queue : timer_task_runners_) {
96 timer_queue->RemoveTaskObserver(
97 &MainThreadOnly().timer_task_cost_estimator);
98 }
99
100 if (virtual_time_domain_)
101 UnregisterTimeDomain(virtual_time_domain_.get());
102
103 // Ensure the renderer scheduler was shut down explicitly, because otherwise
104 // we could end up having stale pointers to the Blink heap which has been
105 // terminated by this point.
106 DCHECK(MainThreadOnly().was_shutdown);
107 }
108
109 RendererSchedulerImpl::MainThreadOnly::MainThreadOnly(
110 RendererSchedulerImpl* renderer_scheduler_impl,
111 const scoped_refptr<TaskQueue>& compositor_task_runner,
112 base::TickClock* time_source)
113 : loading_task_cost_estimator(time_source,
114 kLoadingTaskEstimationSampleCount,
115 kLoadingTaskEstimationPercentile),
116 timer_task_cost_estimator(time_source,
117 kTimerTaskEstimationSampleCount,
118 kTimerTaskEstimationPercentile),
119 queueing_time_estimator(renderer_scheduler_impl,
120 base::TimeDelta::FromSeconds(1)),
121 idle_time_estimator(compositor_task_runner,
122 time_source,
123 kShortIdlePeriodDurationSampleCount,
124 kShortIdlePeriodDurationPercentile),
125 current_use_case(UseCase::NONE),
126 timer_queue_suspend_count(0),
127 navigation_task_expected_count(0),
128 expensive_task_policy(ExpensiveTaskPolicy::RUN),
129 renderer_hidden(false),
130 renderer_backgrounded(false),
131 renderer_suspended(false),
132 timer_queue_suspension_when_backgrounded_enabled(false),
133 timer_queue_suspended_when_backgrounded(false),
134 was_shutdown(false),
135 loading_tasks_seem_expensive(false),
136 timer_tasks_seem_expensive(false),
137 touchstart_expected_soon(false),
138 have_seen_a_begin_main_frame(false),
139 have_reported_blocking_intervention_in_current_policy(false),
140 have_reported_blocking_intervention_since_navigation(false),
141 has_visible_render_widget_with_touch_handler(false),
142 begin_frame_not_expected_soon(false),
143 expensive_task_blocking_allowed(true),
144 in_idle_period_for_testing(false),
145 use_virtual_time(false),
146 rail_mode_observer(nullptr) {}
147
148 RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {}
149
150 RendererSchedulerImpl::AnyThread::AnyThread()
151 : awaiting_touch_start_response(false),
152 in_idle_period(false),
153 begin_main_frame_on_critical_path(false),
154 last_gesture_was_compositor_driven(false),
155 default_gesture_prevented(true),
156 have_seen_touchstart(false) {}
157
158 RendererSchedulerImpl::AnyThread::~AnyThread() {}
159
160 RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly()
161 : last_input_type(blink::WebInputEvent::Undefined) {}
162
163 RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() {}
164
165 void RendererSchedulerImpl::Shutdown() {
166 throttling_helper_.reset();
167 helper_.Shutdown();
168 MainThreadOnly().was_shutdown = true;
169 MainThreadOnly().rail_mode_observer = nullptr;
170 }
171
172 std::unique_ptr<blink::WebThread> RendererSchedulerImpl::CreateMainThread() {
173 return base::WrapUnique(new WebThreadImplForRendererScheduler(this));
174 }
175
176 scoped_refptr<TaskQueue> RendererSchedulerImpl::DefaultTaskRunner() {
177 return helper_.DefaultTaskRunner();
178 }
179
180 scoped_refptr<TaskQueue> RendererSchedulerImpl::CompositorTaskRunner() {
181 helper_.CheckOnValidThread();
182 return compositor_task_runner_;
183 }
184
185 scoped_refptr<SingleThreadIdleTaskRunner>
186 RendererSchedulerImpl::IdleTaskRunner() {
187 return idle_helper_.IdleTaskRunner();
188 }
189
190 scoped_refptr<TaskQueue> RendererSchedulerImpl::LoadingTaskRunner() {
191 helper_.CheckOnValidThread();
192 return default_loading_task_runner_;
193 }
194
195 scoped_refptr<TaskQueue> RendererSchedulerImpl::TimerTaskRunner() {
196 helper_.CheckOnValidThread();
197 return default_timer_task_runner_;
198 }
199
200 scoped_refptr<TaskQueue> RendererSchedulerImpl::ControlTaskRunner() {
201 helper_.CheckOnValidThread();
202 return helper_.ControlTaskRunner();
203 }
204
205 scoped_refptr<TaskQueue> RendererSchedulerImpl::NewLoadingTaskRunner(
206 const char* name) {
207 helper_.CheckOnValidThread();
208 scoped_refptr<TaskQueue> loading_task_queue(helper_.NewTaskQueue(
209 TaskQueue::Spec(name).SetShouldMonitorQuiescence(true).SetTimeDomain(
210 MainThreadOnly().use_virtual_time ? GetVirtualTimeDomain()
211 : nullptr)));
212 loading_task_runners_.insert(loading_task_queue);
213 loading_task_queue->SetQueueEnabled(
214 MainThreadOnly().current_policy.loading_queue_policy.is_enabled);
215 loading_task_queue->SetQueuePriority(
216 MainThreadOnly().current_policy.loading_queue_policy.priority);
217 if (MainThreadOnly().current_policy.loading_queue_policy.time_domain_type ==
218 TimeDomainType::THROTTLED) {
219 throttling_helper_->IncreaseThrottleRefCount(loading_task_queue.get());
220 }
221 loading_task_queue->AddTaskObserver(
222 &MainThreadOnly().loading_task_cost_estimator);
223 return loading_task_queue;
224 }
225
226 scoped_refptr<TaskQueue> RendererSchedulerImpl::NewTimerTaskRunner(
227 const char* name) {
228 helper_.CheckOnValidThread();
229 // TODO(alexclarke): Consider using ApplyTaskQueuePolicy() for brevity.
230 scoped_refptr<TaskQueue> timer_task_queue(
231 helper_.NewTaskQueue(TaskQueue::Spec(name)
232 .SetShouldMonitorQuiescence(true)
233 .SetShouldReportWhenExecutionBlocked(true)
234 .SetTimeDomain(MainThreadOnly().use_virtual_time
235 ? GetVirtualTimeDomain()
236 : nullptr)));
237 timer_task_runners_.insert(timer_task_queue);
238 timer_task_queue->SetQueueEnabled(
239 MainThreadOnly().current_policy.timer_queue_policy.is_enabled);
240 timer_task_queue->SetQueuePriority(
241 MainThreadOnly().current_policy.timer_queue_policy.priority);
242 if (MainThreadOnly().current_policy.timer_queue_policy.time_domain_type ==
243 TimeDomainType::THROTTLED) {
244 throttling_helper_->IncreaseThrottleRefCount(timer_task_queue.get());
245 }
246 timer_task_queue->AddTaskObserver(
247 &MainThreadOnly().timer_task_cost_estimator);
248 return timer_task_queue;
249 }
250
251 scoped_refptr<TaskQueue> RendererSchedulerImpl::NewUnthrottledTaskRunner(
252 const char* name) {
253 helper_.CheckOnValidThread();
254 scoped_refptr<TaskQueue> unthrottled_task_queue(helper_.NewTaskQueue(
255 TaskQueue::Spec(name).SetShouldMonitorQuiescence(true).SetTimeDomain(
256 MainThreadOnly().use_virtual_time ? GetVirtualTimeDomain()
257 : nullptr)));
258 unthrottled_task_runners_.insert(unthrottled_task_queue);
259 return unthrottled_task_queue;
260 }
261
262 std::unique_ptr<RenderWidgetSchedulingState>
263 RendererSchedulerImpl::NewRenderWidgetSchedulingState() {
264 return render_widget_scheduler_signals_.NewRenderWidgetSchedulingState();
265 }
266
267 void RendererSchedulerImpl::OnUnregisterTaskQueue(
268 const scoped_refptr<TaskQueue>& task_queue) {
269 if (throttling_helper_.get())
270 throttling_helper_->UnregisterTaskQueue(task_queue.get());
271
272 if (loading_task_runners_.find(task_queue) != loading_task_runners_.end()) {
273 task_queue->RemoveTaskObserver(
274 &MainThreadOnly().loading_task_cost_estimator);
275 loading_task_runners_.erase(task_queue);
276 } else if (timer_task_runners_.find(task_queue) !=
277 timer_task_runners_.end()) {
278 task_queue->RemoveTaskObserver(&MainThreadOnly().timer_task_cost_estimator);
279 timer_task_runners_.erase(task_queue);
280 } else if (unthrottled_task_runners_.find(task_queue) !=
281 unthrottled_task_runners_.end()) {
282 unthrottled_task_runners_.erase(task_queue);
283 }
284 }
285
286 bool RendererSchedulerImpl::CanExceedIdleDeadlineIfRequired() const {
287 return idle_helper_.CanExceedIdleDeadlineIfRequired();
288 }
289
290 void RendererSchedulerImpl::AddTaskObserver(
291 base::MessageLoop::TaskObserver* task_observer) {
292 helper_.AddTaskObserver(task_observer);
293 }
294
295 void RendererSchedulerImpl::RemoveTaskObserver(
296 base::MessageLoop::TaskObserver* task_observer) {
297 helper_.RemoveTaskObserver(task_observer);
298 }
299
300 void RendererSchedulerImpl::WillBeginFrame(const cc::BeginFrameArgs& args) {
301 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
302 "RendererSchedulerImpl::WillBeginFrame", "args", args.AsValue());
303 helper_.CheckOnValidThread();
304 if (helper_.IsShutdown())
305 return;
306
307 EndIdlePeriod();
308 MainThreadOnly().estimated_next_frame_begin = args.frame_time + args.interval;
309 MainThreadOnly().have_seen_a_begin_main_frame = true;
310 MainThreadOnly().begin_frame_not_expected_soon = false;
311 MainThreadOnly().compositor_frame_interval = args.interval;
312 {
313 base::AutoLock lock(any_thread_lock_);
314 AnyThread().begin_main_frame_on_critical_path = args.on_critical_path;
315 }
316 }
317
318 void RendererSchedulerImpl::DidCommitFrameToCompositor() {
319 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
320 "RendererSchedulerImpl::DidCommitFrameToCompositor");
321 helper_.CheckOnValidThread();
322 if (helper_.IsShutdown())
323 return;
324
325 base::TimeTicks now(helper_.scheduler_tqm_delegate()->NowTicks());
326 if (now < MainThreadOnly().estimated_next_frame_begin) {
327 // TODO(rmcilroy): Consider reducing the idle period based on the runtime of
328 // the next pending delayed tasks (as currently done in for long idle times)
329 idle_helper_.StartIdlePeriod(
330 IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now,
331 MainThreadOnly().estimated_next_frame_begin);
332 }
333
334 MainThreadOnly().idle_time_estimator.DidCommitFrameToCompositor();
335 }
336
337 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() {
338 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
339 "RendererSchedulerImpl::BeginFrameNotExpectedSoon");
340 helper_.CheckOnValidThread();
341 if (helper_.IsShutdown())
342 return;
343
344 MainThreadOnly().begin_frame_not_expected_soon = true;
345 idle_helper_.EnableLongIdlePeriod();
346 {
347 base::AutoLock lock(any_thread_lock_);
348 AnyThread().begin_main_frame_on_critical_path = false;
349 }
350 }
351
352 void RendererSchedulerImpl::SetAllRenderWidgetsHidden(bool hidden) {
353 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
354 "RendererSchedulerImpl::SetAllRenderWidgetsHidden", "hidden",
355 hidden);
356
357 helper_.CheckOnValidThread();
358
359 if (helper_.IsShutdown() || MainThreadOnly().renderer_hidden == hidden)
360 return;
361
362 end_renderer_hidden_idle_period_closure_.Cancel();
363
364 if (hidden) {
365 idle_helper_.EnableLongIdlePeriod();
366
367 // Ensure that we stop running idle tasks after a few seconds of being
368 // hidden.
369 base::TimeDelta end_idle_when_hidden_delay =
370 base::TimeDelta::FromMilliseconds(kEndIdleWhenHiddenDelayMillis);
371 control_task_runner_->PostDelayedTask(
372 FROM_HERE, end_renderer_hidden_idle_period_closure_.callback(),
373 end_idle_when_hidden_delay);
374 MainThreadOnly().renderer_hidden = true;
375 } else {
376 MainThreadOnly().renderer_hidden = false;
377 EndIdlePeriod();
378 }
379
380 // TODO(alexclarke): Should we update policy here?
381 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
382 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
383 this, AsValue(helper_.scheduler_tqm_delegate()->NowTicks()));
384 }
385
386 void RendererSchedulerImpl::SetHasVisibleRenderWidgetWithTouchHandler(
387 bool has_visible_render_widget_with_touch_handler) {
388 helper_.CheckOnValidThread();
389 if (has_visible_render_widget_with_touch_handler ==
390 MainThreadOnly().has_visible_render_widget_with_touch_handler)
391 return;
392
393 MainThreadOnly().has_visible_render_widget_with_touch_handler =
394 has_visible_render_widget_with_touch_handler;
395
396 base::AutoLock lock(any_thread_lock_);
397 UpdatePolicyLocked(UpdateType::FORCE_UPDATE);
398 }
399
400 void RendererSchedulerImpl::OnRendererBackgrounded() {
401 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
402 "RendererSchedulerImpl::OnRendererBackgrounded");
403 helper_.CheckOnValidThread();
404 if (helper_.IsShutdown() || MainThreadOnly().renderer_backgrounded)
405 return;
406
407 MainThreadOnly().renderer_backgrounded = true;
408 if (!MainThreadOnly().timer_queue_suspension_when_backgrounded_enabled)
409 return;
410
411 suspend_timers_when_backgrounded_closure_.Cancel();
412 base::TimeDelta suspend_timers_when_backgrounded_delay =
413 base::TimeDelta::FromMilliseconds(
414 kSuspendTimersWhenBackgroundedDelayMillis);
415 control_task_runner_->PostDelayedTask(
416 FROM_HERE, suspend_timers_when_backgrounded_closure_.callback(),
417 suspend_timers_when_backgrounded_delay);
418 }
419
420 void RendererSchedulerImpl::OnRendererForegrounded() {
421 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
422 "RendererSchedulerImpl::OnRendererForegrounded");
423 helper_.CheckOnValidThread();
424 if (helper_.IsShutdown() || !MainThreadOnly().renderer_backgrounded)
425 return;
426
427 MainThreadOnly().renderer_backgrounded = false;
428 MainThreadOnly().renderer_suspended = false;
429 suspend_timers_when_backgrounded_closure_.Cancel();
430 ResumeTimerQueueWhenForegrounded();
431 }
432
433 void RendererSchedulerImpl::SuspendRenderer() {
434 helper_.CheckOnValidThread();
435 DCHECK(MainThreadOnly().renderer_backgrounded);
436 if (helper_.IsShutdown())
437 return;
438 suspend_timers_when_backgrounded_closure_.Cancel();
439 // TODO(hajimehoshi): We might need to suspend not only timer queue but also
440 // e.g. loading tasks or postMessage.
441 MainThreadOnly().renderer_suspended = true;
442 SuspendTimerQueueWhenBackgrounded();
443 }
444
445 void RendererSchedulerImpl::EndIdlePeriod() {
446 if (MainThreadOnly().in_idle_period_for_testing)
447 return;
448 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
449 "RendererSchedulerImpl::EndIdlePeriod");
450 helper_.CheckOnValidThread();
451 idle_helper_.EndIdlePeriod();
452 }
453
454 void RendererSchedulerImpl::EndIdlePeriodForTesting(
455 const base::Closure& callback,
456 base::TimeTicks time_remaining) {
457 MainThreadOnly().in_idle_period_for_testing = false;
458 EndIdlePeriod();
459 callback.Run();
460 }
461
462 bool RendererSchedulerImpl::PolicyNeedsUpdateForTesting() {
463 return policy_may_need_update_.IsSet();
464 }
465
466 // static
467 bool RendererSchedulerImpl::ShouldPrioritizeInputEvent(
468 const blink::WebInputEvent& web_input_event) {
469 // We regard MouseMove events with the left mouse button down as a signal
470 // that the user is doing something requiring a smooth frame rate.
471 if (web_input_event.type == blink::WebInputEvent::MouseMove &&
472 (web_input_event.modifiers & blink::WebInputEvent::LeftButtonDown)) {
473 return true;
474 }
475 // Ignore all other mouse events because they probably don't signal user
476 // interaction needing a smooth framerate. NOTE isMouseEventType returns false
477 // for mouse wheel events, hence we regard them as user input.
478 // Ignore keyboard events because it doesn't really make sense to enter
479 // compositor priority for them.
480 if (blink::WebInputEvent::isMouseEventType(web_input_event.type) ||
481 blink::WebInputEvent::isKeyboardEventType(web_input_event.type)) {
482 return false;
483 }
484 return true;
485 }
486
487 void RendererSchedulerImpl::DidHandleInputEventOnCompositorThread(
488 const blink::WebInputEvent& web_input_event,
489 InputEventState event_state) {
490 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
491 "RendererSchedulerImpl::DidHandleInputEventOnCompositorThread");
492 if (!ShouldPrioritizeInputEvent(web_input_event))
493 return;
494
495 UpdateForInputEventOnCompositorThread(web_input_event.type, event_state);
496 }
497
498 void RendererSchedulerImpl::DidAnimateForInputOnCompositorThread() {
499 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
500 "RendererSchedulerImpl::DidAnimateForInputOnCompositorThread");
501 base::AutoLock lock(any_thread_lock_);
502 AnyThread().fling_compositor_escalation_deadline =
503 helper_.scheduler_tqm_delegate()->NowTicks() +
504 base::TimeDelta::FromMilliseconds(kFlingEscalationLimitMillis);
505 }
506
507 void RendererSchedulerImpl::UpdateForInputEventOnCompositorThread(
508 blink::WebInputEvent::Type type,
509 InputEventState input_event_state) {
510 base::AutoLock lock(any_thread_lock_);
511 base::TimeTicks now = helper_.scheduler_tqm_delegate()->NowTicks();
512
513 // TODO(alexclarke): Move WebInputEventTraits where we can access it from here
514 // and record the name rather than the integer representation.
515 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
516 "RendererSchedulerImpl::UpdateForInputEventOnCompositorThread",
517 "type", static_cast<int>(type), "input_event_state",
518 InputEventStateToString(input_event_state));
519
520 base::TimeDelta unused_policy_duration;
521 UseCase previous_use_case =
522 ComputeCurrentUseCase(now, &unused_policy_duration);
523 bool was_awaiting_touch_start_response =
524 AnyThread().awaiting_touch_start_response;
525
526 AnyThread().user_model.DidStartProcessingInputEvent(type, now);
527
528 if (input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR)
529 AnyThread().user_model.DidFinishProcessingInputEvent(now);
530
531 if (type) {
532 switch (type) {
533 case blink::WebInputEvent::TouchStart:
534 AnyThread().awaiting_touch_start_response = true;
535 // This is just a fail-safe to reset the state of
536 // |last_gesture_was_compositor_driven| to the default. We don't know
537 // yet where the gesture will run.
538 AnyThread().last_gesture_was_compositor_driven = false;
539 AnyThread().have_seen_touchstart = true;
540 // Assume the default gesture is prevented until we see evidence
541 // otherwise.
542 AnyThread().default_gesture_prevented = true;
543 break;
544
545 case blink::WebInputEvent::TouchMove:
546 // Observation of consecutive touchmoves is a strong signal that the
547 // page is consuming the touch sequence, in which case touchstart
548 // response prioritization is no longer necessary. Otherwise, the
549 // initial touchmove should preserve the touchstart response pending
550 // state.
551 if (AnyThread().awaiting_touch_start_response &&
552 CompositorThreadOnly().last_input_type ==
553 blink::WebInputEvent::TouchMove) {
554 AnyThread().awaiting_touch_start_response = false;
555 }
556 break;
557
558 case blink::WebInputEvent::GesturePinchUpdate:
559 case blink::WebInputEvent::GestureScrollUpdate:
560 // If we see events for an established gesture, we can lock it to the
561 // appropriate thread as the gesture can no longer be cancelled.
562 AnyThread().last_gesture_was_compositor_driven =
563 input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR;
564 AnyThread().awaiting_touch_start_response = false;
565 AnyThread().default_gesture_prevented = false;
566 break;
567
568 case blink::WebInputEvent::GestureFlingCancel:
569 AnyThread().fling_compositor_escalation_deadline = base::TimeTicks();
570 break;
571
572 case blink::WebInputEvent::GestureTapDown:
573 case blink::WebInputEvent::GestureShowPress:
574 case blink::WebInputEvent::GestureScrollEnd:
575 // With no observable effect, these meta events do not indicate a
576 // meaningful touchstart response and should not impact task priority.
577 break;
578
579 default:
580 AnyThread().awaiting_touch_start_response = false;
581 break;
582 }
583 }
584
585 // Avoid unnecessary policy updates if the use case did not change.
586 UseCase use_case = ComputeCurrentUseCase(now, &unused_policy_duration);
587
588 if (use_case != previous_use_case ||
589 was_awaiting_touch_start_response !=
590 AnyThread().awaiting_touch_start_response) {
591 EnsureUrgentPolicyUpdatePostedOnMainThread(FROM_HERE);
592 }
593 CompositorThreadOnly().last_input_type = type;
594 }
595
596 void RendererSchedulerImpl::DidHandleInputEventOnMainThread(
597 const blink::WebInputEvent& web_input_event) {
598 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
599 "RendererSchedulerImpl::DidHandleInputEventOnMainThread");
600 helper_.CheckOnValidThread();
601 if (ShouldPrioritizeInputEvent(web_input_event)) {
602 base::AutoLock lock(any_thread_lock_);
603 AnyThread().user_model.DidFinishProcessingInputEvent(
604 helper_.scheduler_tqm_delegate()->NowTicks());
605 }
606 }
607
608 bool RendererSchedulerImpl::IsHighPriorityWorkAnticipated() {
609 helper_.CheckOnValidThread();
610 if (helper_.IsShutdown())
611 return false;
612
613 MaybeUpdatePolicy();
614 // The touchstart, synchronized gesture and main-thread gesture use cases
615 // indicate a strong likelihood of high-priority work in the near future.
616 UseCase use_case = MainThreadOnly().current_use_case;
617 return MainThreadOnly().touchstart_expected_soon ||
618 use_case == UseCase::TOUCHSTART ||
619 use_case == UseCase::MAIN_THREAD_GESTURE ||
620 use_case == UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING ||
621 use_case == UseCase::SYNCHRONIZED_GESTURE;
622 }
623
624 bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() {
625 helper_.CheckOnValidThread();
626 if (helper_.IsShutdown())
627 return false;
628
629 MaybeUpdatePolicy();
630 // We only yield if there's a urgent task to be run now, or we are expecting
631 // one soon (touch start).
632 // Note: even though the control queue has the highest priority we don't yield
633 // for it since these tasks are not user-provided work and they are only
634 // intended to run before the next task, not interrupt the tasks.
635 switch (MainThreadOnly().current_use_case) {
636 case UseCase::COMPOSITOR_GESTURE:
637 case UseCase::NONE:
638 return MainThreadOnly().touchstart_expected_soon;
639
640 case UseCase::MAIN_THREAD_GESTURE:
641 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING:
642 case UseCase::SYNCHRONIZED_GESTURE:
643 return compositor_task_runner_->HasPendingImmediateWork() ||
644 MainThreadOnly().touchstart_expected_soon;
645
646 case UseCase::TOUCHSTART:
647 return true;
648
649 case UseCase::LOADING:
650 return false;
651
652 default:
653 NOTREACHED();
654 return false;
655 }
656 }
657
658 base::TimeTicks RendererSchedulerImpl::CurrentIdleTaskDeadlineForTesting()
659 const {
660 return idle_helper_.CurrentIdleTaskDeadline();
661 }
662
663 void RendererSchedulerImpl::RunIdleTasksForTesting(
664 const base::Closure& callback) {
665 MainThreadOnly().in_idle_period_for_testing = true;
666 IdleTaskRunner()->PostIdleTask(
667 FROM_HERE,
668 base::Bind(&RendererSchedulerImpl::EndIdlePeriodForTesting,
669 weak_factory_.GetWeakPtr(), callback));
670 idle_helper_.EnableLongIdlePeriod();
671 }
672
673 void RendererSchedulerImpl::MaybeUpdatePolicy() {
674 helper_.CheckOnValidThread();
675 if (policy_may_need_update_.IsSet()) {
676 UpdatePolicy();
677 }
678 }
679
680 void RendererSchedulerImpl::EnsureUrgentPolicyUpdatePostedOnMainThread(
681 const tracked_objects::Location& from_here) {
682 // TODO(scheduler-dev): Check that this method isn't called from the main
683 // thread.
684 any_thread_lock_.AssertAcquired();
685 if (!policy_may_need_update_.IsSet()) {
686 policy_may_need_update_.SetWhileLocked(true);
687 control_task_runner_->PostTask(from_here, update_policy_closure_);
688 }
689 }
690
691 void RendererSchedulerImpl::UpdatePolicy() {
692 base::AutoLock lock(any_thread_lock_);
693 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
694 }
695
696 void RendererSchedulerImpl::ForceUpdatePolicy() {
697 base::AutoLock lock(any_thread_lock_);
698 UpdatePolicyLocked(UpdateType::FORCE_UPDATE);
699 }
700
701 void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
702 helper_.CheckOnValidThread();
703 any_thread_lock_.AssertAcquired();
704 if (helper_.IsShutdown())
705 return;
706
707 base::TimeTicks now = helper_.scheduler_tqm_delegate()->NowTicks();
708 policy_may_need_update_.SetWhileLocked(false);
709
710 base::TimeDelta expected_use_case_duration;
711 UseCase use_case = ComputeCurrentUseCase(now, &expected_use_case_duration);
712 MainThreadOnly().current_use_case = use_case;
713
714 base::TimeDelta touchstart_expected_flag_valid_for_duration;
715 bool touchstart_expected_soon = false;
716 if (MainThreadOnly().has_visible_render_widget_with_touch_handler) {
717 touchstart_expected_soon = AnyThread().user_model.IsGestureExpectedSoon(
718 now, &touchstart_expected_flag_valid_for_duration);
719 }
720 MainThreadOnly().touchstart_expected_soon = touchstart_expected_soon;
721
722 base::TimeDelta longest_jank_free_task_duration =
723 EstimateLongestJankFreeTaskDuration();
724 MainThreadOnly().longest_jank_free_task_duration =
725 longest_jank_free_task_duration;
726
727 bool loading_tasks_seem_expensive = false;
728 bool timer_tasks_seem_expensive = false;
729 loading_tasks_seem_expensive =
730 MainThreadOnly().loading_task_cost_estimator.expected_task_duration() >
731 longest_jank_free_task_duration;
732 timer_tasks_seem_expensive =
733 MainThreadOnly().timer_task_cost_estimator.expected_task_duration() >
734 longest_jank_free_task_duration;
735 MainThreadOnly().timer_tasks_seem_expensive = timer_tasks_seem_expensive;
736 MainThreadOnly().loading_tasks_seem_expensive = loading_tasks_seem_expensive;
737
738 // The |new_policy_duration| is the minimum of |expected_use_case_duration|
739 // and |touchstart_expected_flag_valid_for_duration| unless one is zero in
740 // which case we choose the other.
741 base::TimeDelta new_policy_duration = expected_use_case_duration;
742 if (new_policy_duration.is_zero() ||
743 (touchstart_expected_flag_valid_for_duration > base::TimeDelta() &&
744 new_policy_duration > touchstart_expected_flag_valid_for_duration)) {
745 new_policy_duration = touchstart_expected_flag_valid_for_duration;
746 }
747
748 if (new_policy_duration > base::TimeDelta()) {
749 MainThreadOnly().current_policy_expiration_time = now + new_policy_duration;
750 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration,
751 now);
752 } else {
753 MainThreadOnly().current_policy_expiration_time = base::TimeTicks();
754 }
755
756 // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely
757 // slow, because that can cause starvation in other task sources.
758 bool main_thread_compositing_is_fast =
759 MainThreadOnly().idle_time_estimator.GetExpectedIdleDuration(
760 MainThreadOnly().compositor_frame_interval) >
761 MainThreadOnly().compositor_frame_interval *
762 kFastCompositingIdleTimeThreshold;
763
764 Policy new_policy;
765 ExpensiveTaskPolicy expensive_task_policy = ExpensiveTaskPolicy::RUN;
766 new_policy.rail_mode = v8::PERFORMANCE_ANIMATION;
767
768 switch (use_case) {
769 case UseCase::COMPOSITOR_GESTURE:
770 if (touchstart_expected_soon) {
771 new_policy.rail_mode = v8::PERFORMANCE_RESPONSE;
772 expensive_task_policy = ExpensiveTaskPolicy::BLOCK;
773 new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY;
774 } else {
775 // What we really want to do is priorize loading tasks, but that doesn't
776 // seem to be safe. Instead we do that by proxy by deprioritizing
777 // compositor tasks. This should be safe since we've already gone to the
778 // pain of fixing ordering issues with them.
779 new_policy.compositor_queue_policy.priority =
780 TaskQueue::BEST_EFFORT_PRIORITY;
781 }
782 break;
783
784 case UseCase::SYNCHRONIZED_GESTURE:
785 new_policy.compositor_queue_policy.priority =
786 main_thread_compositing_is_fast ? TaskQueue::HIGH_PRIORITY
787 : TaskQueue::NORMAL_PRIORITY;
788 if (touchstart_expected_soon) {
789 new_policy.rail_mode = v8::PERFORMANCE_RESPONSE;
790 expensive_task_policy = ExpensiveTaskPolicy::BLOCK;
791 } else {
792 expensive_task_policy = ExpensiveTaskPolicy::THROTTLE;
793 }
794 break;
795
796 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING:
797 // In main thread input handling scenarios we don't have perfect knowledge
798 // about which things we should be prioritizing, so we don't attempt to
799 // block expensive tasks because we don't know whether they were integral
800 // to the page's functionality or not.
801 new_policy.compositor_queue_policy.priority =
802 main_thread_compositing_is_fast ? TaskQueue::HIGH_PRIORITY
803 : TaskQueue::NORMAL_PRIORITY;
804 break;
805
806 case UseCase::MAIN_THREAD_GESTURE:
807 // A main thread gesture is for example a scroll gesture which is handled
808 // by the main thread. Since we know the established gesture type, we can
809 // be a little more aggressive about prioritizing compositing and input
810 // handling over other tasks.
811 new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY;
812 if (touchstart_expected_soon) {
813 new_policy.rail_mode = v8::PERFORMANCE_RESPONSE;
814 expensive_task_policy = ExpensiveTaskPolicy::BLOCK;
815 } else {
816 expensive_task_policy = ExpensiveTaskPolicy::THROTTLE;
817 }
818 break;
819
820 case UseCase::TOUCHSTART:
821 new_policy.rail_mode = v8::PERFORMANCE_RESPONSE;
822 new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY;
823 new_policy.loading_queue_policy.is_enabled = false;
824 new_policy.timer_queue_policy.is_enabled = false;
825 // NOTE this is a nop due to the above.
826 expensive_task_policy = ExpensiveTaskPolicy::BLOCK;
827 break;
828
829 case UseCase::NONE:
830 // It's only safe to block tasks that if we are expecting a compositor
831 // driven gesture.
832 if (touchstart_expected_soon &&
833 AnyThread().last_gesture_was_compositor_driven) {
834 new_policy.rail_mode = v8::PERFORMANCE_RESPONSE;
835 expensive_task_policy = ExpensiveTaskPolicy::BLOCK;
836 }
837 break;
838
839 case UseCase::LOADING:
840 new_policy.rail_mode = v8::PERFORMANCE_LOAD;
841 new_policy.loading_queue_policy.priority = TaskQueue::HIGH_PRIORITY;
842 new_policy.default_queue_policy.priority = TaskQueue::HIGH_PRIORITY;
843 break;
844
845 default:
846 NOTREACHED();
847 }
848
849 // TODO(skyostil): Add an idle state for foreground tabs too.
850 if (MainThreadOnly().renderer_hidden)
851 new_policy.rail_mode = v8::PERFORMANCE_IDLE;
852
853 if (expensive_task_policy == ExpensiveTaskPolicy::BLOCK &&
854 (!MainThreadOnly().expensive_task_blocking_allowed ||
855 !MainThreadOnly().have_seen_a_begin_main_frame ||
856 MainThreadOnly().navigation_task_expected_count > 0)) {
857 expensive_task_policy = ExpensiveTaskPolicy::RUN;
858 }
859
860 switch (expensive_task_policy) {
861 case ExpensiveTaskPolicy::RUN:
862 break;
863
864 case ExpensiveTaskPolicy::BLOCK:
865 if (loading_tasks_seem_expensive)
866 new_policy.loading_queue_policy.is_enabled = false;
867 if (timer_tasks_seem_expensive)
868 new_policy.timer_queue_policy.is_enabled = false;
869 break;
870
871 case ExpensiveTaskPolicy::THROTTLE:
872 if (loading_tasks_seem_expensive) {
873 new_policy.loading_queue_policy.time_domain_type =
874 TimeDomainType::THROTTLED;
875 }
876 if (timer_tasks_seem_expensive) {
877 new_policy.timer_queue_policy.time_domain_type =
878 TimeDomainType::THROTTLED;
879 }
880 break;
881 }
882 MainThreadOnly().expensive_task_policy = expensive_task_policy;
883
884 if (MainThreadOnly().timer_queue_suspend_count != 0 ||
885 MainThreadOnly().timer_queue_suspended_when_backgrounded) {
886 new_policy.timer_queue_policy.is_enabled = false;
887 // TODO(alexclarke): Figure out if we really need to do this.
888 new_policy.timer_queue_policy.time_domain_type = TimeDomainType::REAL;
889 }
890
891 if (MainThreadOnly().renderer_suspended) {
892 new_policy.loading_queue_policy.is_enabled = false;
893 DCHECK(!new_policy.timer_queue_policy.is_enabled);
894 }
895
896 if (MainThreadOnly().use_virtual_time) {
897 new_policy.compositor_queue_policy.time_domain_type =
898 TimeDomainType::VIRTUAL;
899 new_policy.default_queue_policy.time_domain_type = TimeDomainType::VIRTUAL;
900 new_policy.loading_queue_policy.time_domain_type = TimeDomainType::VIRTUAL;
901 new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL;
902 }
903
904 // Tracing is done before the early out check, because it's quite possible we
905 // will otherwise miss this information in traces.
906 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
907 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
908 this, AsValueLocked(now));
909 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case",
910 use_case);
911 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode",
912 new_policy.rail_mode);
913 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
914 "touchstart_expected_soon",
915 MainThreadOnly().touchstart_expected_soon);
916 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
917 "expensive_task_policy", expensive_task_policy);
918 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
919 "RendererScheduler.loading_tasks_seem_expensive",
920 MainThreadOnly().loading_tasks_seem_expensive);
921 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
922 "RendererScheduler.timer_tasks_seem_expensive",
923 MainThreadOnly().timer_tasks_seem_expensive);
924
925 // TODO(alexclarke): Can we get rid of force update now?
926 if (update_type == UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED &&
927 new_policy == MainThreadOnly().current_policy) {
928 return;
929 }
930
931 ApplyTaskQueuePolicy(compositor_task_runner_.get(),
932 MainThreadOnly().current_policy.compositor_queue_policy,
933 new_policy.compositor_queue_policy);
934
935 for (const scoped_refptr<TaskQueue>& loading_queue : loading_task_runners_) {
936 ApplyTaskQueuePolicy(loading_queue.get(),
937 MainThreadOnly().current_policy.loading_queue_policy,
938 new_policy.loading_queue_policy);
939 }
940
941 for (const scoped_refptr<TaskQueue>& timer_queue : timer_task_runners_) {
942 ApplyTaskQueuePolicy(timer_queue.get(),
943 MainThreadOnly().current_policy.timer_queue_policy,
944 new_policy.timer_queue_policy);
945 }
946 MainThreadOnly().have_reported_blocking_intervention_in_current_policy =
947 false;
948
949 // TODO(alexclarke): We shouldn't have to prioritize the default queue, but it
950 // appears to be necessary since the order of loading tasks and IPCs (which
951 // are mostly dispatched on the default queue) need to be preserved.
952 ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(),
953 MainThreadOnly().current_policy.default_queue_policy,
954 new_policy.default_queue_policy);
955 if (MainThreadOnly().rail_mode_observer &&
956 new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) {
957 MainThreadOnly().rail_mode_observer->OnRAILModeChanged(
958 new_policy.rail_mode);
959 }
960
961 DCHECK(compositor_task_runner_->IsQueueEnabled());
962 MainThreadOnly().current_policy = new_policy;
963 }
964
965 void RendererSchedulerImpl::ApplyTaskQueuePolicy(
966 TaskQueue* task_queue,
967 const TaskQueuePolicy& old_task_queue_policy,
968 const TaskQueuePolicy& new_task_queue_policy) const {
969 if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) {
970 throttling_helper_->SetQueueEnabled(task_queue,
971 new_task_queue_policy.is_enabled);
972 }
973
974 if (old_task_queue_policy.priority != new_task_queue_policy.priority)
975 task_queue->SetQueuePriority(new_task_queue_policy.priority);
976
977 if (old_task_queue_policy.time_domain_type !=
978 new_task_queue_policy.time_domain_type) {
979 if (old_task_queue_policy.time_domain_type == TimeDomainType::THROTTLED) {
980 throttling_helper_->DecreaseThrottleRefCount(task_queue);
981 } else if (new_task_queue_policy.time_domain_type ==
982 TimeDomainType::THROTTLED) {
983 throttling_helper_->IncreaseThrottleRefCount(task_queue);
984 } else if (new_task_queue_policy.time_domain_type ==
985 TimeDomainType::VIRTUAL) {
986 DCHECK(virtual_time_domain_);
987 task_queue->SetTimeDomain(virtual_time_domain_.get());
988 }
989 }
990 }
991
992 RendererSchedulerImpl::UseCase RendererSchedulerImpl::ComputeCurrentUseCase(
993 base::TimeTicks now,
994 base::TimeDelta* expected_use_case_duration) const {
995 any_thread_lock_.AssertAcquired();
996 // Special case for flings. This is needed because we don't get notification
997 // of a fling ending (although we do for cancellation).
998 if (AnyThread().fling_compositor_escalation_deadline > now &&
999 !AnyThread().awaiting_touch_start_response) {
1000 *expected_use_case_duration =
1001 AnyThread().fling_compositor_escalation_deadline - now;
1002 return UseCase::COMPOSITOR_GESTURE;
1003 }
1004 // Above all else we want to be responsive to user input.
1005 *expected_use_case_duration =
1006 AnyThread().user_model.TimeLeftInUserGesture(now);
1007 if (*expected_use_case_duration > base::TimeDelta()) {
1008 // Has a gesture been fully established?
1009 if (AnyThread().awaiting_touch_start_response) {
1010 // No, so arrange for compositor tasks to be run at the highest priority.
1011 return UseCase::TOUCHSTART;
1012 }
1013
1014 // Yes a gesture has been established. Based on how the gesture is handled
1015 // we need to choose between one of four use cases:
1016 // 1. COMPOSITOR_GESTURE where the gesture is processed only on the
1017 // compositor thread.
1018 // 2. MAIN_THREAD_GESTURE where the gesture is processed only on the main
1019 // thread.
1020 // 3. MAIN_THREAD_CUSTOM_INPUT_HANDLING where the main thread processes a
1021 // stream of input events and has prevented a default gesture from being
1022 // started.
1023 // 4. SYNCHRONIZED_GESTURE where the gesture is processed on both threads.
1024 // TODO(skyostil): Consider removing in_idle_period_ and
1025 // HadAnIdlePeriodRecently() unless we need them here.
1026 if (AnyThread().last_gesture_was_compositor_driven) {
1027 if (AnyThread().begin_main_frame_on_critical_path) {
1028 return UseCase::SYNCHRONIZED_GESTURE;
1029 } else {
1030 return UseCase::COMPOSITOR_GESTURE;
1031 }
1032 }
1033 if (AnyThread().default_gesture_prevented) {
1034 return UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING;
1035 } else {
1036 return UseCase::MAIN_THREAD_GESTURE;
1037 }
1038 }
1039
1040 // TODO(alexclarke): return UseCase::LOADING if signals suggest the system is
1041 // in the initial 1s of RAIL loading.
1042 return UseCase::NONE;
1043 }
1044
1045 base::TimeDelta RendererSchedulerImpl::EstimateLongestJankFreeTaskDuration()
1046 const {
1047 switch (MainThreadOnly().current_use_case) {
1048 case UseCase::TOUCHSTART:
1049 case UseCase::COMPOSITOR_GESTURE:
1050 case UseCase::LOADING:
1051 case UseCase::NONE:
1052 return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis);
1053
1054 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING:
1055 case UseCase::MAIN_THREAD_GESTURE:
1056 case UseCase::SYNCHRONIZED_GESTURE:
1057 return MainThreadOnly().idle_time_estimator.GetExpectedIdleDuration(
1058 MainThreadOnly().compositor_frame_interval);
1059
1060 default:
1061 NOTREACHED();
1062 return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis);
1063 }
1064 }
1065
1066 bool RendererSchedulerImpl::CanEnterLongIdlePeriod(
1067 base::TimeTicks now,
1068 base::TimeDelta* next_long_idle_period_delay_out) {
1069 helper_.CheckOnValidThread();
1070
1071 MaybeUpdatePolicy();
1072 if (MainThreadOnly().current_use_case == UseCase::TOUCHSTART) {
1073 // Don't start a long idle task in touch start priority, try again when
1074 // the policy is scheduled to end.
1075 *next_long_idle_period_delay_out =
1076 std::max(base::TimeDelta(),
1077 MainThreadOnly().current_policy_expiration_time - now);
1078 return false;
1079 }
1080 return true;
1081 }
1082
1083 SchedulerHelper* RendererSchedulerImpl::GetSchedulerHelperForTesting() {
1084 return &helper_;
1085 }
1086
1087 TaskCostEstimator*
1088 RendererSchedulerImpl::GetLoadingTaskCostEstimatorForTesting() {
1089 return &MainThreadOnly().loading_task_cost_estimator;
1090 }
1091
1092 TaskCostEstimator*
1093 RendererSchedulerImpl::GetTimerTaskCostEstimatorForTesting() {
1094 return &MainThreadOnly().timer_task_cost_estimator;
1095 }
1096
1097 IdleTimeEstimator* RendererSchedulerImpl::GetIdleTimeEstimatorForTesting() {
1098 return &MainThreadOnly().idle_time_estimator;
1099 }
1100
1101 void RendererSchedulerImpl::SuspendTimerQueue() {
1102 MainThreadOnly().timer_queue_suspend_count++;
1103 ForceUpdatePolicy();
1104 #ifndef NDEBUG
1105 DCHECK(!default_timer_task_runner_->IsQueueEnabled());
1106 for (const auto& runner : timer_task_runners_) {
1107 DCHECK(!runner->IsQueueEnabled());
1108 }
1109 #endif
1110 }
1111
1112 void RendererSchedulerImpl::ResumeTimerQueue() {
1113 MainThreadOnly().timer_queue_suspend_count--;
1114 DCHECK_GE(MainThreadOnly().timer_queue_suspend_count, 0);
1115 ForceUpdatePolicy();
1116 }
1117
1118 void RendererSchedulerImpl::SetTimerQueueSuspensionWhenBackgroundedEnabled(
1119 bool enabled) {
1120 // Note that this will only take effect for the next backgrounded signal.
1121 MainThreadOnly().timer_queue_suspension_when_backgrounded_enabled = enabled;
1122 }
1123
1124 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
1125 RendererSchedulerImpl::AsValue(base::TimeTicks optional_now) const {
1126 base::AutoLock lock(any_thread_lock_);
1127 return AsValueLocked(optional_now);
1128 }
1129
1130 // static
1131 const char* RendererSchedulerImpl::ExpensiveTaskPolicyToString(
1132 ExpensiveTaskPolicy expensive_task_policy) {
1133 switch (expensive_task_policy) {
1134 case ExpensiveTaskPolicy::RUN:
1135 return "RUN";
1136 case ExpensiveTaskPolicy::BLOCK:
1137 return "BLOCK";
1138 case ExpensiveTaskPolicy::THROTTLE:
1139 return "THROTTLE";
1140 default:
1141 NOTREACHED();
1142 return nullptr;
1143 }
1144 }
1145
1146 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
1147 RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const {
1148 helper_.CheckOnValidThread();
1149 any_thread_lock_.AssertAcquired();
1150
1151 if (optional_now.is_null())
1152 optional_now = helper_.scheduler_tqm_delegate()->NowTicks();
1153 std::unique_ptr<base::trace_event::TracedValue> state(
1154 new base::trace_event::TracedValue());
1155 state->SetBoolean(
1156 "has_visible_render_widget_with_touch_handler",
1157 MainThreadOnly().has_visible_render_widget_with_touch_handler);
1158 state->SetString("current_use_case",
1159 UseCaseToString(MainThreadOnly().current_use_case));
1160 state->SetString("rail_mode",
1161 RAILModeToString(MainThreadOnly().current_policy.rail_mode));
1162 state->SetBoolean("expensive_task_blocking_allowed",
1163 MainThreadOnly().expensive_task_blocking_allowed);
1164 state->SetBoolean("loading_tasks_seem_expensive",
1165 MainThreadOnly().loading_tasks_seem_expensive);
1166 state->SetBoolean("timer_tasks_seem_expensive",
1167 MainThreadOnly().timer_tasks_seem_expensive);
1168 state->SetBoolean("begin_frame_not_expected_soon",
1169 MainThreadOnly().begin_frame_not_expected_soon);
1170 state->SetBoolean("touchstart_expected_soon",
1171 MainThreadOnly().touchstart_expected_soon);
1172 state->SetString("idle_period_state",
1173 IdleHelper::IdlePeriodStateToString(
1174 idle_helper_.SchedulerIdlePeriodState()));
1175 state->SetBoolean("renderer_hidden", MainThreadOnly().renderer_hidden);
1176 state->SetBoolean("have_seen_a_begin_main_frame",
1177 MainThreadOnly().have_seen_a_begin_main_frame);
1178 state->SetBoolean(
1179 "have_reported_blocking_intervention_in_current_policy",
1180 MainThreadOnly().have_reported_blocking_intervention_in_current_policy);
1181 state->SetBoolean(
1182 "have_reported_blocking_intervention_since_navigation",
1183 MainThreadOnly().have_reported_blocking_intervention_since_navigation);
1184 state->SetBoolean("renderer_backgrounded",
1185 MainThreadOnly().renderer_backgrounded);
1186 state->SetBoolean("timer_queue_suspended_when_backgrounded",
1187 MainThreadOnly().timer_queue_suspended_when_backgrounded);
1188 state->SetInteger("timer_queue_suspend_count",
1189 MainThreadOnly().timer_queue_suspend_count);
1190 state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF());
1191 state->SetDouble(
1192 "rails_loading_priority_deadline",
1193 (AnyThread().rails_loading_priority_deadline - base::TimeTicks())
1194 .InMillisecondsF());
1195 state->SetDouble(
1196 "fling_compositor_escalation_deadline",
1197 (AnyThread().fling_compositor_escalation_deadline - base::TimeTicks())
1198 .InMillisecondsF());
1199 state->SetInteger("navigation_task_expected_count",
1200 MainThreadOnly().navigation_task_expected_count);
1201 state->SetDouble("last_idle_period_end_time",
1202 (AnyThread().last_idle_period_end_time - base::TimeTicks())
1203 .InMillisecondsF());
1204 state->SetBoolean("awaiting_touch_start_response",
1205 AnyThread().awaiting_touch_start_response);
1206 state->SetBoolean("begin_main_frame_on_critical_path",
1207 AnyThread().begin_main_frame_on_critical_path);
1208 state->SetBoolean("last_gesture_was_compositor_driven",
1209 AnyThread().last_gesture_was_compositor_driven);
1210 state->SetBoolean("default_gesture_prevented",
1211 AnyThread().default_gesture_prevented);
1212 state->SetDouble("expected_loading_task_duration",
1213 MainThreadOnly()
1214 .loading_task_cost_estimator.expected_task_duration()
1215 .InMillisecondsF());
1216 state->SetDouble("expected_timer_task_duration",
1217 MainThreadOnly()
1218 .timer_task_cost_estimator.expected_task_duration()
1219 .InMillisecondsF());
1220 // TODO(skyostil): Can we somehow trace how accurate these estimates were?
1221 state->SetDouble(
1222 "longest_jank_free_task_duration",
1223 MainThreadOnly().longest_jank_free_task_duration.InMillisecondsF());
1224 state->SetDouble(
1225 "compositor_frame_interval",
1226 MainThreadOnly().compositor_frame_interval.InMillisecondsF());
1227 state->SetDouble(
1228 "estimated_next_frame_begin",
1229 (MainThreadOnly().estimated_next_frame_begin - base::TimeTicks())
1230 .InMillisecondsF());
1231 state->SetBoolean("in_idle_period", AnyThread().in_idle_period);
1232
1233 state->SetString(
1234 "expensive_task_policy",
1235 ExpensiveTaskPolicyToString(MainThreadOnly().expensive_task_policy));
1236
1237 AnyThread().user_model.AsValueInto(state.get());
1238 render_widget_scheduler_signals_.AsValueInto(state.get());
1239
1240 return std::move(state);
1241 }
1242
1243 void RendererSchedulerImpl::OnIdlePeriodStarted() {
1244 base::AutoLock lock(any_thread_lock_);
1245 AnyThread().in_idle_period = true;
1246 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
1247 }
1248
1249 void RendererSchedulerImpl::OnIdlePeriodEnded() {
1250 base::AutoLock lock(any_thread_lock_);
1251 AnyThread().last_idle_period_end_time =
1252 helper_.scheduler_tqm_delegate()->NowTicks();
1253 AnyThread().in_idle_period = false;
1254 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
1255 }
1256
1257 void RendererSchedulerImpl::AddPendingNavigation(
1258 blink::WebScheduler::NavigatingFrameType type) {
1259 helper_.CheckOnValidThread();
1260 if (type == blink::WebScheduler::NavigatingFrameType::kMainFrame) {
1261 MainThreadOnly().navigation_task_expected_count++;
1262 UpdatePolicy();
1263 }
1264 }
1265
1266 void RendererSchedulerImpl::RemovePendingNavigation(
1267 blink::WebScheduler::NavigatingFrameType type) {
1268 helper_.CheckOnValidThread();
1269 DCHECK_GT(MainThreadOnly().navigation_task_expected_count, 0);
1270 if (type == blink::WebScheduler::NavigatingFrameType::kMainFrame &&
1271 MainThreadOnly().navigation_task_expected_count > 0) {
1272 MainThreadOnly().navigation_task_expected_count--;
1273 UpdatePolicy();
1274 }
1275 }
1276
1277 void RendererSchedulerImpl::OnNavigationStarted() {
1278 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1279 "RendererSchedulerImpl::OnNavigationStarted");
1280 base::AutoLock lock(any_thread_lock_);
1281 AnyThread().rails_loading_priority_deadline =
1282 helper_.scheduler_tqm_delegate()->NowTicks() +
1283 base::TimeDelta::FromMilliseconds(
1284 kRailsInitialLoadingPrioritizationMillis);
1285 ResetForNavigationLocked();
1286 }
1287
1288 bool RendererSchedulerImpl::HadAnIdlePeriodRecently(base::TimeTicks now) const {
1289 return (now - AnyThread().last_idle_period_end_time) <=
1290 base::TimeDelta::FromMilliseconds(
1291 kIdlePeriodStarvationThresholdMillis);
1292 }
1293
1294 void RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded() {
1295 DCHECK(MainThreadOnly().renderer_backgrounded);
1296 if (MainThreadOnly().timer_queue_suspended_when_backgrounded)
1297 return;
1298
1299 MainThreadOnly().timer_queue_suspended_when_backgrounded = true;
1300 ForceUpdatePolicy();
1301 }
1302
1303 void RendererSchedulerImpl::ResumeTimerQueueWhenForegrounded() {
1304 DCHECK(!MainThreadOnly().renderer_backgrounded);
1305 if (!MainThreadOnly().timer_queue_suspended_when_backgrounded)
1306 return;
1307
1308 MainThreadOnly().timer_queue_suspended_when_backgrounded = false;
1309 ForceUpdatePolicy();
1310 }
1311
1312 void RendererSchedulerImpl::ResetForNavigationLocked() {
1313 helper_.CheckOnValidThread();
1314 any_thread_lock_.AssertAcquired();
1315 AnyThread().user_model.Reset(helper_.scheduler_tqm_delegate()->NowTicks());
1316 AnyThread().have_seen_touchstart = false;
1317 MainThreadOnly().loading_task_cost_estimator.Clear();
1318 MainThreadOnly().timer_task_cost_estimator.Clear();
1319 MainThreadOnly().idle_time_estimator.Clear();
1320 MainThreadOnly().have_seen_a_begin_main_frame = false;
1321 MainThreadOnly().have_reported_blocking_intervention_since_navigation = false;
1322 UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
1323 }
1324
1325 void RendererSchedulerImpl::SetTopLevelBlameContext(
1326 base::trace_event::BlameContext* blame_context) {
1327 // Any task that runs in the default task runners belongs to the context of
1328 // all frames (as opposed to a particular frame). Note that the task itself
1329 // may still enter a more specific blame context if necessary.
1330 //
1331 // Per-frame task runners (loading, timers, etc.) are configured with a more
1332 // specific blame context by WebFrameSchedulerImpl.
1333 control_task_runner_->SetBlameContext(blame_context);
1334 DefaultTaskRunner()->SetBlameContext(blame_context);
1335 default_loading_task_runner_->SetBlameContext(blame_context);
1336 default_timer_task_runner_->SetBlameContext(blame_context);
1337 compositor_task_runner_->SetBlameContext(blame_context);
1338 idle_helper_.IdleTaskRunner()->SetBlameContext(blame_context);
1339 }
1340
1341 void RendererSchedulerImpl::SetRAILModeObserver(RAILModeObserver* observer) {
1342 MainThreadOnly().rail_mode_observer = observer;
1343 }
1344
1345 void RendererSchedulerImpl::RegisterTimeDomain(TimeDomain* time_domain) {
1346 helper_.RegisterTimeDomain(time_domain);
1347 }
1348
1349 void RendererSchedulerImpl::UnregisterTimeDomain(TimeDomain* time_domain) {
1350 helper_.UnregisterTimeDomain(time_domain);
1351 }
1352
1353 void RendererSchedulerImpl::SetExpensiveTaskBlockingAllowed(bool allowed) {
1354 MainThreadOnly().expensive_task_blocking_allowed = allowed;
1355 }
1356
1357 base::TickClock* RendererSchedulerImpl::tick_clock() const {
1358 return helper_.scheduler_tqm_delegate().get();
1359 }
1360
1361 void RendererSchedulerImpl::AddWebViewScheduler(
1362 WebViewSchedulerImpl* web_view_scheduler) {
1363 MainThreadOnly().web_view_schedulers.insert(web_view_scheduler);
1364 }
1365
1366 void RendererSchedulerImpl::RemoveWebViewScheduler(
1367 WebViewSchedulerImpl* web_view_scheduler) {
1368 DCHECK(MainThreadOnly().web_view_schedulers.find(web_view_scheduler) !=
1369 MainThreadOnly().web_view_schedulers.end());
1370 MainThreadOnly().web_view_schedulers.erase(web_view_scheduler);
1371 }
1372
1373 void RendererSchedulerImpl::BroadcastConsoleWarning(
1374 const std::string& message) {
1375 helper_.CheckOnValidThread();
1376 for (auto* web_view_scheduler : MainThreadOnly().web_view_schedulers)
1377 web_view_scheduler->AddConsoleWarning(message);
1378 }
1379
1380 void RendererSchedulerImpl::OnTriedToExecuteBlockedTask(
1381 const TaskQueue& queue,
1382 const base::PendingTask& task) {
1383 if (!MainThreadOnly().expensive_task_blocking_allowed ||
1384 MainThreadOnly().current_use_case == UseCase::TOUCHSTART ||
1385 MainThreadOnly().longest_jank_free_task_duration <
1386 base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis) ||
1387 MainThreadOnly().timer_queue_suspend_count ||
1388 MainThreadOnly().timer_queue_suspended_when_backgrounded) {
1389 return;
1390 }
1391 if (!MainThreadOnly().timer_tasks_seem_expensive &&
1392 !MainThreadOnly().loading_tasks_seem_expensive) {
1393 return;
1394 }
1395 if (!MainThreadOnly().have_reported_blocking_intervention_in_current_policy) {
1396 MainThreadOnly().have_reported_blocking_intervention_in_current_policy =
1397 true;
1398 TRACE_EVENT_INSTANT0("renderer.scheduler",
1399 "RendererSchedulerImpl::TaskBlocked",
1400 TRACE_EVENT_SCOPE_THREAD);
1401 }
1402
1403 if (!MainThreadOnly().have_reported_blocking_intervention_since_navigation) {
1404 {
1405 base::AutoLock lock(any_thread_lock_);
1406 if (!AnyThread().have_seen_touchstart)
1407 return;
1408 }
1409 MainThreadOnly().have_reported_blocking_intervention_since_navigation =
1410 true;
1411 BroadcastConsoleWarning(
1412 "Blink deferred a task in order to make scrolling smoother. "
1413 "Your timer and network tasks should take less than 50ms to run "
1414 "to avoid this. Please see "
1415 "https://developers.google.com/web/tools/chrome-devtools/profile/evaluat e-performance/rail"
1416 " and https://crbug.com/574343#c40 for more information.");
1417 }
1418 }
1419
1420 void RendererSchedulerImpl::ReportTaskTime(base::TimeTicks start_time,
1421 base::TimeTicks end_time) {
1422 MainThreadOnly().queueing_time_estimator.OnToplevelTaskCompleted(start_time,
1423 end_time);
1424 MainThreadOnly().long_task_tracker.RecordLongTask(
1425 start_time, end_time - start_time);
1426 UMA_HISTOGRAM_CUSTOM_COUNTS("RendererScheduler.TaskTime",
1427 (end_time - start_time).InMicroseconds(), 1,
1428 1000000, 50);
1429 }
1430
1431 LongTaskTracker::LongTaskTiming RendererSchedulerImpl::GetLongTaskTiming() {
1432 return MainThreadOnly().long_task_tracker.GetLongTaskTiming();
1433 }
1434
1435 void RendererSchedulerImpl::OnQueueingTimeForWindowEstimated(
1436 base::TimeDelta queueing_time) {
1437 UMA_HISTOGRAM_TIMES("RendererScheduler.ExpectedTaskQueueingDuration",
1438 queueing_time);
1439 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1440 "estimated_queueing_time_for_window",
1441 queueing_time.InMillisecondsF());
1442 }
1443
1444 AutoAdvancingVirtualTimeDomain* RendererSchedulerImpl::GetVirtualTimeDomain() {
1445 if (!virtual_time_domain_) {
1446 virtual_time_domain_.reset(
1447 new AutoAdvancingVirtualTimeDomain(tick_clock()->NowTicks()));
1448 RegisterTimeDomain(virtual_time_domain_.get());
1449 }
1450 return virtual_time_domain_.get();
1451 }
1452
1453 void RendererSchedulerImpl::EnableVirtualTime() {
1454 MainThreadOnly().use_virtual_time = true;
1455
1456 // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy().
1457 AutoAdvancingVirtualTimeDomain* time_domain = GetVirtualTimeDomain();
1458 for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_)
1459 task_queue->SetTimeDomain(time_domain);
1460
1461 throttling_helper_->EnableVirtualTime();
1462
1463 ForceUpdatePolicy();
1464 }
1465
1466 // static
1467 const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) {
1468 switch (use_case) {
1469 case UseCase::NONE:
1470 return "none";
1471 case UseCase::COMPOSITOR_GESTURE:
1472 return "compositor_gesture";
1473 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING:
1474 return "main_thread_custom_input_handling";
1475 case UseCase::SYNCHRONIZED_GESTURE:
1476 return "synchronized_gesture";
1477 case UseCase::TOUCHSTART:
1478 return "touchstart";
1479 case UseCase::LOADING:
1480 return "loading";
1481 case UseCase::MAIN_THREAD_GESTURE:
1482 return "main_thread_gesture";
1483 default:
1484 NOTREACHED();
1485 return nullptr;
1486 }
1487 }
1488
1489 // static
1490 const char* RendererSchedulerImpl::RAILModeToString(v8::RAILMode rail_mode) {
1491 switch (rail_mode) {
1492 case v8::PERFORMANCE_RESPONSE:
1493 return "response";
1494 case v8::PERFORMANCE_ANIMATION:
1495 return "animation";
1496 case v8::PERFORMANCE_IDLE:
1497 return "idle";
1498 case v8::PERFORMANCE_LOAD:
1499 return "load";
1500 default:
1501 NOTREACHED();
1502 return nullptr;
1503 }
1504 }
1505
1506 } // namespace scheduler
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698