| 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 |