| 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() { |
| 485 bool is_audio_playing = false; |
| 486 for (WebViewSchedulerImpl* web_view_scheduler : |
| 487 MainThreadOnly().web_view_schedulers) { |
| 488 is_audio_playing = is_audio_playing || web_view_scheduler->IsAudioPlaying(); |
| 489 } |
| 490 |
| 491 if (is_audio_playing == MainThreadOnly().is_audio_playing) |
| 492 return; |
| 493 |
| 494 MainThreadOnly().last_audio_state_change = |
| 495 helper_.scheduler_tqm_delegate()->NowTicks(); |
| 496 MainThreadOnly().is_audio_playing = is_audio_playing; |
| 497 |
| 498 UpdatePolicy(); |
| 499 } |
| 500 |
| 479 void RendererSchedulerImpl::SuspendRenderer() { | 501 void RendererSchedulerImpl::SuspendRenderer() { |
| 480 helper_.CheckOnValidThread(); | 502 helper_.CheckOnValidThread(); |
| 481 DCHECK(MainThreadOnly().renderer_backgrounded); | 503 DCHECK(MainThreadOnly().renderer_backgrounded); |
| 482 if (helper_.IsShutdown()) | 504 if (helper_.IsShutdown()) |
| 483 return; | 505 return; |
| 484 suspend_timers_when_backgrounded_closure_.Cancel(); | 506 suspend_timers_when_backgrounded_closure_.Cancel(); |
| 485 // TODO(hajimehoshi): We might need to suspend not only timer queue but also | 507 // TODO(hajimehoshi): We might need to suspend not only timer queue but also |
| 486 // e.g. loading tasks or postMessage. | 508 // e.g. loading tasks or postMessage. |
| 487 MainThreadOnly().renderer_suspended = true; | 509 MainThreadOnly().renderer_suspended = true; |
| 488 SuspendTimerQueueWhenBackgrounded(); | 510 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| | 821 // 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 | 822 // and |touchstart_expected_flag_valid_for_duration| unless one is zero in |
| 801 // which case we choose the other. | 823 // which case we choose the other. |
| 802 base::TimeDelta new_policy_duration = expected_use_case_duration; | 824 base::TimeDelta new_policy_duration = expected_use_case_duration; |
| 803 if (new_policy_duration.is_zero() || | 825 if (new_policy_duration.is_zero() || |
| 804 (touchstart_expected_flag_valid_for_duration > base::TimeDelta() && | 826 (touchstart_expected_flag_valid_for_duration > base::TimeDelta() && |
| 805 new_policy_duration > touchstart_expected_flag_valid_for_duration)) { | 827 new_policy_duration > touchstart_expected_flag_valid_for_duration)) { |
| 806 new_policy_duration = touchstart_expected_flag_valid_for_duration; | 828 new_policy_duration = touchstart_expected_flag_valid_for_duration; |
| 807 } | 829 } |
| 808 | 830 |
| 831 // Do not throttle while audio is playing or for a short period after that |
| 832 // to make sure that pages playing short audio clips powered by timers |
| 833 // work. |
| 834 if (MainThreadOnly().last_audio_state_change && |
| 835 !MainThreadOnly().is_audio_playing) { |
| 836 base::TimeTicks audio_will_expire = |
| 837 MainThreadOnly().last_audio_state_change.value() + |
| 838 MainThreadOnly().throttling_delay_after_audio_is_played; |
| 839 |
| 840 base::TimeDelta audio_will_expire_after = audio_will_expire - now; |
| 841 |
| 842 if (audio_will_expire_after > base::TimeDelta()) { |
| 843 if (new_policy_duration.is_zero()) { |
| 844 new_policy_duration = audio_will_expire_after; |
| 845 } else { |
| 846 new_policy_duration = |
| 847 std::min(new_policy_duration, audio_will_expire_after); |
| 848 } |
| 849 } |
| 850 } |
| 851 |
| 809 if (new_policy_duration > base::TimeDelta()) { | 852 if (new_policy_duration > base::TimeDelta()) { |
| 810 MainThreadOnly().current_policy_expiration_time = now + new_policy_duration; | 853 MainThreadOnly().current_policy_expiration_time = now + new_policy_duration; |
| 811 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, | 854 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, |
| 812 now); | 855 now); |
| 813 } else { | 856 } else { |
| 814 MainThreadOnly().current_policy_expiration_time = base::TimeTicks(); | 857 MainThreadOnly().current_policy_expiration_time = base::TimeTicks(); |
| 815 } | 858 } |
| 816 | 859 |
| 817 // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely | 860 // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely |
| 818 // slow, because that can cause starvation in other task sources. | 861 // slow, because that can cause starvation in other task sources. |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 954 } | 997 } |
| 955 | 998 |
| 956 if (MainThreadOnly().use_virtual_time) { | 999 if (MainThreadOnly().use_virtual_time) { |
| 957 new_policy.compositor_queue_policy.time_domain_type = | 1000 new_policy.compositor_queue_policy.time_domain_type = |
| 958 TimeDomainType::VIRTUAL; | 1001 TimeDomainType::VIRTUAL; |
| 959 new_policy.default_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; | 1002 new_policy.default_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; |
| 960 new_policy.loading_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; | 1003 new_policy.loading_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; |
| 961 new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; | 1004 new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; |
| 962 } | 1005 } |
| 963 | 1006 |
| 1007 new_policy.should_disable_throttling = |
| 1008 ShouldDisableThrottlingBecauseOfAudio(now) || |
| 1009 MainThreadOnly().use_virtual_time; |
| 1010 |
| 964 // Tracing is done before the early out check, because it's quite possible we | 1011 // Tracing is done before the early out check, because it's quite possible we |
| 965 // will otherwise miss this information in traces. | 1012 // will otherwise miss this information in traces. |
| 966 CreateTraceEventObjectSnapshotLocked(); | 1013 CreateTraceEventObjectSnapshotLocked(); |
| 967 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case", | 1014 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case", |
| 968 use_case); | 1015 use_case); |
| 969 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode", | 1016 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode", |
| 970 new_policy.rail_mode); | 1017 new_policy.rail_mode); |
| 971 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 1018 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
| 972 "touchstart_expected_soon", | 1019 "touchstart_expected_soon", |
| 973 MainThreadOnly().touchstart_expected_soon); | 1020 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. | 1056 // are mostly dispatched on the default queue) need to be preserved. |
| 1010 ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(), | 1057 ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(), |
| 1011 MainThreadOnly().current_policy.default_queue_policy, | 1058 MainThreadOnly().current_policy.default_queue_policy, |
| 1012 new_policy.default_queue_policy); | 1059 new_policy.default_queue_policy); |
| 1013 if (MainThreadOnly().rail_mode_observer && | 1060 if (MainThreadOnly().rail_mode_observer && |
| 1014 new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) { | 1061 new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) { |
| 1015 MainThreadOnly().rail_mode_observer->OnRAILModeChanged( | 1062 MainThreadOnly().rail_mode_observer->OnRAILModeChanged( |
| 1016 new_policy.rail_mode); | 1063 new_policy.rail_mode); |
| 1017 } | 1064 } |
| 1018 | 1065 |
| 1066 if (new_policy.should_disable_throttling != |
| 1067 MainThreadOnly().current_policy.should_disable_throttling) { |
| 1068 if (new_policy.should_disable_throttling) { |
| 1069 task_queue_throttler()->DisableThrottling(); |
| 1070 } else { |
| 1071 task_queue_throttler()->EnableThrottling(); |
| 1072 } |
| 1073 } |
| 1074 |
| 1019 DCHECK(compositor_task_runner_->IsQueueEnabled()); | 1075 DCHECK(compositor_task_runner_->IsQueueEnabled()); |
| 1020 MainThreadOnly().current_policy = new_policy; | 1076 MainThreadOnly().current_policy = new_policy; |
| 1021 } | 1077 } |
| 1022 | 1078 |
| 1023 void RendererSchedulerImpl::ApplyTaskQueuePolicy( | 1079 void RendererSchedulerImpl::ApplyTaskQueuePolicy( |
| 1024 TaskQueue* task_queue, | 1080 TaskQueue* task_queue, |
| 1025 const TaskQueuePolicy& old_task_queue_policy, | 1081 const TaskQueuePolicy& old_task_queue_policy, |
| 1026 const TaskQueuePolicy& new_task_queue_policy) const { | 1082 const TaskQueuePolicy& new_task_queue_policy) const { |
| 1027 if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) { | 1083 if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) { |
| 1028 task_queue_throttler_->SetQueueEnabled(task_queue, | 1084 task_queue_throttler_->SetQueueEnabled(task_queue, |
| (...skipping 502 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1531 } | 1587 } |
| 1532 | 1588 |
| 1533 void RendererSchedulerImpl::EnableVirtualTime() { | 1589 void RendererSchedulerImpl::EnableVirtualTime() { |
| 1534 MainThreadOnly().use_virtual_time = true; | 1590 MainThreadOnly().use_virtual_time = true; |
| 1535 | 1591 |
| 1536 // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy(). | 1592 // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy(). |
| 1537 AutoAdvancingVirtualTimeDomain* time_domain = GetVirtualTimeDomain(); | 1593 AutoAdvancingVirtualTimeDomain* time_domain = GetVirtualTimeDomain(); |
| 1538 for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_) | 1594 for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_) |
| 1539 task_queue->SetTimeDomain(time_domain); | 1595 task_queue->SetTimeDomain(time_domain); |
| 1540 | 1596 |
| 1541 task_queue_throttler_->EnableVirtualTime(); | 1597 ForceUpdatePolicy(); |
| 1598 } |
| 1542 | 1599 |
| 1543 ForceUpdatePolicy(); | 1600 bool RendererSchedulerImpl::ShouldDisableThrottlingBecauseOfAudio( |
| 1601 base::TimeTicks now) { |
| 1602 if (!MainThreadOnly().last_audio_state_change) |
| 1603 return false; |
| 1604 |
| 1605 if (MainThreadOnly().is_audio_playing) |
| 1606 return true; |
| 1607 |
| 1608 return MainThreadOnly().last_audio_state_change.value() + |
| 1609 MainThreadOnly().throttling_delay_after_audio_is_played > |
| 1610 now; |
| 1611 } |
| 1612 |
| 1613 TimeDomain* RendererSchedulerImpl::GetActiveTimeDomain() { |
| 1614 if (MainThreadOnly().use_virtual_time) { |
| 1615 return GetVirtualTimeDomain(); |
| 1616 } else { |
| 1617 return real_time_domain(); |
| 1618 } |
| 1544 } | 1619 } |
| 1545 | 1620 |
| 1546 // static | 1621 // static |
| 1547 const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) { | 1622 const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) { |
| 1548 switch (use_case) { | 1623 switch (use_case) { |
| 1549 case UseCase::NONE: | 1624 case UseCase::NONE: |
| 1550 return "none"; | 1625 return "none"; |
| 1551 case UseCase::COMPOSITOR_GESTURE: | 1626 case UseCase::COMPOSITOR_GESTURE: |
| 1552 return "compositor_gesture"; | 1627 return "compositor_gesture"; |
| 1553 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: | 1628 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1578 case v8::PERFORMANCE_LOAD: | 1653 case v8::PERFORMANCE_LOAD: |
| 1579 return "load"; | 1654 return "load"; |
| 1580 default: | 1655 default: |
| 1581 NOTREACHED(); | 1656 NOTREACHED(); |
| 1582 return nullptr; | 1657 return nullptr; |
| 1583 } | 1658 } |
| 1584 } | 1659 } |
| 1585 | 1660 |
| 1586 } // namespace scheduler | 1661 } // namespace scheduler |
| 1587 } // namespace blink | 1662 } // namespace blink |
| OLD | NEW |