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

Side by Side 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, 9 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 "content/renderer/scheduler/renderer_scheduler_impl.h" 5 #include "content/renderer/scheduler/renderer_scheduler_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/message_loop/message_loop_proxy.h" 8 #include "base/message_loop/message_loop_proxy.h"
9 #include "base/trace_event/trace_event.h" 9 #include "base/trace_event/trace_event.h"
10 #include "base/trace_event/trace_event_argument.h" 10 #include "base/trace_event/trace_event_argument.h"
(...skipping 23 matching lines...) Expand all
34 current_policy_(Policy::NORMAL), 34 current_policy_(Policy::NORMAL),
35 last_input_type_(blink::WebInputEvent::Undefined), 35 last_input_type_(blink::WebInputEvent::Undefined),
36 input_stream_state_(InputStreamState::INACTIVE), 36 input_stream_state_(InputStreamState::INACTIVE),
37 policy_may_need_update_(&incoming_signals_lock_), 37 policy_may_need_update_(&incoming_signals_lock_),
38 weak_factory_(this) { 38 weak_factory_(this) {
39 weak_renderer_scheduler_ptr_ = weak_factory_.GetWeakPtr(); 39 weak_renderer_scheduler_ptr_ = weak_factory_.GetWeakPtr();
40 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, 40 update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy,
41 weak_renderer_scheduler_ptr_); 41 weak_renderer_scheduler_ptr_);
42 end_idle_period_closure_.Reset(base::Bind( 42 end_idle_period_closure_.Reset(base::Bind(
43 &RendererSchedulerImpl::EndIdlePeriod, weak_renderer_scheduler_ptr_)); 43 &RendererSchedulerImpl::EndIdlePeriod, weak_renderer_scheduler_ptr_));
44 initiate_next_long_idle_period_closure_.Reset(base::Bind(
45 &RendererSchedulerImpl::InitiateLongIdlePeriod,
46 weak_renderer_scheduler_ptr_));
47 after_wakeup_initiate_next_long_idle_period_closure_.Reset(base::Bind(
48 &RendererSchedulerImpl::AfterWakeupInitiateLongIdlePeriod,
49 weak_renderer_scheduler_ptr_));
50
44 idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner( 51 idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner(
45 task_queue_manager_->TaskRunnerForQueue(IDLE_TASK_QUEUE), 52 task_queue_manager_->TaskRunnerForQueue(IDLE_TASK_QUEUE),
46 control_task_after_wakeup_runner_, 53 control_task_after_wakeup_runner_,
47 base::Bind(&RendererSchedulerImpl::CurrentIdleTaskDeadlineCallback, 54 base::Bind(&RendererSchedulerImpl::CurrentIdleTaskDeadlineCallback,
48 weak_renderer_scheduler_ptr_))); 55 weak_renderer_scheduler_ptr_)));
49 56
50 renderer_task_queue_selector_->SetQueuePriority( 57 renderer_task_queue_selector_->SetQueuePriority(
51 CONTROL_TASK_QUEUE, RendererTaskQueueSelector::CONTROL_PRIORITY); 58 CONTROL_TASK_QUEUE, RendererTaskQueueSelector::CONTROL_PRIORITY);
52 59
53 renderer_task_queue_selector_->SetQueuePriority( 60 renderer_task_queue_selector_->SetQueuePriority(
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 control_task_runner_->PostDelayedTask(FROM_HERE, 142 control_task_runner_->PostDelayedTask(FROM_HERE,
136 end_idle_period_closure_.callback(), 143 end_idle_period_closure_.callback(),
137 estimated_next_frame_begin_ - now); 144 estimated_next_frame_begin_ - now);
138 } 145 }
139 } 146 }
140 147
141 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() { 148 void RendererSchedulerImpl::BeginFrameNotExpectedSoon() {
142 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), 149 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
143 "RendererSchedulerImpl::BeginFrameNotExpectedSoon"); 150 "RendererSchedulerImpl::BeginFrameNotExpectedSoon");
144 DCHECK(main_thread_checker_.CalledOnValidThread()); 151 DCHECK(main_thread_checker_.CalledOnValidThread());
152 if (!task_queue_manager_)
153 return;
154
145 // TODO(skyostil): Wire up real notification of input events processing 155 // TODO(skyostil): Wire up real notification of input events processing
146 // instead of this approximation. 156 // instead of this approximation.
147 DidProcessInputEvent(base::TimeTicks()); 157 DidProcessInputEvent(base::TimeTicks());
148 // TODO(rmcilroy): Implement long idle times. 158
159 InitiateLongIdlePeriod();
149 } 160 }
150 161
151 void RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread( 162 void RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread(
152 const blink::WebInputEvent& web_input_event) { 163 const blink::WebInputEvent& web_input_event) {
153 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), 164 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
154 "RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread"); 165 "RendererSchedulerImpl::DidReceiveInputEventOnCompositorThread");
155 // We regard MouseMove events with the left mouse button down as a signal 166 // We regard MouseMove events with the left mouse button down as a signal
156 // that the user is doing something requiring a smooth frame rate. 167 // that the user is doing something requiring a smooth frame rate.
157 if (web_input_event.type == blink::WebInputEvent::MouseMove && 168 if (web_input_event.type == blink::WebInputEvent::MouseMove &&
158 (web_input_event.modifiers & blink::WebInputEvent::LeftButtonDown)) { 169 (web_input_event.modifiers & blink::WebInputEvent::LeftButtonDown)) {
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 329
319 current_policy_ = new_policy; 330 current_policy_ = new_policy;
320 331
321 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( 332 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
322 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", 333 TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
323 this, AsValueLocked(now)); 334 this, AsValueLocked(now));
324 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), 335 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
325 "RendererScheduler.policy", current_policy_); 336 "RendererScheduler.policy", current_policy_);
326 } 337 }
327 338
339 base::TimeDelta RendererSchedulerImpl::TimeLeftInInputEscalatedPolicy() {
340 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.
341 incoming_signals_lock_.AssertAcquired();
342
343 base::TimeDelta escalate_priority_duration =
Sami 2015/03/03 16:55:36 nit: escalated_priority_duration
rmcilroy 2015/03/04 14:23:11 Done.
344 base::TimeDelta::FromMilliseconds(kPriorityEscalationAfterInputMillis);
345 base::TimeDelta time_left_in_policy;
346 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
347 !task_queue_manager_->IsQueueEmpty(COMPOSITOR_TASK_QUEUE)) {
348 // If the input event is still pending, go into input prioritized policy
349 // and check again later.
350 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
351 } else {
352 // Otherwise make sure the input prioritization policy ends on time.
353 base::TimeTicks new_priority_end(
354 std::max(last_input_receipt_time_on_compositor_,
355 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
356 escalate_priority_duration);
357 time_left_in_policy = new_priority_end - Now();
358 }
359 return time_left_in_policy;
360 }
361
328 RendererSchedulerImpl::Policy RendererSchedulerImpl::ComputeNewPolicy( 362 RendererSchedulerImpl::Policy RendererSchedulerImpl::ComputeNewPolicy(
329 base::TimeDelta* new_policy_duration) { 363 base::TimeDelta* new_policy_duration) {
330 DCHECK(main_thread_checker_.CalledOnValidThread()); 364 DCHECK(main_thread_checker_.CalledOnValidThread());
331 incoming_signals_lock_.AssertAcquired(); 365 incoming_signals_lock_.AssertAcquired();
332 366
333 Policy new_policy = Policy::NORMAL; 367 Policy new_policy = Policy::NORMAL;
334 *new_policy_duration = base::TimeDelta(); 368 *new_policy_duration = base::TimeDelta();
335 369
336 if (input_stream_state_ == InputStreamState::INACTIVE) 370 if (input_stream_state_ == InputStreamState::INACTIVE)
337 return new_policy; 371 return new_policy;
338 372
339 base::TimeDelta new_priority_duration =
340 base::TimeDelta::FromMilliseconds(kPriorityEscalationAfterInputMillis);
341 Policy input_priority_policy = 373 Policy input_priority_policy =
342 input_stream_state_ == 374 input_stream_state_ ==
343 InputStreamState::ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE 375 InputStreamState::ACTIVE_AND_AWAITING_TOUCHSTART_RESPONSE
344 ? Policy::TOUCHSTART_PRIORITY 376 ? Policy::TOUCHSTART_PRIORITY
345 : Policy::COMPOSITOR_PRIORITY; 377 : Policy::COMPOSITOR_PRIORITY;
346 378 base::TimeDelta time_left_in_policy = TimeLeftInInputEscalatedPolicy();
347 // If the input event is still pending, go into input prioritized policy 379 if (time_left_in_policy > base::TimeDelta()) {
348 // and check again later.
349 if (last_input_process_time_on_main_.is_null() &&
350 !task_queue_manager_->IsQueueEmpty(COMPOSITOR_TASK_QUEUE)) {
351 new_policy = input_priority_policy; 380 new_policy = input_priority_policy;
352 *new_policy_duration = new_priority_duration; 381 *new_policy_duration = time_left_in_policy;
353 } else { 382 } else {
354 // Otherwise make sure the input prioritization policy ends on time. 383 // Reset |input_stream_state_| to ensure
355 base::TimeTicks new_priority_end( 384 // DidReceiveInputEventOnCompositorThread will post an UpdatePolicy task
356 std::max(last_input_receipt_time_on_compositor_, 385 // when it's next called.
357 last_input_process_time_on_main_) + 386 input_stream_state_ = InputStreamState::INACTIVE;
358 new_priority_duration);
359 base::TimeDelta time_left_in_policy = new_priority_end - Now();
360
361 if (time_left_in_policy > base::TimeDelta()) {
362 new_policy = input_priority_policy;
363 *new_policy_duration = time_left_in_policy;
364 } else {
365 // Reset |input_stream_state_| to ensure
366 // DidReceiveInputEventOnCompositorThread will post an UpdatePolicy task
367 // when it's next called.
368 input_stream_state_ = InputStreamState::INACTIVE;
369 }
370 } 387 }
371 return new_policy; 388 return new_policy;
372 } 389 }
373 390
391 bool RendererSchedulerImpl::ShouldStartLongIdlePeriod(
392 const base::TimeTicks& now,
393 base::TimeDelta* next_long_idle_period_delay_out) {
394 DCHECK(main_thread_checker_.CalledOnValidThread());
395
396 MaybeUpdatePolicy();
397 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.
398 // Don't start a long idle task in touch start priority, try again when
399 // the policy is scheduled to end.
400 base::AutoLock lock(incoming_signals_lock_);
401 *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.
402 return false;
403 }
404
405 base::TimeTicks next_pending_delayed_task =
406 task_queue_manager_->NextPendingDelayedTask();
407
408 base::TimeDelta long_idle_period_duration =
409 base::TimeDelta::FromMilliseconds(kMaximumIdlePeriodMillis);
410 if (!next_pending_delayed_task.is_null()) {
411 // Limit the idle period duration to be before the next pending task.
412 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.
413 next_pending_delayed_task - now, long_idle_period_duration);
414 }
415
416 if (long_idle_period_duration > base::TimeDelta()) {
417 *next_long_idle_period_delay_out = long_idle_period_duration;
418 return true;
419 } else {
420 // If we can't start the idle period yet then try again after a short delay.
421 *next_long_idle_period_delay_out =
422 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
423 return false;
424 }
425 }
426
427 void RendererSchedulerImpl::InitiateLongIdlePeriod() {
428 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
429 "AfterWakeupInitiateLongIdlePeriod");
Sami 2015/03/03 16:55:35 Trace event doesn't match the function name.
rmcilroy 2015/03/04 14:23:11 Done.
430 DCHECK(main_thread_checker_.CalledOnValidThread());
431
432 // End any previous idle period.
433 EndIdlePeriod();
434
435 base::TimeTicks now(Now());
436 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.
437 if (ShouldStartLongIdlePeriod(now, &next_long_idle_period_delay_out)) {
438 estimated_next_frame_begin_ = now + next_long_idle_period_delay_out;
439 StartIdlePeriod();
440 }
441
442 if (task_queue_manager_->IsQueueEmpty(IDLE_TASK_QUEUE)) {
443 // If there are no current idle tasks then post the call to initiate the
444 // next idle for execution after wakeup (at which point after-wakeup idle
445 // tasks might be eligible to run or more idle tasks posted).
446 control_task_after_wakeup_runner_->PostDelayedTask(
447 FROM_HERE,
448 after_wakeup_initiate_next_long_idle_period_closure_.callback(),
449 next_long_idle_period_delay_out);
450 } else {
451 // Otherwise post on the normal control task queue.
452 control_task_runner_->PostDelayedTask(
453 FROM_HERE,
454 initiate_next_long_idle_period_closure_.callback(),
455 next_long_idle_period_delay_out);
456 }
457 }
458
459 void RendererSchedulerImpl::AfterWakeupInitiateLongIdlePeriod() {
460 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
461 "AfterWakeupInitiateLongIdlePeriod");
462 DCHECK(main_thread_checker_.CalledOnValidThread());
463 // Since we were asleep until now, end the async idle period trace event at
464 // the time when it would have ended were we awake.
465 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
466 "renderer.scheduler", "RendererSchedulerIdlePeriod", this,
467 std::min(estimated_next_frame_begin_, Now()).ToInternalValue());
468 // Post a task to initiate the next long idle period rather than calling it
469 // directly to allow all pending PostIdleTaskAfterWakeup tasks to get enqueued
470 // on the idle task queue before the next idle period starts so they are
471 // eligible to be run during the new idle period.
472 control_task_runner_->PostTask(
473 FROM_HERE,
474 initiate_next_long_idle_period_closure_.callback());
475 }
476
374 void RendererSchedulerImpl::StartIdlePeriod() { 477 void RendererSchedulerImpl::StartIdlePeriod() {
375 TRACE_EVENT_ASYNC_BEGIN0("renderer.scheduler", 478 TRACE_EVENT_ASYNC_BEGIN0("renderer.scheduler",
376 "RendererSchedulerIdlePeriod", this); 479 "RendererSchedulerIdlePeriod", this);
377 DCHECK(main_thread_checker_.CalledOnValidThread()); 480 DCHECK(main_thread_checker_.CalledOnValidThread());
378 renderer_task_queue_selector_->EnableQueue( 481 renderer_task_queue_selector_->EnableQueue(
379 IDLE_TASK_QUEUE, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY); 482 IDLE_TASK_QUEUE, RendererTaskQueueSelector::BEST_EFFORT_PRIORITY);
380 task_queue_manager_->PumpQueue(IDLE_TASK_QUEUE); 483 task_queue_manager_->PumpQueue(IDLE_TASK_QUEUE);
381 } 484 }
382 485
383 void RendererSchedulerImpl::EndIdlePeriod() { 486 void RendererSchedulerImpl::EndIdlePeriod() {
384 bool is_tracing; 487 bool is_tracing;
385 TRACE_EVENT_CATEGORY_GROUP_ENABLED("renderer.scheduler", &is_tracing); 488 TRACE_EVENT_CATEGORY_GROUP_ENABLED("renderer.scheduler", &is_tracing);
386 if (is_tracing && !estimated_next_frame_begin_.is_null() && 489 if (is_tracing && !estimated_next_frame_begin_.is_null() &&
387 base::TimeTicks::Now() > estimated_next_frame_begin_) { 490 base::TimeTicks::Now() > estimated_next_frame_begin_) {
388 TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0( 491 TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(
389 "renderer.scheduler", 492 "renderer.scheduler",
390 "RendererSchedulerIdlePeriod", 493 "RendererSchedulerIdlePeriod",
391 this, 494 this,
392 "DeadlineOverrun", 495 "DeadlineOverrun",
393 estimated_next_frame_begin_.ToInternalValue()); 496 estimated_next_frame_begin_.ToInternalValue());
394 } 497 }
395 TRACE_EVENT_ASYNC_END0("renderer.scheduler", 498 TRACE_EVENT_ASYNC_END0("renderer.scheduler",
396 "RendererSchedulerIdlePeriod", this); 499 "RendererSchedulerIdlePeriod", this);
397 DCHECK(main_thread_checker_.CalledOnValidThread()); 500 DCHECK(main_thread_checker_.CalledOnValidThread());
398 end_idle_period_closure_.Cancel(); 501 end_idle_period_closure_.Cancel();
502 initiate_next_long_idle_period_closure_.Cancel();
503 after_wakeup_initiate_next_long_idle_period_closure_.Cancel();
399 renderer_task_queue_selector_->DisableQueue(IDLE_TASK_QUEUE); 504 renderer_task_queue_selector_->DisableQueue(IDLE_TASK_QUEUE);
400 } 505 }
401 506
402 void RendererSchedulerImpl::SetTimeSourceForTesting( 507 void RendererSchedulerImpl::SetTimeSourceForTesting(
403 scoped_refptr<cc::TestNowSource> time_source) { 508 scoped_refptr<cc::TestNowSource> time_source) {
404 DCHECK(main_thread_checker_.CalledOnValidThread()); 509 DCHECK(main_thread_checker_.CalledOnValidThread());
405 time_source_ = time_source; 510 time_source_ = time_source;
406 task_queue_manager_->SetTimeSourceForTesting(time_source); 511 task_queue_manager_->SetTimeSourceForTesting(time_source);
407 } 512 }
408 513
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 } 660 }
556 661
557 void RendererSchedulerImpl::RemoveTaskObserver( 662 void RendererSchedulerImpl::RemoveTaskObserver(
558 base::MessageLoop::TaskObserver* task_observer) { 663 base::MessageLoop::TaskObserver* task_observer) {
559 DCHECK(main_thread_checker_.CalledOnValidThread()); 664 DCHECK(main_thread_checker_.CalledOnValidThread());
560 if (task_queue_manager_) 665 if (task_queue_manager_)
561 task_queue_manager_->RemoveTaskObserver(task_observer); 666 task_queue_manager_->RemoveTaskObserver(task_observer);
562 } 667 }
563 668
564 } // namespace content 669 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698