Chromium Code Reviews| Index: third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc |
| diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc |
| index 25376e87f14eab36a4df8cfeac668a9928540ad9..9430977554e611ef4bdb6568464884859c6415fa 100644 |
| --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc |
| +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc |
| @@ -45,6 +45,9 @@ constexpr base::TimeDelta kThreadLoadTrackerWaitingPeriodBeforeReporting = |
| // We do not throttle anything while audio is played and shortly after that. |
| constexpr base::TimeDelta kThrottlingDelayAfterAudioIsPlayed = |
| base::TimeDelta::FromSeconds(5); |
| +// Maximum task queueing time before the main thread is considered unresponsive. |
| +constexpr base::TimeDelta kMainThreadResponsivenessThreshold = |
| + base::TimeDelta::FromMilliseconds(200); |
| void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) { |
| int load_percentage = static_cast<int>(load * 100); |
| @@ -64,8 +67,8 @@ void ReportBackgroundRendererTaskLoad(base::TimeTicks time, double load) { |
| base::TimeTicks MonotonicTimeInSecondsToTimeTicks( |
| double monotonicTimeInSeconds) { |
| - return base::TimeTicks() + base::TimeDelta::FromSecondsD( |
| - monotonicTimeInSeconds); |
| + return base::TimeTicks() + |
| + base::TimeDelta::FromSecondsD(monotonicTimeInSeconds); |
| } |
| } // namespace |
| @@ -90,11 +93,15 @@ RendererSchedulerImpl::RendererSchedulerImpl( |
| base::Bind(&RendererSchedulerImpl::UpdatePolicy, |
| base::Unretained(this)), |
| helper_.ControlTaskRunner()), |
| + seqlock_queueing_time_estimator_( |
| + QueueingTimeEstimator(this, base::TimeDelta::FromSeconds(1))), |
| main_thread_only_(this, |
| compositor_task_runner_, |
| helper_.scheduler_tqm_delegate().get(), |
| helper_.scheduler_tqm_delegate()->NowTicks()), |
| + any_thread_(this), |
| policy_may_need_update_(&any_thread_lock_), |
| + main_thread_responsiveness_threshold_(kMainThreadResponsivenessThreshold), |
| weak_factory_(this) { |
| task_queue_throttler_.reset( |
| new TaskQueueThrottler(this, "renderer.scheduler")); |
| @@ -156,8 +163,6 @@ RendererSchedulerImpl::MainThreadOnly::MainThreadOnly( |
| timer_task_cost_estimator(time_source, |
| kTimerTaskEstimationSampleCount, |
| kTimerTaskEstimationPercentile), |
| - queueing_time_estimator(renderer_scheduler_impl, |
| - base::TimeDelta::FromSeconds(1)), |
| idle_time_estimator(compositor_task_runner, |
| time_source, |
| kShortIdlePeriodDurationSampleCount, |
| @@ -197,7 +202,8 @@ RendererSchedulerImpl::MainThreadOnly::MainThreadOnly( |
| RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {} |
| -RendererSchedulerImpl::AnyThread::AnyThread() |
| +RendererSchedulerImpl::AnyThread::AnyThread( |
| + RendererSchedulerImpl* renderer_scheduler_impl) |
| : awaiting_touch_start_response(false), |
| in_idle_period(false), |
| begin_main_frame_on_critical_path(false), |
| @@ -208,7 +214,8 @@ RendererSchedulerImpl::AnyThread::AnyThread() |
| RendererSchedulerImpl::AnyThread::~AnyThread() {} |
| RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly() |
| - : last_input_type(blink::WebInputEvent::Undefined) {} |
| + : last_input_type(blink::WebInputEvent::Undefined), |
| + main_thread_seems_unresponsive(false) {} |
| RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() {} |
| @@ -1510,6 +1517,43 @@ void RendererSchedulerImpl::SetRAILModeObserver(RAILModeObserver* observer) { |
| MainThreadOnly().rail_mode_observer = observer; |
| } |
| +bool RendererSchedulerImpl::MainThreadSeemsUnresponsive() { |
| + base::TimeTicks now = tick_clock()->NowTicks(); |
|
alex clarke (OOO till 29th)
2016/11/14 17:00:17
Is it worth adding a TRACE_EVENT here?
tdresser
2016/12/15 13:17:00
For when we're checking if the main thread is unre
|
| + base::TimeDelta estimated_queueing_time; |
| + |
| + bool can_read = false; |
| + QueueingTimeEstimator::Data queueing_time_estimator_data; |
| + |
| + base::subtle::Atomic32 version; |
| + seqlock_queueing_time_estimator_.seqlock.ReadOrFail(&can_read, &version); |
| + |
| + // If we fail to determine if the main thread is busy, assume whether or not |
| + // it's busy hasn't change since the last time we asked. |
| + if (!can_read) |
| + return CompositorThreadOnly().main_thread_seems_unresponsive; |
| + |
| + queueing_time_estimator_data = seqlock_queueing_time_estimator_.data.data(); |
| + |
| + // If we fail to determine if the main thread is busy, assume whether or not |
| + // it's busy hasn't change since the last time we asked. |
| + if (seqlock_queueing_time_estimator_.seqlock.ReadRetry(version)) |
| + return CompositorThreadOnly().main_thread_seems_unresponsive; |
| + |
| + QueueingTimeEstimator queueing_time_estimator(queueing_time_estimator_data); |
| + |
| + estimated_queueing_time = |
| + queueing_time_estimator.EstimateQueueingTimeIncludingCurrentTask(now); |
| + |
| + bool main_thread_seems_unresponsive = |
| + estimated_queueing_time > main_thread_responsiveness_threshold_; |
| + { |
|
Sami
2016/11/14 21:16:45
nit: any reason for these braces? We're not grabbi
tdresser
2016/12/15 13:17:00
Done.
|
| + CompositorThreadOnly().main_thread_seems_unresponsive = |
| + main_thread_seems_unresponsive; |
| + } |
| + |
| + return main_thread_seems_unresponsive; |
| +} |
| + |
| void RendererSchedulerImpl::RegisterTimeDomain(TimeDomain* time_domain) { |
| helper_.RegisterTimeDomain(time_domain); |
| } |
| @@ -1574,22 +1618,33 @@ void RendererSchedulerImpl::OnTriedToExecuteBlockedTask( |
| "Blink deferred a task in order to make scrolling smoother. " |
| "Your timer and network tasks should take less than 50ms to run " |
| "to avoid this. Please see " |
| - "https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/rail" |
| + "https://developers.google.com/web/tools/chrome-devtools/profile/" |
| + "evaluate-performance/rail" |
| " and https://crbug.com/574343#c40 for more information."); |
| } |
| } |
| -void RendererSchedulerImpl::ReportTaskTime(TaskQueue* task_queue, |
| - double start_time, |
| - double end_time) { |
| +void RendererSchedulerImpl::ReportTaskStartTime(double start_time) { |
| + base::TimeTicks start_time_ticks = |
| + MonotonicTimeInSecondsToTimeTicks(start_time); |
| + MainThreadOnly().current_task_start_time = start_time_ticks; |
| + seqlock_queueing_time_estimator_.seqlock.WriteBegin(); |
| + seqlock_queueing_time_estimator_.data.OnTopLevelTaskStarted(start_time_ticks); |
| + seqlock_queueing_time_estimator_.seqlock.WriteEnd(); |
| +} |
| + |
| +void RendererSchedulerImpl::ReportTaskEndTime(TaskQueue* task_queue, |
| + double start_time, |
| + double end_time) { |
| // TODO(scheduler-dev): Remove conversions when Blink starts using |
| // base::TimeTicks instead of doubles for time. |
| base::TimeTicks start_time_ticks = |
| MonotonicTimeInSecondsToTimeTicks(start_time); |
| base::TimeTicks end_time_ticks = MonotonicTimeInSecondsToTimeTicks(end_time); |
| - MainThreadOnly().queueing_time_estimator.OnToplevelTaskCompleted( |
| - start_time_ticks, end_time_ticks); |
| + seqlock_queueing_time_estimator_.seqlock.WriteBegin(); |
| + seqlock_queueing_time_estimator_.data.OnTopLevelTaskCompleted(end_time_ticks); |
| + seqlock_queueing_time_estimator_.seqlock.WriteEnd(); |
| task_queue_throttler()->OnTaskRunTimeReported(task_queue, start_time_ticks, |
| end_time_ticks); |
| @@ -1601,9 +1656,9 @@ void RendererSchedulerImpl::ReportTaskTime(TaskQueue* task_queue, |
| MainThreadOnly().background_main_thread_load_tracker.RecordTaskTime( |
| start_time_ticks, end_time_ticks); |
| // TODO(altimin): Per-page metrics should also be considered. |
| - UMA_HISTOGRAM_CUSTOM_COUNTS("RendererScheduler.TaskTime", |
| - (end_time_ticks - start_time_ticks).InMicroseconds(), 1, |
| - 1000000, 50); |
| + UMA_HISTOGRAM_CUSTOM_COUNTS( |
| + "RendererScheduler.TaskTime", |
| + (end_time_ticks - start_time_ticks).InMicroseconds(), 1, 1000000, 50); |
| UMA_HISTOGRAM_ENUMERATION("RendererScheduler.NumberOfTasksPerQueueType", |
| static_cast<int>(task_queue->GetQueueType()), |
| static_cast<int>(TaskQueue::QueueType::COUNT)); |