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, &params);
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