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; |
41 // We do not throttle anything while audio is played and shortly after that. | |
42 const int kThrottlingDelayAfterAudioIsPlayedInSeconds = 5; | |
40 | 43 |
41 void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) { | 44 void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) { |
42 int load_percentage = static_cast<int>(load * 100); | 45 int load_percentage = static_cast<int>(load * 100); |
43 UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.ForegroundRendererMainThreadLoad", | 46 UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.ForegroundRendererMainThreadLoad", |
44 load_percentage); | 47 load_percentage); |
45 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 48 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
46 "RendererScheduler.ForegroundRendererLoad", load_percentage); | 49 "RendererScheduler.ForegroundRendererLoad", load_percentage); |
47 } | 50 } |
48 | 51 |
49 void ReportBackgroundRendererTaskLoad(base::TimeTicks time, double load) { | 52 void ReportBackgroundRendererTaskLoad(base::TimeTicks time, double load) { |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
151 time_source, | 154 time_source, |
152 kShortIdlePeriodDurationSampleCount, | 155 kShortIdlePeriodDurationSampleCount, |
153 kShortIdlePeriodDurationPercentile), | 156 kShortIdlePeriodDurationPercentile), |
154 background_main_thread_load_tracker( | 157 background_main_thread_load_tracker( |
155 now, | 158 now, |
156 base::Bind(&ReportBackgroundRendererTaskLoad)), | 159 base::Bind(&ReportBackgroundRendererTaskLoad)), |
157 foreground_main_thread_load_tracker( | 160 foreground_main_thread_load_tracker( |
158 now, | 161 now, |
159 base::Bind(&ReportForegroundRendererTaskLoad)), | 162 base::Bind(&ReportForegroundRendererTaskLoad)), |
160 current_use_case(UseCase::NONE), | 163 current_use_case(UseCase::NONE), |
164 throttling_delay_after_audio_is_played(base::TimeDelta::FromSeconds( | |
165 kThrottlingDelayAfterAudioIsPlayedInSeconds)), | |
161 timer_queue_suspend_count(0), | 166 timer_queue_suspend_count(0), |
162 navigation_task_expected_count(0), | 167 navigation_task_expected_count(0), |
163 expensive_task_policy(ExpensiveTaskPolicy::RUN), | 168 expensive_task_policy(ExpensiveTaskPolicy::RUN), |
164 renderer_hidden(false), | 169 renderer_hidden(false), |
165 renderer_backgrounded(false), | 170 renderer_backgrounded(false), |
166 renderer_suspended(false), | 171 renderer_suspended(false), |
167 timer_queue_suspension_when_backgrounded_enabled(false), | 172 timer_queue_suspension_when_backgrounded_enabled(false), |
168 timer_queue_suspended_when_backgrounded(false), | 173 timer_queue_suspended_when_backgrounded(false), |
169 was_shutdown(false), | 174 was_shutdown(false), |
170 loading_tasks_seem_expensive(false), | 175 loading_tasks_seem_expensive(false), |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
469 MainThreadOnly().renderer_suspended = false; | 474 MainThreadOnly().renderer_suspended = false; |
470 | 475 |
471 base::TimeTicks now = tick_clock()->NowTicks(); | 476 base::TimeTicks now = tick_clock()->NowTicks(); |
472 MainThreadOnly().foreground_main_thread_load_tracker.Resume(now); | 477 MainThreadOnly().foreground_main_thread_load_tracker.Resume(now); |
473 MainThreadOnly().background_main_thread_load_tracker.Pause(now); | 478 MainThreadOnly().background_main_thread_load_tracker.Pause(now); |
474 | 479 |
475 suspend_timers_when_backgrounded_closure_.Cancel(); | 480 suspend_timers_when_backgrounded_closure_.Cancel(); |
476 ResumeTimerQueueWhenForegrounded(); | 481 ResumeTimerQueueWhenForegrounded(); |
477 } | 482 } |
478 | 483 |
484 void RendererSchedulerImpl::OnAudioStateChanged(bool is_audio_playing) { | |
485 MainThreadOnly().last_audio_state_change = | |
486 helper_.scheduler_tqm_delegate()->NowTicks(); | |
487 MainThreadOnly().is_audio_playing = is_audio_playing; | |
488 | |
489 UpdatePolicy(); | |
490 } | |
491 | |
479 void RendererSchedulerImpl::SuspendRenderer() { | 492 void RendererSchedulerImpl::SuspendRenderer() { |
480 helper_.CheckOnValidThread(); | 493 helper_.CheckOnValidThread(); |
481 DCHECK(MainThreadOnly().renderer_backgrounded); | 494 DCHECK(MainThreadOnly().renderer_backgrounded); |
482 if (helper_.IsShutdown()) | 495 if (helper_.IsShutdown()) |
483 return; | 496 return; |
484 suspend_timers_when_backgrounded_closure_.Cancel(); | 497 suspend_timers_when_backgrounded_closure_.Cancel(); |
485 // TODO(hajimehoshi): We might need to suspend not only timer queue but also | 498 // TODO(hajimehoshi): We might need to suspend not only timer queue but also |
486 // e.g. loading tasks or postMessage. | 499 // e.g. loading tasks or postMessage. |
487 MainThreadOnly().renderer_suspended = true; | 500 MainThreadOnly().renderer_suspended = true; |
488 SuspendTimerQueueWhenBackgrounded(); | 501 SuspendTimerQueueWhenBackgrounded(); |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
799 // The |new_policy_duration| is the minimum of |expected_use_case_duration| | 812 // The |new_policy_duration| is the minimum of |expected_use_case_duration| |
800 // and |touchstart_expected_flag_valid_for_duration| unless one is zero in | 813 // and |touchstart_expected_flag_valid_for_duration| unless one is zero in |
801 // which case we choose the other. | 814 // which case we choose the other. |
802 base::TimeDelta new_policy_duration = expected_use_case_duration; | 815 base::TimeDelta new_policy_duration = expected_use_case_duration; |
803 if (new_policy_duration.is_zero() || | 816 if (new_policy_duration.is_zero() || |
804 (touchstart_expected_flag_valid_for_duration > base::TimeDelta() && | 817 (touchstart_expected_flag_valid_for_duration > base::TimeDelta() && |
805 new_policy_duration > touchstart_expected_flag_valid_for_duration)) { | 818 new_policy_duration > touchstart_expected_flag_valid_for_duration)) { |
806 new_policy_duration = touchstart_expected_flag_valid_for_duration; | 819 new_policy_duration = touchstart_expected_flag_valid_for_duration; |
807 } | 820 } |
808 | 821 |
822 if (MainThreadOnly().last_audio_state_change && | |
alex clarke (OOO till 29th)
2016/09/30 10:33:46
Please add a brief comment outlining why we do thi
altimin
2016/10/03 11:15:25
Done.
| |
823 !MainThreadOnly().is_audio_playing) { | |
824 base::TimeTicks audio_will_expire = | |
825 MainThreadOnly().last_audio_state_change.value() + | |
826 MainThreadOnly().throttling_delay_after_audio_is_played; | |
827 | |
828 base::TimeDelta audio_will_expire_after = audio_will_expire - now; | |
829 | |
830 if (audio_will_expire_after > base::TimeDelta()) { | |
831 if (new_policy_duration.is_zero()) { | |
832 new_policy_duration = audio_will_expire_after; | |
833 } else { | |
834 new_policy_duration = | |
835 std::min(new_policy_duration, audio_will_expire_after); | |
836 } | |
837 } | |
838 } | |
839 | |
809 if (new_policy_duration > base::TimeDelta()) { | 840 if (new_policy_duration > base::TimeDelta()) { |
810 MainThreadOnly().current_policy_expiration_time = now + new_policy_duration; | 841 MainThreadOnly().current_policy_expiration_time = now + new_policy_duration; |
811 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, | 842 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, |
812 now); | 843 now); |
813 } else { | 844 } else { |
814 MainThreadOnly().current_policy_expiration_time = base::TimeTicks(); | 845 MainThreadOnly().current_policy_expiration_time = base::TimeTicks(); |
815 } | 846 } |
816 | 847 |
817 // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely | 848 // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely |
818 // slow, because that can cause starvation in other task sources. | 849 // slow, because that can cause starvation in other task sources. |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
954 } | 985 } |
955 | 986 |
956 if (MainThreadOnly().use_virtual_time) { | 987 if (MainThreadOnly().use_virtual_time) { |
957 new_policy.compositor_queue_policy.time_domain_type = | 988 new_policy.compositor_queue_policy.time_domain_type = |
958 TimeDomainType::VIRTUAL; | 989 TimeDomainType::VIRTUAL; |
959 new_policy.default_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; | 990 new_policy.default_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; |
960 new_policy.loading_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; | 991 new_policy.loading_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; |
961 new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; | 992 new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; |
962 } | 993 } |
963 | 994 |
995 new_policy.should_disable_throttling = | |
996 ShouldDisableThrottlingBecauseOfAudio(now) || | |
Sami
2016/09/30 11:52:09
By the way, this means that we might get more scro
altimin
2016/10/03 11:15:25
How are throttling and scroll jank related? Are yo
Sami
2016/10/03 14:36:31
Not just visibility-based throttling. Previously w
| |
997 MainThreadOnly().use_virtual_time; | |
998 | |
964 // Tracing is done before the early out check, because it's quite possible we | 999 // Tracing is done before the early out check, because it's quite possible we |
965 // will otherwise miss this information in traces. | 1000 // will otherwise miss this information in traces. |
966 CreateTraceEventObjectSnapshotLocked(); | 1001 CreateTraceEventObjectSnapshotLocked(); |
967 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case", | 1002 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case", |
968 use_case); | 1003 use_case); |
969 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode", | 1004 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode", |
970 new_policy.rail_mode); | 1005 new_policy.rail_mode); |
971 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 1006 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
972 "touchstart_expected_soon", | 1007 "touchstart_expected_soon", |
973 MainThreadOnly().touchstart_expected_soon); | 1008 MainThreadOnly().touchstart_expected_soon); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1009 // are mostly dispatched on the default queue) need to be preserved. | 1044 // are mostly dispatched on the default queue) need to be preserved. |
1010 ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(), | 1045 ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(), |
1011 MainThreadOnly().current_policy.default_queue_policy, | 1046 MainThreadOnly().current_policy.default_queue_policy, |
1012 new_policy.default_queue_policy); | 1047 new_policy.default_queue_policy); |
1013 if (MainThreadOnly().rail_mode_observer && | 1048 if (MainThreadOnly().rail_mode_observer && |
1014 new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) { | 1049 new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) { |
1015 MainThreadOnly().rail_mode_observer->OnRAILModeChanged( | 1050 MainThreadOnly().rail_mode_observer->OnRAILModeChanged( |
1016 new_policy.rail_mode); | 1051 new_policy.rail_mode); |
1017 } | 1052 } |
1018 | 1053 |
1054 if (new_policy.should_disable_throttling != | |
1055 MainThreadOnly().current_policy.should_disable_throttling) { | |
1056 if (new_policy.should_disable_throttling) { | |
1057 task_queue_throttler()->DisableThrottling(); | |
1058 } else { | |
1059 task_queue_throttler()->EnableThrottling(); | |
1060 } | |
1061 } | |
1062 | |
1019 DCHECK(compositor_task_runner_->IsQueueEnabled()); | 1063 DCHECK(compositor_task_runner_->IsQueueEnabled()); |
1020 MainThreadOnly().current_policy = new_policy; | 1064 MainThreadOnly().current_policy = new_policy; |
1021 } | 1065 } |
1022 | 1066 |
1023 void RendererSchedulerImpl::ApplyTaskQueuePolicy( | 1067 void RendererSchedulerImpl::ApplyTaskQueuePolicy( |
1024 TaskQueue* task_queue, | 1068 TaskQueue* task_queue, |
1025 const TaskQueuePolicy& old_task_queue_policy, | 1069 const TaskQueuePolicy& old_task_queue_policy, |
1026 const TaskQueuePolicy& new_task_queue_policy) const { | 1070 const TaskQueuePolicy& new_task_queue_policy) const { |
1027 if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) { | 1071 if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) { |
1028 task_queue_throttler_->SetQueueEnabled(task_queue, | 1072 task_queue_throttler_->SetQueueEnabled(task_queue, |
(...skipping 502 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1531 } | 1575 } |
1532 | 1576 |
1533 void RendererSchedulerImpl::EnableVirtualTime() { | 1577 void RendererSchedulerImpl::EnableVirtualTime() { |
1534 MainThreadOnly().use_virtual_time = true; | 1578 MainThreadOnly().use_virtual_time = true; |
1535 | 1579 |
1536 // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy(). | 1580 // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy(). |
1537 AutoAdvancingVirtualTimeDomain* time_domain = GetVirtualTimeDomain(); | 1581 AutoAdvancingVirtualTimeDomain* time_domain = GetVirtualTimeDomain(); |
1538 for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_) | 1582 for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_) |
1539 task_queue->SetTimeDomain(time_domain); | 1583 task_queue->SetTimeDomain(time_domain); |
1540 | 1584 |
1541 task_queue_throttler_->EnableVirtualTime(); | 1585 ForceUpdatePolicy(); |
1586 } | |
1542 | 1587 |
1543 ForceUpdatePolicy(); | 1588 bool RendererSchedulerImpl::ShouldDisableThrottlingBecauseOfAudio( |
1589 base::TimeTicks now) { | |
1590 if (!MainThreadOnly().last_audio_state_change) | |
1591 return false; | |
1592 | |
1593 if (MainThreadOnly().is_audio_playing) | |
1594 return true; | |
1595 | |
1596 return MainThreadOnly().last_audio_state_change.value() + | |
1597 MainThreadOnly().throttling_delay_after_audio_is_played > | |
1598 now; | |
1599 } | |
1600 | |
1601 TimeDomain* RendererSchedulerImpl::GetActiveTimeDomain() { | |
1602 if (MainThreadOnly().use_virtual_time) { | |
1603 return GetVirtualTimeDomain(); | |
1604 } else { | |
1605 return real_time_domain(); | |
1606 } | |
1544 } | 1607 } |
1545 | 1608 |
1546 // static | 1609 // static |
1547 const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) { | 1610 const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) { |
1548 switch (use_case) { | 1611 switch (use_case) { |
1549 case UseCase::NONE: | 1612 case UseCase::NONE: |
1550 return "none"; | 1613 return "none"; |
1551 case UseCase::COMPOSITOR_GESTURE: | 1614 case UseCase::COMPOSITOR_GESTURE: |
1552 return "compositor_gesture"; | 1615 return "compositor_gesture"; |
1553 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: | 1616 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: |
(...skipping 24 matching lines...) Expand all Loading... | |
1578 case v8::PERFORMANCE_LOAD: | 1641 case v8::PERFORMANCE_LOAD: |
1579 return "load"; | 1642 return "load"; |
1580 default: | 1643 default: |
1581 NOTREACHED(); | 1644 NOTREACHED(); |
1582 return nullptr; | 1645 return nullptr; |
1583 } | 1646 } |
1584 } | 1647 } |
1585 | 1648 |
1586 } // namespace scheduler | 1649 } // namespace scheduler |
1587 } // namespace blink | 1650 } // namespace blink |
OLD | NEW |