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 "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/feature_list.h"
12 #include "base/logging.h"
13 #include "base/metrics/field_trial_params.h"
14 #include "base/metrics/histogram.h"
15 #include "base/metrics/histogram_functions.h"
16 #include "base/metrics/histogram_macros.h"
17 #include "base/numerics/safe_conversions.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/threading/thread_task_runner_handle.h"
20 #include "base/trace_event/trace_event.h"
21 #include "base/trace_event/traced_value.h"
22 #include "build/build_config.h"
23 #include "components/viz/common/frame_sinks/begin_frame_args.h"
24 #include "services/metrics/public/cpp/ukm_builders.h"
25 #include "third_party/blink/public/common/input/web_input_event_attribution.h"
26 #include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
27 #include "third_party/blink/public/common/input/web_touch_event.h"
28 #include "third_party/blink/public/common/page/launching_process_state.h"
29 #include "third_party/blink/public/platform/scheduler/web_renderer_process_type.h"
30 #include "third_party/blink/renderer/platform/bindings/parkable_string_manager.h"
31 #include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h"
32 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
33 #include "third_party/blink/renderer/platform/scheduler/common/features.h"
34 #include "third_party/blink/renderer/platform/scheduler/common/process_state.h"
35 #include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
36 #include "third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h"
37 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
38 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h"
39 #include "third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h"
40 #include "third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.h"
41 #include "third_party/blink/renderer/platform/scheduler/main_thread/widget_scheduler.h"
42 #include "third_party/blink/renderer/platform/scheduler/public/event_loop.h"
43 #include "v8/include/v8.h"
44
45 namespace blink {
46 namespace scheduler {
47
48 using base::sequence_manager::TaskQueue;
49 using base::sequence_manager::TaskTimeObserver;
50 using base::sequence_manager::TimeDomain;
51
52 namespace {
53 const int kShortIdlePeriodDurationSampleCount = 10;
54 const double kShortIdlePeriodDurationPercentile = 50;
55 // Amount of idle time left in a frame (as a ratio of the vsync interval) above
56 // which main thread compositing can be considered fast.
57 const double kFastCompositingIdleTimeThreshold = .2;
58 constexpr base::TimeDelta kQueueingTimeWindowDuration =
59 base::TimeDelta::FromSeconds(1);
60 const int64_t kSecondsPerMinute = 60;
61
62 // Wake-up throttling trial.
63 const char kWakeUpThrottlingTrial[] = "RendererSchedulerWakeUpThrottling";
64 const char kWakeUpDurationParam[] = "wake_up_duration_ms";
65
66 constexpr base::TimeDelta kDefaultWakeUpDuration =
67 base::TimeDelta::FromMilliseconds(3);
68
69 // Name of the finch study that enables using resource fetch priorities to
70 // schedule tasks on Blink.
71 constexpr const char kResourceFetchPriorityExperiment[] =
72 "ResourceFetchPriorityExperiment";
73
GetWakeUpDuration()74 base::TimeDelta GetWakeUpDuration() {
75 int duration_ms;
76 if (!base::StringToInt(base::GetFieldTrialParamValue(kWakeUpThrottlingTrial,
77 kWakeUpDurationParam),
78 &duration_ms))
79 return kDefaultWakeUpDuration;
80 return base::TimeDelta::FromMilliseconds(duration_ms);
81 }
82
RAILModeToV8RAILMode(RAILMode rail_mode)83 v8::RAILMode RAILModeToV8RAILMode(RAILMode rail_mode) {
84 switch (rail_mode) {
85 case RAILMode::kResponse:
86 return v8::RAILMode::PERFORMANCE_RESPONSE;
87 case RAILMode::kAnimation:
88 return v8::RAILMode::PERFORMANCE_ANIMATION;
89 case RAILMode::kIdle:
90 return v8::RAILMode::PERFORMANCE_IDLE;
91 case RAILMode::kLoad:
92 return v8::RAILMode::PERFORMANCE_LOAD;
93 default:
94 NOTREACHED();
95 }
96 }
97
BackgroundStateToString(bool is_backgrounded)98 const char* BackgroundStateToString(bool is_backgrounded) {
99 if (is_backgrounded) {
100 return "renderer_backgrounded";
101 } else {
102 return "renderer_foregrounded";
103 }
104 }
105
HiddenStateToString(bool is_hidden)106 const char* HiddenStateToString(bool is_hidden) {
107 if (is_hidden) {
108 return "hidden";
109 } else {
110 return "visible";
111 }
112 }
113
AudioPlayingStateToString(bool is_audio_playing)114 const char* AudioPlayingStateToString(bool is_audio_playing) {
115 if (is_audio_playing) {
116 return "playing";
117 } else {
118 return "silent";
119 }
120 }
121
RendererProcessTypeToString(WebRendererProcessType process_type)122 const char* RendererProcessTypeToString(WebRendererProcessType process_type) {
123 switch (process_type) {
124 case WebRendererProcessType::kRenderer:
125 return "normal";
126 case WebRendererProcessType::kExtensionRenderer:
127 return "extension";
128 }
129 NOTREACHED();
130 return ""; // MSVC needs that.
131 }
132
OptionalTaskDescriptionToString(base::Optional<MainThreadSchedulerImpl::TaskDescriptionForTracing> desc)133 const char* OptionalTaskDescriptionToString(
134 base::Optional<MainThreadSchedulerImpl::TaskDescriptionForTracing> desc) {
135 if (!desc)
136 return nullptr;
137 if (desc->task_type != TaskType::kDeprecatedNone)
138 return TaskTypeNames::TaskTypeToString(desc->task_type);
139 if (!desc->queue_type)
140 return "detached_tq";
141 return MainThreadTaskQueue::NameForQueueType(desc->queue_type.value());
142 }
143
OptionalTaskPriorityToString(base::Optional<TaskQueue::QueuePriority> priority)144 const char* OptionalTaskPriorityToString(
145 base::Optional<TaskQueue::QueuePriority> priority) {
146 if (!priority)
147 return nullptr;
148 return TaskQueue::PriorityToString(priority.value());
149 }
150
StringToTaskQueuePriority(const std::string & priority)151 TaskQueue::QueuePriority StringToTaskQueuePriority(
152 const std::string& priority) {
153 if (priority == "CONTROL") {
154 return TaskQueue::QueuePriority::kControlPriority;
155 } else if (priority == "HIGHEST") {
156 return TaskQueue::QueuePriority::kHighestPriority;
157 } else if (priority == "HIGH") {
158 return TaskQueue::QueuePriority::kHighPriority;
159 } else if (priority == "NORMAL") {
160 return TaskQueue::QueuePriority::kNormalPriority;
161 } else if (priority == "LOW") {
162 return TaskQueue::QueuePriority::kLowPriority;
163 } else if (priority == "BEST_EFFORT") {
164 return TaskQueue::QueuePriority::kBestEffortPriority;
165 } else {
166 NOTREACHED();
167 return TaskQueue::QueuePriority::kQueuePriorityCount;
168 }
169 }
170
IsBlockingEvent(const blink::WebInputEvent & web_input_event)171 bool IsBlockingEvent(const blink::WebInputEvent& web_input_event) {
172 blink::WebInputEvent::Type type = web_input_event.GetType();
173 DCHECK(type == blink::WebInputEvent::kTouchStart ||
174 type == blink::WebInputEvent::kMouseWheel);
175
176 if (type == blink::WebInputEvent::kTouchStart) {
177 const WebTouchEvent& touch_event =
178 static_cast<const WebTouchEvent&>(web_input_event);
179 return touch_event.dispatch_type == blink::WebInputEvent::kBlocking;
180 }
181
182 const WebMouseWheelEvent& mouse_event =
183 static_cast<const WebMouseWheelEvent&>(web_input_event);
184 return mouse_event.dispatch_type == blink::WebInputEvent::kBlocking;
185 }
186
187 MainThreadSchedulerImpl* g_main_thread_scheduler = nullptr;
188
189 } // namespace
190
MainThreadSchedulerImpl(std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager,base::Optional<base::Time> initial_virtual_time)191 MainThreadSchedulerImpl::MainThreadSchedulerImpl(
192 std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager,
193 base::Optional<base::Time> initial_virtual_time)
194 : sequence_manager_(std::move(sequence_manager)),
195 helper_(sequence_manager_.get(), this),
196 idle_helper_(&helper_,
197 this,
198 "MainThreadSchedulerIdlePeriod",
199 base::TimeDelta(),
200 helper_.NewTaskQueue(
201 MainThreadTaskQueue::QueueCreationParams(
202 MainThreadTaskQueue::QueueType::kIdle)
203 .SetFixedPriority(
204 TaskQueue::QueuePriority::kBestEffortPriority))),
205 render_widget_scheduler_signals_(this),
206 find_in_page_budget_pool_controller_(
207 new FindInPageBudgetPoolController(this)),
208 control_task_queue_(helper_.ControlMainThreadTaskQueue()),
209 compositor_task_queue_(
210 helper_.NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
211 MainThreadTaskQueue::QueueType::kCompositor)
212 .SetShouldMonitorQuiescence(true))),
213 compositor_task_queue_enabled_voter_(
214 compositor_task_queue_->CreateQueueEnabledVoter()),
215 memory_purge_task_queue_(helper_.NewTaskQueue(
216 MainThreadTaskQueue::QueueCreationParams(
217 MainThreadTaskQueue::QueueType::kIdle)
218 .SetFixedPriority(
219 TaskQueue::QueuePriority::kBestEffortPriority))),
220 memory_purge_manager_(memory_purge_task_queue_->CreateTaskRunner(
221 TaskType::kMainThreadTaskQueueMemoryPurge)),
222 non_waking_time_domain_(tick_clock()),
223 delayed_update_policy_runner_(
224 base::BindRepeating(&MainThreadSchedulerImpl::UpdatePolicy,
225 base::Unretained(this)),
226 helper_.ControlMainThreadTaskQueue()->CreateTaskRunner(
227 TaskType::kMainThreadTaskQueueControl)),
228 queueing_time_estimator_(this,
229 kQueueingTimeWindowDuration,
230 20,
231 kLaunchingProcessIsBackgrounded),
232 main_thread_only_(this,
233 compositor_task_queue_,
234 helper_.GetClock(),
235 helper_.NowTicks()),
236 any_thread_(this),
237 policy_may_need_update_(&any_thread_lock_) {
238 // Compositor task queue and default task queue should be managed by
239 // WebThreadScheduler. Control task queue should not.
240 task_runners_.emplace(helper_.DefaultMainThreadTaskQueue(), nullptr);
241 task_runners_.emplace(compositor_task_queue_,
242 compositor_task_queue_->CreateQueueEnabledVoter());
243
244 RegisterTimeDomain(&non_waking_time_domain_);
245
246 v8_task_queue_ = NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
247 MainThreadTaskQueue::QueueType::kV8));
248 ipc_task_queue_ = NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
249 MainThreadTaskQueue::QueueType::kIPC));
250 cleanup_task_queue_ = NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
251 MainThreadTaskQueue::QueueType::kCleanup));
252 non_waking_task_queue_ =
253 NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
254 MainThreadTaskQueue::QueueType::kNonWaking)
255 .SetTimeDomain(&non_waking_time_domain_));
256
257 v8_task_runner_ =
258 v8_task_queue_->CreateTaskRunner(TaskType::kMainThreadTaskQueueV8);
259 compositor_task_runner_ = compositor_task_queue_->CreateTaskRunner(
260 TaskType::kMainThreadTaskQueueCompositor);
261 control_task_runner_ = helper_.ControlMainThreadTaskQueue()->CreateTaskRunner(
262 TaskType::kMainThreadTaskQueueControl);
263 ipc_task_runner_ =
264 ipc_task_queue_->CreateTaskRunner(TaskType::kMainThreadTaskQueueIPC);
265 cleanup_task_runner_ = cleanup_task_queue_->CreateTaskRunner(
266 TaskType::kMainThreadTaskQueueCleanup);
267 non_waking_task_runner_ = non_waking_task_queue_->CreateTaskRunner(
268 TaskType::kMainThreadTaskQueueNonWaking);
269
270 // TaskQueueThrottler requires some task runners, then initialize
271 // TaskQueueThrottler after task queues/runners are initialized.
272 task_queue_throttler_.reset(
273 new TaskQueueThrottler(this, &tracing_controller_));
274 update_policy_closure_ = base::BindRepeating(
275 &MainThreadSchedulerImpl::UpdatePolicy, weak_factory_.GetWeakPtr());
276 end_renderer_hidden_idle_period_closure_.Reset(base::BindRepeating(
277 &MainThreadSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr()));
278
279 TRACE_EVENT_OBJECT_CREATED_WITH_ID(
280 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "MainThreadScheduler",
281 this);
282
283 helper_.SetObserver(this);
284
285 // Register a tracing state observer unless we're running in a test without a
286 // task runner. Note that it's safe to remove a non-existent observer.
287 if (base::ThreadTaskRunnerHandle::IsSet()) {
288 base::trace_event::TraceLog::GetInstance()->AddAsyncEnabledStateObserver(
289 weak_factory_.GetWeakPtr());
290 }
291
292 internal::ProcessState::Get()->is_process_backgrounded =
293 main_thread_only().renderer_backgrounded;
294
295 if (initial_virtual_time) {
296 main_thread_only().initial_virtual_time = *initial_virtual_time;
297 // The real uptime of the machine is irrelevant if we're using virtual time
298 // we choose an arbitrary initial offset.
299 main_thread_only().initial_virtual_time_ticks =
300 base::TimeTicks() + base::TimeDelta::FromSeconds(10);
301 EnableVirtualTime(BaseTimeOverridePolicy::OVERRIDE);
302 SetVirtualTimePolicy(VirtualTimePolicy::kPause);
303 }
304
305 main_thread_only()
306 .compositor_priority_experiments.OnMainThreadSchedulerInitialized();
307
308 main_thread_only().current_policy.find_in_page_priority() =
309 find_in_page_budget_pool_controller_->CurrentTaskPriority();
310
311 g_main_thread_scheduler = this;
312 }
313
~MainThreadSchedulerImpl()314 MainThreadSchedulerImpl::~MainThreadSchedulerImpl() {
315 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
316 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "MainThreadScheduler",
317 this);
318
319 for (auto& pair : task_runners_) {
320 pair.first->ShutdownTaskQueue();
321 }
322
323 UnregisterTimeDomain(&non_waking_time_domain_);
324
325 if (virtual_time_domain_)
326 UnregisterTimeDomain(virtual_time_domain_.get());
327
328 if (virtual_time_control_task_queue_)
329 virtual_time_control_task_queue_->ShutdownTaskQueue();
330
331 base::trace_event::TraceLog::GetInstance()->RemoveAsyncEnabledStateObserver(
332 this);
333
334 // Ensure the renderer scheduler was shut down explicitly, because otherwise
335 // we could end up having stale pointers to the Blink heap which has been
336 // terminated by this point.
337 DCHECK(was_shutdown_);
338
339 g_main_thread_scheduler = nullptr;
340 }
341
342 // static
MainThreadScheduler()343 WebThreadScheduler* WebThreadScheduler::MainThreadScheduler() {
344 return g_main_thread_scheduler;
345 }
346
MainThreadOnly(MainThreadSchedulerImpl * main_thread_scheduler_impl,const scoped_refptr<MainThreadTaskQueue> & compositor_task_runner,const base::TickClock * time_source,base::TimeTicks now)347 MainThreadSchedulerImpl::MainThreadOnly::MainThreadOnly(
348 MainThreadSchedulerImpl* main_thread_scheduler_impl,
349 const scoped_refptr<MainThreadTaskQueue>& compositor_task_runner,
350 const base::TickClock* time_source,
351 base::TimeTicks now)
352 : idle_time_estimator(compositor_task_runner,
353 time_source,
354 kShortIdlePeriodDurationSampleCount,
355 kShortIdlePeriodDurationPercentile),
356 current_use_case(UseCase::kNone,
357 "Scheduler.UseCase",
358 main_thread_scheduler_impl,
359 &main_thread_scheduler_impl->tracing_controller_,
360 UseCaseToString),
361 longest_jank_free_task_duration(
362 base::TimeDelta(),
363 "Scheduler.LongestJankFreeTaskDuration",
364 main_thread_scheduler_impl,
365 &main_thread_scheduler_impl->tracing_controller_,
366 TimeDeltaToMilliseconds),
367 renderer_pause_count(0,
368 "Scheduler.PauseCount",
369 main_thread_scheduler_impl,
370 &main_thread_scheduler_impl->tracing_controller_),
371 rail_mode_for_tracing(current_policy.rail_mode(),
372 "Scheduler.RAILMode",
373 main_thread_scheduler_impl,
374 &main_thread_scheduler_impl->tracing_controller_,
375 RAILModeToString),
376 renderer_hidden(false,
377 "RendererVisibility",
378 main_thread_scheduler_impl,
379 &main_thread_scheduler_impl->tracing_controller_,
380 HiddenStateToString),
381 renderer_backgrounded(kLaunchingProcessIsBackgrounded,
382 "RendererPriority",
383 main_thread_scheduler_impl,
384 &main_thread_scheduler_impl->tracing_controller_,
385 BackgroundStateToString),
386 keep_active_fetch_or_worker(
387 false,
388 "Scheduler.KeepRendererActive",
389 main_thread_scheduler_impl,
390 &main_thread_scheduler_impl->tracing_controller_,
391 YesNoStateToString),
392 blocking_input_expected_soon(
393 false,
394 "Scheduler.BlockingInputExpectedSoon",
395 main_thread_scheduler_impl,
396 &main_thread_scheduler_impl->tracing_controller_,
397 YesNoStateToString),
398 have_seen_a_begin_main_frame(
399 false,
400 "Scheduler.HasSeenBeginMainFrame",
401 main_thread_scheduler_impl,
402 &main_thread_scheduler_impl->tracing_controller_,
403 YesNoStateToString),
404 have_reported_blocking_intervention_in_current_policy(
405 false,
406 "Scheduler.HasReportedBlockingInterventionInCurrentPolicy",
407 main_thread_scheduler_impl,
408 &main_thread_scheduler_impl->tracing_controller_,
409 YesNoStateToString),
410 have_reported_blocking_intervention_since_navigation(
411 false,
412 "Scheduler.HasReportedBlockingInterventionSinceNavigation",
413 main_thread_scheduler_impl,
414 &main_thread_scheduler_impl->tracing_controller_,
415 YesNoStateToString),
416 has_visible_render_widget_with_touch_handler(
417 false,
418 "Scheduler.HasVisibleRenderWidgetWithTouchHandler",
419 main_thread_scheduler_impl,
420 &main_thread_scheduler_impl->tracing_controller_,
421 YesNoStateToString),
422 begin_frame_not_expected_soon(
423 false,
424 "Scheduler.BeginFrameNotExpectedSoon",
425 main_thread_scheduler_impl,
426 &main_thread_scheduler_impl->tracing_controller_,
427 YesNoStateToString),
428 in_idle_period_for_testing(
429 false,
430 "Scheduler.InIdlePeriod",
431 main_thread_scheduler_impl,
432 &main_thread_scheduler_impl->tracing_controller_,
433 YesNoStateToString),
434 use_virtual_time(false,
435 "Scheduler.UseVirtualTime",
436 main_thread_scheduler_impl,
437 &main_thread_scheduler_impl->tracing_controller_,
438 YesNoStateToString),
439 is_audio_playing(false,
440 "RendererAudioState",
441 main_thread_scheduler_impl,
442 &main_thread_scheduler_impl->tracing_controller_,
443 AudioPlayingStateToString),
444 compositor_will_send_main_frame_not_expected(
445 false,
446 "Scheduler.CompositorWillSendMainFrameNotExpected",
447 main_thread_scheduler_impl,
448 &main_thread_scheduler_impl->tracing_controller_,
449 YesNoStateToString),
450 has_navigated(false,
451 "Scheduler.HasNavigated",
452 main_thread_scheduler_impl,
453 &main_thread_scheduler_impl->tracing_controller_,
454 YesNoStateToString),
455 pause_timers_for_webview(false,
456 "Scheduler.PauseTimersForWebview",
457 main_thread_scheduler_impl,
458 &main_thread_scheduler_impl->tracing_controller_,
459 YesNoStateToString),
460 background_status_changed_at(now),
461 wake_up_budget_pool(nullptr),
462 metrics_helper(
463 main_thread_scheduler_impl,
464 main_thread_scheduler_impl->helper_.HasCPUTimingForEachTask(),
465 now,
466 renderer_backgrounded),
467 process_type(WebRendererProcessType::kRenderer,
468 "RendererProcessType",
469 main_thread_scheduler_impl,
470 &main_thread_scheduler_impl->tracing_controller_,
471 RendererProcessTypeToString),
472 task_description_for_tracing(
473 base::nullopt,
474 "Scheduler.MainThreadTask",
475 main_thread_scheduler_impl,
476 &main_thread_scheduler_impl->tracing_controller_,
477 OptionalTaskDescriptionToString),
478 task_priority_for_tracing(
479 base::nullopt,
480 "Scheduler.TaskPriority",
481 main_thread_scheduler_impl,
482 &main_thread_scheduler_impl->tracing_controller_,
483 OptionalTaskPriorityToString),
484 virtual_time_policy(VirtualTimePolicy::kAdvance),
485 virtual_time_pause_count(0),
486 max_virtual_time_task_starvation_count(0),
487 virtual_time_stopped(false),
488 nested_runloop(false),
489 compositing_experiment(main_thread_scheduler_impl),
490 should_prioritize_compositing(false),
491 compositor_priority_experiments(main_thread_scheduler_impl),
492 main_thread_compositing_is_fast(false) {}
493
494 MainThreadSchedulerImpl::MainThreadOnly::~MainThreadOnly() = default;
495
AnyThread(MainThreadSchedulerImpl * main_thread_scheduler_impl)496 MainThreadSchedulerImpl::AnyThread::AnyThread(
497 MainThreadSchedulerImpl* main_thread_scheduler_impl)
498 : awaiting_touch_start_response(
499 false,
500 "Scheduler.AwaitingTouchstartResponse",
501 main_thread_scheduler_impl,
502 &main_thread_scheduler_impl->tracing_controller_,
503 YesNoStateToString),
504 in_idle_period(false,
505 "Scheduler.InIdlePeriod",
506 main_thread_scheduler_impl,
507 &main_thread_scheduler_impl->tracing_controller_,
508 YesNoStateToString),
509 begin_main_frame_on_critical_path(
510 false,
511 "Scheduler.BeginMainFrameOnCriticalPath",
512 main_thread_scheduler_impl,
513 &main_thread_scheduler_impl->tracing_controller_,
514 YesNoStateToString),
515 last_gesture_was_compositor_driven(
516 false,
517 "Scheduler.LastGestureWasCompositorDriven",
518 main_thread_scheduler_impl,
519 &main_thread_scheduler_impl->tracing_controller_,
520 YesNoStateToString),
521 default_gesture_prevented(
522 true,
523 "Scheduler.DefaultGesturePrevented",
524 main_thread_scheduler_impl,
525 &main_thread_scheduler_impl->tracing_controller_,
526 YesNoStateToString),
527 have_seen_a_blocking_gesture(
528 false,
529 "Scheduler.HaveSeenBlockingGesture",
530 main_thread_scheduler_impl,
531 &main_thread_scheduler_impl->tracing_controller_,
532 YesNoStateToString),
533 waiting_for_contentful_paint(
534 true,
535 "Scheduler.WaitingForContentfulPaint",
536 main_thread_scheduler_impl,
537 &main_thread_scheduler_impl->tracing_controller_,
538 YesNoStateToString),
539 waiting_for_meaningful_paint(
540 true,
541 "Scheduler.WaitingForMeaningfulPaint",
542 main_thread_scheduler_impl,
543 &main_thread_scheduler_impl->tracing_controller_,
544 YesNoStateToString),
545 have_seen_input_since_navigation(
546 false,
547 "Scheduler.HaveSeenInputSinceNavigation",
548 main_thread_scheduler_impl,
549 &main_thread_scheduler_impl->tracing_controller_,
550 YesNoStateToString),
551 begin_main_frame_scheduled_count(
552 0,
553 "Scheduler.BeginMainFrameScheduledCount",
554 main_thread_scheduler_impl,
555 &main_thread_scheduler_impl->tracing_controller_) {}
556
SchedulingSettings()557 MainThreadSchedulerImpl::SchedulingSettings::SchedulingSettings() {
558 low_priority_background_page =
559 base::FeatureList::IsEnabled(kLowPriorityForBackgroundPages);
560 best_effort_background_page =
561 base::FeatureList::IsEnabled(kBestEffortPriorityForBackgroundPages);
562
563 low_priority_hidden_frame =
564 base::FeatureList::IsEnabled(kLowPriorityForHiddenFrame);
565 low_priority_subframe = base::FeatureList::IsEnabled(kLowPriorityForSubFrame);
566 low_priority_throttleable =
567 base::FeatureList::IsEnabled(kLowPriorityForThrottleableTask);
568 low_priority_subframe_throttleable =
569 base::FeatureList::IsEnabled(kLowPriorityForSubFrameThrottleableTask);
570 use_frame_priorities_only_during_loading =
571 base::FeatureList::IsEnabled(kFrameExperimentOnlyWhenLoading);
572
573 low_priority_ad_frame = base::FeatureList::IsEnabled(kLowPriorityForAdFrame);
574 best_effort_ad_frame =
575 base::FeatureList::IsEnabled(kBestEffortPriorityForAdFrame);
576 use_adframe_priorities_only_during_loading =
577 base::FeatureList::IsEnabled(kAdFrameExperimentOnlyWhenLoading);
578
579 low_priority_cross_origin =
580 base::FeatureList::IsEnabled(kLowPriorityForCrossOrigin);
581 low_priority_cross_origin_only_during_loading =
582 base::FeatureList::IsEnabled(kLowPriorityForCrossOriginOnlyWhenLoading);
583
584 use_resource_fetch_priority =
585 base::FeatureList::IsEnabled(kUseResourceFetchPriority);
586 use_resource_priorities_only_during_loading =
587 base::FeatureList::IsEnabled(kUseResourceFetchPriorityOnlyWhenLoading);
588
589 prioritize_compositing_and_loading_during_early_loading =
590 base::FeatureList::IsEnabled(
591 kPrioritizeCompositingAndLoadingDuringEarlyLoading);
592
593 if (use_resource_fetch_priority ||
594 use_resource_priorities_only_during_loading) {
595 base::FieldTrialParams params;
596 base::GetFieldTrialParams(kResourceFetchPriorityExperiment, ¶ms);
597 for (size_t net_priority = 0;
598 net_priority < net::RequestPrioritySize::NUM_PRIORITIES;
599 net_priority++) {
600 net_to_blink_priority[net_priority] =
601 TaskQueue::QueuePriority::kNormalPriority;
602 auto iter = params.find(net::RequestPriorityToString(
603 static_cast<net::RequestPriority>(net_priority)));
604 if (iter != params.end()) {
605 net_to_blink_priority[net_priority] =
606 StringToTaskQueuePriority(iter->second);
607 }
608 }
609 }
610 }
611
612 MainThreadSchedulerImpl::AnyThread::~AnyThread() = default;
613
CompositorThreadOnly()614 MainThreadSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly()
615 : last_input_type(blink::WebInputEvent::kUndefined) {}
616
617 MainThreadSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() =
618 default;
619
RendererPauseHandleImpl(MainThreadSchedulerImpl * scheduler)620 MainThreadSchedulerImpl::RendererPauseHandleImpl::RendererPauseHandleImpl(
621 MainThreadSchedulerImpl* scheduler)
622 : scheduler_(scheduler) {
623 scheduler_->PauseRendererImpl();
624 }
625
~RendererPauseHandleImpl()626 MainThreadSchedulerImpl::RendererPauseHandleImpl::~RendererPauseHandleImpl() {
627 scheduler_->ResumeRendererImpl();
628 }
629
ShutdownAllQueues()630 void MainThreadSchedulerImpl::ShutdownAllQueues() {
631 while (!task_runners_.empty()) {
632 scoped_refptr<MainThreadTaskQueue> queue = task_runners_.begin()->first;
633 queue->ShutdownTaskQueue();
634 }
635
636 if (virtual_time_control_task_queue_)
637 virtual_time_control_task_queue_->ShutdownTaskQueue();
638 }
639
Shutdown()640 void MainThreadSchedulerImpl::Shutdown() {
641 if (was_shutdown_)
642 return;
643
644 base::TimeTicks now = tick_clock()->NowTicks();
645 main_thread_only().metrics_helper.OnRendererShutdown(now);
646 main_thread_only()
647 .compositor_priority_experiments.OnMainThreadSchedulerShutdown();
648
649 ShutdownAllQueues();
650 task_queue_throttler_.reset();
651 idle_helper_.Shutdown();
652 helper_.Shutdown();
653 sequence_manager_.reset();
654 main_thread_only().rail_mode_observers.Clear();
655 was_shutdown_ = true;
656 }
657
CreateMainThread()658 std::unique_ptr<Thread> MainThreadSchedulerImpl::CreateMainThread() {
659 return std::make_unique<MainThread>(this);
660 }
661
662 std::unique_ptr<WebWidgetScheduler>
CreateWidgetScheduler()663 MainThreadSchedulerImpl::CreateWidgetScheduler() {
664 return std::make_unique<WidgetScheduler>(this);
665 }
666
667 scoped_refptr<base::SingleThreadTaskRunner>
ControlTaskRunner()668 MainThreadSchedulerImpl::ControlTaskRunner() {
669 return control_task_runner_;
670 }
671
672 scoped_refptr<base::SingleThreadTaskRunner>
DefaultTaskRunner()673 MainThreadSchedulerImpl::DefaultTaskRunner() {
674 return helper_.DefaultTaskRunner();
675 }
676
677 scoped_refptr<SingleThreadIdleTaskRunner>
IdleTaskRunner()678 MainThreadSchedulerImpl::IdleTaskRunner() {
679 return idle_helper_.IdleTaskRunner();
680 }
681
682 scoped_refptr<base::SingleThreadTaskRunner>
IPCTaskRunner()683 MainThreadSchedulerImpl::IPCTaskRunner() {
684 return ipc_task_runner_;
685 }
686
687 scoped_refptr<base::SingleThreadTaskRunner>
CleanupTaskRunner()688 MainThreadSchedulerImpl::CleanupTaskRunner() {
689 return cleanup_task_runner_;
690 }
691
692 scoped_refptr<base::SingleThreadTaskRunner>
DeprecatedDefaultTaskRunner()693 MainThreadSchedulerImpl::DeprecatedDefaultTaskRunner() {
694 return helper_.DeprecatedDefaultTaskRunner();
695 }
696
697 scoped_refptr<base::SingleThreadTaskRunner>
VirtualTimeControlTaskRunner()698 MainThreadSchedulerImpl::VirtualTimeControlTaskRunner() {
699 return virtual_time_control_task_queue_->task_runner();
700 }
701
702 scoped_refptr<MainThreadTaskQueue>
CompositorTaskQueue()703 MainThreadSchedulerImpl::CompositorTaskQueue() {
704 helper_.CheckOnValidThread();
705 return compositor_task_queue_;
706 }
707
V8TaskQueue()708 scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::V8TaskQueue() {
709 helper_.CheckOnValidThread();
710 return v8_task_queue_;
711 }
712
ControlTaskQueue()713 scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::ControlTaskQueue() {
714 return helper_.ControlMainThreadTaskQueue();
715 }
716
DefaultTaskQueue()717 scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::DefaultTaskQueue() {
718 return helper_.DefaultMainThreadTaskQueue();
719 }
720
721 scoped_refptr<MainThreadTaskQueue>
VirtualTimeControlTaskQueue()722 MainThreadSchedulerImpl::VirtualTimeControlTaskQueue() {
723 helper_.CheckOnValidThread();
724 return virtual_time_control_task_queue_;
725 }
726
NewTaskQueue(const MainThreadTaskQueue::QueueCreationParams & params)727 scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::NewTaskQueue(
728 const MainThreadTaskQueue::QueueCreationParams& params) {
729 helper_.CheckOnValidThread();
730 scoped_refptr<MainThreadTaskQueue> task_queue(helper_.NewTaskQueue(params));
731
732 std::unique_ptr<TaskQueue::QueueEnabledVoter> voter;
733 if (params.queue_traits.can_be_deferred ||
734 params.queue_traits.can_be_paused || params.queue_traits.can_be_frozen) {
735 voter = task_queue->CreateQueueEnabledVoter();
736 }
737
738 auto insert_result = task_runners_.emplace(task_queue, std::move(voter));
739 auto queue_class = task_queue->queue_class();
740
741 ApplyTaskQueuePolicy(
742 task_queue.get(), insert_result.first->second.get(), TaskQueuePolicy(),
743 main_thread_only().current_policy.GetQueuePolicy(queue_class));
744
745 task_queue->SetQueuePriority(ComputePriority(task_queue.get()));
746
747 if (task_queue->CanBeThrottled())
748 AddQueueToWakeUpBudgetPool(task_queue.get());
749
750 // If this is a timer queue, and virtual time is enabled and paused, it should
751 // be suspended by adding a fence to prevent immediate tasks from running when
752 // they're not supposed to.
753 if (main_thread_only().virtual_time_stopped &&
754 main_thread_only().use_virtual_time &&
755 !task_queue->CanRunWhenVirtualTimePaused()) {
756 task_queue->InsertFence(TaskQueue::InsertFencePosition::kNow);
757 }
758
759 return task_queue;
760 }
761
762 // TODO(sreejakshetty): Cleanup NewLoadingTaskQueue and NewTimerTaskQueue.
NewLoadingTaskQueue(MainThreadTaskQueue::QueueType queue_type,FrameSchedulerImpl * frame_scheduler)763 scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::NewLoadingTaskQueue(
764 MainThreadTaskQueue::QueueType queue_type,
765 FrameSchedulerImpl* frame_scheduler) {
766 DCHECK_EQ(MainThreadTaskQueue::QueueClassForQueueType(queue_type),
767 MainThreadTaskQueue::QueueClass::kLoading);
768 return NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(queue_type)
769 .SetCanBePaused(true)
770 .SetCanBeFrozen(true)
771 .SetCanBeDeferred(true)
772 .SetFrameScheduler(frame_scheduler));
773 }
774
NewTimerTaskQueue(MainThreadTaskQueue::QueueType queue_type,FrameSchedulerImpl * frame_scheduler)775 scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::NewTimerTaskQueue(
776 MainThreadTaskQueue::QueueType queue_type,
777 FrameSchedulerImpl* frame_scheduler) {
778 DCHECK_EQ(MainThreadTaskQueue::QueueClassForQueueType(queue_type),
779 MainThreadTaskQueue::QueueClass::kTimer);
780 return NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(queue_type)
781 .SetCanBePaused(true)
782 .SetCanBeFrozen(true)
783 .SetCanBeDeferred(true)
784 .SetCanBeThrottled(true)
785 .SetFrameScheduler(frame_scheduler)
786 .SetCanRunWhenVirtualTimePaused(false));
787 }
788
789 std::unique_ptr<WebRenderWidgetSchedulingState>
NewRenderWidgetSchedulingState()790 MainThreadSchedulerImpl::NewRenderWidgetSchedulingState() {
791 return render_widget_scheduler_signals_.NewRenderWidgetSchedulingState();
792 }
793
OnShutdownTaskQueue(const scoped_refptr<MainThreadTaskQueue> & task_queue)794 void MainThreadSchedulerImpl::OnShutdownTaskQueue(
795 const scoped_refptr<MainThreadTaskQueue>& task_queue) {
796 if (was_shutdown_)
797 return;
798
799 if (task_queue_throttler_)
800 task_queue_throttler_->ShutdownTaskQueue(task_queue.get());
801
802 task_runners_.erase(task_queue.get());
803 }
804
CanExceedIdleDeadlineIfRequired() const805 bool MainThreadSchedulerImpl::CanExceedIdleDeadlineIfRequired() const {
806 return idle_helper_.CanExceedIdleDeadlineIfRequired();
807 }
808
AddTaskObserver(base::TaskObserver * task_observer)809 void MainThreadSchedulerImpl::AddTaskObserver(
810 base::TaskObserver* task_observer) {
811 helper_.AddTaskObserver(task_observer);
812 }
813
RemoveTaskObserver(base::TaskObserver * task_observer)814 void MainThreadSchedulerImpl::RemoveTaskObserver(
815 base::TaskObserver* task_observer) {
816 helper_.RemoveTaskObserver(task_observer);
817 }
818
WillBeginFrame(const viz::BeginFrameArgs & args)819 void MainThreadSchedulerImpl::WillBeginFrame(const viz::BeginFrameArgs& args) {
820 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
821 "MainThreadSchedulerImpl::WillBeginFrame", "args",
822 args.AsValue());
823 helper_.CheckOnValidThread();
824 if (helper_.IsShutdown())
825 return;
826
827 EndIdlePeriod();
828 main_thread_only().estimated_next_frame_begin =
829 args.frame_time + args.interval;
830 main_thread_only().have_seen_a_begin_main_frame = true;
831 main_thread_only().begin_frame_not_expected_soon = false;
832 main_thread_only().compositor_frame_interval = args.interval;
833 {
834 base::AutoLock lock(any_thread_lock_);
835 any_thread().begin_main_frame_on_critical_path = args.on_critical_path;
836 }
837 main_thread_only().compositing_experiment.OnWillBeginMainFrame();
838 main_thread_only().compositor_priority_experiments.OnWillBeginMainFrame();
839 }
840
DidCommitFrameToCompositor()841 void MainThreadSchedulerImpl::DidCommitFrameToCompositor() {
842 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
843 "MainThreadSchedulerImpl::DidCommitFrameToCompositor");
844 helper_.CheckOnValidThread();
845 if (helper_.IsShutdown())
846 return;
847
848 base::TimeTicks now(helper_.NowTicks());
849 if (now < main_thread_only().estimated_next_frame_begin) {
850 // TODO(rmcilroy): Consider reducing the idle period based on the runtime of
851 // the next pending delayed tasks (as currently done in for long idle times)
852 idle_helper_.StartIdlePeriod(
853 IdleHelper::IdlePeriodState::kInShortIdlePeriod, now,
854 main_thread_only().estimated_next_frame_begin);
855 }
856
857 main_thread_only().idle_time_estimator.DidCommitFrameToCompositor();
858 }
859
BeginFrameNotExpectedSoon()860 void MainThreadSchedulerImpl::BeginFrameNotExpectedSoon() {
861 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
862 "MainThreadSchedulerImpl::BeginFrameNotExpectedSoon");
863 helper_.CheckOnValidThread();
864 if (helper_.IsShutdown())
865 return;
866
867 main_thread_only().begin_frame_not_expected_soon = true;
868 idle_helper_.EnableLongIdlePeriod();
869 {
870 base::AutoLock lock(any_thread_lock_);
871 any_thread().begin_main_frame_on_critical_path = false;
872 }
873 }
874
BeginMainFrameNotExpectedUntil(base::TimeTicks time)875 void MainThreadSchedulerImpl::BeginMainFrameNotExpectedUntil(
876 base::TimeTicks time) {
877 helper_.CheckOnValidThread();
878 if (helper_.IsShutdown())
879 return;
880
881 base::TimeTicks now(helper_.NowTicks());
882 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
883 "MainThreadSchedulerImpl::BeginMainFrameNotExpectedUntil",
884 "time_remaining", (time - now).InMillisecondsF());
885
886 if (now < time) {
887 // End any previous idle period.
888 EndIdlePeriod();
889
890 // TODO(rmcilroy): Consider reducing the idle period based on the runtime of
891 // the next pending delayed tasks (as currently done in for long idle times)
892 idle_helper_.StartIdlePeriod(
893 IdleHelper::IdlePeriodState::kInShortIdlePeriod, now, time);
894 }
895 }
896
SetAllRenderWidgetsHidden(bool hidden)897 void MainThreadSchedulerImpl::SetAllRenderWidgetsHidden(bool hidden) {
898 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
899 "MainThreadSchedulerImpl::SetAllRenderWidgetsHidden", "hidden",
900 hidden);
901
902 helper_.CheckOnValidThread();
903
904 if (helper_.IsShutdown() || main_thread_only().renderer_hidden == hidden)
905 return;
906
907 end_renderer_hidden_idle_period_closure_.Cancel();
908
909 if (hidden) {
910 idle_helper_.EnableLongIdlePeriod();
911
912 // Ensure that we stop running idle tasks after a few seconds of being
913 // hidden.
914 base::TimeDelta end_idle_when_hidden_delay =
915 base::TimeDelta::FromMilliseconds(kEndIdleWhenHiddenDelayMillis);
916 control_task_queue_->task_runner()->PostDelayedTask(
917 FROM_HERE, end_renderer_hidden_idle_period_closure_.GetCallback(),
918 end_idle_when_hidden_delay);
919 main_thread_only().renderer_hidden = true;
920 } else {
921 main_thread_only().renderer_hidden = false;
922 EndIdlePeriod();
923 }
924
925 // TODO(alexclarke): Should we update policy here?
926 CreateTraceEventObjectSnapshot();
927 }
928
SetHasVisibleRenderWidgetWithTouchHandler(bool has_visible_render_widget_with_touch_handler)929 void MainThreadSchedulerImpl::SetHasVisibleRenderWidgetWithTouchHandler(
930 bool has_visible_render_widget_with_touch_handler) {
931 helper_.CheckOnValidThread();
932 if (has_visible_render_widget_with_touch_handler ==
933 main_thread_only().has_visible_render_widget_with_touch_handler)
934 return;
935
936 main_thread_only().has_visible_render_widget_with_touch_handler =
937 has_visible_render_widget_with_touch_handler;
938
939 base::AutoLock lock(any_thread_lock_);
940 UpdatePolicyLocked(UpdateType::kForceUpdate);
941 }
942
SetRendererHidden(bool hidden)943 void MainThreadSchedulerImpl::SetRendererHidden(bool hidden) {
944 if (hidden) {
945 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
946 "MainThreadSchedulerImpl::OnRendererHidden");
947 } else {
948 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
949 "MainThreadSchedulerImpl::OnRendererVisible");
950 }
951 helper_.CheckOnValidThread();
952 main_thread_only().renderer_hidden = hidden;
953 }
954
SetRendererBackgrounded(bool backgrounded)955 void MainThreadSchedulerImpl::SetRendererBackgrounded(bool backgrounded) {
956 helper_.CheckOnValidThread();
957
958 // Increasing timer slack helps the OS to coalesce timers efficiently.
959 base::TimerSlack timer_slack = base::TIMER_SLACK_NONE;
960 if (backgrounded)
961 timer_slack = base::TIMER_SLACK_MAXIMUM;
962 helper_.SetTimerSlack(timer_slack);
963
964 if (helper_.IsShutdown() ||
965 main_thread_only().renderer_backgrounded == backgrounded)
966 return;
967 if (backgrounded) {
968 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
969 "MainThreadSchedulerImpl::OnRendererBackgrounded");
970 } else {
971 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
972 "MainThreadSchedulerImpl::OnRendererForegrounded");
973 }
974
975 main_thread_only().renderer_backgrounded = backgrounded;
976 internal::ProcessState::Get()->is_process_backgrounded = backgrounded;
977
978 main_thread_only().background_status_changed_at = tick_clock()->NowTicks();
979 queueing_time_estimator_.OnRecordingStateChanged(
980 backgrounded, main_thread_only().background_status_changed_at);
981
982 UpdatePolicy();
983
984 base::TimeTicks now = tick_clock()->NowTicks();
985 if (backgrounded) {
986 main_thread_only().metrics_helper.OnRendererBackgrounded(now);
987 } else {
988 main_thread_only().metrics_helper.OnRendererForegrounded(now);
989 }
990
991 ParkableStringManager::Instance().SetRendererBackgrounded(backgrounded);
992 memory_purge_manager_.SetRendererBackgrounded(backgrounded);
993 }
994
SetSchedulerKeepActive(bool keep_active)995 void MainThreadSchedulerImpl::SetSchedulerKeepActive(bool keep_active) {
996 main_thread_only().keep_active_fetch_or_worker = keep_active;
997 for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
998 page_scheduler->SetKeepActive(keep_active);
999 }
1000 }
1001
OnMainFrameRequestedForInput()1002 void MainThreadSchedulerImpl::OnMainFrameRequestedForInput() {
1003 main_thread_only().compositing_experiment.OnMainFrameRequestedForInput();
1004 }
1005
SchedulerKeepActive()1006 bool MainThreadSchedulerImpl::SchedulerKeepActive() {
1007 return main_thread_only().keep_active_fetch_or_worker;
1008 }
1009
1010 #if defined(OS_ANDROID)
PauseTimersForAndroidWebView()1011 void MainThreadSchedulerImpl::PauseTimersForAndroidWebView() {
1012 main_thread_only().pause_timers_for_webview = true;
1013 UpdatePolicy();
1014 }
1015
ResumeTimersForAndroidWebView()1016 void MainThreadSchedulerImpl::ResumeTimersForAndroidWebView() {
1017 main_thread_only().pause_timers_for_webview = false;
1018 UpdatePolicy();
1019 }
1020 #endif
1021
OnAudioStateChanged()1022 void MainThreadSchedulerImpl::OnAudioStateChanged() {
1023 bool is_audio_playing = false;
1024 for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
1025 is_audio_playing = is_audio_playing || page_scheduler->IsAudioPlaying();
1026 }
1027
1028 if (is_audio_playing == main_thread_only().is_audio_playing)
1029 return;
1030
1031 main_thread_only().is_audio_playing = is_audio_playing;
1032 }
1033
1034 std::unique_ptr<ThreadScheduler::RendererPauseHandle>
PauseRenderer()1035 MainThreadSchedulerImpl::PauseRenderer() {
1036 return std::make_unique<RendererPauseHandleImpl>(this);
1037 }
1038
PauseRendererImpl()1039 void MainThreadSchedulerImpl::PauseRendererImpl() {
1040 helper_.CheckOnValidThread();
1041 if (helper_.IsShutdown())
1042 return;
1043
1044 ++main_thread_only().renderer_pause_count;
1045 UpdatePolicy();
1046 }
1047
ResumeRendererImpl()1048 void MainThreadSchedulerImpl::ResumeRendererImpl() {
1049 helper_.CheckOnValidThread();
1050 if (helper_.IsShutdown())
1051 return;
1052 --main_thread_only().renderer_pause_count;
1053 DCHECK_GE(main_thread_only().renderer_pause_count.value(), 0);
1054 UpdatePolicy();
1055 }
1056
EndIdlePeriod()1057 void MainThreadSchedulerImpl::EndIdlePeriod() {
1058 if (main_thread_only().in_idle_period_for_testing)
1059 return;
1060 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1061 "MainThreadSchedulerImpl::EndIdlePeriod");
1062 helper_.CheckOnValidThread();
1063 idle_helper_.EndIdlePeriod();
1064 }
1065
EndIdlePeriodForTesting(base::OnceClosure callback,base::TimeTicks time_remaining)1066 void MainThreadSchedulerImpl::EndIdlePeriodForTesting(
1067 base::OnceClosure callback,
1068 base::TimeTicks time_remaining) {
1069 main_thread_only().in_idle_period_for_testing = false;
1070 EndIdlePeriod();
1071 std::move(callback).Run();
1072 }
1073
PolicyNeedsUpdateForTesting()1074 bool MainThreadSchedulerImpl::PolicyNeedsUpdateForTesting() {
1075 return policy_may_need_update_.IsSet();
1076 }
1077
SetHaveSeenABlockingGestureForTesting(bool status)1078 void MainThreadSchedulerImpl::SetHaveSeenABlockingGestureForTesting(
1079 bool status) {
1080 base::AutoLock lock(any_thread_lock_);
1081 any_thread().have_seen_a_blocking_gesture = status;
1082 }
1083
PerformMicrotaskCheckpoint()1084 void MainThreadSchedulerImpl::PerformMicrotaskCheckpoint() {
1085 if (isolate())
1086 EventLoop::PerformIsolateGlobalMicrotasksCheckpoint(isolate());
1087 }
1088
1089 // static
ShouldPrioritizeInputEvent(const blink::WebInputEvent & web_input_event)1090 bool MainThreadSchedulerImpl::ShouldPrioritizeInputEvent(
1091 const blink::WebInputEvent& web_input_event) {
1092 // We regard MouseMove events with the left mouse button down as a signal
1093 // that the user is doing something requiring a smooth frame rate.
1094 if ((web_input_event.GetType() == blink::WebInputEvent::kMouseDown ||
1095 web_input_event.GetType() == blink::WebInputEvent::kMouseMove) &&
1096 (web_input_event.GetModifiers() &
1097 blink::WebInputEvent::kLeftButtonDown)) {
1098 return true;
1099 }
1100 // Ignore all other mouse events because they probably don't signal user
1101 // interaction needing a smooth framerate. NOTE isMouseEventType returns false
1102 // for mouse wheel events, hence we regard them as user input.
1103 // Ignore keyboard events because it doesn't really make sense to enter
1104 // compositor priority for them.
1105 if (blink::WebInputEvent::IsMouseEventType(web_input_event.GetType()) ||
1106 blink::WebInputEvent::IsKeyboardEventType(web_input_event.GetType())) {
1107 return false;
1108 }
1109 return true;
1110 }
1111
DidHandleInputEventOnCompositorThread(const blink::WebInputEvent & web_input_event,InputEventState event_state)1112 void MainThreadSchedulerImpl::DidHandleInputEventOnCompositorThread(
1113 const blink::WebInputEvent& web_input_event,
1114 InputEventState event_state) {
1115 TRACE_EVENT0(
1116 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1117 "MainThreadSchedulerImpl::DidHandleInputEventOnCompositorThread");
1118 if (!ShouldPrioritizeInputEvent(web_input_event))
1119 return;
1120
1121 UpdateForInputEventOnCompositorThread(web_input_event, event_state);
1122 }
1123
DidAnimateForInputOnCompositorThread()1124 void MainThreadSchedulerImpl::DidAnimateForInputOnCompositorThread() {
1125 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1126 "MainThreadSchedulerImpl::DidAnimateForInputOnCompositorThread");
1127 base::AutoLock lock(any_thread_lock_);
1128 any_thread().fling_compositor_escalation_deadline =
1129 helper_.NowTicks() +
1130 base::TimeDelta::FromMilliseconds(kFlingEscalationLimitMillis);
1131 }
1132
DidScheduleBeginMainFrame()1133 void MainThreadSchedulerImpl::DidScheduleBeginMainFrame() {
1134 base::AutoLock lock(any_thread_lock_);
1135 any_thread().begin_main_frame_scheduled_count += 1;
1136 }
1137
DidRunBeginMainFrame()1138 void MainThreadSchedulerImpl::DidRunBeginMainFrame() {
1139 base::AutoLock lock(any_thread_lock_);
1140 any_thread().begin_main_frame_scheduled_count -= 1;
1141 }
1142
UpdateForInputEventOnCompositorThread(const blink::WebInputEvent & web_input_event,InputEventState input_event_state)1143 void MainThreadSchedulerImpl::UpdateForInputEventOnCompositorThread(
1144 const blink::WebInputEvent& web_input_event,
1145 InputEventState input_event_state) {
1146 base::AutoLock lock(any_thread_lock_);
1147 base::TimeTicks now = helper_.NowTicks();
1148
1149 blink::WebInputEvent::Type type = web_input_event.GetType();
1150
1151 // TODO(alexclarke): Move WebInputEventTraits where we can access it from here
1152 // and record the name rather than the integer representation.
1153 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1154 "MainThreadSchedulerImpl::UpdateForInputEventOnCompositorThread",
1155 "type", static_cast<int>(type), "input_event_state",
1156 InputEventStateToString(input_event_state));
1157
1158 base::TimeDelta unused_policy_duration;
1159 UseCase previous_use_case =
1160 ComputeCurrentUseCase(now, &unused_policy_duration);
1161 bool was_awaiting_touch_start_response =
1162 any_thread().awaiting_touch_start_response;
1163
1164 any_thread().user_model.DidStartProcessingInputEvent(type, now);
1165 any_thread().have_seen_input_since_navigation = true;
1166
1167 if (input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR)
1168 any_thread().user_model.DidFinishProcessingInputEvent(now);
1169
1170 switch (type) {
1171 case blink::WebInputEvent::kTouchStart:
1172 any_thread().awaiting_touch_start_response = true;
1173 // This is just a fail-safe to reset the state of
1174 // |last_gesture_was_compositor_driven| to the default. We don't know
1175 // yet where the gesture will run.
1176 any_thread().last_gesture_was_compositor_driven = false;
1177 // Assume the default gesture is prevented until we see evidence
1178 // otherwise.
1179 any_thread().default_gesture_prevented = true;
1180
1181 if (IsBlockingEvent(web_input_event))
1182 any_thread().have_seen_a_blocking_gesture = true;
1183 break;
1184 case blink::WebInputEvent::kTouchMove:
1185 // Observation of consecutive touchmoves is a strong signal that the
1186 // page is consuming the touch sequence, in which case touchstart
1187 // response prioritization is no longer necessary. Otherwise, the
1188 // initial touchmove should preserve the touchstart response pending
1189 // state.
1190 if (any_thread().awaiting_touch_start_response &&
1191 GetCompositorThreadOnly().last_input_type ==
1192 blink::WebInputEvent::kTouchMove) {
1193 any_thread().awaiting_touch_start_response = false;
1194 }
1195 break;
1196
1197 case blink::WebInputEvent::kGesturePinchUpdate:
1198 case blink::WebInputEvent::kGestureScrollUpdate:
1199 // If we see events for an established gesture, we can lock it to the
1200 // appropriate thread as the gesture can no longer be cancelled.
1201 any_thread().last_gesture_was_compositor_driven =
1202 input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR;
1203 any_thread().awaiting_touch_start_response = false;
1204 any_thread().default_gesture_prevented = false;
1205 break;
1206
1207 case blink::WebInputEvent::kGestureFlingCancel:
1208 any_thread().fling_compositor_escalation_deadline = base::TimeTicks();
1209 break;
1210
1211 case blink::WebInputEvent::kGestureTapDown:
1212 case blink::WebInputEvent::kGestureShowPress:
1213 case blink::WebInputEvent::kGestureScrollEnd:
1214 // With no observable effect, these meta events do not indicate a
1215 // meaningful touchstart response and should not impact task priority.
1216 break;
1217
1218 case blink::WebInputEvent::kMouseDown:
1219 // Reset tracking state at the start of a new mouse drag gesture.
1220 any_thread().last_gesture_was_compositor_driven = false;
1221 any_thread().default_gesture_prevented = true;
1222 break;
1223
1224 case blink::WebInputEvent::kMouseMove:
1225 // Consider mouse movement with the left button held down (see
1226 // ShouldPrioritizeInputEvent) similarly to a touch gesture.
1227 any_thread().last_gesture_was_compositor_driven =
1228 input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR;
1229 any_thread().awaiting_touch_start_response = false;
1230 break;
1231
1232 case blink::WebInputEvent::kMouseWheel:
1233 any_thread().last_gesture_was_compositor_driven =
1234 input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR;
1235 any_thread().awaiting_touch_start_response = false;
1236 // If the event was sent to the main thread, assume the default gesture is
1237 // prevented until we see evidence otherwise.
1238 any_thread().default_gesture_prevented =
1239 !any_thread().last_gesture_was_compositor_driven;
1240 if (IsBlockingEvent(web_input_event))
1241 any_thread().have_seen_a_blocking_gesture = true;
1242 break;
1243 case blink::WebInputEvent::kUndefined:
1244 break;
1245
1246 default:
1247 any_thread().awaiting_touch_start_response = false;
1248 break;
1249 }
1250
1251 // Avoid unnecessary policy updates if the use case did not change.
1252 UseCase use_case = ComputeCurrentUseCase(now, &unused_policy_duration);
1253
1254 if (use_case != previous_use_case ||
1255 was_awaiting_touch_start_response !=
1256 any_thread().awaiting_touch_start_response) {
1257 EnsureUrgentPolicyUpdatePostedOnMainThread(FROM_HERE);
1258 }
1259 GetCompositorThreadOnly().last_input_type = type;
1260 }
1261
WillPostInputEventToMainThread(WebInputEvent::Type web_input_event_type,const WebInputEventAttribution & web_input_event_attribution)1262 void MainThreadSchedulerImpl::WillPostInputEventToMainThread(
1263 WebInputEvent::Type web_input_event_type,
1264 const WebInputEventAttribution& web_input_event_attribution) {
1265 base::AutoLock lock(any_thread_lock_);
1266 any_thread().pending_input_monitor.OnEnqueue(web_input_event_type);
1267 }
1268
WillHandleInputEventOnMainThread(WebInputEvent::Type web_input_event_type,const WebInputEventAttribution & web_input_event_attribution)1269 void MainThreadSchedulerImpl::WillHandleInputEventOnMainThread(
1270 WebInputEvent::Type web_input_event_type,
1271 const WebInputEventAttribution& web_input_event_attribution) {
1272 helper_.CheckOnValidThread();
1273
1274 base::AutoLock lock(any_thread_lock_);
1275 any_thread().pending_input_monitor.OnDequeue(web_input_event_type);
1276 }
1277
DidHandleInputEventOnMainThread(const WebInputEvent & web_input_event,WebInputEventResult result)1278 void MainThreadSchedulerImpl::DidHandleInputEventOnMainThread(
1279 const WebInputEvent& web_input_event,
1280 WebInputEventResult result) {
1281 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
1282 "MainThreadSchedulerImpl::DidHandleInputEventOnMainThread");
1283 helper_.CheckOnValidThread();
1284 if (ShouldPrioritizeInputEvent(web_input_event)) {
1285 base::AutoLock lock(any_thread_lock_);
1286 any_thread().user_model.DidFinishProcessingInputEvent(helper_.NowTicks());
1287
1288 // If we were waiting for a touchstart response and the main thread has
1289 // prevented the default gesture, consider the gesture established. This
1290 // ensures single-event gestures such as button presses are promptly
1291 // detected.
1292 if (any_thread().awaiting_touch_start_response &&
1293 result == WebInputEventResult::kHandledApplication) {
1294 any_thread().awaiting_touch_start_response = false;
1295 any_thread().default_gesture_prevented = true;
1296 UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
1297 }
1298 }
1299 }
1300
IsHighPriorityWorkAnticipated()1301 bool MainThreadSchedulerImpl::IsHighPriorityWorkAnticipated() {
1302 helper_.CheckOnValidThread();
1303 if (helper_.IsShutdown())
1304 return false;
1305
1306 MaybeUpdatePolicy();
1307 // The touchstart, synchronized gesture and main-thread gesture use cases
1308 // indicate a strong likelihood of high-priority work in the near future.
1309 UseCase use_case = main_thread_only().current_use_case;
1310 return main_thread_only().blocking_input_expected_soon ||
1311 use_case == UseCase::kTouchstart ||
1312 use_case == UseCase::kMainThreadGesture ||
1313 use_case == UseCase::kMainThreadCustomInputHandling ||
1314 use_case == UseCase::kSynchronizedGesture;
1315 }
1316
ShouldYieldForHighPriorityWork()1317 bool MainThreadSchedulerImpl::ShouldYieldForHighPriorityWork() {
1318 helper_.CheckOnValidThread();
1319 if (helper_.IsShutdown())
1320 return false;
1321
1322 MaybeUpdatePolicy();
1323 // We only yield if there's a urgent task to be run now, or we are expecting
1324 // one soon (touch start).
1325 // Note: even though the control queue has the highest priority we don't yield
1326 // for it since these tasks are not user-provided work and they are only
1327 // intended to run before the next task, not interrupt the tasks.
1328 switch (main_thread_only().current_use_case) {
1329 case UseCase::kCompositorGesture:
1330 case UseCase::kNone:
1331 return main_thread_only().blocking_input_expected_soon;
1332
1333 case UseCase::kMainThreadGesture:
1334 case UseCase::kMainThreadCustomInputHandling:
1335 case UseCase::kSynchronizedGesture:
1336 return compositor_task_queue_->HasTaskToRunImmediately() ||
1337 main_thread_only().blocking_input_expected_soon;
1338
1339 case UseCase::kTouchstart:
1340 return true;
1341
1342 case UseCase::kEarlyLoading:
1343 case UseCase::kLoading:
1344 return false;
1345
1346 default:
1347 NOTREACHED();
1348 return false;
1349 }
1350 }
1351
CurrentIdleTaskDeadlineForTesting() const1352 base::TimeTicks MainThreadSchedulerImpl::CurrentIdleTaskDeadlineForTesting()
1353 const {
1354 return idle_helper_.CurrentIdleTaskDeadline();
1355 }
1356
RunIdleTasksForTesting(base::OnceClosure callback)1357 void MainThreadSchedulerImpl::RunIdleTasksForTesting(
1358 base::OnceClosure callback) {
1359 main_thread_only().in_idle_period_for_testing = true;
1360 IdleTaskRunner()->PostIdleTask(
1361 FROM_HERE,
1362 base::BindOnce(&MainThreadSchedulerImpl::EndIdlePeriodForTesting,
1363 weak_factory_.GetWeakPtr(), std::move(callback)));
1364 idle_helper_.EnableLongIdlePeriod();
1365 }
1366
MaybeUpdatePolicy()1367 void MainThreadSchedulerImpl::MaybeUpdatePolicy() {
1368 helper_.CheckOnValidThread();
1369 if (policy_may_need_update_.IsSet()) {
1370 UpdatePolicy();
1371 }
1372 }
1373
EnsureUrgentPolicyUpdatePostedOnMainThread(const base::Location & from_here)1374 void MainThreadSchedulerImpl::EnsureUrgentPolicyUpdatePostedOnMainThread(
1375 const base::Location& from_here) {
1376 // TODO(scheduler-dev): Check that this method isn't called from the main
1377 // thread.
1378 any_thread_lock_.AssertAcquired();
1379 if (!policy_may_need_update_.IsSet()) {
1380 policy_may_need_update_.SetWhileLocked(true);
1381 control_task_queue_->task_runner()->PostTask(from_here,
1382 update_policy_closure_);
1383 }
1384 }
1385
UpdatePolicy()1386 void MainThreadSchedulerImpl::UpdatePolicy() {
1387 base::AutoLock lock(any_thread_lock_);
1388 UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
1389 }
1390
ForceUpdatePolicy()1391 void MainThreadSchedulerImpl::ForceUpdatePolicy() {
1392 base::AutoLock lock(any_thread_lock_);
1393 UpdatePolicyLocked(UpdateType::kForceUpdate);
1394 }
1395
UpdatePolicyLocked(UpdateType update_type)1396 void MainThreadSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
1397 helper_.CheckOnValidThread();
1398 any_thread_lock_.AssertAcquired();
1399 if (helper_.IsShutdown())
1400 return;
1401
1402 base::TimeTicks now = helper_.NowTicks();
1403 policy_may_need_update_.SetWhileLocked(false);
1404
1405 base::TimeDelta expected_use_case_duration;
1406 main_thread_only().current_use_case =
1407 ComputeCurrentUseCase(now, &expected_use_case_duration);
1408
1409 base::TimeDelta gesture_expected_flag_valid_for_duration;
1410
1411 main_thread_only().blocking_input_expected_soon = false;
1412 if (any_thread().have_seen_a_blocking_gesture) {
1413 main_thread_only().blocking_input_expected_soon =
1414 any_thread().user_model.IsGestureExpectedSoon(
1415 now, &gesture_expected_flag_valid_for_duration);
1416 }
1417
1418 base::TimeDelta longest_jank_free_task_duration =
1419 EstimateLongestJankFreeTaskDuration();
1420 main_thread_only().longest_jank_free_task_duration =
1421 longest_jank_free_task_duration;
1422
1423 // The |new_policy_duration| is the minimum of |expected_use_case_duration|
1424 // and |gesture_expected_flag_valid_for_duration| unless one is zero in
1425 // which case we choose the other.
1426 base::TimeDelta new_policy_duration = expected_use_case_duration;
1427 if (new_policy_duration.is_zero() ||
1428 (gesture_expected_flag_valid_for_duration > base::TimeDelta() &&
1429 new_policy_duration > gesture_expected_flag_valid_for_duration)) {
1430 new_policy_duration = gesture_expected_flag_valid_for_duration;
1431 }
1432
1433 if (new_policy_duration > base::TimeDelta()) {
1434 main_thread_only().current_policy_expiration_time =
1435 now + new_policy_duration;
1436 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration,
1437 now);
1438 } else {
1439 main_thread_only().current_policy_expiration_time = base::TimeTicks();
1440 }
1441
1442 // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely
1443 // slow, because that can cause starvation in other task sources.
1444 main_thread_only().main_thread_compositing_is_fast =
1445 main_thread_only().idle_time_estimator.GetExpectedIdleDuration(
1446 main_thread_only().compositor_frame_interval) >
1447 main_thread_only().compositor_frame_interval *
1448 kFastCompositingIdleTimeThreshold;
1449
1450 Policy new_policy;
1451 new_policy.rail_mode() = RAILMode::kAnimation;
1452 new_policy.use_case() = main_thread_only().current_use_case;
1453
1454 switch (new_policy.use_case()) {
1455 case UseCase::kCompositorGesture:
1456 if (main_thread_only().blocking_input_expected_soon)
1457 new_policy.rail_mode() = RAILMode::kResponse;
1458 break;
1459
1460 case UseCase::kSynchronizedGesture:
1461 if (main_thread_only().blocking_input_expected_soon)
1462 new_policy.rail_mode() = RAILMode::kResponse;
1463 break;
1464
1465 case UseCase::kMainThreadCustomInputHandling:
1466 break;
1467
1468 case UseCase::kMainThreadGesture:
1469 if (main_thread_only().blocking_input_expected_soon)
1470 new_policy.rail_mode() = RAILMode::kResponse;
1471 break;
1472
1473 case UseCase::kTouchstart:
1474 new_policy.rail_mode() = RAILMode::kResponse;
1475 new_policy.loading_queue_policy().is_deferred = true;
1476 new_policy.timer_queue_policy().is_deferred = true;
1477 break;
1478
1479 case UseCase::kNone:
1480 // It's only safe to block tasks if we are expecting a compositor
1481 // driven gesture.
1482 if (main_thread_only().blocking_input_expected_soon &&
1483 any_thread().last_gesture_was_compositor_driven) {
1484 new_policy.rail_mode() = RAILMode::kResponse;
1485 }
1486 break;
1487
1488 case UseCase::kEarlyLoading:
1489 new_policy.rail_mode() = RAILMode::kLoad;
1490 break;
1491
1492 case UseCase::kLoading:
1493 new_policy.rail_mode() = RAILMode::kLoad;
1494 // TODO(skyostil): Experiment with throttling rendering frame rate.
1495 break;
1496
1497 default:
1498 NOTREACHED();
1499 }
1500
1501 if (main_thread_only().should_prioritize_compositing) {
1502 new_policy.compositor_priority() =
1503 main_thread_only()
1504 .compositing_experiment.GetIncreasedCompositingPriority();
1505 } else if (scheduling_settings_
1506 .prioritize_compositing_and_loading_during_early_loading &&
1507 current_use_case() == UseCase::kEarlyLoading) {
1508 new_policy.compositor_priority() =
1509 base::sequence_manager::TaskQueue::QueuePriority::kHighPriority;
1510 new_policy.should_prioritize_loading_with_compositing() = true;
1511 } else {
1512 base::Optional<TaskQueue::QueuePriority> computed_compositor_priority =
1513 ComputeCompositorPriorityFromUseCase();
1514 if (computed_compositor_priority) {
1515 new_policy.compositor_priority() = computed_compositor_priority.value();
1516 } else if (main_thread_only()
1517 .compositor_priority_experiments.IsExperimentActive()) {
1518 new_policy.compositor_priority() =
1519 main_thread_only()
1520 .compositor_priority_experiments.GetCompositorPriority();
1521 }
1522 }
1523
1524 // TODO(skyostil): Add an idle state for foreground tabs too.
1525 if (main_thread_only().renderer_hidden)
1526 new_policy.rail_mode() = RAILMode::kIdle;
1527
1528 if (main_thread_only().renderer_pause_count != 0) {
1529 new_policy.loading_queue_policy().is_paused = true;
1530 new_policy.timer_queue_policy().is_paused = true;
1531 }
1532 if (main_thread_only().pause_timers_for_webview) {
1533 new_policy.timer_queue_policy().is_paused = true;
1534 }
1535
1536 if (main_thread_only().use_virtual_time) {
1537 new_policy.compositor_queue_policy().use_virtual_time = true;
1538 new_policy.default_queue_policy().use_virtual_time = true;
1539 new_policy.loading_queue_policy().use_virtual_time = true;
1540 new_policy.timer_queue_policy().use_virtual_time = true;
1541 }
1542
1543 new_policy.should_disable_throttling() = main_thread_only().use_virtual_time;
1544
1545 new_policy.find_in_page_priority() =
1546 find_in_page_budget_pool_controller_->CurrentTaskPriority();
1547
1548 // Tracing is done before the early out check, because it's quite possible we
1549 // will otherwise miss this information in traces.
1550 CreateTraceEventObjectSnapshotLocked();
1551
1552 // TODO(alexclarke): Can we get rid of force update now?
1553 if (update_type == UpdateType::kMayEarlyOutIfPolicyUnchanged &&
1554 new_policy == main_thread_only().current_policy) {
1555 return;
1556 }
1557
1558 for (const auto& pair : task_runners_) {
1559 MainThreadTaskQueue::QueueClass queue_class = pair.first->queue_class();
1560
1561 ApplyTaskQueuePolicy(
1562 pair.first.get(), pair.second.get(),
1563 main_thread_only().current_policy.GetQueuePolicy(queue_class),
1564 new_policy.GetQueuePolicy(queue_class));
1565 }
1566
1567 main_thread_only().rail_mode_for_tracing = new_policy.rail_mode();
1568 if (new_policy.rail_mode() != main_thread_only().current_policy.rail_mode()) {
1569 if (isolate()) {
1570 isolate()->SetRAILMode(RAILModeToV8RAILMode(new_policy.rail_mode()));
1571 }
1572 for (auto& observer : main_thread_only().rail_mode_observers) {
1573 observer.OnRAILModeChanged(new_policy.rail_mode());
1574 }
1575 }
1576
1577 if (new_policy.should_disable_throttling() !=
1578 main_thread_only().current_policy.should_disable_throttling()) {
1579 if (new_policy.should_disable_throttling()) {
1580 task_queue_throttler()->DisableThrottling();
1581 } else {
1582 task_queue_throttler()->EnableThrottling();
1583 }
1584 }
1585
1586 DCHECK(compositor_task_queue_->IsQueueEnabled());
1587
1588 Policy old_policy = main_thread_only().current_policy;
1589 main_thread_only().current_policy = new_policy;
1590
1591 if (ShouldUpdateTaskQueuePriorities(old_policy)) {
1592 for (const auto& pair : task_runners_) {
1593 MainThreadTaskQueue* task_queue = pair.first.get();
1594 task_queue->SetQueuePriority(ComputePriority(task_queue));
1595 }
1596 }
1597 }
1598
ApplyTaskQueuePolicy(MainThreadTaskQueue * task_queue,TaskQueue::QueueEnabledVoter * task_queue_enabled_voter,const TaskQueuePolicy & old_task_queue_policy,const TaskQueuePolicy & new_task_queue_policy) const1599 void MainThreadSchedulerImpl::ApplyTaskQueuePolicy(
1600 MainThreadTaskQueue* task_queue,
1601 TaskQueue::QueueEnabledVoter* task_queue_enabled_voter,
1602 const TaskQueuePolicy& old_task_queue_policy,
1603 const TaskQueuePolicy& new_task_queue_policy) const {
1604 DCHECK(old_task_queue_policy.IsQueueEnabled(task_queue) ||
1605 task_queue_enabled_voter);
1606 if (task_queue_enabled_voter) {
1607 task_queue_enabled_voter->SetVoteToEnable(
1608 new_task_queue_policy.IsQueueEnabled(task_queue));
1609 }
1610
1611 // Make sure if there's no voter that the task queue is enabled.
1612 DCHECK(task_queue_enabled_voter ||
1613 old_task_queue_policy.IsQueueEnabled(task_queue));
1614
1615 TimeDomainType old_time_domain_type =
1616 old_task_queue_policy.GetTimeDomainType(task_queue);
1617 TimeDomainType new_time_domain_type =
1618 new_task_queue_policy.GetTimeDomainType(task_queue);
1619
1620 if (old_time_domain_type != new_time_domain_type) {
1621 if (new_time_domain_type == TimeDomainType::kVirtual) {
1622 DCHECK(virtual_time_domain_);
1623 task_queue->SetTimeDomain(virtual_time_domain_.get());
1624 } else {
1625 task_queue->SetTimeDomain(real_time_domain());
1626 }
1627 }
1628 }
1629
ComputeCurrentUseCase(base::TimeTicks now,base::TimeDelta * expected_use_case_duration) const1630 UseCase MainThreadSchedulerImpl::ComputeCurrentUseCase(
1631 base::TimeTicks now,
1632 base::TimeDelta* expected_use_case_duration) const {
1633 any_thread_lock_.AssertAcquired();
1634 // Special case for flings. This is needed because we don't get notification
1635 // of a fling ending (although we do for cancellation).
1636 if (any_thread().fling_compositor_escalation_deadline > now &&
1637 !any_thread().awaiting_touch_start_response) {
1638 *expected_use_case_duration =
1639 any_thread().fling_compositor_escalation_deadline - now;
1640 return UseCase::kCompositorGesture;
1641 }
1642 // Above all else we want to be responsive to user input.
1643 *expected_use_case_duration =
1644 any_thread().user_model.TimeLeftInUserGesture(now);
1645 if (*expected_use_case_duration > base::TimeDelta()) {
1646 // Has a gesture been fully established?
1647 if (any_thread().awaiting_touch_start_response) {
1648 // No, so arrange for compositor tasks to be run at the highest priority.
1649 return UseCase::kTouchstart;
1650 }
1651
1652 // Yes a gesture has been established. Based on how the gesture is handled
1653 // we need to choose between one of four use cases:
1654 // 1. kCompositorGesture where the gesture is processed only on the
1655 // compositor thread.
1656 // 2. MAIN_THREAD_GESTURE where the gesture is processed only on the main
1657 // thread.
1658 // 3. MAIN_THREAD_CUSTOM_INPUT_HANDLING where the main thread processes a
1659 // stream of input events and has prevented a default gesture from being
1660 // started.
1661 // 4. SYNCHRONIZED_GESTURE where the gesture is processed on both threads.
1662 if (any_thread().last_gesture_was_compositor_driven) {
1663 if (any_thread().begin_main_frame_on_critical_path) {
1664 return UseCase::kSynchronizedGesture;
1665 } else {
1666 return UseCase::kCompositorGesture;
1667 }
1668 }
1669 if (any_thread().default_gesture_prevented) {
1670 return UseCase::kMainThreadCustomInputHandling;
1671 } else {
1672 return UseCase::kMainThreadGesture;
1673 }
1674 }
1675
1676 // Occasionally the meaningful paint fails to be detected, so as a fallback we
1677 // treat the presence of input as an indirect signal that there is meaningful
1678 // content on the page.
1679 if (!any_thread().have_seen_input_since_navigation) {
1680 if (any_thread().waiting_for_contentful_paint)
1681 return UseCase::kEarlyLoading;
1682
1683 if (any_thread().waiting_for_meaningful_paint)
1684 return UseCase::kLoading;
1685 }
1686 return UseCase::kNone;
1687 }
1688
EstimateLongestJankFreeTaskDuration() const1689 base::TimeDelta MainThreadSchedulerImpl::EstimateLongestJankFreeTaskDuration()
1690 const {
1691 switch (main_thread_only().current_use_case) {
1692 case UseCase::kTouchstart:
1693 case UseCase::kCompositorGesture:
1694 case UseCase::kEarlyLoading:
1695 case UseCase::kLoading:
1696 case UseCase::kNone:
1697 return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis);
1698
1699 case UseCase::kMainThreadCustomInputHandling:
1700 case UseCase::kMainThreadGesture:
1701 case UseCase::kSynchronizedGesture:
1702 return main_thread_only().idle_time_estimator.GetExpectedIdleDuration(
1703 main_thread_only().compositor_frame_interval);
1704
1705 default:
1706 NOTREACHED();
1707 return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis);
1708 }
1709 }
1710
CanEnterLongIdlePeriod(base::TimeTicks now,base::TimeDelta * next_long_idle_period_delay_out)1711 bool MainThreadSchedulerImpl::CanEnterLongIdlePeriod(
1712 base::TimeTicks now,
1713 base::TimeDelta* next_long_idle_period_delay_out) {
1714 helper_.CheckOnValidThread();
1715
1716 MaybeUpdatePolicy();
1717 if (main_thread_only().current_use_case == UseCase::kTouchstart) {
1718 // Don't start a long idle task in touch start priority, try again when
1719 // the policy is scheduled to end.
1720 *next_long_idle_period_delay_out =
1721 std::max(base::TimeDelta(),
1722 main_thread_only().current_policy_expiration_time - now);
1723 return false;
1724 }
1725 return true;
1726 }
1727
1728 MainThreadSchedulerHelper*
GetSchedulerHelperForTesting()1729 MainThreadSchedulerImpl::GetSchedulerHelperForTesting() {
1730 return &helper_;
1731 }
1732
GetIdleTimeEstimatorForTesting()1733 IdleTimeEstimator* MainThreadSchedulerImpl::GetIdleTimeEstimatorForTesting() {
1734 return &main_thread_only().idle_time_estimator;
1735 }
1736
GetWakeUpBudgetPoolForTesting()1737 WakeUpBudgetPool* MainThreadSchedulerImpl::GetWakeUpBudgetPoolForTesting() {
1738 InitWakeUpBudgetPoolIfNeeded();
1739 return main_thread_only().wake_up_budget_pool;
1740 }
1741
EnableVirtualTime()1742 base::TimeTicks MainThreadSchedulerImpl::EnableVirtualTime() {
1743 return EnableVirtualTime(main_thread_only().initial_virtual_time.is_null()
1744 ? BaseTimeOverridePolicy::DO_NOT_OVERRIDE
1745 : BaseTimeOverridePolicy::OVERRIDE);
1746 }
1747
EnableVirtualTime(BaseTimeOverridePolicy policy)1748 base::TimeTicks MainThreadSchedulerImpl::EnableVirtualTime(
1749 BaseTimeOverridePolicy policy) {
1750 if (main_thread_only().use_virtual_time)
1751 return main_thread_only().initial_virtual_time_ticks;
1752 main_thread_only().use_virtual_time = true;
1753 DCHECK(!virtual_time_domain_);
1754 if (main_thread_only().initial_virtual_time.is_null())
1755 main_thread_only().initial_virtual_time = base::Time::Now();
1756 if (main_thread_only().initial_virtual_time_ticks.is_null())
1757 main_thread_only().initial_virtual_time_ticks = tick_clock()->NowTicks();
1758 virtual_time_domain_.reset(new AutoAdvancingVirtualTimeDomain(
1759 main_thread_only().initial_virtual_time +
1760 main_thread_only().initial_virtual_time_offset,
1761 main_thread_only().initial_virtual_time_ticks +
1762 main_thread_only().initial_virtual_time_offset,
1763 &helper_, policy));
1764 RegisterTimeDomain(virtual_time_domain_.get());
1765
1766 DCHECK(!virtual_time_control_task_queue_);
1767 virtual_time_control_task_queue_ =
1768 helper_.NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
1769 MainThreadTaskQueue::QueueType::kControl));
1770 virtual_time_control_task_queue_->SetQueuePriority(
1771 TaskQueue::kControlPriority);
1772 virtual_time_control_task_queue_->SetTimeDomain(virtual_time_domain_.get());
1773
1774 main_thread_only().use_virtual_time = true;
1775 ForceUpdatePolicy();
1776
1777 virtual_time_domain_->SetCanAdvanceVirtualTime(
1778 !main_thread_only().virtual_time_stopped);
1779
1780 if (main_thread_only().virtual_time_stopped)
1781 VirtualTimePaused();
1782 return main_thread_only().initial_virtual_time_ticks;
1783 }
1784
IsVirtualTimeEnabled() const1785 bool MainThreadSchedulerImpl::IsVirtualTimeEnabled() const {
1786 return main_thread_only().use_virtual_time;
1787 }
1788
DisableVirtualTimeForTesting()1789 void MainThreadSchedulerImpl::DisableVirtualTimeForTesting() {
1790 if (!main_thread_only().use_virtual_time)
1791 return;
1792 // Reset virtual time and all tasks queues back to their initial state.
1793 main_thread_only().use_virtual_time = false;
1794
1795 if (main_thread_only().virtual_time_stopped) {
1796 main_thread_only().virtual_time_stopped = false;
1797 VirtualTimeResumed();
1798 }
1799
1800 ForceUpdatePolicy();
1801
1802 virtual_time_control_task_queue_->ShutdownTaskQueue();
1803 virtual_time_control_task_queue_ = nullptr;
1804 UnregisterTimeDomain(virtual_time_domain_.get());
1805 virtual_time_domain_.reset();
1806 virtual_time_control_task_queue_ = nullptr;
1807 ApplyVirtualTimePolicy();
1808
1809 main_thread_only().initial_virtual_time = base::Time();
1810 main_thread_only().initial_virtual_time_ticks = base::TimeTicks();
1811
1812 // Reset the MetricsHelper because it gets confused by time going backwards.
1813 base::TimeTicks now = tick_clock()->NowTicks();
1814 main_thread_only().metrics_helper.ResetForTest(now);
1815 }
1816
SetVirtualTimeStopped(bool virtual_time_stopped)1817 void MainThreadSchedulerImpl::SetVirtualTimeStopped(bool virtual_time_stopped) {
1818 if (main_thread_only().virtual_time_stopped == virtual_time_stopped)
1819 return;
1820 main_thread_only().virtual_time_stopped = virtual_time_stopped;
1821
1822 if (!main_thread_only().use_virtual_time)
1823 return;
1824
1825 virtual_time_domain_->SetCanAdvanceVirtualTime(!virtual_time_stopped);
1826
1827 if (virtual_time_stopped) {
1828 VirtualTimePaused();
1829 } else {
1830 VirtualTimeResumed();
1831 }
1832 }
1833
VirtualTimePaused()1834 void MainThreadSchedulerImpl::VirtualTimePaused() {
1835 for (const auto& pair : task_runners_) {
1836 if (pair.first->CanRunWhenVirtualTimePaused())
1837 continue;
1838 DCHECK(!task_queue_throttler_->IsThrottled(pair.first.get()));
1839 pair.first->InsertFence(TaskQueue::InsertFencePosition::kNow);
1840 }
1841 }
1842
VirtualTimeResumed()1843 void MainThreadSchedulerImpl::VirtualTimeResumed() {
1844 for (const auto& pair : task_runners_) {
1845 if (pair.first->CanRunWhenVirtualTimePaused())
1846 continue;
1847 DCHECK(!task_queue_throttler_->IsThrottled(pair.first.get()));
1848 DCHECK(pair.first->HasActiveFence());
1849 pair.first->RemoveFence();
1850 }
1851 }
1852
VirtualTimeAllowedToAdvance() const1853 bool MainThreadSchedulerImpl::VirtualTimeAllowedToAdvance() const {
1854 return !main_thread_only().virtual_time_stopped;
1855 }
1856
IncrementVirtualTimePauseCount()1857 base::TimeTicks MainThreadSchedulerImpl::IncrementVirtualTimePauseCount() {
1858 main_thread_only().virtual_time_pause_count++;
1859 ApplyVirtualTimePolicy();
1860
1861 if (virtual_time_domain_)
1862 return virtual_time_domain_->Now();
1863 return tick_clock()->NowTicks();
1864 }
1865
DecrementVirtualTimePauseCount()1866 void MainThreadSchedulerImpl::DecrementVirtualTimePauseCount() {
1867 main_thread_only().virtual_time_pause_count--;
1868 DCHECK_GE(main_thread_only().virtual_time_pause_count, 0);
1869 ApplyVirtualTimePolicy();
1870 }
1871
MaybeAdvanceVirtualTime(base::TimeTicks new_virtual_time)1872 void MainThreadSchedulerImpl::MaybeAdvanceVirtualTime(
1873 base::TimeTicks new_virtual_time) {
1874 if (virtual_time_domain_)
1875 virtual_time_domain_->MaybeAdvanceVirtualTime(new_virtual_time);
1876 }
1877
SetVirtualTimePolicy(VirtualTimePolicy policy)1878 void MainThreadSchedulerImpl::SetVirtualTimePolicy(VirtualTimePolicy policy) {
1879 main_thread_only().virtual_time_policy = policy;
1880 ApplyVirtualTimePolicy();
1881 }
1882
SetInitialVirtualTime(base::Time time)1883 void MainThreadSchedulerImpl::SetInitialVirtualTime(base::Time time) {
1884 main_thread_only().initial_virtual_time = time;
1885 }
1886
SetInitialVirtualTimeOffset(base::TimeDelta offset)1887 void MainThreadSchedulerImpl::SetInitialVirtualTimeOffset(
1888 base::TimeDelta offset) {
1889 main_thread_only().initial_virtual_time_offset = offset;
1890 }
1891
ApplyVirtualTimePolicy()1892 void MainThreadSchedulerImpl::ApplyVirtualTimePolicy() {
1893 switch (main_thread_only().virtual_time_policy) {
1894 case VirtualTimePolicy::kAdvance:
1895 if (virtual_time_domain_) {
1896 virtual_time_domain_->SetMaxVirtualTimeTaskStarvationCount(
1897 main_thread_only().nested_runloop
1898 ? 0
1899 : main_thread_only().max_virtual_time_task_starvation_count);
1900 virtual_time_domain_->SetVirtualTimeFence(base::TimeTicks());
1901 }
1902 SetVirtualTimeStopped(false);
1903 break;
1904 case VirtualTimePolicy::kPause:
1905 if (virtual_time_domain_) {
1906 virtual_time_domain_->SetMaxVirtualTimeTaskStarvationCount(0);
1907 virtual_time_domain_->SetVirtualTimeFence(virtual_time_domain_->Now());
1908 }
1909 SetVirtualTimeStopped(true);
1910 break;
1911 case VirtualTimePolicy::kDeterministicLoading:
1912 if (virtual_time_domain_) {
1913 virtual_time_domain_->SetMaxVirtualTimeTaskStarvationCount(
1914 main_thread_only().nested_runloop
1915 ? 0
1916 : main_thread_only().max_virtual_time_task_starvation_count);
1917 }
1918
1919 // We pause virtual time while the run loop is nested because that implies
1920 // something modal is happening such as the DevTools debugger pausing the
1921 // system. We also pause while the renderer is waiting for various
1922 // asynchronous things e.g. resource load or navigation.
1923 SetVirtualTimeStopped(main_thread_only().virtual_time_pause_count != 0 ||
1924 main_thread_only().nested_runloop);
1925 break;
1926 }
1927 }
1928
SetMaxVirtualTimeTaskStarvationCount(int max_task_starvation_count)1929 void MainThreadSchedulerImpl::SetMaxVirtualTimeTaskStarvationCount(
1930 int max_task_starvation_count) {
1931 main_thread_only().max_virtual_time_task_starvation_count =
1932 max_task_starvation_count;
1933 ApplyVirtualTimePolicy();
1934 }
1935
1936 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
AsValue(base::TimeTicks optional_now) const1937 MainThreadSchedulerImpl::AsValue(base::TimeTicks optional_now) const {
1938 base::AutoLock lock(any_thread_lock_);
1939 return AsValueLocked(optional_now);
1940 }
1941
CreateTraceEventObjectSnapshot() const1942 void MainThreadSchedulerImpl::CreateTraceEventObjectSnapshot() const {
1943 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
1944 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug"),
1945 "MainThreadScheduler", this, AsValue(helper_.NowTicks()));
1946 }
1947
CreateTraceEventObjectSnapshotLocked() const1948 void MainThreadSchedulerImpl::CreateTraceEventObjectSnapshotLocked() const {
1949 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
1950 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug"),
1951 "MainThreadScheduler", this, AsValueLocked(helper_.NowTicks()));
1952 }
1953
1954 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
AsValueLocked(base::TimeTicks optional_now) const1955 MainThreadSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const {
1956 auto state = std::make_unique<base::trace_event::TracedValue>();
1957 AsValueIntoLocked(state.get(), optional_now);
1958 return std::move(state);
1959 }
1960
ToString() const1961 std::string MainThreadSchedulerImpl::ToString() const {
1962 base::AutoLock lock(any_thread_lock_);
1963 base::trace_event::TracedValueJSON value;
1964 AsValueIntoLocked(&value, base::TimeTicks());
1965 return value.ToJSON();
1966 }
1967
AsValueIntoLocked(base::trace_event::TracedValue * state,base::TimeTicks optional_now) const1968 void MainThreadSchedulerImpl::AsValueIntoLocked(
1969 base::trace_event::TracedValue* state,
1970 base::TimeTicks optional_now) const {
1971 helper_.CheckOnValidThread();
1972 any_thread_lock_.AssertAcquired();
1973
1974 if (optional_now.is_null())
1975 optional_now = helper_.NowTicks();
1976 state->SetBoolean(
1977 "has_visible_render_widget_with_touch_handler",
1978 main_thread_only().has_visible_render_widget_with_touch_handler);
1979 state->SetString("current_use_case",
1980 UseCaseToString(main_thread_only().current_use_case));
1981 state->SetBoolean("begin_frame_not_expected_soon",
1982 main_thread_only().begin_frame_not_expected_soon);
1983 state->SetBoolean(
1984 "compositor_will_send_main_frame_not_expected",
1985 main_thread_only().compositor_will_send_main_frame_not_expected);
1986 state->SetBoolean("blocking_input_expected_soon",
1987 main_thread_only().blocking_input_expected_soon);
1988 state->SetString("idle_period_state",
1989 IdleHelper::IdlePeriodStateToString(
1990 idle_helper_.SchedulerIdlePeriodState()));
1991 state->SetBoolean("renderer_hidden", main_thread_only().renderer_hidden);
1992 state->SetBoolean("have_seen_a_begin_main_frame",
1993 main_thread_only().have_seen_a_begin_main_frame);
1994 state->SetBoolean("waiting_for_contentful_paint",
1995 any_thread().waiting_for_contentful_paint);
1996 state->SetBoolean("waiting_for_meaningful_paint",
1997 any_thread().waiting_for_meaningful_paint);
1998 state->SetBoolean("have_seen_input_since_navigation",
1999 any_thread().have_seen_input_since_navigation);
2000 state->SetBoolean(
2001 "have_reported_blocking_intervention_in_current_policy",
2002 main_thread_only().have_reported_blocking_intervention_in_current_policy);
2003 state->SetBoolean(
2004 "have_reported_blocking_intervention_since_navigation",
2005 main_thread_only().have_reported_blocking_intervention_since_navigation);
2006 state->SetBoolean("renderer_backgrounded",
2007 main_thread_only().renderer_backgrounded);
2008 state->SetBoolean("keep_active_fetch_or_worker",
2009 main_thread_only().keep_active_fetch_or_worker);
2010 state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF());
2011 state->SetDouble(
2012 "fling_compositor_escalation_deadline",
2013 (any_thread().fling_compositor_escalation_deadline - base::TimeTicks())
2014 .InMillisecondsF());
2015 state->SetDouble("last_idle_period_end_time",
2016 (any_thread().last_idle_period_end_time - base::TimeTicks())
2017 .InMillisecondsF());
2018 state->SetBoolean("awaiting_touch_start_response",
2019 any_thread().awaiting_touch_start_response);
2020 state->SetBoolean("begin_main_frame_on_critical_path",
2021 any_thread().begin_main_frame_on_critical_path);
2022 state->SetBoolean("last_gesture_was_compositor_driven",
2023 any_thread().last_gesture_was_compositor_driven);
2024 state->SetBoolean("default_gesture_prevented",
2025 any_thread().default_gesture_prevented);
2026 state->SetBoolean("is_audio_playing", main_thread_only().is_audio_playing);
2027 state->SetBoolean("virtual_time_stopped",
2028 main_thread_only().virtual_time_stopped);
2029 state->SetDouble("virtual_time_pause_count",
2030 main_thread_only().virtual_time_pause_count);
2031 state->SetString(
2032 "virtual_time_policy",
2033 VirtualTimePolicyToString(main_thread_only().virtual_time_policy));
2034 state->SetBoolean("virtual_time", main_thread_only().use_virtual_time);
2035
2036 state->BeginDictionary("page_schedulers");
2037 for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
2038 state->BeginDictionaryWithCopiedName(PointerToString(page_scheduler));
2039 page_scheduler->AsValueInto(state);
2040 state->EndDictionary();
2041 }
2042 state->EndDictionary();
2043
2044 state->BeginDictionary("policy");
2045 main_thread_only().current_policy.AsValueInto(state);
2046 state->EndDictionary();
2047
2048 // TODO(skyostil): Can we somehow trace how accurate these estimates were?
2049 state->SetDouble(
2050 "longest_jank_free_task_duration",
2051 main_thread_only().longest_jank_free_task_duration->InMillisecondsF());
2052 state->SetDouble(
2053 "compositor_frame_interval",
2054 main_thread_only().compositor_frame_interval.InMillisecondsF());
2055 state->SetDouble(
2056 "estimated_next_frame_begin",
2057 (main_thread_only().estimated_next_frame_begin - base::TimeTicks())
2058 .InMillisecondsF());
2059 state->SetBoolean("in_idle_period", any_thread().in_idle_period);
2060
2061 any_thread().user_model.AsValueInto(state);
2062 render_widget_scheduler_signals_.AsValueInto(state);
2063
2064 state->BeginDictionary("task_queue_throttler");
2065 task_queue_throttler_->AsValueInto(state, optional_now);
2066 state->EndDictionary();
2067 }
2068
IsQueueEnabled(MainThreadTaskQueue * task_queue) const2069 bool MainThreadSchedulerImpl::TaskQueuePolicy::IsQueueEnabled(
2070 MainThreadTaskQueue* task_queue) const {
2071 if (!is_enabled)
2072 return false;
2073 if (is_paused && task_queue->CanBePaused())
2074 return false;
2075 if (is_deferred && task_queue->CanBeDeferred())
2076 return false;
2077 return true;
2078 }
2079
2080 MainThreadSchedulerImpl::TimeDomainType
GetTimeDomainType(MainThreadTaskQueue * task_queue) const2081 MainThreadSchedulerImpl::TaskQueuePolicy::GetTimeDomainType(
2082 MainThreadTaskQueue* task_queue) const {
2083 if (use_virtual_time)
2084 return TimeDomainType::kVirtual;
2085 return TimeDomainType::kReal;
2086 }
2087
AsValueInto(base::trace_event::TracedValue * state) const2088 void MainThreadSchedulerImpl::TaskQueuePolicy::AsValueInto(
2089 base::trace_event::TracedValue* state) const {
2090 state->SetBoolean("is_enabled", is_enabled);
2091 state->SetBoolean("is_paused", is_paused);
2092 state->SetBoolean("is_deferred", is_deferred);
2093 state->SetBoolean("use_virtual_time", use_virtual_time);
2094 }
2095
Policy()2096 MainThreadSchedulerImpl::Policy::Policy()
2097 : rail_mode_(RAILMode::kAnimation),
2098 should_disable_throttling_(false),
2099 frozen_when_backgrounded_(false),
2100 should_prioritize_loading_with_compositing_(false),
2101 compositor_priority_(
2102 base::sequence_manager::TaskQueue::QueuePriority::kNormalPriority),
2103 find_in_page_priority_(FindInPageBudgetPoolController::
2104 kFindInPageBudgetNotExhaustedPriority),
2105 use_case_(UseCase::kNone) {}
2106
AsValueInto(base::trace_event::TracedValue * state) const2107 void MainThreadSchedulerImpl::Policy::AsValueInto(
2108 base::trace_event::TracedValue* state) const {
2109 state->BeginDictionary("compositor_queue_policy");
2110 compositor_queue_policy().AsValueInto(state);
2111 state->EndDictionary();
2112
2113 state->BeginDictionary("loading_queue_policy");
2114 loading_queue_policy().AsValueInto(state);
2115 state->EndDictionary();
2116
2117 state->BeginDictionary("timer_queue_policy");
2118 timer_queue_policy().AsValueInto(state);
2119 state->EndDictionary();
2120
2121 state->BeginDictionary("default_queue_policy");
2122 default_queue_policy().AsValueInto(state);
2123 state->EndDictionary();
2124
2125 state->SetString("rail_mode", RAILModeToString(rail_mode()));
2126 state->SetString("compositor_priority",
2127 TaskQueue::PriorityToString(compositor_priority()));
2128 state->SetString("use_case", UseCaseToString(use_case()));
2129
2130 state->SetBoolean("should_disable_throttling", should_disable_throttling());
2131 }
2132
OnIdlePeriodStarted()2133 void MainThreadSchedulerImpl::OnIdlePeriodStarted() {
2134 base::AutoLock lock(any_thread_lock_);
2135 any_thread().in_idle_period = true;
2136 UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
2137 }
2138
OnIdlePeriodEnded()2139 void MainThreadSchedulerImpl::OnIdlePeriodEnded() {
2140 base::AutoLock lock(any_thread_lock_);
2141 any_thread().last_idle_period_end_time = helper_.NowTicks();
2142 any_thread().in_idle_period = false;
2143 UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
2144 }
2145
OnPendingTasksChanged(bool has_tasks)2146 void MainThreadSchedulerImpl::OnPendingTasksChanged(bool has_tasks) {
2147 if (has_tasks ==
2148 main_thread_only().compositor_will_send_main_frame_not_expected.get())
2149 return;
2150
2151 // Dispatch RequestBeginMainFrameNotExpectedSoon notifications asynchronously.
2152 // This is needed because idle task can be posted (and OnPendingTasksChanged
2153 // called) at any moment, including in the middle of allocating an object,
2154 // when state is not consistent. Posting a task to dispatch notifications
2155 // minimizes the amount of code that runs and sees an inconsistent state .
2156 control_task_queue_->task_runner()->PostTask(
2157 FROM_HERE,
2158 base::BindOnce(
2159 &MainThreadSchedulerImpl::DispatchRequestBeginMainFrameNotExpected,
2160 weak_factory_.GetWeakPtr(), has_tasks));
2161 }
2162
DispatchRequestBeginMainFrameNotExpected(bool has_tasks)2163 void MainThreadSchedulerImpl::DispatchRequestBeginMainFrameNotExpected(
2164 bool has_tasks) {
2165 if (has_tasks ==
2166 main_thread_only().compositor_will_send_main_frame_not_expected.get())
2167 return;
2168
2169 TRACE_EVENT1(
2170 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2171 "MainThreadSchedulerImpl::DispatchRequestBeginMainFrameNotExpected",
2172 "has_tasks", has_tasks);
2173 bool success = false;
2174 for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
2175 success |= page_scheduler->RequestBeginMainFrameNotExpected(has_tasks);
2176 }
2177 main_thread_only().compositor_will_send_main_frame_not_expected =
2178 success && has_tasks;
2179 }
2180
2181 std::unique_ptr<base::SingleSampleMetric>
CreateMaxQueueingTimeMetric()2182 MainThreadSchedulerImpl::CreateMaxQueueingTimeMetric() {
2183 return base::SingleSampleMetricsFactory::Get()->CreateCustomCountsMetric(
2184 "RendererScheduler.MaxQueueingTime", 1, 10000, 50);
2185 }
2186
DidStartProvisionalLoad(bool is_main_frame)2187 void MainThreadSchedulerImpl::DidStartProvisionalLoad(bool is_main_frame) {
2188 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2189 "MainThreadSchedulerImpl::DidStartProvisionalLoad");
2190 if (is_main_frame) {
2191 base::AutoLock lock(any_thread_lock_);
2192 ResetForNavigationLocked();
2193 }
2194 }
2195
DidCommitProvisionalLoad(bool is_web_history_inert_commit,bool is_reload,bool is_main_frame)2196 void MainThreadSchedulerImpl::DidCommitProvisionalLoad(
2197 bool is_web_history_inert_commit,
2198 bool is_reload,
2199 bool is_main_frame) {
2200 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2201 "MainThreadSchedulerImpl::DidCommitProvisionalLoad");
2202 // Initialize |max_queueing_time_metric| lazily so that
2203 // |SingleSampleMetricsFactory::SetFactory()| is called before
2204 // |SingleSampleMetricsFactory::Get()|
2205 if (!main_thread_only().max_queueing_time_metric) {
2206 main_thread_only().max_queueing_time_metric = CreateMaxQueueingTimeMetric();
2207 }
2208 main_thread_only().max_queueing_time_metric.reset();
2209 main_thread_only().max_queueing_time = base::TimeDelta();
2210 main_thread_only().has_navigated = true;
2211
2212 // If this either isn't a history inert commit or it's a reload then we must
2213 // reset the task cost estimators.
2214 if (is_main_frame && (!is_web_history_inert_commit || is_reload)) {
2215 base::AutoLock lock(any_thread_lock_);
2216 ResetForNavigationLocked();
2217 }
2218 }
2219
OnFirstContentfulPaint()2220 void MainThreadSchedulerImpl::OnFirstContentfulPaint() {
2221 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2222 "MainThreadSchedulerImpl::OnFirstContentfulPaint");
2223 base::AutoLock lock(any_thread_lock_);
2224 any_thread().waiting_for_contentful_paint = false;
2225 UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
2226 }
2227
OnFirstMeaningfulPaint()2228 void MainThreadSchedulerImpl::OnFirstMeaningfulPaint() {
2229 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2230 "MainThreadSchedulerImpl::OnFirstMeaningfulPaint");
2231 base::AutoLock lock(any_thread_lock_);
2232 any_thread().waiting_for_meaningful_paint = false;
2233 UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
2234 }
2235
ResetForNavigationLocked()2236 void MainThreadSchedulerImpl::ResetForNavigationLocked() {
2237 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2238 "MainThreadSchedulerImpl::ResetForNavigationLocked");
2239 helper_.CheckOnValidThread();
2240 any_thread_lock_.AssertAcquired();
2241 any_thread().user_model.Reset(helper_.NowTicks());
2242 any_thread().have_seen_a_blocking_gesture = false;
2243 any_thread().waiting_for_contentful_paint = true;
2244 any_thread().waiting_for_meaningful_paint = true;
2245 any_thread().have_seen_input_since_navigation = false;
2246 main_thread_only().idle_time_estimator.Clear();
2247 main_thread_only().have_seen_a_begin_main_frame = false;
2248 main_thread_only().have_reported_blocking_intervention_since_navigation =
2249 false;
2250 for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
2251 page_scheduler->OnNavigation();
2252 }
2253 UpdatePolicyLocked(UpdateType::kMayEarlyOutIfPolicyUnchanged);
2254
2255 UMA_HISTOGRAM_COUNTS_100("RendererScheduler.WebViewsPerScheduler",
2256 base::saturated_cast<base::HistogramBase::Sample>(
2257 main_thread_only().page_schedulers.size()));
2258
2259 size_t frame_count = 0;
2260 for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
2261 frame_count += page_scheduler->FrameCount();
2262 }
2263 UMA_HISTOGRAM_COUNTS_100(
2264 "RendererScheduler.WebFramesPerScheduler",
2265 base::saturated_cast<base::HistogramBase::Sample>(frame_count));
2266 }
2267
SetTopLevelBlameContext(base::trace_event::BlameContext * blame_context)2268 void MainThreadSchedulerImpl::SetTopLevelBlameContext(
2269 base::trace_event::BlameContext* blame_context) {
2270 // Any task that runs in the default task runners belongs to the context of
2271 // all frames (as opposed to a particular frame). Note that the task itself
2272 // may still enter a more specific blame context if necessary.
2273 //
2274 // Per-frame task runners (loading, timers, etc.) are configured with a more
2275 // specific blame context by FrameSchedulerImpl.
2276 //
2277 // TODO(altimin): automatically enter top-level for all task queues associated
2278 // with renderer scheduler which do not have a corresponding frame.
2279 control_task_queue_->SetBlameContext(blame_context);
2280 DefaultTaskQueue()->SetBlameContext(blame_context);
2281 compositor_task_queue_->SetBlameContext(blame_context);
2282 idle_helper_.IdleTaskRunner()->SetBlameContext(blame_context);
2283 v8_task_queue_->SetBlameContext(blame_context);
2284 ipc_task_queue_->SetBlameContext(blame_context);
2285 }
2286
AddRAILModeObserver(RAILModeObserver * observer)2287 void MainThreadSchedulerImpl::AddRAILModeObserver(RAILModeObserver* observer) {
2288 main_thread_only().rail_mode_observers.AddObserver(observer);
2289 observer->OnRAILModeChanged(main_thread_only().current_policy.rail_mode());
2290 }
2291
RemoveRAILModeObserver(RAILModeObserver const * observer)2292 void MainThreadSchedulerImpl::RemoveRAILModeObserver(
2293 RAILModeObserver const* observer) {
2294 main_thread_only().rail_mode_observers.RemoveObserver(observer);
2295 }
2296
SetRendererProcessType(WebRendererProcessType type)2297 void MainThreadSchedulerImpl::SetRendererProcessType(
2298 WebRendererProcessType type) {
2299 main_thread_only().process_type = type;
2300 }
2301
GetPendingUserInputInfo() const2302 PendingUserInputInfo MainThreadSchedulerImpl::GetPendingUserInputInfo() const {
2303 base::AutoLock lock(any_thread_lock_);
2304 return any_thread().pending_input_monitor.Info();
2305 }
2306
IsBeginMainFrameScheduled() const2307 bool MainThreadSchedulerImpl::IsBeginMainFrameScheduled() const {
2308 base::AutoLock lock(any_thread_lock_);
2309 return any_thread().begin_main_frame_scheduled_count.value() > 0;
2310 }
2311
RunIdleTask(Thread::IdleTask task,base::TimeTicks deadline)2312 void MainThreadSchedulerImpl::RunIdleTask(Thread::IdleTask task,
2313 base::TimeTicks deadline) {
2314 std::move(task).Run(deadline);
2315 }
2316
PostIdleTask(const base::Location & location,Thread::IdleTask task)2317 void MainThreadSchedulerImpl::PostIdleTask(const base::Location& location,
2318 Thread::IdleTask task) {
2319 IdleTaskRunner()->PostIdleTask(
2320 location,
2321 base::BindOnce(&MainThreadSchedulerImpl::RunIdleTask, std::move(task)));
2322 }
2323
PostDelayedIdleTask(const base::Location & location,base::TimeDelta delay,Thread::IdleTask task)2324 void MainThreadSchedulerImpl::PostDelayedIdleTask(
2325 const base::Location& location,
2326 base::TimeDelta delay,
2327 Thread::IdleTask task) {
2328 IdleTaskRunner()->PostDelayedIdleTask(
2329 location, delay,
2330 base::BindOnce(&MainThreadSchedulerImpl::RunIdleTask, std::move(task)));
2331 }
2332
PostNonNestableIdleTask(const base::Location & location,Thread::IdleTask task)2333 void MainThreadSchedulerImpl::PostNonNestableIdleTask(
2334 const base::Location& location,
2335 Thread::IdleTask task) {
2336 IdleTaskRunner()->PostNonNestableIdleTask(
2337 location,
2338 base::BindOnce(&MainThreadSchedulerImpl::RunIdleTask, std::move(task)));
2339 }
2340
2341 scoped_refptr<base::SingleThreadTaskRunner>
V8TaskRunner()2342 MainThreadSchedulerImpl::V8TaskRunner() {
2343 return v8_task_runner_;
2344 }
2345
2346 scoped_refptr<base::SingleThreadTaskRunner>
CompositorTaskRunner()2347 MainThreadSchedulerImpl::CompositorTaskRunner() {
2348 return compositor_task_runner_;
2349 }
2350
2351 scoped_refptr<base::SingleThreadTaskRunner>
NonWakingTaskRunner()2352 MainThreadSchedulerImpl::NonWakingTaskRunner() {
2353 return non_waking_task_runner_;
2354 }
2355
CreatePageScheduler(PageScheduler::Delegate * delegate)2356 std::unique_ptr<PageScheduler> MainThreadSchedulerImpl::CreatePageScheduler(
2357 PageScheduler::Delegate* delegate) {
2358 return std::make_unique<PageSchedulerImpl>(delegate, this);
2359 }
2360
2361 std::unique_ptr<ThreadScheduler::RendererPauseHandle>
PauseScheduler()2362 MainThreadSchedulerImpl::PauseScheduler() {
2363 return PauseRenderer();
2364 }
2365
MonotonicallyIncreasingVirtualTime()2366 base::TimeTicks MainThreadSchedulerImpl::MonotonicallyIncreasingVirtualTime() {
2367 return GetActiveTimeDomain()->Now();
2368 }
2369
2370 WebThreadScheduler*
GetWebMainThreadSchedulerForTest()2371 MainThreadSchedulerImpl::GetWebMainThreadSchedulerForTest() {
2372 return this;
2373 }
2374
RegisterTimeDomain(TimeDomain * time_domain)2375 void MainThreadSchedulerImpl::RegisterTimeDomain(TimeDomain* time_domain) {
2376 helper_.RegisterTimeDomain(time_domain);
2377 }
2378
UnregisterTimeDomain(TimeDomain * time_domain)2379 void MainThreadSchedulerImpl::UnregisterTimeDomain(TimeDomain* time_domain) {
2380 helper_.UnregisterTimeDomain(time_domain);
2381 }
2382
GetTickClock()2383 const base::TickClock* MainThreadSchedulerImpl::GetTickClock() {
2384 return tick_clock();
2385 }
2386
tick_clock() const2387 const base::TickClock* MainThreadSchedulerImpl::tick_clock() const {
2388 return helper_.GetClock();
2389 }
2390
AddPageScheduler(PageSchedulerImpl * page_scheduler)2391 void MainThreadSchedulerImpl::AddPageScheduler(
2392 PageSchedulerImpl* page_scheduler) {
2393 main_thread_only().page_schedulers.insert(page_scheduler);
2394 if (page_scheduler->IsOrdinary()) {
2395 memory_purge_manager_.OnPageCreated(
2396 page_scheduler->GetPageLifecycleState());
2397 }
2398 }
2399
RemovePageScheduler(PageSchedulerImpl * page_scheduler)2400 void MainThreadSchedulerImpl::RemovePageScheduler(
2401 PageSchedulerImpl* page_scheduler) {
2402 DCHECK(main_thread_only().page_schedulers.find(page_scheduler) !=
2403 main_thread_only().page_schedulers.end());
2404 main_thread_only().page_schedulers.erase(page_scheduler);
2405 if (page_scheduler->IsOrdinary()) {
2406 memory_purge_manager_.OnPageDestroyed(
2407 page_scheduler->GetPageLifecycleState());
2408 }
2409 }
2410
OnPageFrozen()2411 void MainThreadSchedulerImpl::OnPageFrozen() {
2412 memory_purge_manager_.OnPageFrozen();
2413 }
2414
OnPageResumed()2415 void MainThreadSchedulerImpl::OnPageResumed() {
2416 memory_purge_manager_.OnPageResumed();
2417 }
2418
BroadcastIntervention(const String & message)2419 void MainThreadSchedulerImpl::BroadcastIntervention(const String& message) {
2420 helper_.CheckOnValidThread();
2421 for (auto* page_scheduler : main_thread_only().page_schedulers)
2422 page_scheduler->ReportIntervention(message);
2423 }
2424
OnTaskReady(const void * frame_scheduler,const base::sequence_manager::Task & task,base::sequence_manager::LazyNow * lazy_now)2425 void MainThreadSchedulerImpl::OnTaskReady(
2426 const void* frame_scheduler,
2427 const base::sequence_manager::Task& task,
2428 base::sequence_manager::LazyNow* lazy_now) {
2429 agent_interference_recorder_.OnTaskReady(frame_scheduler,
2430 task.enqueue_order(), lazy_now);
2431 }
2432
OnTaskStarted(MainThreadTaskQueue * queue,const base::sequence_manager::Task & task,const TaskQueue::TaskTiming & task_timing)2433 void MainThreadSchedulerImpl::OnTaskStarted(
2434 MainThreadTaskQueue* queue,
2435 const base::sequence_manager::Task& task,
2436 const TaskQueue::TaskTiming& task_timing) {
2437 main_thread_only().running_queues.push(queue);
2438 queueing_time_estimator_.OnExecutionStarted(task_timing.start_time());
2439 agent_interference_recorder_.OnTaskStarted(queue, task.enqueue_order(),
2440 task_timing.start_time());
2441 if (main_thread_only().nested_runloop)
2442 return;
2443
2444 main_thread_only().current_task_start_time = task_timing.start_time();
2445 main_thread_only().task_description_for_tracing = TaskDescriptionForTracing{
2446 static_cast<TaskType>(task.task_type),
2447 queue
2448 ? base::Optional<MainThreadTaskQueue::QueueType>(queue->queue_type())
2449 : base::nullopt};
2450
2451 main_thread_only().task_priority_for_tracing =
2452 queue
2453 ? base::Optional<TaskQueue::QueuePriority>(queue->GetQueuePriority())
2454 : base::nullopt;
2455 }
2456
OnTaskCompleted(base::WeakPtr<MainThreadTaskQueue> queue,const base::sequence_manager::Task & task,TaskQueue::TaskTiming * task_timing,base::sequence_manager::LazyNow * lazy_now)2457 void MainThreadSchedulerImpl::OnTaskCompleted(
2458 base::WeakPtr<MainThreadTaskQueue> queue,
2459 const base::sequence_manager::Task& task,
2460 TaskQueue::TaskTiming* task_timing,
2461 base::sequence_manager::LazyNow* lazy_now) {
2462 // Microtasks may detach the task queue and invalidate |queue|.
2463 PerformMicrotaskCheckpoint();
2464
2465 task_timing->RecordTaskEnd(lazy_now);
2466
2467 DCHECK_LE(task_timing->start_time(), task_timing->end_time());
2468 DCHECK(!main_thread_only().running_queues.empty());
2469 DCHECK(!queue ||
2470 main_thread_only().running_queues.top().get() == queue.get());
2471 if (task_timing->has_wall_time() && queue && queue->GetFrameScheduler())
2472 queue->GetFrameScheduler()->AddTaskTime(task_timing->wall_duration());
2473 main_thread_only().running_queues.pop();
2474 queueing_time_estimator_.OnExecutionStopped(task_timing->end_time());
2475 agent_interference_recorder_.OnTaskCompleted(queue.get(),
2476 task_timing->end_time());
2477 if (main_thread_only().nested_runloop)
2478 return;
2479
2480 DispatchOnTaskCompletionCallbacks();
2481
2482 if (queue) {
2483 task_queue_throttler()->OnTaskRunTimeReported(
2484 queue.get(), task_timing->start_time(), task_timing->end_time());
2485 }
2486
2487 main_thread_only().compositing_experiment.OnTaskCompleted(queue.get());
2488
2489 // TODO(altimin): Per-page metrics should also be considered.
2490 main_thread_only().metrics_helper.RecordTaskMetrics(queue.get(), task,
2491 *task_timing);
2492 main_thread_only().task_description_for_tracing = base::nullopt;
2493
2494 // Unset the state of |task_priority_for_tracing|.
2495 main_thread_only().task_priority_for_tracing = base::nullopt;
2496
2497 RecordTaskUkm(queue.get(), task, *task_timing);
2498
2499 main_thread_only().compositor_priority_experiments.OnTaskCompleted(
2500 queue.get(), main_thread_only().current_policy.compositor_priority(),
2501 task_timing);
2502
2503 find_in_page_budget_pool_controller_->OnTaskCompleted(queue.get(),
2504 task_timing);
2505 }
2506
RecordTaskUkm(MainThreadTaskQueue * queue,const base::sequence_manager::Task & task,const TaskQueue::TaskTiming & task_timing)2507 void MainThreadSchedulerImpl::RecordTaskUkm(
2508 MainThreadTaskQueue* queue,
2509 const base::sequence_manager::Task& task,
2510 const TaskQueue::TaskTiming& task_timing) {
2511 if (!helper_.ShouldRecordTaskUkm(task_timing.has_thread_time()))
2512 return;
2513
2514 if (queue && queue->GetFrameScheduler()) {
2515 auto status = RecordTaskUkmImpl(queue, task, task_timing,
2516 queue->GetFrameScheduler(), true);
2517 UMA_HISTOGRAM_ENUMERATION(
2518 "Scheduler.Experimental.Renderer.UkmRecordingStatus", status,
2519 UkmRecordingStatus::kCount);
2520 return;
2521 }
2522
2523 for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
2524 auto status = RecordTaskUkmImpl(
2525 queue, task, task_timing,
2526 page_scheduler->SelectFrameForUkmAttribution(), false);
2527 UMA_HISTOGRAM_ENUMERATION(
2528 "Scheduler.Experimental.Renderer.UkmRecordingStatus", status,
2529 UkmRecordingStatus::kCount);
2530 }
2531 }
2532
RecordTaskUkmImpl(MainThreadTaskQueue * queue,const base::sequence_manager::Task & task,const TaskQueue::TaskTiming & task_timing,FrameSchedulerImpl * frame_scheduler,bool precise_attribution)2533 UkmRecordingStatus MainThreadSchedulerImpl::RecordTaskUkmImpl(
2534 MainThreadTaskQueue* queue,
2535 const base::sequence_manager::Task& task,
2536 const TaskQueue::TaskTiming& task_timing,
2537 FrameSchedulerImpl* frame_scheduler,
2538 bool precise_attribution) {
2539 // Skip tasks which have deleted the frame or the page scheduler.
2540 if (!frame_scheduler)
2541 return UkmRecordingStatus::kErrorMissingFrame;
2542 if (!frame_scheduler->GetPageScheduler())
2543 return UkmRecordingStatus::kErrorDetachedFrame;
2544
2545 ukm::UkmRecorder* ukm_recorder = frame_scheduler->GetUkmRecorder();
2546 // OOPIFs are not supported.
2547 if (!ukm_recorder)
2548 return UkmRecordingStatus::kErrorMissingUkmRecorder;
2549
2550 ukm::builders::RendererSchedulerTask builder(
2551 frame_scheduler->GetUkmSourceId());
2552
2553 builder.SetVersion(kUkmMetricVersion);
2554 builder.SetPageSchedulers(main_thread_only().page_schedulers.size());
2555
2556 builder.SetRendererBackgrounded(main_thread_only().renderer_backgrounded);
2557 builder.SetRendererHidden(main_thread_only().renderer_hidden);
2558 builder.SetRendererAudible(main_thread_only().is_audio_playing);
2559 builder.SetUseCase(
2560 static_cast<int>(main_thread_only().current_use_case.get()));
2561 builder.SetTaskType(task.task_type);
2562 builder.SetQueueType(static_cast<int>(
2563 queue ? queue->queue_type() : MainThreadTaskQueue::QueueType::kDetached));
2564 builder.SetFrameStatus(static_cast<int>(
2565 GetFrameStatus(queue ? queue->GetFrameScheduler() : nullptr)));
2566 builder.SetTaskDuration(task_timing.wall_duration().InMicroseconds());
2567 builder.SetIsOOPIF(!frame_scheduler->GetPageScheduler()->IsMainFrameLocal());
2568
2569 if (main_thread_only().renderer_backgrounded) {
2570 base::TimeDelta time_since_backgrounded =
2571 (task_timing.end_time() -
2572 main_thread_only().background_status_changed_at);
2573
2574 // Trade off for privacy: Round to seconds for times below 10 minutes and
2575 // minutes afterwards.
2576 int64_t seconds_since_backgrounded = 0;
2577 if (time_since_backgrounded < base::TimeDelta::FromMinutes(10)) {
2578 seconds_since_backgrounded = time_since_backgrounded.InSeconds();
2579 } else {
2580 seconds_since_backgrounded =
2581 time_since_backgrounded.InMinutes() * kSecondsPerMinute;
2582 }
2583
2584 builder.SetSecondsSinceBackgrounded(seconds_since_backgrounded);
2585 }
2586
2587 if (task_timing.has_thread_time()) {
2588 builder.SetTaskCPUDuration(task_timing.thread_duration().InMicroseconds());
2589 }
2590
2591 builder.Record(ukm_recorder);
2592
2593 return UkmRecordingStatus::kSuccess;
2594 }
2595
ComputePriority(MainThreadTaskQueue * task_queue) const2596 TaskQueue::QueuePriority MainThreadSchedulerImpl::ComputePriority(
2597 MainThreadTaskQueue* task_queue) const {
2598 DCHECK(task_queue);
2599
2600 // If |task_queue| is associated to a frame, then the frame scheduler computes
2601 // the priority.
2602 FrameSchedulerImpl* frame_scheduler = task_queue->GetFrameScheduler();
2603
2604 if (frame_scheduler) {
2605 return frame_scheduler->ComputePriority(task_queue);
2606 }
2607
2608 base::Optional<TaskQueue::QueuePriority> fixed_priority =
2609 task_queue->FixedPriority();
2610 if (fixed_priority) {
2611 return fixed_priority.value();
2612 }
2613
2614 if (task_queue->queue_class() ==
2615 MainThreadTaskQueue::QueueClass::kCompositor) {
2616 return main_thread_only().current_policy.compositor_priority();
2617 }
2618
2619 // Default priority.
2620 return TaskQueue::QueuePriority::kNormalPriority;
2621 }
2622
OnBeginNestedRunLoop()2623 void MainThreadSchedulerImpl::OnBeginNestedRunLoop() {
2624 DCHECK(!main_thread_only().running_queues.empty());
2625 const base::TimeTicks now = real_time_domain()->Now();
2626 // When a nested loop is entered, simulate completing the current task. It
2627 // will be resumed when the run loop is exited.
2628 queueing_time_estimator_.OnExecutionStopped(now);
2629 agent_interference_recorder_.OnTaskCompleted(
2630 main_thread_only().running_queues.top().get(), now);
2631 main_thread_only().nested_runloop = true;
2632 ApplyVirtualTimePolicy();
2633 }
2634
OnExitNestedRunLoop()2635 void MainThreadSchedulerImpl::OnExitNestedRunLoop() {
2636 DCHECK(!main_thread_only().running_queues.empty());
2637 base::TimeTicks now = real_time_domain()->Now();
2638 queueing_time_estimator_.OnExecutionStarted(now);
2639 // When a nested loop is exited, resume the task that was running when the
2640 // nested loop was entered.
2641 agent_interference_recorder_.OnTaskStarted(
2642 main_thread_only().running_queues.top().get(),
2643 base::sequence_manager::EnqueueOrder::none(), now);
2644 main_thread_only().nested_runloop = false;
2645 ApplyVirtualTimePolicy();
2646 }
2647
AddTaskTimeObserver(TaskTimeObserver * task_time_observer)2648 void MainThreadSchedulerImpl::AddTaskTimeObserver(
2649 TaskTimeObserver* task_time_observer) {
2650 helper_.AddTaskTimeObserver(task_time_observer);
2651 }
2652
RemoveTaskTimeObserver(TaskTimeObserver * task_time_observer)2653 void MainThreadSchedulerImpl::RemoveTaskTimeObserver(
2654 TaskTimeObserver* task_time_observer) {
2655 helper_.RemoveTaskTimeObserver(task_time_observer);
2656 }
2657
ContainsLocalMainFrame()2658 bool MainThreadSchedulerImpl::ContainsLocalMainFrame() {
2659 for (auto* page_scheduler : main_thread_only().page_schedulers) {
2660 if (page_scheduler->IsMainFrameLocal())
2661 return true;
2662 }
2663 return false;
2664 }
2665
OnQueueingTimeForWindowEstimated(base::TimeDelta queueing_time,bool is_disjoint_window)2666 void MainThreadSchedulerImpl::OnQueueingTimeForWindowEstimated(
2667 base::TimeDelta queueing_time,
2668 bool is_disjoint_window) {
2669 if (main_thread_only().has_navigated) {
2670 if (main_thread_only().max_queueing_time < queueing_time) {
2671 if (!main_thread_only().max_queueing_time_metric) {
2672 main_thread_only().max_queueing_time_metric =
2673 CreateMaxQueueingTimeMetric();
2674 }
2675 main_thread_only().max_queueing_time_metric->SetSample(
2676 base::saturated_cast<base::HistogramBase::Sample>(
2677 queueing_time.InMilliseconds()));
2678 main_thread_only().max_queueing_time = queueing_time;
2679 }
2680 }
2681
2682 if (!is_disjoint_window || !ContainsLocalMainFrame())
2683 return;
2684
2685 UMA_HISTOGRAM_TIMES("RendererScheduler.ExpectedTaskQueueingDuration",
2686 queueing_time);
2687 UMA_HISTOGRAM_CUSTOM_COUNTS("RendererScheduler.ExpectedTaskQueueingDuration3",
2688 base::saturated_cast<base::HistogramBase::Sample>(
2689 queueing_time.InMicroseconds()),
2690 kMinExpectedQueueingTimeBucket,
2691 kMaxExpectedQueueingTimeBucket,
2692 kNumberExpectedQueueingTimeBuckets);
2693 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
2694 "estimated_queueing_time_for_window",
2695 queueing_time.InMillisecondsF());
2696
2697 if (auto* renderer_resource_coordinator =
2698 RendererResourceCoordinator::Get()) {
2699 renderer_resource_coordinator->SetExpectedTaskQueueingDuration(
2700 queueing_time);
2701 }
2702 }
2703
2704 AutoAdvancingVirtualTimeDomain*
GetVirtualTimeDomain()2705 MainThreadSchedulerImpl::GetVirtualTimeDomain() {
2706 return virtual_time_domain_.get();
2707 }
2708
AddQueueToWakeUpBudgetPool(MainThreadTaskQueue * queue)2709 void MainThreadSchedulerImpl::AddQueueToWakeUpBudgetPool(
2710 MainThreadTaskQueue* queue) {
2711 InitWakeUpBudgetPoolIfNeeded();
2712 main_thread_only().wake_up_budget_pool->AddQueue(tick_clock()->NowTicks(),
2713 queue);
2714 }
2715
InitWakeUpBudgetPoolIfNeeded()2716 void MainThreadSchedulerImpl::InitWakeUpBudgetPoolIfNeeded() {
2717 if (main_thread_only().wake_up_budget_pool)
2718 return;
2719
2720 main_thread_only().wake_up_budget_pool =
2721 task_queue_throttler()->CreateWakeUpBudgetPool("renderer_wake_up_pool");
2722 main_thread_only().wake_up_budget_pool->SetWakeUpRate(1);
2723 main_thread_only().wake_up_budget_pool->SetWakeUpDuration(
2724 GetWakeUpDuration());
2725 }
2726
GetActiveTimeDomain()2727 TimeDomain* MainThreadSchedulerImpl::GetActiveTimeDomain() {
2728 if (main_thread_only().use_virtual_time) {
2729 return GetVirtualTimeDomain();
2730 } else {
2731 return real_time_domain();
2732 }
2733 }
2734
OnTraceLogEnabled()2735 void MainThreadSchedulerImpl::OnTraceLogEnabled() {
2736 CreateTraceEventObjectSnapshot();
2737 tracing_controller_.OnTraceLogEnabled();
2738 for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
2739 page_scheduler->OnTraceLogEnabled();
2740 }
2741 }
2742
OnTraceLogDisabled()2743 void MainThreadSchedulerImpl::OnTraceLogDisabled() {}
2744
GetWeakPtr()2745 base::WeakPtr<MainThreadSchedulerImpl> MainThreadSchedulerImpl::GetWeakPtr() {
2746 return weak_factory_.GetWeakPtr();
2747 }
2748
IsAudioPlaying() const2749 bool MainThreadSchedulerImpl::IsAudioPlaying() const {
2750 return main_thread_only().is_audio_playing;
2751 }
2752
ShouldUpdateTaskQueuePriorities(Policy old_policy) const2753 bool MainThreadSchedulerImpl::ShouldUpdateTaskQueuePriorities(
2754 Policy old_policy) const {
2755 return old_policy.use_case() !=
2756 main_thread_only().current_policy.use_case() ||
2757 old_policy.compositor_priority() !=
2758 main_thread_only().current_policy.compositor_priority() ||
2759 old_policy.find_in_page_priority() !=
2760 main_thread_only().current_policy.find_in_page_priority();
2761 }
2762
current_use_case() const2763 UseCase MainThreadSchedulerImpl::current_use_case() const {
2764 return main_thread_only().current_use_case;
2765 }
2766
2767 const MainThreadSchedulerImpl::SchedulingSettings&
scheduling_settings() const2768 MainThreadSchedulerImpl::scheduling_settings() const {
2769 return scheduling_settings_;
2770 }
2771
SetShouldPrioritizeCompositing(bool should_prioritize_compositing)2772 void MainThreadSchedulerImpl::SetShouldPrioritizeCompositing(
2773 bool should_prioritize_compositing) {
2774 if (main_thread_only().should_prioritize_compositing ==
2775 should_prioritize_compositing) {
2776 return;
2777 }
2778 main_thread_only().should_prioritize_compositing =
2779 should_prioritize_compositing;
2780 UpdatePolicy();
2781 }
2782
2783 void MainThreadSchedulerImpl::
OnCompositorPriorityExperimentUpdateCompositorPriority()2784 OnCompositorPriorityExperimentUpdateCompositorPriority() {
2785 if (!ComputeCompositorPriorityFromUseCase())
2786 UpdatePolicy();
2787 }
2788
2789 base::Optional<TaskQueue::QueuePriority>
ComputeCompositorPriorityFromUseCase() const2790 MainThreadSchedulerImpl::ComputeCompositorPriorityFromUseCase() const {
2791 switch (current_use_case()) {
2792 case UseCase::kCompositorGesture:
2793 if (main_thread_only().blocking_input_expected_soon)
2794 return TaskQueue::QueuePriority::kHighestPriority;
2795 // What we really want to do is priorize loading tasks, but that doesn't
2796 // seem to be safe. Instead we do that by proxy by deprioritizing
2797 // compositor tasks. This should be safe since we've already gone to the
2798 // pain of fixing ordering issues with them.
2799 return TaskQueue::QueuePriority::kLowPriority;
2800
2801 case UseCase::kSynchronizedGesture:
2802 case UseCase::kMainThreadCustomInputHandling:
2803 // In main thread input handling use case we don't have perfect knowledge
2804 // about which things we should be prioritizing, so we don't attempt to
2805 // block expensive tasks because we don't know whether they were integral
2806 // to the page's functionality or not.
2807 if (main_thread_only().main_thread_compositing_is_fast)
2808 return TaskQueue::QueuePriority::kHighestPriority;
2809 return base::nullopt;
2810
2811 case UseCase::kMainThreadGesture:
2812 case UseCase::kTouchstart:
2813 // A main thread gesture is for example a scroll gesture which is handled
2814 // by the main thread. Since we know the established gesture type, we can
2815 // be a little more aggressive about prioritizing compositing and input
2816 // handling over other tasks.
2817 return TaskQueue::QueuePriority::kHighestPriority;
2818
2819 case UseCase::kNone:
2820 case UseCase::kEarlyLoading:
2821 case UseCase::kLoading:
2822 return base::nullopt;
2823
2824 default:
2825 NOTREACHED();
2826 return base::nullopt;
2827 }
2828 }
2829
OnSafepointEntered()2830 void MainThreadSchedulerImpl::OnSafepointEntered() {
2831 DCHECK(WTF::IsMainThread());
2832 DCHECK(!main_thread_only().nested_runloop);
2833 main_thread_only().metrics_helper.OnSafepointEntered(helper_.NowTicks());
2834 }
2835
OnSafepointExited()2836 void MainThreadSchedulerImpl::OnSafepointExited() {
2837 DCHECK(WTF::IsMainThread());
2838 DCHECK(!main_thread_only().nested_runloop);
2839 main_thread_only().metrics_helper.OnSafepointExited(helper_.NowTicks());
2840 }
2841
ExecuteAfterCurrentTask(base::OnceClosure on_completion_task)2842 void MainThreadSchedulerImpl::ExecuteAfterCurrentTask(
2843 base::OnceClosure on_completion_task) {
2844 main_thread_only().on_task_completion_callbacks.push_back(
2845 std::move(on_completion_task));
2846 }
2847
OnFrameSchedulerDestroyed(FrameSchedulerImpl * frame_scheduler)2848 void MainThreadSchedulerImpl::OnFrameSchedulerDestroyed(
2849 FrameSchedulerImpl* frame_scheduler) {
2850 agent_interference_recorder_.OnFrameSchedulerDestroyed(frame_scheduler);
2851 }
2852
DispatchOnTaskCompletionCallbacks()2853 void MainThreadSchedulerImpl::DispatchOnTaskCompletionCallbacks() {
2854 for (auto& closure : main_thread_only().on_task_completion_callbacks) {
2855 std::move(closure).Run();
2856 }
2857 main_thread_only().on_task_completion_callbacks.clear();
2858 }
2859
2860 // static
UseCaseToString(UseCase use_case)2861 const char* MainThreadSchedulerImpl::UseCaseToString(UseCase use_case) {
2862 switch (use_case) {
2863 case UseCase::kNone:
2864 return "none";
2865 case UseCase::kCompositorGesture:
2866 return "compositor_gesture";
2867 case UseCase::kMainThreadCustomInputHandling:
2868 return "main_thread_custom_input_handling";
2869 case UseCase::kSynchronizedGesture:
2870 return "synchronized_gesture";
2871 case UseCase::kTouchstart:
2872 return "touchstart";
2873 case UseCase::kEarlyLoading:
2874 return "early_loading";
2875 case UseCase::kLoading:
2876 return "loading";
2877 case UseCase::kMainThreadGesture:
2878 return "main_thread_gesture";
2879 default:
2880 NOTREACHED();
2881 return nullptr;
2882 }
2883 }
2884
2885 // static
RAILModeToString(RAILMode rail_mode)2886 const char* MainThreadSchedulerImpl::RAILModeToString(RAILMode rail_mode) {
2887 switch (rail_mode) {
2888 case RAILMode::kResponse:
2889 return "response";
2890 case RAILMode::kAnimation:
2891 return "animation";
2892 case RAILMode::kIdle:
2893 return "idle";
2894 case RAILMode::kLoad:
2895 return "load";
2896 default:
2897 NOTREACHED();
2898 return nullptr;
2899 }
2900 }
2901
2902 // static
TimeDomainTypeToString(TimeDomainType domain_type)2903 const char* MainThreadSchedulerImpl::TimeDomainTypeToString(
2904 TimeDomainType domain_type) {
2905 switch (domain_type) {
2906 case TimeDomainType::kReal:
2907 return "real";
2908 case TimeDomainType::kVirtual:
2909 return "virtual";
2910 default:
2911 NOTREACHED();
2912 return nullptr;
2913 }
2914 }
2915
2916 // static
VirtualTimePolicyToString(VirtualTimePolicy virtual_time_policy)2917 const char* MainThreadSchedulerImpl::VirtualTimePolicyToString(
2918 VirtualTimePolicy virtual_time_policy) {
2919 switch (virtual_time_policy) {
2920 case VirtualTimePolicy::kAdvance:
2921 return "ADVANCE";
2922 case VirtualTimePolicy::kPause:
2923 return "PAUSE";
2924 case VirtualTimePolicy::kDeterministicLoading:
2925 return "DETERMINISTIC_LOADING";
2926 default:
2927 NOTREACHED();
2928 return nullptr;
2929 }
2930 }
2931
2932 } // namespace scheduler
2933 } // namespace blink
2934