OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "platform/scheduler/renderer/renderer_scheduler_impl.h" | 5 #include "platform/scheduler/renderer/renderer_scheduler_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/debug/stack_trace.h" | 8 #include "base/debug/stack_trace.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
11 #include "base/metrics/histogram_macros.h" | 11 #include "base/metrics/histogram_macros.h" |
12 #include "base/trace_event/trace_event.h" | 12 #include "base/trace_event/trace_event.h" |
13 #include "base/trace_event/trace_event_argument.h" | 13 #include "base/trace_event/trace_event_argument.h" |
14 #include "cc/output/begin_frame_args.h" | 14 #include "cc/output/begin_frame_args.h" |
15 #include "platform/scheduler/base/real_time_domain.h" | |
16 #include "platform/scheduler/base/task_queue_impl.h" | 15 #include "platform/scheduler/base/task_queue_impl.h" |
17 #include "platform/scheduler/base/task_queue_selector.h" | 16 #include "platform/scheduler/base/task_queue_selector.h" |
18 #include "platform/scheduler/base/virtual_time_domain.h" | 17 #include "platform/scheduler/base/virtual_time_domain.h" |
19 #include "platform/scheduler/child/scheduler_tqm_delegate.h" | 18 #include "platform/scheduler/child/scheduler_tqm_delegate.h" |
20 #include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" | 19 #include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" |
21 #include "platform/scheduler/renderer/task_queue_throttler.h" | 20 #include "platform/scheduler/renderer/task_queue_throttler.h" |
22 #include "platform/scheduler/renderer/web_view_scheduler_impl.h" | 21 #include "platform/scheduler/renderer/web_view_scheduler_impl.h" |
23 #include "platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h" | 22 #include "platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h" |
24 | 23 |
25 namespace blink { | 24 namespace blink { |
26 namespace scheduler { | 25 namespace scheduler { |
27 namespace { | 26 namespace { |
28 // The run time of loading tasks is strongly bimodal. The vast majority are | 27 // The run time of loading tasks is strongly bimodal. The vast majority are |
29 // very cheap, but there are usually a handful of very expensive tasks (e.g ~1 | 28 // very cheap, but there are usually a handful of very expensive tasks (e.g ~1 |
30 // second on a mobile device) so we take a very pessimistic view when estimating | 29 // second on a mobile device) so we take a very pessimistic view when estimating |
31 // the cost of loading tasks. | 30 // the cost of loading tasks. |
32 const int kLoadingTaskEstimationSampleCount = 1000; | 31 const int kLoadingTaskEstimationSampleCount = 1000; |
33 const double kLoadingTaskEstimationPercentile = 99; | 32 const double kLoadingTaskEstimationPercentile = 99; |
34 const int kTimerTaskEstimationSampleCount = 1000; | 33 const int kTimerTaskEstimationSampleCount = 1000; |
35 const double kTimerTaskEstimationPercentile = 99; | 34 const double kTimerTaskEstimationPercentile = 99; |
36 const int kShortIdlePeriodDurationSampleCount = 10; | 35 const int kShortIdlePeriodDurationSampleCount = 10; |
37 const double kShortIdlePeriodDurationPercentile = 50; | 36 const double kShortIdlePeriodDurationPercentile = 50; |
38 // Amount of idle time left in a frame (as a ratio of the vsync interval) above | 37 // Amount of idle time left in a frame (as a ratio of the vsync interval) above |
39 // which main thread compositing can be considered fast. | 38 // which main thread compositing can be considered fast. |
40 const double kFastCompositingIdleTimeThreshold = .2; | 39 const double kFastCompositingIdleTimeThreshold = .2; |
41 constexpr base::TimeDelta kThreadLoadTrackerReportingInterval = | 40 constexpr base::TimeDelta kThreadLoadTrackerReportingInterval = |
42 base::TimeDelta::FromMinutes(1); | 41 base::TimeDelta::FromMinutes(1); |
43 constexpr base::TimeDelta kThreadLoadTrackerWaitingPeriodBeforeReporting = | 42 constexpr base::TimeDelta kThreadLoadTrackerWaitingPeriodBeforeReporting = |
44 base::TimeDelta::FromMinutes(2); | 43 base::TimeDelta::FromMinutes(2); |
45 // We do not throttle anything while audio is played and shortly after that. | |
46 constexpr base::TimeDelta kThrottlingDelayAfterAudioIsPlayed = | |
47 base::TimeDelta::FromSeconds(5); | |
48 | 44 |
49 void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) { | 45 void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) { |
50 int load_percentage = static_cast<int>(load * 100); | 46 int load_percentage = static_cast<int>(load * 100); |
51 UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.ForegroundRendererMainThreadLoad", | 47 UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.ForegroundRendererMainThreadLoad", |
52 load_percentage); | 48 load_percentage); |
53 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 49 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
54 "RendererScheduler.ForegroundRendererLoad", load_percentage); | 50 "RendererScheduler.ForegroundRendererLoad", load_percentage); |
55 } | 51 } |
56 | 52 |
57 void ReportBackgroundRendererTaskLoad(base::TimeTicks time, double load) { | 53 void ReportBackgroundRendererTaskLoad(base::TimeTicks time, double load) { |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 loading_tasks_seem_expensive(false), | 182 loading_tasks_seem_expensive(false), |
187 timer_tasks_seem_expensive(false), | 183 timer_tasks_seem_expensive(false), |
188 touchstart_expected_soon(false), | 184 touchstart_expected_soon(false), |
189 have_seen_a_begin_main_frame(false), | 185 have_seen_a_begin_main_frame(false), |
190 have_reported_blocking_intervention_in_current_policy(false), | 186 have_reported_blocking_intervention_in_current_policy(false), |
191 have_reported_blocking_intervention_since_navigation(false), | 187 have_reported_blocking_intervention_since_navigation(false), |
192 has_visible_render_widget_with_touch_handler(false), | 188 has_visible_render_widget_with_touch_handler(false), |
193 begin_frame_not_expected_soon(false), | 189 begin_frame_not_expected_soon(false), |
194 in_idle_period_for_testing(false), | 190 in_idle_period_for_testing(false), |
195 use_virtual_time(false), | 191 use_virtual_time(false), |
196 is_audio_playing(false), | |
197 rail_mode_observer(nullptr) {} | 192 rail_mode_observer(nullptr) {} |
198 | 193 |
199 RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {} | 194 RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {} |
200 | 195 |
201 RendererSchedulerImpl::AnyThread::AnyThread() | 196 RendererSchedulerImpl::AnyThread::AnyThread() |
202 : awaiting_touch_start_response(false), | 197 : awaiting_touch_start_response(false), |
203 in_idle_period(false), | 198 in_idle_period(false), |
204 begin_main_frame_on_critical_path(false), | 199 begin_main_frame_on_critical_path(false), |
205 last_gesture_was_compositor_driven(false), | 200 last_gesture_was_compositor_driven(false), |
206 default_gesture_prevented(true), | 201 default_gesture_prevented(true), |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 MainThreadOnly().renderer_suspended = false; | 485 MainThreadOnly().renderer_suspended = false; |
491 | 486 |
492 base::TimeTicks now = tick_clock()->NowTicks(); | 487 base::TimeTicks now = tick_clock()->NowTicks(); |
493 MainThreadOnly().foreground_main_thread_load_tracker.Resume(now); | 488 MainThreadOnly().foreground_main_thread_load_tracker.Resume(now); |
494 MainThreadOnly().background_main_thread_load_tracker.Pause(now); | 489 MainThreadOnly().background_main_thread_load_tracker.Pause(now); |
495 | 490 |
496 suspend_timers_when_backgrounded_closure_.Cancel(); | 491 suspend_timers_when_backgrounded_closure_.Cancel(); |
497 ResumeTimerQueueWhenForegroundedOrResumed(); | 492 ResumeTimerQueueWhenForegroundedOrResumed(); |
498 } | 493 } |
499 | 494 |
500 void RendererSchedulerImpl::OnAudioStateChanged() { | |
501 bool is_audio_playing = false; | |
502 for (WebViewSchedulerImpl* web_view_scheduler : | |
503 MainThreadOnly().web_view_schedulers) { | |
504 is_audio_playing = is_audio_playing || web_view_scheduler->IsAudioPlaying(); | |
505 } | |
506 | |
507 if (is_audio_playing == MainThreadOnly().is_audio_playing) | |
508 return; | |
509 | |
510 MainThreadOnly().last_audio_state_change = | |
511 helper_.scheduler_tqm_delegate()->NowTicks(); | |
512 MainThreadOnly().is_audio_playing = is_audio_playing; | |
513 | |
514 UpdatePolicy(); | |
515 } | |
516 | |
517 void RendererSchedulerImpl::SuspendRenderer() { | 495 void RendererSchedulerImpl::SuspendRenderer() { |
518 helper_.CheckOnValidThread(); | 496 helper_.CheckOnValidThread(); |
519 DCHECK(MainThreadOnly().renderer_backgrounded); | 497 DCHECK(MainThreadOnly().renderer_backgrounded); |
520 if (helper_.IsShutdown()) | 498 if (helper_.IsShutdown()) |
521 return; | 499 return; |
522 suspend_timers_when_backgrounded_closure_.Cancel(); | 500 suspend_timers_when_backgrounded_closure_.Cancel(); |
523 | 501 |
524 UMA_HISTOGRAM_COUNTS("PurgeAndSuspend.PendingTaskCount", | 502 UMA_HISTOGRAM_COUNTS("PurgeAndSuspend.PendingTaskCount", |
525 helper_.GetNumberOfPendingTasks()); | 503 helper_.GetNumberOfPendingTasks()); |
526 | 504 |
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 // The |new_policy_duration| is the minimum of |expected_use_case_duration| | 829 // The |new_policy_duration| is the minimum of |expected_use_case_duration| |
852 // and |touchstart_expected_flag_valid_for_duration| unless one is zero in | 830 // and |touchstart_expected_flag_valid_for_duration| unless one is zero in |
853 // which case we choose the other. | 831 // which case we choose the other. |
854 base::TimeDelta new_policy_duration = expected_use_case_duration; | 832 base::TimeDelta new_policy_duration = expected_use_case_duration; |
855 if (new_policy_duration.is_zero() || | 833 if (new_policy_duration.is_zero() || |
856 (touchstart_expected_flag_valid_for_duration > base::TimeDelta() && | 834 (touchstart_expected_flag_valid_for_duration > base::TimeDelta() && |
857 new_policy_duration > touchstart_expected_flag_valid_for_duration)) { | 835 new_policy_duration > touchstart_expected_flag_valid_for_duration)) { |
858 new_policy_duration = touchstart_expected_flag_valid_for_duration; | 836 new_policy_duration = touchstart_expected_flag_valid_for_duration; |
859 } | 837 } |
860 | 838 |
861 // Do not throttle while audio is playing or for a short period after that | |
862 // to make sure that pages playing short audio clips powered by timers | |
863 // work. | |
864 if (MainThreadOnly().last_audio_state_change && | |
865 !MainThreadOnly().is_audio_playing) { | |
866 base::TimeTicks audio_will_expire = | |
867 MainThreadOnly().last_audio_state_change.value() + | |
868 kThrottlingDelayAfterAudioIsPlayed; | |
869 | |
870 base::TimeDelta audio_will_expire_after = audio_will_expire - now; | |
871 | |
872 if (audio_will_expire_after > base::TimeDelta()) { | |
873 if (new_policy_duration.is_zero()) { | |
874 new_policy_duration = audio_will_expire_after; | |
875 } else { | |
876 new_policy_duration = | |
877 std::min(new_policy_duration, audio_will_expire_after); | |
878 } | |
879 } | |
880 } | |
881 | |
882 if (new_policy_duration > base::TimeDelta()) { | 839 if (new_policy_duration > base::TimeDelta()) { |
883 MainThreadOnly().current_policy_expiration_time = now + new_policy_duration; | 840 MainThreadOnly().current_policy_expiration_time = now + new_policy_duration; |
884 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, | 841 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, |
885 now); | 842 now); |
886 } else { | 843 } else { |
887 MainThreadOnly().current_policy_expiration_time = base::TimeTicks(); | 844 MainThreadOnly().current_policy_expiration_time = base::TimeTicks(); |
888 } | 845 } |
889 | 846 |
890 // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely | 847 // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely |
891 // slow, because that can cause starvation in other task sources. | 848 // slow, because that can cause starvation in other task sources. |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1027 } | 984 } |
1028 | 985 |
1029 if (MainThreadOnly().use_virtual_time) { | 986 if (MainThreadOnly().use_virtual_time) { |
1030 new_policy.compositor_queue_policy.time_domain_type = | 987 new_policy.compositor_queue_policy.time_domain_type = |
1031 TimeDomainType::VIRTUAL; | 988 TimeDomainType::VIRTUAL; |
1032 new_policy.default_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; | 989 new_policy.default_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; |
1033 new_policy.loading_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; | 990 new_policy.loading_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; |
1034 new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; | 991 new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; |
1035 } | 992 } |
1036 | 993 |
1037 new_policy.should_disable_throttling = | |
1038 ShouldDisableThrottlingBecauseOfAudio(now) || | |
1039 MainThreadOnly().use_virtual_time; | |
1040 | |
1041 // Tracing is done before the early out check, because it's quite possible we | 994 // Tracing is done before the early out check, because it's quite possible we |
1042 // will otherwise miss this information in traces. | 995 // will otherwise miss this information in traces. |
1043 CreateTraceEventObjectSnapshotLocked(); | 996 CreateTraceEventObjectSnapshotLocked(); |
1044 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case", | 997 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case", |
1045 use_case); | 998 use_case); |
1046 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode", | 999 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode", |
1047 new_policy.rail_mode); | 1000 new_policy.rail_mode); |
1048 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 1001 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
1049 "touchstart_expected_soon", | 1002 "touchstart_expected_soon", |
1050 MainThreadOnly().touchstart_expected_soon); | 1003 MainThreadOnly().touchstart_expected_soon); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1086 // are mostly dispatched on the default queue) need to be preserved. | 1039 // are mostly dispatched on the default queue) need to be preserved. |
1087 ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(), | 1040 ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(), |
1088 MainThreadOnly().current_policy.default_queue_policy, | 1041 MainThreadOnly().current_policy.default_queue_policy, |
1089 new_policy.default_queue_policy); | 1042 new_policy.default_queue_policy); |
1090 if (MainThreadOnly().rail_mode_observer && | 1043 if (MainThreadOnly().rail_mode_observer && |
1091 new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) { | 1044 new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) { |
1092 MainThreadOnly().rail_mode_observer->OnRAILModeChanged( | 1045 MainThreadOnly().rail_mode_observer->OnRAILModeChanged( |
1093 new_policy.rail_mode); | 1046 new_policy.rail_mode); |
1094 } | 1047 } |
1095 | 1048 |
1096 if (new_policy.should_disable_throttling != | |
1097 MainThreadOnly().current_policy.should_disable_throttling) { | |
1098 if (new_policy.should_disable_throttling) { | |
1099 task_queue_throttler()->DisableThrottling(); | |
1100 } else { | |
1101 task_queue_throttler()->EnableThrottling(); | |
1102 } | |
1103 } | |
1104 | |
1105 DCHECK(compositor_task_runner_->IsQueueEnabled()); | 1049 DCHECK(compositor_task_runner_->IsQueueEnabled()); |
1106 MainThreadOnly().current_policy = new_policy; | 1050 MainThreadOnly().current_policy = new_policy; |
1107 } | 1051 } |
1108 | 1052 |
1109 void RendererSchedulerImpl::ApplyTaskQueuePolicy( | 1053 void RendererSchedulerImpl::ApplyTaskQueuePolicy( |
1110 TaskQueue* task_queue, | 1054 TaskQueue* task_queue, |
1111 const TaskQueuePolicy& old_task_queue_policy, | 1055 const TaskQueuePolicy& old_task_queue_policy, |
1112 const TaskQueuePolicy& new_task_queue_policy) const { | 1056 const TaskQueuePolicy& new_task_queue_policy) const { |
1113 if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) { | 1057 if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) { |
1114 task_queue_throttler_->SetQueueEnabled(task_queue, | 1058 task_queue_throttler_->SetQueueEnabled(task_queue, |
(...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1624 } | 1568 } |
1625 | 1569 |
1626 void RendererSchedulerImpl::EnableVirtualTime() { | 1570 void RendererSchedulerImpl::EnableVirtualTime() { |
1627 MainThreadOnly().use_virtual_time = true; | 1571 MainThreadOnly().use_virtual_time = true; |
1628 | 1572 |
1629 // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy(). | 1573 // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy(). |
1630 AutoAdvancingVirtualTimeDomain* time_domain = GetVirtualTimeDomain(); | 1574 AutoAdvancingVirtualTimeDomain* time_domain = GetVirtualTimeDomain(); |
1631 for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_) | 1575 for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_) |
1632 task_queue->SetTimeDomain(time_domain); | 1576 task_queue->SetTimeDomain(time_domain); |
1633 | 1577 |
| 1578 task_queue_throttler_->EnableVirtualTime(); |
| 1579 |
1634 ForceUpdatePolicy(); | 1580 ForceUpdatePolicy(); |
1635 } | 1581 } |
1636 | 1582 |
1637 bool RendererSchedulerImpl::ShouldDisableThrottlingBecauseOfAudio( | |
1638 base::TimeTicks now) { | |
1639 if (!MainThreadOnly().last_audio_state_change) | |
1640 return false; | |
1641 | |
1642 if (MainThreadOnly().is_audio_playing) | |
1643 return true; | |
1644 | |
1645 return MainThreadOnly().last_audio_state_change.value() + | |
1646 kThrottlingDelayAfterAudioIsPlayed > | |
1647 now; | |
1648 } | |
1649 | |
1650 TimeDomain* RendererSchedulerImpl::GetActiveTimeDomain() { | |
1651 if (MainThreadOnly().use_virtual_time) { | |
1652 return GetVirtualTimeDomain(); | |
1653 } else { | |
1654 return real_time_domain(); | |
1655 } | |
1656 } | |
1657 | |
1658 // static | 1583 // static |
1659 const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) { | 1584 const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) { |
1660 switch (use_case) { | 1585 switch (use_case) { |
1661 case UseCase::NONE: | 1586 case UseCase::NONE: |
1662 return "none"; | 1587 return "none"; |
1663 case UseCase::COMPOSITOR_GESTURE: | 1588 case UseCase::COMPOSITOR_GESTURE: |
1664 return "compositor_gesture"; | 1589 return "compositor_gesture"; |
1665 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: | 1590 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: |
1666 return "main_thread_custom_input_handling"; | 1591 return "main_thread_custom_input_handling"; |
1667 case UseCase::SYNCHRONIZED_GESTURE: | 1592 case UseCase::SYNCHRONIZED_GESTURE: |
(...skipping 22 matching lines...) Expand all Loading... |
1690 case v8::PERFORMANCE_LOAD: | 1615 case v8::PERFORMANCE_LOAD: |
1691 return "load"; | 1616 return "load"; |
1692 default: | 1617 default: |
1693 NOTREACHED(); | 1618 NOTREACHED(); |
1694 return nullptr; | 1619 return nullptr; |
1695 } | 1620 } |
1696 } | 1621 } |
1697 | 1622 |
1698 } // namespace scheduler | 1623 } // namespace scheduler |
1699 } // namespace blink | 1624 } // namespace blink |
OLD | NEW |