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" |
(...skipping 29 matching lines...) Expand all Loading... |
40 // Amount of idle time left in a frame (as a ratio of the vsync interval) above | 40 // Amount of idle time left in a frame (as a ratio of the vsync interval) above |
41 // which main thread compositing can be considered fast. | 41 // which main thread compositing can be considered fast. |
42 const double kFastCompositingIdleTimeThreshold = .2; | 42 const double kFastCompositingIdleTimeThreshold = .2; |
43 constexpr base::TimeDelta kThreadLoadTrackerReportingInterval = | 43 constexpr base::TimeDelta kThreadLoadTrackerReportingInterval = |
44 base::TimeDelta::FromMinutes(1); | 44 base::TimeDelta::FromMinutes(1); |
45 constexpr base::TimeDelta kThreadLoadTrackerWaitingPeriodBeforeReporting = | 45 constexpr base::TimeDelta kThreadLoadTrackerWaitingPeriodBeforeReporting = |
46 base::TimeDelta::FromMinutes(2); | 46 base::TimeDelta::FromMinutes(2); |
47 // We do not throttle anything while audio is played and shortly after that. | 47 // We do not throttle anything while audio is played and shortly after that. |
48 constexpr base::TimeDelta kThrottlingDelayAfterAudioIsPlayed = | 48 constexpr base::TimeDelta kThrottlingDelayAfterAudioIsPlayed = |
49 base::TimeDelta::FromSeconds(5); | 49 base::TimeDelta::FromSeconds(5); |
| 50 // Maximum task queueing time before the main thread is considered unresponsive. |
| 51 constexpr base::TimeDelta kMainThreadResponsivenessThreshold = |
| 52 base::TimeDelta::FromMilliseconds(200); |
50 | 53 |
51 void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) { | 54 void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) { |
52 int load_percentage = static_cast<int>(load * 100); | 55 int load_percentage = static_cast<int>(load * 100); |
53 UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.ForegroundRendererMainThreadLoad", | 56 UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.ForegroundRendererMainThreadLoad", |
54 load_percentage); | 57 load_percentage); |
55 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 58 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
56 "RendererScheduler.ForegroundRendererLoad", load_percentage); | 59 "RendererScheduler.ForegroundRendererLoad", load_percentage); |
57 } | 60 } |
58 | 61 |
59 void ReportBackgroundRendererTaskLoad(base::TimeTicks time, double load) { | 62 void ReportBackgroundRendererTaskLoad(base::TimeTicks time, double load) { |
60 int load_percentage = static_cast<int>(load * 100); | 63 int load_percentage = static_cast<int>(load * 100); |
61 UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.BackgroundRendererMainThreadLoad", | 64 UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.BackgroundRendererMainThreadLoad", |
62 load_percentage); | 65 load_percentage); |
63 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), | 66 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), |
64 "RendererScheduler.BackgroundRendererLoad", load_percentage); | 67 "RendererScheduler.BackgroundRendererLoad", load_percentage); |
65 } | 68 } |
66 | 69 |
67 base::TimeTicks MonotonicTimeInSecondsToTimeTicks( | 70 base::TimeTicks MonotonicTimeInSecondsToTimeTicks( |
68 double monotonicTimeInSeconds) { | 71 double monotonicTimeInSeconds) { |
69 return base::TimeTicks() + base::TimeDelta::FromSecondsD( | 72 return base::TimeTicks() + |
70 monotonicTimeInSeconds); | 73 base::TimeDelta::FromSecondsD(monotonicTimeInSeconds); |
71 } | 74 } |
72 | 75 |
73 std::string PointerToId(void* pointer) { | 76 std::string PointerToId(void* pointer) { |
74 return base::StringPrintf( | 77 return base::StringPrintf( |
75 "0x%" PRIx64, | 78 "0x%" PRIx64, |
76 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pointer))); | 79 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pointer))); |
77 } | 80 } |
78 | 81 |
79 } // namespace | 82 } // namespace |
80 | 83 |
(...skipping 13 matching lines...) Expand all Loading... |
94 control_task_runner_(helper_.ControlTaskRunner()), | 97 control_task_runner_(helper_.ControlTaskRunner()), |
95 compositor_task_runner_( | 98 compositor_task_runner_( |
96 helper_.NewTaskQueue(TaskQueue::Spec(TaskQueue::QueueType::COMPOSITOR) | 99 helper_.NewTaskQueue(TaskQueue::Spec(TaskQueue::QueueType::COMPOSITOR) |
97 .SetShouldMonitorQuiescence(true))), | 100 .SetShouldMonitorQuiescence(true))), |
98 compositor_task_runner_enabled_voter_( | 101 compositor_task_runner_enabled_voter_( |
99 compositor_task_runner_->CreateQueueEnabledVoter()), | 102 compositor_task_runner_->CreateQueueEnabledVoter()), |
100 delayed_update_policy_runner_( | 103 delayed_update_policy_runner_( |
101 base::Bind(&RendererSchedulerImpl::UpdatePolicy, | 104 base::Bind(&RendererSchedulerImpl::UpdatePolicy, |
102 base::Unretained(this)), | 105 base::Unretained(this)), |
103 helper_.ControlTaskRunner()), | 106 helper_.ControlTaskRunner()), |
| 107 seqlock_queueing_time_estimator_( |
| 108 QueueingTimeEstimator(this, base::TimeDelta::FromSeconds(1))), |
104 main_thread_only_(this, | 109 main_thread_only_(this, |
105 compositor_task_runner_, | 110 compositor_task_runner_, |
106 helper_.scheduler_tqm_delegate().get(), | 111 helper_.scheduler_tqm_delegate().get(), |
107 helper_.scheduler_tqm_delegate()->NowTicks()), | 112 helper_.scheduler_tqm_delegate()->NowTicks()), |
108 policy_may_need_update_(&any_thread_lock_), | 113 policy_may_need_update_(&any_thread_lock_), |
| 114 main_thread_responsiveness_threshold_(kMainThreadResponsivenessThreshold), |
109 weak_factory_(this) { | 115 weak_factory_(this) { |
110 task_queue_throttler_.reset( | 116 task_queue_throttler_.reset( |
111 new TaskQueueThrottler(this, "renderer.scheduler")); | 117 new TaskQueueThrottler(this, "renderer.scheduler")); |
112 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, | 118 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, |
113 weak_factory_.GetWeakPtr()); | 119 weak_factory_.GetWeakPtr()); |
114 end_renderer_hidden_idle_period_closure_.Reset(base::Bind( | 120 end_renderer_hidden_idle_period_closure_.Reset(base::Bind( |
115 &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr())); | 121 &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr())); |
116 | 122 |
117 suspend_timers_when_backgrounded_closure_.Reset( | 123 suspend_timers_when_backgrounded_closure_.Reset( |
118 base::Bind(&RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded, | 124 base::Bind(&RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded, |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 RendererSchedulerImpl* renderer_scheduler_impl, | 175 RendererSchedulerImpl* renderer_scheduler_impl, |
170 const scoped_refptr<TaskQueue>& compositor_task_runner, | 176 const scoped_refptr<TaskQueue>& compositor_task_runner, |
171 base::TickClock* time_source, | 177 base::TickClock* time_source, |
172 base::TimeTicks now) | 178 base::TimeTicks now) |
173 : loading_task_cost_estimator(time_source, | 179 : loading_task_cost_estimator(time_source, |
174 kLoadingTaskEstimationSampleCount, | 180 kLoadingTaskEstimationSampleCount, |
175 kLoadingTaskEstimationPercentile), | 181 kLoadingTaskEstimationPercentile), |
176 timer_task_cost_estimator(time_source, | 182 timer_task_cost_estimator(time_source, |
177 kTimerTaskEstimationSampleCount, | 183 kTimerTaskEstimationSampleCount, |
178 kTimerTaskEstimationPercentile), | 184 kTimerTaskEstimationPercentile), |
179 queueing_time_estimator(renderer_scheduler_impl, | |
180 base::TimeDelta::FromSeconds(1)), | |
181 idle_time_estimator(compositor_task_runner, | 185 idle_time_estimator(compositor_task_runner, |
182 time_source, | 186 time_source, |
183 kShortIdlePeriodDurationSampleCount, | 187 kShortIdlePeriodDurationSampleCount, |
184 kShortIdlePeriodDurationPercentile), | 188 kShortIdlePeriodDurationPercentile), |
185 background_main_thread_load_tracker( | 189 background_main_thread_load_tracker( |
186 now, | 190 now, |
187 base::Bind(&ReportBackgroundRendererTaskLoad), | 191 base::Bind(&ReportBackgroundRendererTaskLoad), |
188 kThreadLoadTrackerReportingInterval, | 192 kThreadLoadTrackerReportingInterval, |
189 kThreadLoadTrackerWaitingPeriodBeforeReporting), | 193 kThreadLoadTrackerWaitingPeriodBeforeReporting), |
190 foreground_main_thread_load_tracker( | 194 foreground_main_thread_load_tracker( |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 begin_main_frame_on_critical_path(false), | 227 begin_main_frame_on_critical_path(false), |
224 last_gesture_was_compositor_driven(false), | 228 last_gesture_was_compositor_driven(false), |
225 default_gesture_prevented(true), | 229 default_gesture_prevented(true), |
226 have_seen_touchstart(false), | 230 have_seen_touchstart(false), |
227 waiting_for_meaningful_paint(false), | 231 waiting_for_meaningful_paint(false), |
228 have_seen_input_since_navigation(false) {} | 232 have_seen_input_since_navigation(false) {} |
229 | 233 |
230 RendererSchedulerImpl::AnyThread::~AnyThread() {} | 234 RendererSchedulerImpl::AnyThread::~AnyThread() {} |
231 | 235 |
232 RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly() | 236 RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly() |
233 : last_input_type(blink::WebInputEvent::Undefined) {} | 237 : last_input_type(blink::WebInputEvent::Undefined), |
| 238 main_thread_seems_unresponsive(false) {} |
234 | 239 |
235 RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() {} | 240 RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() {} |
236 | 241 |
237 void RendererSchedulerImpl::Shutdown() { | 242 void RendererSchedulerImpl::Shutdown() { |
238 base::TimeTicks now = tick_clock()->NowTicks(); | 243 base::TimeTicks now = tick_clock()->NowTicks(); |
239 MainThreadOnly().background_main_thread_load_tracker.RecordIdle(now); | 244 MainThreadOnly().background_main_thread_load_tracker.RecordIdle(now); |
240 MainThreadOnly().foreground_main_thread_load_tracker.RecordIdle(now); | 245 MainThreadOnly().foreground_main_thread_load_tracker.RecordIdle(now); |
241 | 246 |
242 task_queue_throttler_.reset(); | 247 task_queue_throttler_.reset(); |
243 helper_.Shutdown(); | 248 helper_.Shutdown(); |
(...skipping 1350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1594 default_loading_task_runner_->SetBlameContext(blame_context); | 1599 default_loading_task_runner_->SetBlameContext(blame_context); |
1595 default_timer_task_runner_->SetBlameContext(blame_context); | 1600 default_timer_task_runner_->SetBlameContext(blame_context); |
1596 compositor_task_runner_->SetBlameContext(blame_context); | 1601 compositor_task_runner_->SetBlameContext(blame_context); |
1597 idle_helper_.IdleTaskRunner()->SetBlameContext(blame_context); | 1602 idle_helper_.IdleTaskRunner()->SetBlameContext(blame_context); |
1598 } | 1603 } |
1599 | 1604 |
1600 void RendererSchedulerImpl::SetRAILModeObserver(RAILModeObserver* observer) { | 1605 void RendererSchedulerImpl::SetRAILModeObserver(RAILModeObserver* observer) { |
1601 MainThreadOnly().rail_mode_observer = observer; | 1606 MainThreadOnly().rail_mode_observer = observer; |
1602 } | 1607 } |
1603 | 1608 |
| 1609 bool RendererSchedulerImpl::MainThreadSeemsUnresponsive() { |
| 1610 base::TimeTicks now = tick_clock()->NowTicks(); |
| 1611 base::TimeDelta estimated_queueing_time; |
| 1612 |
| 1613 bool can_read = false; |
| 1614 QueueingTimeEstimator::State queueing_time_estimator_state; |
| 1615 |
| 1616 base::subtle::Atomic32 version; |
| 1617 seqlock_queueing_time_estimator_.seqlock.ReadOrFail(&can_read, &version); |
| 1618 |
| 1619 // If we fail to determine if the main thread is busy, assume whether or not |
| 1620 // it's busy hasn't change since the last time we asked. |
| 1621 if (!can_read) |
| 1622 return CompositorThreadOnly().main_thread_seems_unresponsive; |
| 1623 |
| 1624 queueing_time_estimator_state = seqlock_queueing_time_estimator_.data.state(); |
| 1625 |
| 1626 // If we fail to determine if the main thread is busy, assume whether or not |
| 1627 // it's busy hasn't change since the last time we asked. |
| 1628 if (seqlock_queueing_time_estimator_.seqlock.ReadRetry(version)) |
| 1629 return CompositorThreadOnly().main_thread_seems_unresponsive; |
| 1630 |
| 1631 QueueingTimeEstimator queueing_time_estimator(queueing_time_estimator_state); |
| 1632 |
| 1633 estimated_queueing_time = |
| 1634 queueing_time_estimator.EstimateQueueingTimeIncludingCurrentTask(now); |
| 1635 |
| 1636 bool main_thread_seems_unresponsive = |
| 1637 estimated_queueing_time > main_thread_responsiveness_threshold_; |
| 1638 CompositorThreadOnly().main_thread_seems_unresponsive = |
| 1639 main_thread_seems_unresponsive; |
| 1640 |
| 1641 return main_thread_seems_unresponsive; |
| 1642 } |
| 1643 |
1604 void RendererSchedulerImpl::RegisterTimeDomain(TimeDomain* time_domain) { | 1644 void RendererSchedulerImpl::RegisterTimeDomain(TimeDomain* time_domain) { |
1605 helper_.RegisterTimeDomain(time_domain); | 1645 helper_.RegisterTimeDomain(time_domain); |
1606 } | 1646 } |
1607 | 1647 |
1608 void RendererSchedulerImpl::UnregisterTimeDomain(TimeDomain* time_domain) { | 1648 void RendererSchedulerImpl::UnregisterTimeDomain(TimeDomain* time_domain) { |
1609 helper_.UnregisterTimeDomain(time_domain); | 1649 helper_.UnregisterTimeDomain(time_domain); |
1610 } | 1650 } |
1611 | 1651 |
1612 base::TickClock* RendererSchedulerImpl::tick_clock() const { | 1652 base::TickClock* RendererSchedulerImpl::tick_clock() const { |
1613 return helper_.scheduler_tqm_delegate().get(); | 1653 return helper_.scheduler_tqm_delegate().get(); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1658 base::AutoLock lock(any_thread_lock_); | 1698 base::AutoLock lock(any_thread_lock_); |
1659 if (!AnyThread().have_seen_touchstart) | 1699 if (!AnyThread().have_seen_touchstart) |
1660 return; | 1700 return; |
1661 } | 1701 } |
1662 MainThreadOnly().have_reported_blocking_intervention_since_navigation = | 1702 MainThreadOnly().have_reported_blocking_intervention_since_navigation = |
1663 true; | 1703 true; |
1664 BroadcastIntervention( | 1704 BroadcastIntervention( |
1665 "Blink deferred a task in order to make scrolling smoother. " | 1705 "Blink deferred a task in order to make scrolling smoother. " |
1666 "Your timer and network tasks should take less than 50ms to run " | 1706 "Your timer and network tasks should take less than 50ms to run " |
1667 "to avoid this. Please see " | 1707 "to avoid this. Please see " |
1668 "https://developers.google.com/web/tools/chrome-devtools/profile/evaluat
e-performance/rail" | 1708 "https://developers.google.com/web/tools/chrome-devtools/profile/" |
| 1709 "evaluate-performance/rail" |
1669 " and https://crbug.com/574343#c40 for more information."); | 1710 " and https://crbug.com/574343#c40 for more information."); |
1670 } | 1711 } |
1671 } | 1712 } |
1672 | 1713 |
| 1714 void RendererSchedulerImpl::willProcessTask(TaskQueue* task_queue, |
| 1715 double start_time) { |
| 1716 base::TimeTicks start_time_ticks = |
| 1717 MonotonicTimeInSecondsToTimeTicks(start_time); |
| 1718 MainThreadOnly().current_task_start_time = start_time_ticks; |
| 1719 seqlock_queueing_time_estimator_.seqlock.WriteBegin(); |
| 1720 seqlock_queueing_time_estimator_.data.OnTopLevelTaskStarted(start_time_ticks); |
| 1721 seqlock_queueing_time_estimator_.seqlock.WriteEnd(); |
| 1722 } |
| 1723 |
1673 void RendererSchedulerImpl::didProcessTask(TaskQueue* task_queue, | 1724 void RendererSchedulerImpl::didProcessTask(TaskQueue* task_queue, |
1674 double start_time, | 1725 double start_time, |
1675 double end_time) { | 1726 double end_time) { |
1676 // TODO(scheduler-dev): Remove conversions when Blink starts using | 1727 // TODO(scheduler-dev): Remove conversions when Blink starts using |
1677 // base::TimeTicks instead of doubles for time. | 1728 // base::TimeTicks instead of doubles for time. |
1678 base::TimeTicks start_time_ticks = | 1729 base::TimeTicks start_time_ticks = |
1679 MonotonicTimeInSecondsToTimeTicks(start_time); | 1730 MonotonicTimeInSecondsToTimeTicks(start_time); |
1680 base::TimeTicks end_time_ticks = MonotonicTimeInSecondsToTimeTicks(end_time); | 1731 base::TimeTicks end_time_ticks = MonotonicTimeInSecondsToTimeTicks(end_time); |
1681 | 1732 |
1682 MainThreadOnly().queueing_time_estimator.OnToplevelTaskCompleted( | 1733 seqlock_queueing_time_estimator_.seqlock.WriteBegin(); |
1683 start_time_ticks, end_time_ticks); | 1734 seqlock_queueing_time_estimator_.data.OnTopLevelTaskCompleted(end_time_ticks); |
| 1735 seqlock_queueing_time_estimator_.seqlock.WriteEnd(); |
1684 | 1736 |
1685 task_queue_throttler()->OnTaskRunTimeReported(task_queue, start_time_ticks, | 1737 task_queue_throttler()->OnTaskRunTimeReported(task_queue, start_time_ticks, |
1686 end_time_ticks); | 1738 end_time_ticks); |
1687 | 1739 |
1688 // We want to measure thread time here, but for efficiency reasons | 1740 // We want to measure thread time here, but for efficiency reasons |
1689 // we stick with wall time. | 1741 // we stick with wall time. |
1690 MainThreadOnly().foreground_main_thread_load_tracker.RecordTaskTime( | 1742 MainThreadOnly().foreground_main_thread_load_tracker.RecordTaskTime( |
1691 start_time_ticks, end_time_ticks); | 1743 start_time_ticks, end_time_ticks); |
1692 MainThreadOnly().background_main_thread_load_tracker.RecordTaskTime( | 1744 MainThreadOnly().background_main_thread_load_tracker.RecordTaskTime( |
1693 start_time_ticks, end_time_ticks); | 1745 start_time_ticks, end_time_ticks); |
1694 // TODO(altimin): Per-page metrics should also be considered. | 1746 // TODO(altimin): Per-page metrics should also be considered. |
1695 UMA_HISTOGRAM_CUSTOM_COUNTS("RendererScheduler.TaskTime", | 1747 UMA_HISTOGRAM_CUSTOM_COUNTS( |
1696 (end_time_ticks - start_time_ticks).InMicroseconds
(), 1, | 1748 "RendererScheduler.TaskTime", |
1697 1000000, 50); | 1749 (end_time_ticks - start_time_ticks).InMicroseconds(), 1, 1000000, 50); |
1698 UMA_HISTOGRAM_ENUMERATION("RendererScheduler.NumberOfTasksPerQueueType", | 1750 UMA_HISTOGRAM_ENUMERATION("RendererScheduler.NumberOfTasksPerQueueType", |
1699 static_cast<int>(task_queue->GetQueueType()), | 1751 static_cast<int>(task_queue->GetQueueType()), |
1700 static_cast<int>(TaskQueue::QueueType::COUNT)); | 1752 static_cast<int>(TaskQueue::QueueType::COUNT)); |
1701 } | 1753 } |
1702 | 1754 |
1703 void RendererSchedulerImpl::AddTaskTimeObserver( | 1755 void RendererSchedulerImpl::AddTaskTimeObserver( |
1704 TaskTimeObserver* task_time_observer) { | 1756 TaskTimeObserver* task_time_observer) { |
1705 helper_.AddTaskTimeObserver(task_time_observer); | 1757 helper_.AddTaskTimeObserver(task_time_observer); |
1706 } | 1758 } |
1707 | 1759 |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1817 case TimeDomainType::VIRTUAL: | 1869 case TimeDomainType::VIRTUAL: |
1818 return "virtual"; | 1870 return "virtual"; |
1819 default: | 1871 default: |
1820 NOTREACHED(); | 1872 NOTREACHED(); |
1821 return nullptr; | 1873 return nullptr; |
1822 } | 1874 } |
1823 } | 1875 } |
1824 | 1876 |
1825 } // namespace scheduler | 1877 } // namespace scheduler |
1826 } // namespace blink | 1878 } // namespace blink |
OLD | NEW |