OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_IMPL_H_ | |
6 #define COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_IMPL_H_ | |
7 | |
8 #include "base/atomicops.h" | |
9 #include "base/macros.h" | |
10 #include "base/synchronization/lock.h" | |
11 #include "components/scheduler/base/long_task_tracker.h" | |
12 #include "components/scheduler/base/pollable_thread_safe_flag.h" | |
13 #include "components/scheduler/base/queueing_time_estimator.h" | |
14 #include "components/scheduler/base/task_time_tracker.h" | |
15 #include "components/scheduler/child/idle_helper.h" | |
16 #include "components/scheduler/child/scheduler_helper.h" | |
17 #include "components/scheduler/renderer/deadline_task_runner.h" | |
18 #include "components/scheduler/renderer/idle_time_estimator.h" | |
19 #include "components/scheduler/renderer/render_widget_signals.h" | |
20 #include "components/scheduler/renderer/renderer_scheduler.h" | |
21 #include "components/scheduler/renderer/task_cost_estimator.h" | |
22 #include "components/scheduler/renderer/throttling_helper.h" | |
23 #include "components/scheduler/renderer/user_model.h" | |
24 #include "components/scheduler/renderer/web_view_scheduler_impl.h" | |
25 #include "components/scheduler/scheduler_export.h" | |
26 | |
27 namespace base { | |
28 namespace trace_event { | |
29 class ConvertableToTraceFormat; | |
30 } | |
31 } | |
32 | |
33 namespace scheduler { | |
34 class AutoAdvancingVirtualTimeDomain; | |
35 class RenderWidgetSchedulingState; | |
36 class WebViewSchedulerImpl; | |
37 class ThrottlingHelper; | |
38 | |
39 class SCHEDULER_EXPORT RendererSchedulerImpl | |
40 : public RendererScheduler, | |
41 public IdleHelper::Delegate, | |
42 public SchedulerHelper::Observer, | |
43 public RenderWidgetSignals::Observer, | |
44 public TaskTimeTracker, | |
45 public QueueingTimeEstimator::Client { | |
46 public: | |
47 // Keep RendererScheduler::UseCaseToString in sync with this enum. | |
48 enum class UseCase { | |
49 // No active use case detected. | |
50 NONE, | |
51 // A continuous gesture (e.g., scroll, pinch) which is being driven by the | |
52 // compositor thread. | |
53 COMPOSITOR_GESTURE, | |
54 // An unspecified touch gesture which is being handled by the main thread. | |
55 // Note that since we don't have a full view of the use case, we should be | |
56 // careful to prioritize all work equally. | |
57 MAIN_THREAD_CUSTOM_INPUT_HANDLING, | |
58 // A continuous gesture (e.g., scroll, pinch) which is being driven by the | |
59 // compositor thread but also observed by the main thread. An example is | |
60 // synchronized scrolling where a scroll listener on the main thread changes | |
61 // page layout based on the current scroll position. | |
62 SYNCHRONIZED_GESTURE, | |
63 // A gesture has recently started and we are about to run main thread touch | |
64 // listeners to find out the actual gesture type. To minimize touch latency, | |
65 // only input handling work should run in this state. | |
66 TOUCHSTART, | |
67 // The page is loading. | |
68 LOADING, | |
69 // A continuous gesture (e.g., scroll) which is being handled by the main | |
70 // thread. | |
71 MAIN_THREAD_GESTURE, | |
72 // Must be the last entry. | |
73 USE_CASE_COUNT, | |
74 FIRST_USE_CASE = NONE, | |
75 }; | |
76 static const char* UseCaseToString(UseCase use_case); | |
77 static const char* RAILModeToString(v8::RAILMode rail_mode); | |
78 | |
79 RendererSchedulerImpl(scoped_refptr<SchedulerTqmDelegate> main_task_runner); | |
80 ~RendererSchedulerImpl() override; | |
81 | |
82 // RendererScheduler implementation: | |
83 std::unique_ptr<blink::WebThread> CreateMainThread() override; | |
84 scoped_refptr<TaskQueue> DefaultTaskRunner() override; | |
85 scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override; | |
86 scoped_refptr<TaskQueue> CompositorTaskRunner() override; | |
87 scoped_refptr<TaskQueue> LoadingTaskRunner() override; | |
88 scoped_refptr<TaskQueue> TimerTaskRunner() override; | |
89 scoped_refptr<TaskQueue> NewLoadingTaskRunner(const char* name) override; | |
90 scoped_refptr<TaskQueue> NewTimerTaskRunner(const char* name) override; | |
91 scoped_refptr<TaskQueue> NewUnthrottledTaskRunner(const char* name) override; | |
92 std::unique_ptr<RenderWidgetSchedulingState> NewRenderWidgetSchedulingState() | |
93 override; | |
94 void WillBeginFrame(const cc::BeginFrameArgs& args) override; | |
95 void BeginFrameNotExpectedSoon() override; | |
96 void DidCommitFrameToCompositor() override; | |
97 void DidHandleInputEventOnCompositorThread( | |
98 const blink::WebInputEvent& web_input_event, | |
99 InputEventState event_state) override; | |
100 void DidHandleInputEventOnMainThread( | |
101 const blink::WebInputEvent& web_input_event) override; | |
102 void DidAnimateForInputOnCompositorThread() override; | |
103 void OnRendererBackgrounded() override; | |
104 void OnRendererForegrounded() override; | |
105 void SuspendRenderer() override; | |
106 void AddPendingNavigation( | |
107 blink::WebScheduler::NavigatingFrameType type) override; | |
108 void RemovePendingNavigation( | |
109 blink::WebScheduler::NavigatingFrameType type) override; | |
110 void OnNavigationStarted() override; | |
111 bool IsHighPriorityWorkAnticipated() override; | |
112 bool ShouldYieldForHighPriorityWork() override; | |
113 bool CanExceedIdleDeadlineIfRequired() const override; | |
114 void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override; | |
115 void RemoveTaskObserver( | |
116 base::MessageLoop::TaskObserver* task_observer) override; | |
117 void Shutdown() override; | |
118 void SuspendTimerQueue() override; | |
119 void ResumeTimerQueue() override; | |
120 void SetTimerQueueSuspensionWhenBackgroundedEnabled(bool enabled) override; | |
121 void SetTopLevelBlameContext( | |
122 base::trace_event::BlameContext* blame_context) override; | |
123 void SetRAILModeObserver(RAILModeObserver* observer) override; | |
124 | |
125 // RenderWidgetSignals::Observer implementation: | |
126 void SetAllRenderWidgetsHidden(bool hidden) override; | |
127 void SetHasVisibleRenderWidgetWithTouchHandler( | |
128 bool has_visible_render_widget_with_touch_handler) override; | |
129 | |
130 // SchedulerHelper::Observer implementation: | |
131 void OnUnregisterTaskQueue(const scoped_refptr<TaskQueue>& queue) override; | |
132 void OnTriedToExecuteBlockedTask(const TaskQueue& queue, | |
133 const base::PendingTask& task) override; | |
134 | |
135 // TaskTimeTracker implementation: | |
136 void ReportTaskTime(base::TimeTicks start_time, | |
137 base::TimeTicks end_time) override; | |
138 | |
139 // QueueingTimeEstimator::Client implementation: | |
140 void OnQueueingTimeForWindowEstimated(base::TimeDelta queueing_time) override; | |
141 | |
142 // Returns a task runner where tasks run at the highest possible priority. | |
143 scoped_refptr<TaskQueue> ControlTaskRunner(); | |
144 | |
145 void RegisterTimeDomain(TimeDomain* time_domain); | |
146 void UnregisterTimeDomain(TimeDomain* time_domain); | |
147 | |
148 // Tells the scheduler that all TaskQueues should use virtual time. | |
149 void EnableVirtualTime(); | |
150 | |
151 void SetExpensiveTaskBlockingAllowed(bool allowed); | |
152 | |
153 void AddWebViewScheduler(WebViewSchedulerImpl* web_view_scheduler); | |
154 void RemoveWebViewScheduler(WebViewSchedulerImpl* web_view_scheduler); | |
155 | |
156 LongTaskTracker::LongTaskTiming GetLongTaskTiming(); | |
157 | |
158 // Test helpers. | |
159 SchedulerHelper* GetSchedulerHelperForTesting(); | |
160 TaskCostEstimator* GetLoadingTaskCostEstimatorForTesting(); | |
161 TaskCostEstimator* GetTimerTaskCostEstimatorForTesting(); | |
162 IdleTimeEstimator* GetIdleTimeEstimatorForTesting(); | |
163 base::TimeTicks CurrentIdleTaskDeadlineForTesting() const; | |
164 void RunIdleTasksForTesting(const base::Closure& callback); | |
165 void EndIdlePeriodForTesting(const base::Closure& callback, | |
166 base::TimeTicks time_remaining); | |
167 bool PolicyNeedsUpdateForTesting(); | |
168 | |
169 base::TickClock* tick_clock() const; | |
170 | |
171 RealTimeDomain* real_time_domain() const { | |
172 return helper_.real_time_domain(); | |
173 } | |
174 | |
175 AutoAdvancingVirtualTimeDomain* GetVirtualTimeDomain(); | |
176 | |
177 ThrottlingHelper* throttling_helper() { return throttling_helper_.get(); } | |
178 | |
179 private: | |
180 friend class RendererSchedulerImplTest; | |
181 friend class RendererSchedulerImplForTest; | |
182 friend class RenderWidgetSchedulingState; | |
183 | |
184 enum class ExpensiveTaskPolicy { RUN, BLOCK, THROTTLE }; | |
185 | |
186 enum class TimeDomainType { | |
187 REAL, | |
188 THROTTLED, | |
189 VIRTUAL, | |
190 }; | |
191 | |
192 struct TaskQueuePolicy { | |
193 TaskQueuePolicy() | |
194 : is_enabled(true), | |
195 priority(TaskQueue::NORMAL_PRIORITY), | |
196 time_domain_type(TimeDomainType::REAL) {} | |
197 | |
198 bool is_enabled; | |
199 TaskQueue::QueuePriority priority; | |
200 TimeDomainType time_domain_type; | |
201 | |
202 bool operator==(const TaskQueuePolicy& other) const { | |
203 return is_enabled == other.is_enabled && priority == other.priority && | |
204 time_domain_type == other.time_domain_type; | |
205 } | |
206 }; | |
207 | |
208 struct Policy { | |
209 TaskQueuePolicy compositor_queue_policy; | |
210 TaskQueuePolicy loading_queue_policy; | |
211 TaskQueuePolicy timer_queue_policy; | |
212 TaskQueuePolicy default_queue_policy; | |
213 v8::RAILMode rail_mode = v8::PERFORMANCE_ANIMATION; | |
214 | |
215 bool operator==(const Policy& other) const { | |
216 return compositor_queue_policy == other.compositor_queue_policy && | |
217 loading_queue_policy == other.loading_queue_policy && | |
218 timer_queue_policy == other.timer_queue_policy && | |
219 default_queue_policy == other.default_queue_policy && | |
220 rail_mode == other.rail_mode; | |
221 } | |
222 }; | |
223 | |
224 class PollableNeedsUpdateFlag { | |
225 public: | |
226 PollableNeedsUpdateFlag(base::Lock* write_lock); | |
227 ~PollableNeedsUpdateFlag(); | |
228 | |
229 // Set the flag. May only be called if |write_lock| is held. | |
230 void SetWhileLocked(bool value); | |
231 | |
232 // Returns true iff the flag is set to true. | |
233 bool IsSet() const; | |
234 | |
235 private: | |
236 base::subtle::Atomic32 flag_; | |
237 base::Lock* write_lock_; // Not owned. | |
238 | |
239 DISALLOW_COPY_AND_ASSIGN(PollableNeedsUpdateFlag); | |
240 }; | |
241 | |
242 // IdleHelper::Delegate implementation: | |
243 bool CanEnterLongIdlePeriod( | |
244 base::TimeTicks now, | |
245 base::TimeDelta* next_long_idle_period_delay_out) override; | |
246 void IsNotQuiescent() override {} | |
247 void OnIdlePeriodStarted() override; | |
248 void OnIdlePeriodEnded() override; | |
249 | |
250 void EndIdlePeriod(); | |
251 | |
252 // Returns the serialized scheduler state for tracing. | |
253 std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue( | |
254 base::TimeTicks optional_now) const; | |
255 std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValueLocked( | |
256 base::TimeTicks optional_now) const; | |
257 | |
258 static bool ShouldPrioritizeInputEvent( | |
259 const blink::WebInputEvent& web_input_event); | |
260 | |
261 // The amount of time which idle periods can continue being scheduled when the | |
262 // renderer has been hidden, before going to sleep for good. | |
263 static const int kEndIdleWhenHiddenDelayMillis = 10000; | |
264 | |
265 // The amount of time for which loading tasks will be prioritized over | |
266 // other tasks during the initial page load. | |
267 static const int kRailsInitialLoadingPrioritizationMillis = 1000; | |
268 | |
269 // The amount of time in milliseconds we have to respond to user input as | |
270 // defined by RAILS. | |
271 static const int kRailsResponseTimeMillis = 50; | |
272 | |
273 // For the purposes of deciding whether or not it's safe to turn timers and | |
274 // loading tasks on only in idle periods, we regard the system as being as | |
275 // being "idle period" starved if there hasn't been an idle period in the last | |
276 // 10 seconds. This was chosen to be long enough to cover most anticipated | |
277 // user gestures. | |
278 static const int kIdlePeriodStarvationThresholdMillis = 10000; | |
279 | |
280 // The amount of time to wait before suspending shared timers after the | |
281 // renderer has been backgrounded. This is used only if background suspension | |
282 // of shared timers is enabled. | |
283 static const int kSuspendTimersWhenBackgroundedDelayMillis = 5 * 60 * 1000; | |
284 | |
285 // The time we should stay in a priority-escalated mode after a call to | |
286 // DidAnimateForInputOnCompositorThread(). | |
287 static const int kFlingEscalationLimitMillis = 100; | |
288 | |
289 // Schedules an immediate PolicyUpdate, if there isn't one already pending and | |
290 // sets |policy_may_need_update_|. Note |any_thread_lock_| must be | |
291 // locked. | |
292 void EnsureUrgentPolicyUpdatePostedOnMainThread( | |
293 const tracked_objects::Location& from_here); | |
294 | |
295 // Update the policy if a new signal has arrived. Must be called from the main | |
296 // thread. | |
297 void MaybeUpdatePolicy(); | |
298 | |
299 // Locks |any_thread_lock_| and updates the scheduler policy. May early | |
300 // out if the policy is unchanged. Must be called from the main thread. | |
301 void UpdatePolicy(); | |
302 | |
303 // Like UpdatePolicy, except it doesn't early out. | |
304 void ForceUpdatePolicy(); | |
305 | |
306 enum class UpdateType { | |
307 MAY_EARLY_OUT_IF_POLICY_UNCHANGED, | |
308 FORCE_UPDATE, | |
309 }; | |
310 | |
311 // The implelemtation of UpdatePolicy & ForceUpdatePolicy. It is allowed to | |
312 // early out if |update_type| is MAY_EARLY_OUT_IF_POLICY_UNCHANGED. | |
313 virtual void UpdatePolicyLocked(UpdateType update_type); | |
314 | |
315 // Helper for computing the use case. |expected_usecase_duration| will be | |
316 // filled with the amount of time after which the use case should be updated | |
317 // again. If the duration is zero, a new use case update should not be | |
318 // scheduled. Must be called with |any_thread_lock_| held. Can be called from | |
319 // any thread. | |
320 UseCase ComputeCurrentUseCase( | |
321 base::TimeTicks now, | |
322 base::TimeDelta* expected_use_case_duration) const; | |
323 | |
324 // An input event of some sort happened, the policy may need updating. | |
325 void UpdateForInputEventOnCompositorThread(blink::WebInputEvent::Type type, | |
326 InputEventState input_event_state); | |
327 | |
328 // Returns true if there has been at least one idle period in the last | |
329 // |kIdlePeriodStarvationThresholdMillis|. | |
330 bool HadAnIdlePeriodRecently(base::TimeTicks now) const; | |
331 | |
332 // Helpers for safely suspending/resuming the timer queue after a | |
333 // background/foreground signal. | |
334 void SuspendTimerQueueWhenBackgrounded(); | |
335 void ResumeTimerQueueWhenForegrounded(); | |
336 | |
337 // The task cost estimators and the UserModel need to be reset upon page | |
338 // nagigation. This function does that. Must be called from the main thread. | |
339 void ResetForNavigationLocked(); | |
340 | |
341 // Estimates the maximum task length that won't cause a jank based on the | |
342 // current system state. Must be called from the main thread. | |
343 base::TimeDelta EstimateLongestJankFreeTaskDuration() const; | |
344 | |
345 // Log a console warning message to all WebViews in this process. | |
346 void BroadcastConsoleWarning(const std::string& message); | |
347 | |
348 void ApplyTaskQueuePolicy(TaskQueue* task_queue, | |
349 const TaskQueuePolicy& old_task_queue_policy, | |
350 const TaskQueuePolicy& new_task_queue_policy) const; | |
351 | |
352 static const char* ExpensiveTaskPolicyToString( | |
353 ExpensiveTaskPolicy expensive_task_policy); | |
354 | |
355 SchedulerHelper helper_; | |
356 IdleHelper idle_helper_; | |
357 std::unique_ptr<ThrottlingHelper> throttling_helper_; | |
358 RenderWidgetSignals render_widget_scheduler_signals_; | |
359 | |
360 const scoped_refptr<TaskQueue> control_task_runner_; | |
361 const scoped_refptr<TaskQueue> compositor_task_runner_; | |
362 std::set<scoped_refptr<TaskQueue>> loading_task_runners_; | |
363 std::set<scoped_refptr<TaskQueue>> timer_task_runners_; | |
364 std::set<scoped_refptr<TaskQueue>> unthrottled_task_runners_; | |
365 scoped_refptr<TaskQueue> default_loading_task_runner_; | |
366 scoped_refptr<TaskQueue> default_timer_task_runner_; | |
367 | |
368 // Note |virtual_time_domain_| is lazily created. | |
369 std::unique_ptr<AutoAdvancingVirtualTimeDomain> virtual_time_domain_; | |
370 | |
371 base::Closure update_policy_closure_; | |
372 DeadlineTaskRunner delayed_update_policy_runner_; | |
373 CancelableClosureHolder end_renderer_hidden_idle_period_closure_; | |
374 CancelableClosureHolder suspend_timers_when_backgrounded_closure_; | |
375 | |
376 // We have decided to improve thread safety at the cost of some boilerplate | |
377 // (the accessors) for the following data members. | |
378 | |
379 struct MainThreadOnly { | |
380 MainThreadOnly(RendererSchedulerImpl* renderer_scheduler_impl, | |
381 const scoped_refptr<TaskQueue>& compositor_task_runner, | |
382 base::TickClock* time_source); | |
383 ~MainThreadOnly(); | |
384 | |
385 TaskCostEstimator loading_task_cost_estimator; | |
386 TaskCostEstimator timer_task_cost_estimator; | |
387 QueueingTimeEstimator queueing_time_estimator; | |
388 LongTaskTracker long_task_tracker; | |
389 IdleTimeEstimator idle_time_estimator; | |
390 UseCase current_use_case; | |
391 Policy current_policy; | |
392 base::TimeTicks current_policy_expiration_time; | |
393 base::TimeTicks estimated_next_frame_begin; | |
394 base::TimeDelta compositor_frame_interval; | |
395 base::TimeDelta longest_jank_free_task_duration; | |
396 int timer_queue_suspend_count; // TIMER_TASK_QUEUE suspended if non-zero. | |
397 int navigation_task_expected_count; | |
398 ExpensiveTaskPolicy expensive_task_policy; | |
399 bool renderer_hidden; | |
400 bool renderer_backgrounded; | |
401 bool renderer_suspended; | |
402 bool timer_queue_suspension_when_backgrounded_enabled; | |
403 bool timer_queue_suspended_when_backgrounded; | |
404 bool was_shutdown; | |
405 bool loading_tasks_seem_expensive; | |
406 bool timer_tasks_seem_expensive; | |
407 bool touchstart_expected_soon; | |
408 bool have_seen_a_begin_main_frame; | |
409 bool have_reported_blocking_intervention_in_current_policy; | |
410 bool have_reported_blocking_intervention_since_navigation; | |
411 bool has_visible_render_widget_with_touch_handler; | |
412 bool begin_frame_not_expected_soon; | |
413 bool expensive_task_blocking_allowed; | |
414 bool in_idle_period_for_testing; | |
415 bool use_virtual_time; | |
416 std::set<WebViewSchedulerImpl*> web_view_schedulers; // Not owned. | |
417 RAILModeObserver* rail_mode_observer; // Not owned. | |
418 }; | |
419 | |
420 struct AnyThread { | |
421 AnyThread(); | |
422 ~AnyThread(); | |
423 | |
424 base::TimeTicks last_idle_period_end_time; | |
425 base::TimeTicks rails_loading_priority_deadline; | |
426 base::TimeTicks fling_compositor_escalation_deadline; | |
427 UserModel user_model; | |
428 bool awaiting_touch_start_response; | |
429 bool in_idle_period; | |
430 bool begin_main_frame_on_critical_path; | |
431 bool last_gesture_was_compositor_driven; | |
432 bool default_gesture_prevented; | |
433 bool have_seen_touchstart; | |
434 }; | |
435 | |
436 struct CompositorThreadOnly { | |
437 CompositorThreadOnly(); | |
438 ~CompositorThreadOnly(); | |
439 | |
440 blink::WebInputEvent::Type last_input_type; | |
441 std::unique_ptr<base::ThreadChecker> compositor_thread_checker; | |
442 | |
443 void CheckOnValidThread() { | |
444 #if DCHECK_IS_ON() | |
445 // We don't actually care which thread this called from, just so long as | |
446 // its consistent. | |
447 if (!compositor_thread_checker) | |
448 compositor_thread_checker.reset(new base::ThreadChecker()); | |
449 DCHECK(compositor_thread_checker->CalledOnValidThread()); | |
450 #endif | |
451 } | |
452 }; | |
453 | |
454 // Don't access main_thread_only_, instead use MainThreadOnly(). | |
455 MainThreadOnly main_thread_only_; | |
456 MainThreadOnly& MainThreadOnly() { | |
457 helper_.CheckOnValidThread(); | |
458 return main_thread_only_; | |
459 } | |
460 const struct MainThreadOnly& MainThreadOnly() const { | |
461 helper_.CheckOnValidThread(); | |
462 return main_thread_only_; | |
463 } | |
464 | |
465 mutable base::Lock any_thread_lock_; | |
466 // Don't access any_thread_, instead use AnyThread(). | |
467 AnyThread any_thread_; | |
468 AnyThread& AnyThread() { | |
469 any_thread_lock_.AssertAcquired(); | |
470 return any_thread_; | |
471 } | |
472 const struct AnyThread& AnyThread() const { | |
473 any_thread_lock_.AssertAcquired(); | |
474 return any_thread_; | |
475 } | |
476 | |
477 // Don't access compositor_thread_only_, instead use CompositorThreadOnly(). | |
478 CompositorThreadOnly compositor_thread_only_; | |
479 CompositorThreadOnly& CompositorThreadOnly() { | |
480 compositor_thread_only_.CheckOnValidThread(); | |
481 return compositor_thread_only_; | |
482 } | |
483 | |
484 PollableThreadSafeFlag policy_may_need_update_; | |
485 base::WeakPtrFactory<RendererSchedulerImpl> weak_factory_; | |
486 | |
487 DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImpl); | |
488 }; | |
489 | |
490 } // namespace scheduler | |
491 | |
492 #endif // COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_IMPL_H_ | |
OLD | NEW |