Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(363)

Side by Side Diff: third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc

Issue 2383473002: [scheduler] Teach scheduler about audio state (Closed)
Patch Set: Rebased Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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;
40 constexpr base::TimeDelta kThreadLoadTrackerReportingInterval = 41 constexpr base::TimeDelta kThreadLoadTrackerReportingInterval =
41 base::TimeDelta::FromMinutes(1); 42 base::TimeDelta::FromMinutes(1);
42 constexpr base::TimeDelta kThreadLoadTrackerWaitingPeriodBeforeReporting = 43 constexpr base::TimeDelta kThreadLoadTrackerWaitingPeriodBeforeReporting =
43 base::TimeDelta::FromMinutes(2); 44 base::TimeDelta::FromMinutes(2);
45 // We do not throttle anything while audio is played and shortly after that.
46 constexpr base::TimeDelta kThrottlingDelayAfterAudioIsPlayed =
47 base::TimeDelta::FromSeconds(5);
44 48
45 void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) { 49 void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) {
46 int load_percentage = static_cast<int>(load * 100); 50 int load_percentage = static_cast<int>(load * 100);
47 UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.ForegroundRendererMainThreadLoad", 51 UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.ForegroundRendererMainThreadLoad",
48 load_percentage); 52 load_percentage);
49 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), 53 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
50 "RendererScheduler.ForegroundRendererLoad", load_percentage); 54 "RendererScheduler.ForegroundRendererLoad", load_percentage);
51 } 55 }
52 56
53 void ReportBackgroundRendererTaskLoad(base::TimeTicks time, double load) { 57 void ReportBackgroundRendererTaskLoad(base::TimeTicks time, double load) {
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 loading_tasks_seem_expensive(false), 182 loading_tasks_seem_expensive(false),
179 timer_tasks_seem_expensive(false), 183 timer_tasks_seem_expensive(false),
180 touchstart_expected_soon(false), 184 touchstart_expected_soon(false),
181 have_seen_a_begin_main_frame(false), 185 have_seen_a_begin_main_frame(false),
182 have_reported_blocking_intervention_in_current_policy(false), 186 have_reported_blocking_intervention_in_current_policy(false),
183 have_reported_blocking_intervention_since_navigation(false), 187 have_reported_blocking_intervention_since_navigation(false),
184 has_visible_render_widget_with_touch_handler(false), 188 has_visible_render_widget_with_touch_handler(false),
185 begin_frame_not_expected_soon(false), 189 begin_frame_not_expected_soon(false),
186 in_idle_period_for_testing(false), 190 in_idle_period_for_testing(false),
187 use_virtual_time(false), 191 use_virtual_time(false),
192 is_audio_playing(false),
188 rail_mode_observer(nullptr) {} 193 rail_mode_observer(nullptr) {}
189 194
190 RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {} 195 RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {}
191 196
192 RendererSchedulerImpl::AnyThread::AnyThread() 197 RendererSchedulerImpl::AnyThread::AnyThread()
193 : awaiting_touch_start_response(false), 198 : awaiting_touch_start_response(false),
194 in_idle_period(false), 199 in_idle_period(false),
195 begin_main_frame_on_critical_path(false), 200 begin_main_frame_on_critical_path(false),
196 last_gesture_was_compositor_driven(false), 201 last_gesture_was_compositor_driven(false),
197 default_gesture_prevented(true), 202 default_gesture_prevented(true),
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after
477 MainThreadOnly().renderer_suspended = false; 482 MainThreadOnly().renderer_suspended = false;
478 483
479 base::TimeTicks now = tick_clock()->NowTicks(); 484 base::TimeTicks now = tick_clock()->NowTicks();
480 MainThreadOnly().foreground_main_thread_load_tracker.Resume(now); 485 MainThreadOnly().foreground_main_thread_load_tracker.Resume(now);
481 MainThreadOnly().background_main_thread_load_tracker.Pause(now); 486 MainThreadOnly().background_main_thread_load_tracker.Pause(now);
482 487
483 suspend_timers_when_backgrounded_closure_.Cancel(); 488 suspend_timers_when_backgrounded_closure_.Cancel();
484 ResumeTimerQueueWhenForegrounded(); 489 ResumeTimerQueueWhenForegrounded();
485 } 490 }
486 491
492 void RendererSchedulerImpl::OnAudioStateChanged() {
493 bool is_audio_playing = false;
494 for (WebViewSchedulerImpl* web_view_scheduler :
495 MainThreadOnly().web_view_schedulers) {
496 is_audio_playing = is_audio_playing || web_view_scheduler->IsAudioPlaying();
497 }
498
499 if (is_audio_playing == MainThreadOnly().is_audio_playing)
500 return;
501
502 MainThreadOnly().last_audio_state_change =
503 helper_.scheduler_tqm_delegate()->NowTicks();
504 MainThreadOnly().is_audio_playing = is_audio_playing;
505
506 UpdatePolicy();
507 }
508
487 void RendererSchedulerImpl::SuspendRenderer() { 509 void RendererSchedulerImpl::SuspendRenderer() {
488 helper_.CheckOnValidThread(); 510 helper_.CheckOnValidThread();
489 DCHECK(MainThreadOnly().renderer_backgrounded); 511 DCHECK(MainThreadOnly().renderer_backgrounded);
490 if (helper_.IsShutdown()) 512 if (helper_.IsShutdown())
491 return; 513 return;
492 suspend_timers_when_backgrounded_closure_.Cancel(); 514 suspend_timers_when_backgrounded_closure_.Cancel();
493 515
494 UMA_HISTOGRAM_COUNTS("PurgeAndSuspend.PendingTaskCount", 516 UMA_HISTOGRAM_COUNTS("PurgeAndSuspend.PendingTaskCount",
495 helper_.GetNumberOfPendingTasks()); 517 helper_.GetNumberOfPendingTasks());
496 518
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after
811 // The |new_policy_duration| is the minimum of |expected_use_case_duration| 833 // The |new_policy_duration| is the minimum of |expected_use_case_duration|
812 // and |touchstart_expected_flag_valid_for_duration| unless one is zero in 834 // and |touchstart_expected_flag_valid_for_duration| unless one is zero in
813 // which case we choose the other. 835 // which case we choose the other.
814 base::TimeDelta new_policy_duration = expected_use_case_duration; 836 base::TimeDelta new_policy_duration = expected_use_case_duration;
815 if (new_policy_duration.is_zero() || 837 if (new_policy_duration.is_zero() ||
816 (touchstart_expected_flag_valid_for_duration > base::TimeDelta() && 838 (touchstart_expected_flag_valid_for_duration > base::TimeDelta() &&
817 new_policy_duration > touchstart_expected_flag_valid_for_duration)) { 839 new_policy_duration > touchstart_expected_flag_valid_for_duration)) {
818 new_policy_duration = touchstart_expected_flag_valid_for_duration; 840 new_policy_duration = touchstart_expected_flag_valid_for_duration;
819 } 841 }
820 842
843 // Do not throttle while audio is playing or for a short period after that
844 // to make sure that pages playing short audio clips powered by timers
845 // work.
846 if (MainThreadOnly().last_audio_state_change &&
847 !MainThreadOnly().is_audio_playing) {
848 base::TimeTicks audio_will_expire =
849 MainThreadOnly().last_audio_state_change.value() +
850 kThrottlingDelayAfterAudioIsPlayed;
851
852 base::TimeDelta audio_will_expire_after = audio_will_expire - now;
853
854 if (audio_will_expire_after > base::TimeDelta()) {
855 if (new_policy_duration.is_zero()) {
856 new_policy_duration = audio_will_expire_after;
857 } else {
858 new_policy_duration =
859 std::min(new_policy_duration, audio_will_expire_after);
860 }
861 }
862 }
863
821 if (new_policy_duration > base::TimeDelta()) { 864 if (new_policy_duration > base::TimeDelta()) {
822 MainThreadOnly().current_policy_expiration_time = now + new_policy_duration; 865 MainThreadOnly().current_policy_expiration_time = now + new_policy_duration;
823 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, 866 delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration,
824 now); 867 now);
825 } else { 868 } else {
826 MainThreadOnly().current_policy_expiration_time = base::TimeTicks(); 869 MainThreadOnly().current_policy_expiration_time = base::TimeTicks();
827 } 870 }
828 871
829 // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely 872 // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely
830 // slow, because that can cause starvation in other task sources. 873 // slow, because that can cause starvation in other task sources.
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
966 } 1009 }
967 1010
968 if (MainThreadOnly().use_virtual_time) { 1011 if (MainThreadOnly().use_virtual_time) {
969 new_policy.compositor_queue_policy.time_domain_type = 1012 new_policy.compositor_queue_policy.time_domain_type =
970 TimeDomainType::VIRTUAL; 1013 TimeDomainType::VIRTUAL;
971 new_policy.default_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; 1014 new_policy.default_queue_policy.time_domain_type = TimeDomainType::VIRTUAL;
972 new_policy.loading_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; 1015 new_policy.loading_queue_policy.time_domain_type = TimeDomainType::VIRTUAL;
973 new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; 1016 new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL;
974 } 1017 }
975 1018
1019 new_policy.should_disable_throttling =
1020 ShouldDisableThrottlingBecauseOfAudio(now) ||
1021 MainThreadOnly().use_virtual_time;
1022
976 // Tracing is done before the early out check, because it's quite possible we 1023 // Tracing is done before the early out check, because it's quite possible we
977 // will otherwise miss this information in traces. 1024 // will otherwise miss this information in traces.
978 CreateTraceEventObjectSnapshotLocked(); 1025 CreateTraceEventObjectSnapshotLocked();
979 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case", 1026 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case",
980 use_case); 1027 use_case);
981 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode", 1028 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode",
982 new_policy.rail_mode); 1029 new_policy.rail_mode);
983 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), 1030 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
984 "touchstart_expected_soon", 1031 "touchstart_expected_soon",
985 MainThreadOnly().touchstart_expected_soon); 1032 MainThreadOnly().touchstart_expected_soon);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1021 // are mostly dispatched on the default queue) need to be preserved. 1068 // are mostly dispatched on the default queue) need to be preserved.
1022 ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(), 1069 ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(),
1023 MainThreadOnly().current_policy.default_queue_policy, 1070 MainThreadOnly().current_policy.default_queue_policy,
1024 new_policy.default_queue_policy); 1071 new_policy.default_queue_policy);
1025 if (MainThreadOnly().rail_mode_observer && 1072 if (MainThreadOnly().rail_mode_observer &&
1026 new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) { 1073 new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) {
1027 MainThreadOnly().rail_mode_observer->OnRAILModeChanged( 1074 MainThreadOnly().rail_mode_observer->OnRAILModeChanged(
1028 new_policy.rail_mode); 1075 new_policy.rail_mode);
1029 } 1076 }
1030 1077
1078 if (new_policy.should_disable_throttling !=
1079 MainThreadOnly().current_policy.should_disable_throttling) {
1080 if (new_policy.should_disable_throttling) {
1081 task_queue_throttler()->DisableThrottling();
1082 } else {
1083 task_queue_throttler()->EnableThrottling();
1084 }
1085 }
1086
1031 DCHECK(compositor_task_runner_->IsQueueEnabled()); 1087 DCHECK(compositor_task_runner_->IsQueueEnabled());
1032 MainThreadOnly().current_policy = new_policy; 1088 MainThreadOnly().current_policy = new_policy;
1033 } 1089 }
1034 1090
1035 void RendererSchedulerImpl::ApplyTaskQueuePolicy( 1091 void RendererSchedulerImpl::ApplyTaskQueuePolicy(
1036 TaskQueue* task_queue, 1092 TaskQueue* task_queue,
1037 const TaskQueuePolicy& old_task_queue_policy, 1093 const TaskQueuePolicy& old_task_queue_policy,
1038 const TaskQueuePolicy& new_task_queue_policy) const { 1094 const TaskQueuePolicy& new_task_queue_policy) const {
1039 if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) { 1095 if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) {
1040 task_queue_throttler_->SetQueueEnabled(task_queue, 1096 task_queue_throttler_->SetQueueEnabled(task_queue,
(...skipping 502 matching lines...) Expand 10 before | Expand all | Expand 10 after
1543 } 1599 }
1544 1600
1545 void RendererSchedulerImpl::EnableVirtualTime() { 1601 void RendererSchedulerImpl::EnableVirtualTime() {
1546 MainThreadOnly().use_virtual_time = true; 1602 MainThreadOnly().use_virtual_time = true;
1547 1603
1548 // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy(). 1604 // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy().
1549 AutoAdvancingVirtualTimeDomain* time_domain = GetVirtualTimeDomain(); 1605 AutoAdvancingVirtualTimeDomain* time_domain = GetVirtualTimeDomain();
1550 for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_) 1606 for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_)
1551 task_queue->SetTimeDomain(time_domain); 1607 task_queue->SetTimeDomain(time_domain);
1552 1608
1553 task_queue_throttler_->EnableVirtualTime(); 1609 ForceUpdatePolicy();
1610 }
1554 1611
1555 ForceUpdatePolicy(); 1612 bool RendererSchedulerImpl::ShouldDisableThrottlingBecauseOfAudio(
1613 base::TimeTicks now) {
1614 if (!MainThreadOnly().last_audio_state_change)
1615 return false;
1616
1617 if (MainThreadOnly().is_audio_playing)
1618 return true;
1619
1620 return MainThreadOnly().last_audio_state_change.value() +
1621 kThrottlingDelayAfterAudioIsPlayed >
1622 now;
1623 }
1624
1625 TimeDomain* RendererSchedulerImpl::GetActiveTimeDomain() {
1626 if (MainThreadOnly().use_virtual_time) {
1627 return GetVirtualTimeDomain();
1628 } else {
1629 return real_time_domain();
1630 }
1556 } 1631 }
1557 1632
1558 // static 1633 // static
1559 const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) { 1634 const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) {
1560 switch (use_case) { 1635 switch (use_case) {
1561 case UseCase::NONE: 1636 case UseCase::NONE:
1562 return "none"; 1637 return "none";
1563 case UseCase::COMPOSITOR_GESTURE: 1638 case UseCase::COMPOSITOR_GESTURE:
1564 return "compositor_gesture"; 1639 return "compositor_gesture";
1565 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: 1640 case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING:
(...skipping 24 matching lines...) Expand all
1590 case v8::PERFORMANCE_LOAD: 1665 case v8::PERFORMANCE_LOAD:
1591 return "load"; 1666 return "load";
1592 default: 1667 default:
1593 NOTREACHED(); 1668 NOTREACHED();
1594 return nullptr; 1669 return nullptr;
1595 } 1670 }
1596 } 1671 }
1597 1672
1598 } // namespace scheduler 1673 } // namespace scheduler
1599 } // namespace blink 1674 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698