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" |
15 #include "platform/scheduler/base/task_queue_impl.h" | 16 #include "platform/scheduler/base/task_queue_impl.h" |
16 #include "platform/scheduler/base/task_queue_selector.h" | 17 #include "platform/scheduler/base/task_queue_selector.h" |
17 #include "platform/scheduler/base/virtual_time_domain.h" | 18 #include "platform/scheduler/base/virtual_time_domain.h" |
18 #include "platform/scheduler/child/scheduler_tqm_delegate.h" | 19 #include "platform/scheduler/child/scheduler_tqm_delegate.h" |
19 #include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" | 20 #include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" |
20 #include "platform/scheduler/renderer/task_queue_throttler.h" | 21 #include "platform/scheduler/renderer/task_queue_throttler.h" |
21 #include "platform/scheduler/renderer/web_view_scheduler_impl.h" | 22 #include "platform/scheduler/renderer/web_view_scheduler_impl.h" |
22 #include "platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h" | 23 #include "platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h" |
23 | 24 |
24 namespace blink { | 25 namespace blink { |
25 namespace scheduler { | 26 namespace scheduler { |
26 namespace { | 27 namespace { |
27 // The run time of loading tasks is strongly bimodal. The vast majority are | 28 // The run time of loading tasks is strongly bimodal. The vast majority are |
28 // very cheap, but there are usually a handful of very expensive tasks (e.g ~1 | 29 // very cheap, but there are usually a handful of very expensive tasks (e.g ~1 |
29 // second on a mobile device) so we take a very pessimistic view when estimating | 30 // second on a mobile device) so we take a very pessimistic view when estimating |
30 // the cost of loading tasks. | 31 // the cost of loading tasks. |
31 const int kLoadingTaskEstimationSampleCount = 1000; | 32 const int kLoadingTaskEstimationSampleCount = 1000; |
32 const double kLoadingTaskEstimationPercentile = 99; | 33 const double kLoadingTaskEstimationPercentile = 99; |
33 const int kTimerTaskEstimationSampleCount = 1000; | 34 const int kTimerTaskEstimationSampleCount = 1000; |
34 const double kTimerTaskEstimationPercentile = 99; | 35 const double kTimerTaskEstimationPercentile = 99; |
35 const int kShortIdlePeriodDurationSampleCount = 10; | 36 const int kShortIdlePeriodDurationSampleCount = 10; |
36 const double kShortIdlePeriodDurationPercentile = 50; | 37 const double kShortIdlePeriodDurationPercentile = 50; |
37 // Amount of idle time left in a frame (as a ratio of the vsync interval) above | 38 // Amount of idle time left in a frame (as a ratio of the vsync interval) above |
38 // which main thread compositing can be considered fast. | 39 // which main thread compositing can be considered fast. |
39 const double kFastCompositingIdleTimeThreshold = .2; | 40 const double kFastCompositingIdleTimeThreshold = .2; |
40 constexpr base::TimeDelta kThreadLoadTrackerReportingInterval = | 41 constexpr base::TimeDelta kThreadLoadTrackerReportingInterval = |
41 base::TimeDelta::FromMinutes(1); | 42 base::TimeDelta::FromMinutes(1); |
42 constexpr base::TimeDelta kThreadLoadTrackerWaitingPeriodBeforeReporting = | 43 constexpr base::TimeDelta kThreadLoadTrackerWaitingPeriodBeforeReporting = |
43 base::TimeDelta::FromMinutes(2); | 44 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); |
44 | 48 |
45 void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) { | 49 void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) { |
46 int load_percentage = static_cast<int>(load * 100); | 50 int load_percentage = static_cast<int>(load * 100); |
47 UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.ForegroundRendererMainThreadLoad", | 51 UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.ForegroundRendererMainThreadLoad", |
48 load_percentage); | 52 load_percentage); |
49 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 53 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
50 "RendererScheduler.ForegroundRendererLoad", load_percentage); | 54 "RendererScheduler.ForegroundRendererLoad", load_percentage); |
51 } | 55 } |
52 | 56 |
53 void ReportBackgroundRendererTaskLoad(base::TimeTicks time, double load) { | 57 void ReportBackgroundRendererTaskLoad(base::TimeTicks time, double load) { |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 loading_tasks_seem_expensive(false), | 182 loading_tasks_seem_expensive(false), |
179 timer_tasks_seem_expensive(false), | 183 timer_tasks_seem_expensive(false), |
180 touchstart_expected_soon(false), | 184 touchstart_expected_soon(false), |
181 have_seen_a_begin_main_frame(false), | 185 have_seen_a_begin_main_frame(false), |
182 have_reported_blocking_intervention_in_current_policy(false), | 186 have_reported_blocking_intervention_in_current_policy(false), |
183 have_reported_blocking_intervention_since_navigation(false), | 187 have_reported_blocking_intervention_since_navigation(false), |
184 has_visible_render_widget_with_touch_handler(false), | 188 has_visible_render_widget_with_touch_handler(false), |
185 begin_frame_not_expected_soon(false), | 189 begin_frame_not_expected_soon(false), |
186 in_idle_period_for_testing(false), | 190 in_idle_period_for_testing(false), |
187 use_virtual_time(false), | 191 use_virtual_time(false), |
| 192 is_audio_playing(false), |
188 rail_mode_observer(nullptr) {} | 193 rail_mode_observer(nullptr) {} |
189 | 194 |
190 RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {} | 195 RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {} |
191 | 196 |
192 RendererSchedulerImpl::AnyThread::AnyThread() | 197 RendererSchedulerImpl::AnyThread::AnyThread() |
193 : awaiting_touch_start_response(false), | 198 : awaiting_touch_start_response(false), |
194 in_idle_period(false), | 199 in_idle_period(false), |
195 begin_main_frame_on_critical_path(false), | 200 begin_main_frame_on_critical_path(false), |
196 last_gesture_was_compositor_driven(false), | 201 last_gesture_was_compositor_driven(false), |
197 default_gesture_prevented(true), | 202 default_gesture_prevented(true), |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
477 MainThreadOnly().renderer_suspended = false; | 482 MainThreadOnly().renderer_suspended = false; |
478 | 483 |
479 base::TimeTicks now = tick_clock()->NowTicks(); | 484 base::TimeTicks now = tick_clock()->NowTicks(); |
480 MainThreadOnly().foreground_main_thread_load_tracker.Resume(now); | 485 MainThreadOnly().foreground_main_thread_load_tracker.Resume(now); |
481 MainThreadOnly().background_main_thread_load_tracker.Pause(now); | 486 MainThreadOnly().background_main_thread_load_tracker.Pause(now); |
482 | 487 |
483 suspend_timers_when_backgrounded_closure_.Cancel(); | 488 suspend_timers_when_backgrounded_closure_.Cancel(); |
484 ResumeTimerQueueWhenForegrounded(); | 489 ResumeTimerQueueWhenForegrounded(); |
485 } | 490 } |
486 | 491 |
| 492 void RendererSchedulerImpl::OnAudioStateChanged() { |
| 493 bool is_audio_playing = false; |
| 494 for (WebViewSchedulerImpl* web_view_scheduler : |
| 495 MainThreadOnly().web_view_schedulers) { |
| 496 is_audio_playing = is_audio_playing || web_view_scheduler->IsAudioPlaying(); |
| 497 } |
| 498 |
| 499 if (is_audio_playing == MainThreadOnly().is_audio_playing) |
| 500 return; |
| 501 |
| 502 MainThreadOnly().last_audio_state_change = |
| 503 helper_.scheduler_tqm_delegate()->NowTicks(); |
| 504 MainThreadOnly().is_audio_playing = is_audio_playing; |
| 505 |
| 506 UpdatePolicy(); |
| 507 } |
| 508 |
487 void RendererSchedulerImpl::SuspendRenderer() { | 509 void RendererSchedulerImpl::SuspendRenderer() { |
488 helper_.CheckOnValidThread(); | 510 helper_.CheckOnValidThread(); |
489 DCHECK(MainThreadOnly().renderer_backgrounded); | 511 DCHECK(MainThreadOnly().renderer_backgrounded); |
490 if (helper_.IsShutdown()) | 512 if (helper_.IsShutdown()) |
491 return; | 513 return; |
492 suspend_timers_when_backgrounded_closure_.Cancel(); | 514 suspend_timers_when_backgrounded_closure_.Cancel(); |
493 | 515 |
494 UMA_HISTOGRAM_COUNTS("PurgeAndSuspend.PendingTaskCount", | 516 UMA_HISTOGRAM_COUNTS("PurgeAndSuspend.PendingTaskCount", |
495 helper_.GetNumberOfPendingTasks()); | 517 helper_.GetNumberOfPendingTasks()); |
496 | 518 |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
811 // The |new_policy_duration| is the minimum of |expected_use_case_duration| | 833 // The |new_policy_duration| is the minimum of |expected_use_case_duration| |
812 // and |touchstart_expected_flag_valid_for_duration| unless one is zero in | 834 // and |touchstart_expected_flag_valid_for_duration| unless one is zero in |
813 // which case we choose the other. | 835 // which case we choose the other. |
814 base::TimeDelta new_policy_duration = expected_use_case_duration; | 836 base::TimeDelta new_policy_duration = expected_use_case_duration; |
815 if (new_policy_duration.is_zero() || | 837 if (new_policy_duration.is_zero() || |
816 (touchstart_expected_flag_valid_for_duration > base::TimeDelta() && | 838 (touchstart_expected_flag_valid_for_duration > base::TimeDelta() && |
817 new_policy_duration > touchstart_expected_flag_valid_for_duration)) { | 839 new_policy_duration > touchstart_expected_flag_valid_for_duration)) { |
818 new_policy_duration = touchstart_expected_flag_valid_for_duration; | 840 new_policy_duration = touchstart_expected_flag_valid_for_duration; |
819 } | 841 } |
820 | 842 |
| 843 // Do not throttle while audio is playing or for a short period after that |
| 844 // to make sure that pages playing short audio clips powered by timers |
| 845 // work. |
| 846 if (MainThreadOnly().last_audio_state_change && |
| 847 !MainThreadOnly().is_audio_playing) { |
| 848 base::TimeTicks audio_will_expire = |
| 849 MainThreadOnly().last_audio_state_change.value() + |
| 850 kThrottlingDelayAfterAudioIsPlayed; |
| 851 |
| 852 base::TimeDelta audio_will_expire_after = audio_will_expire - now; |
| 853 |
| 854 if (audio_will_expire_after > base::TimeDelta()) { |
| 855 if (new_policy_duration.is_zero()) { |
| 856 new_policy_duration = audio_will_expire_after; |
| 857 } else { |
| 858 new_policy_duration = |
| 859 std::min(new_policy_duration, audio_will_expire_after); |
| 860 } |
| 861 } |
| 862 } |
| 863 |
821 if (new_policy_duration > base::TimeDelta()) { | 864 if (new_policy_duration > base::TimeDelta()) { |
822 MainThreadOnly().current_policy_expiration_time = now + new_policy_duration; | 865 MainThreadOnly().current_policy_expiration_time = now + new_policy_duration; |
823 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, | 866 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, |
824 now); | 867 now); |
825 } else { | 868 } else { |
826 MainThreadOnly().current_policy_expiration_time = base::TimeTicks(); | 869 MainThreadOnly().current_policy_expiration_time = base::TimeTicks(); |
827 } | 870 } |
828 | 871 |
829 // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely | 872 // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely |
830 // slow, because that can cause starvation in other task sources. | 873 // slow, because that can cause starvation in other task sources. |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
966 } | 1009 } |
967 | 1010 |
968 if (MainThreadOnly().use_virtual_time) { | 1011 if (MainThreadOnly().use_virtual_time) { |
969 new_policy.compositor_queue_policy.time_domain_type = | 1012 new_policy.compositor_queue_policy.time_domain_type = |
970 TimeDomainType::VIRTUAL; | 1013 TimeDomainType::VIRTUAL; |
971 new_policy.default_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; | 1014 new_policy.default_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; |
972 new_policy.loading_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; | 1015 new_policy.loading_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; |
973 new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; | 1016 new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; |
974 } | 1017 } |
975 | 1018 |
| 1019 new_policy.should_disable_throttling = |
| 1020 ShouldDisableThrottlingBecauseOfAudio(now) || |
| 1021 MainThreadOnly().use_virtual_time; |
| 1022 |
976 // Tracing is done before the early out check, because it's quite possible we | 1023 // Tracing is done before the early out check, because it's quite possible we |
977 // will otherwise miss this information in traces. | 1024 // will otherwise miss this information in traces. |
978 CreateTraceEventObjectSnapshotLocked(); | 1025 CreateTraceEventObjectSnapshotLocked(); |
979 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case", | 1026 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case", |
980 use_case); | 1027 use_case); |
981 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode", | 1028 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode", |
982 new_policy.rail_mode); | 1029 new_policy.rail_mode); |
983 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 1030 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
984 "touchstart_expected_soon", | 1031 "touchstart_expected_soon", |
985 MainThreadOnly().touchstart_expected_soon); | 1032 MainThreadOnly().touchstart_expected_soon); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1021 // are mostly dispatched on the default queue) need to be preserved. | 1068 // are mostly dispatched on the default queue) need to be preserved. |
1022 ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(), | 1069 ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(), |
1023 MainThreadOnly().current_policy.default_queue_policy, | 1070 MainThreadOnly().current_policy.default_queue_policy, |
1024 new_policy.default_queue_policy); | 1071 new_policy.default_queue_policy); |
1025 if (MainThreadOnly().rail_mode_observer && | 1072 if (MainThreadOnly().rail_mode_observer && |
1026 new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) { | 1073 new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) { |
1027 MainThreadOnly().rail_mode_observer->OnRAILModeChanged( | 1074 MainThreadOnly().rail_mode_observer->OnRAILModeChanged( |
1028 new_policy.rail_mode); | 1075 new_policy.rail_mode); |
1029 } | 1076 } |
1030 | 1077 |
| 1078 if (new_policy.should_disable_throttling != |
| 1079 MainThreadOnly().current_policy.should_disable_throttling) { |
| 1080 if (new_policy.should_disable_throttling) { |
| 1081 task_queue_throttler()->DisableThrottling(); |
| 1082 } else { |
| 1083 task_queue_throttler()->EnableThrottling(); |
| 1084 } |
| 1085 } |
| 1086 |
1031 DCHECK(compositor_task_runner_->IsQueueEnabled()); | 1087 DCHECK(compositor_task_runner_->IsQueueEnabled()); |
1032 MainThreadOnly().current_policy = new_policy; | 1088 MainThreadOnly().current_policy = new_policy; |
1033 } | 1089 } |
1034 | 1090 |
1035 void RendererSchedulerImpl::ApplyTaskQueuePolicy( | 1091 void RendererSchedulerImpl::ApplyTaskQueuePolicy( |
1036 TaskQueue* task_queue, | 1092 TaskQueue* task_queue, |
1037 const TaskQueuePolicy& old_task_queue_policy, | 1093 const TaskQueuePolicy& old_task_queue_policy, |
1038 const TaskQueuePolicy& new_task_queue_policy) const { | 1094 const TaskQueuePolicy& new_task_queue_policy) const { |
1039 if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) { | 1095 if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) { |
1040 task_queue_throttler_->SetQueueEnabled(task_queue, | 1096 task_queue_throttler_->SetQueueEnabled(task_queue, |
(...skipping 502 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1543 } | 1599 } |
1544 | 1600 |
1545 void RendererSchedulerImpl::EnableVirtualTime() { | 1601 void RendererSchedulerImpl::EnableVirtualTime() { |
1546 MainThreadOnly().use_virtual_time = true; | 1602 MainThreadOnly().use_virtual_time = true; |
1547 | 1603 |
1548 // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy(). | 1604 // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy(). |
1549 AutoAdvancingVirtualTimeDomain* time_domain = GetVirtualTimeDomain(); | 1605 AutoAdvancingVirtualTimeDomain* time_domain = GetVirtualTimeDomain(); |
1550 for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_) | 1606 for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_) |
1551 task_queue->SetTimeDomain(time_domain); | 1607 task_queue->SetTimeDomain(time_domain); |
1552 | 1608 |
1553 task_queue_throttler_->EnableVirtualTime(); | 1609 ForceUpdatePolicy(); |
| 1610 } |
1554 | 1611 |
1555 ForceUpdatePolicy(); | 1612 bool RendererSchedulerImpl::ShouldDisableThrottlingBecauseOfAudio( |
| 1613 base::TimeTicks now) { |
| 1614 if (!MainThreadOnly().last_audio_state_change) |
| 1615 return false; |
| 1616 |
| 1617 if (MainThreadOnly().is_audio_playing) |
| 1618 return true; |
| 1619 |
| 1620 return MainThreadOnly().last_audio_state_change.value() + |
| 1621 kThrottlingDelayAfterAudioIsPlayed > |
| 1622 now; |
| 1623 } |
| 1624 |
| 1625 TimeDomain* RendererSchedulerImpl::GetActiveTimeDomain() { |
| 1626 if (MainThreadOnly().use_virtual_time) { |
| 1627 return GetVirtualTimeDomain(); |
| 1628 } else { |
| 1629 return real_time_domain(); |
| 1630 } |
1556 } | 1631 } |
1557 | 1632 |
1558 // static | 1633 // static |
1559 const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) { | 1634 const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) { |
1560 switch (use_case) { | 1635 switch (use_case) { |
1561 case UseCase::NONE: | 1636 case UseCase::NONE: |
1562 return "none"; | 1637 return "none"; |
1563 case UseCase::COMPOSITOR_GESTURE: | 1638 case UseCase::COMPOSITOR_GESTURE: |
1564 return "compositor_gesture"; | 1639 return "compositor_gesture"; |
1565 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: | 1640 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: |
(...skipping 24 matching lines...) Expand all Loading... |
1590 case v8::PERFORMANCE_LOAD: | 1665 case v8::PERFORMANCE_LOAD: |
1591 return "load"; | 1666 return "load"; |
1592 default: | 1667 default: |
1593 NOTREACHED(); | 1668 NOTREACHED(); |
1594 return nullptr; | 1669 return nullptr; |
1595 } | 1670 } |
1596 } | 1671 } |
1597 | 1672 |
1598 } // namespace scheduler | 1673 } // namespace scheduler |
1599 } // namespace blink | 1674 } // namespace blink |
OLD | NEW |