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