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

Unified Diff: content/renderer/scheduler/renderer_scheduler_impl.cc

Issue 968073003: [content]: Add support for long idle times in the Blink Scheduler. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@long_idle_4
Patch Set: Minor tweaks Created 5 years, 10 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 side-by-side diff with in-line comments
Download patch
Index: content/renderer/scheduler/renderer_scheduler_impl.cc
diff --git a/content/renderer/scheduler/renderer_scheduler_impl.cc b/content/renderer/scheduler/renderer_scheduler_impl.cc
index 6f7821690393a3b8c61b9956f28deb523e766a6b..8580e893fb1ea7a2a78da8721d557284f5e2707f 100644
--- a/content/renderer/scheduler/renderer_scheduler_impl.cc
+++ b/content/renderer/scheduler/renderer_scheduler_impl.cc
@@ -41,6 +41,13 @@ RendererSchedulerImpl::RendererSchedulerImpl(
weak_renderer_scheduler_ptr_);
end_idle_period_closure_.Reset(base::Bind(
&RendererSchedulerImpl::EndIdlePeriod, weak_renderer_scheduler_ptr_));
+ initiate_next_long_idle_period_closure_.Reset(base::Bind(
+ &RendererSchedulerImpl::InitiateLongIdlePeriod,
+ weak_renderer_scheduler_ptr_));
+ after_wakeup_initiate_next_long_idle_period_closure_.Reset(base::Bind(
+ &RendererSchedulerImpl::AfterWakeupInitiateLongIdlePeriod,
+ weak_renderer_scheduler_ptr_));
+
idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner(
task_queue_manager_->TaskRunnerForQueue(IDLE_TASK_QUEUE),
control_task_after_wakeup_runner_,
@@ -142,10 +149,14 @@ void RendererSchedulerImpl::BeginFrameNotExpectedSoon() {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
"RendererSchedulerImpl::BeginFrameNotExpectedSoon");
DCHECK(main_thread_checker_.CalledOnValidThread());
+ if (!task_queue_manager_)
+ return;
+
// TODO(skyostil): Wire up real notification of input events processing
// instead of this approximation.
DidProcessInputEvent(base::TimeTicks());
- // TODO(rmcilroy): Implement long idle times.
+
+ InitiateLongIdlePeriod();
}
void RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread(
@@ -325,6 +336,29 @@ void RendererSchedulerImpl::UpdatePolicy() {
"RendererScheduler.policy", current_policy_);
}
+base::TimeDelta RendererSchedulerImpl::TimeLeftInInputEscalatedPolicy() {
+ DCHECK(main_thread_checker_.CalledOnValidThread());
Sami 2015/03/03 16:55:35 DCHECK_NE(input_stream_state_, InputStreamState::I
rmcilroy 2015/03/04 14:23:11 Done.
+ incoming_signals_lock_.AssertAcquired();
+
+ base::TimeDelta escalate_priority_duration =
Sami 2015/03/03 16:55:36 nit: escalated_priority_duration
rmcilroy 2015/03/04 14:23:11 Done.
+ base::TimeDelta::FromMilliseconds(kPriorityEscalationAfterInputMillis);
+ base::TimeDelta time_left_in_policy;
+ if (last_input_process_time_on_main_.is_null() &&
picksi 2015/03/04 10:43:22 In the 'else' section you also check last_input_re
rmcilroy 2015/03/04 14:23:11 No - input_stream_state_ would be INACTIVE if last
+ !task_queue_manager_->IsQueueEmpty(COMPOSITOR_TASK_QUEUE)) {
+ // If the input event is still pending, go into input prioritized policy
+ // and check again later.
+ time_left_in_policy = escalate_priority_duration;
picksi 2015/03/04 10:43:22 code style question: I assume we prefer a single r
rmcilroy 2015/03/04 14:23:11 I've been previously advised to avoid early return
+ } else {
+ // Otherwise make sure the input prioritization policy ends on time.
+ base::TimeTicks new_priority_end(
+ std::max(last_input_receipt_time_on_compositor_,
+ last_input_process_time_on_main_) +
picksi 2015/03/04 10:43:22 Philosophy: It makes my palms slightly itchy to se
rmcilroy 2015/03/04 14:23:11 Personally I would prefer to avoid the extra bool
Sami 2015/03/04 18:26:40 Since TimeTicks is already a nullable type (for be
+ escalate_priority_duration);
+ time_left_in_policy = new_priority_end - Now();
+ }
+ return time_left_in_policy;
+}
+
RendererSchedulerImpl::Policy RendererSchedulerImpl::ComputeNewPolicy(
base::TimeDelta* new_policy_duration) {
DCHECK(main_thread_checker_.CalledOnValidThread());
@@ -336,41 +370,110 @@ RendererSchedulerImpl::Policy RendererSchedulerImpl::ComputeNewPolicy(
if (input_stream_state_ == InputStreamState::INACTIVE)
return new_policy;
- base::TimeDelta new_priority_duration =
- base::TimeDelta::FromMilliseconds(kPriorityEscalationAfterInputMillis);
Policy input_priority_policy =
input_stream_state_ ==
InputStreamState::ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE
? Policy::TOUCHSTART_PRIORITY
: Policy::COMPOSITOR_PRIORITY;
-
- // If the input event is still pending, go into input prioritized policy
- // and check again later.
- if (last_input_process_time_on_main_.is_null() &&
- !task_queue_manager_->IsQueueEmpty(COMPOSITOR_TASK_QUEUE)) {
+ base::TimeDelta time_left_in_policy = TimeLeftInInputEscalatedPolicy();
+ if (time_left_in_policy > base::TimeDelta()) {
new_policy = input_priority_policy;
- *new_policy_duration = new_priority_duration;
+ *new_policy_duration = time_left_in_policy;
} else {
- // Otherwise make sure the input prioritization policy ends on time.
- base::TimeTicks new_priority_end(
- std::max(last_input_receipt_time_on_compositor_,
- last_input_process_time_on_main_) +
- new_priority_duration);
- base::TimeDelta time_left_in_policy = new_priority_end - Now();
-
- if (time_left_in_policy > base::TimeDelta()) {
- new_policy = input_priority_policy;
- *new_policy_duration = time_left_in_policy;
- } else {
- // Reset |input_stream_state_| to ensure
- // DidReceiveInputEventOnCompositorThread will post an UpdatePolicy task
- // when it's next called.
- input_stream_state_ = InputStreamState::INACTIVE;
- }
+ // Reset |input_stream_state_| to ensure
+ // DidReceiveInputEventOnCompositorThread will post an UpdatePolicy task
+ // when it's next called.
+ input_stream_state_ = InputStreamState::INACTIVE;
}
return new_policy;
}
+bool RendererSchedulerImpl::ShouldStartLongIdlePeriod(
+ const base::TimeTicks& now,
+ base::TimeDelta* next_long_idle_period_delay_out) {
+ DCHECK(main_thread_checker_.CalledOnValidThread());
+
+ MaybeUpdatePolicy();
+ if (current_policy_ == Policy::TOUCHSTART_PRIORITY) {
Sami 2015/03/03 16:55:36 We have a comment in the .h saying we should use S
rmcilroy 2015/03/04 14:23:11 I think it was because it used to do MaybeUpdatePo
Sami 2015/03/04 18:26:40 Right, makes sense.
+ // Don't start a long idle task in touch start priority, try again when
+ // the policy is scheduled to end.
+ base::AutoLock lock(incoming_signals_lock_);
+ *next_long_idle_period_delay_out = TimeLeftInInputEscalatedPolicy();
Sami 2015/03/03 16:55:35 Instead of recomputing this here, how about we mai
rmcilroy 2015/03/04 14:23:11 sgtm, done.
+ return false;
+ }
+
+ base::TimeTicks next_pending_delayed_task =
+ task_queue_manager_->NextPendingDelayedTask();
+
+ base::TimeDelta long_idle_period_duration =
+ base::TimeDelta::FromMilliseconds(kMaximumIdlePeriodMillis);
+ if (!next_pending_delayed_task.is_null()) {
+ // Limit the idle period duration to be before the next pending task.
+ long_idle_period_duration = std::min(
Sami 2015/03/03 16:55:35 Dumb question: why aren't we doing this adjustment
rmcilroy 2015/03/04 14:23:11 Not a dumb question :). The main reason for doing
Sami 2015/03/04 18:26:40 Okay, sounds good to me. Mind adding a TODO here o
rmcilroy 2015/03/05 11:48:52 Done in DidCommitFrameToCompositor.
+ next_pending_delayed_task - now, long_idle_period_duration);
+ }
+
+ if (long_idle_period_duration > base::TimeDelta()) {
+ *next_long_idle_period_delay_out = long_idle_period_duration;
+ return true;
+ } else {
+ // If we can't start the idle period yet then try again after a short delay.
+ *next_long_idle_period_delay_out =
+ base::TimeDelta::FromMilliseconds(1);
Sami 2015/03/03 16:55:36 Instead of this, could we schedule a check after t
picksi 2015/03/04 10:43:22 Is there any logic behind the 1 ms duration that w
rmcilroy 2015/03/04 14:23:11 This doesn't quite work due to the fact that the a
rmcilroy 2015/03/04 14:23:11 Done.
Sami 2015/03/04 18:26:40 Oh right, that's a good point. Since presumable th
rmcilroy 2015/03/05 11:48:52 Yes exactly - I think this is best to avoid racy c
+ return false;
+ }
+}
+
+void RendererSchedulerImpl::InitiateLongIdlePeriod() {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+ "AfterWakeupInitiateLongIdlePeriod");
Sami 2015/03/03 16:55:35 Trace event doesn't match the function name.
rmcilroy 2015/03/04 14:23:11 Done.
+ DCHECK(main_thread_checker_.CalledOnValidThread());
+
+ // End any previous idle period.
+ EndIdlePeriod();
+
+ base::TimeTicks now(Now());
+ base::TimeDelta next_long_idle_period_delay_out;
Sami 2015/03/03 16:55:36 nit: It feels weird to call a stack variable "_out
rmcilroy 2015/03/04 14:23:11 Yes this was wrong - done.
+ if (ShouldStartLongIdlePeriod(now, &next_long_idle_period_delay_out)) {
+ estimated_next_frame_begin_ = now + next_long_idle_period_delay_out;
+ StartIdlePeriod();
+ }
+
+ if (task_queue_manager_->IsQueueEmpty(IDLE_TASK_QUEUE)) {
+ // If there are no current idle tasks then post the call to initiate the
+ // next idle for execution after wakeup (at which point after-wakeup idle
+ // tasks might be eligible to run or more idle tasks posted).
+ control_task_after_wakeup_runner_->PostDelayedTask(
+ FROM_HERE,
+ after_wakeup_initiate_next_long_idle_period_closure_.callback(),
+ next_long_idle_period_delay_out);
+ } else {
+ // Otherwise post on the normal control task queue.
+ control_task_runner_->PostDelayedTask(
+ FROM_HERE,
+ initiate_next_long_idle_period_closure_.callback(),
+ next_long_idle_period_delay_out);
+ }
+}
+
+void RendererSchedulerImpl::AfterWakeupInitiateLongIdlePeriod() {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+ "AfterWakeupInitiateLongIdlePeriod");
+ DCHECK(main_thread_checker_.CalledOnValidThread());
+ // Since we were asleep until now, end the async idle period trace event at
+ // the time when it would have ended were we awake.
+ TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(
Sami 2015/03/03 16:55:35 Will we get duplicate trace events from this if In
rmcilroy 2015/03/04 14:23:11 We don't (at least in about::tracing) but agreed w
+ "renderer.scheduler", "RendererSchedulerIdlePeriod", this,
+ std::min(estimated_next_frame_begin_, Now()).ToInternalValue());
+ // Post a task to initiate the next long idle period rather than calling it
+ // directly to allow all pending PostIdleTaskAfterWakeup tasks to get enqueued
+ // on the idle task queue before the next idle period starts so they are
+ // eligible to be run during the new idle period.
+ control_task_runner_->PostTask(
+ FROM_HERE,
+ initiate_next_long_idle_period_closure_.callback());
+}
+
void RendererSchedulerImpl::StartIdlePeriod() {
TRACE_EVENT_ASYNC_BEGIN0("renderer.scheduler",
"RendererSchedulerIdlePeriod", this);
@@ -396,6 +499,8 @@ void RendererSchedulerImpl::EndIdlePeriod() {
"RendererSchedulerIdlePeriod", this);
DCHECK(main_thread_checker_.CalledOnValidThread());
end_idle_period_closure_.Cancel();
+ initiate_next_long_idle_period_closure_.Cancel();
+ after_wakeup_initiate_next_long_idle_period_closure_.Cancel();
renderer_task_queue_selector_->DisableQueue(IDLE_TASK_QUEUE);
}

Powered by Google App Engine
This is Rietveld 408576698