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

Side by Side Diff: cc/scheduler/scheduler.cc

Issue 1133673004: cc: Heuristic for Renderer latency recovery (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix lots of issues; improve test coverage; Created 5 years, 7 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 2011 The Chromium Authors. All rights reserved. 1 // Copyright 2011 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 "cc/scheduler/scheduler.h" 5 #include "cc/scheduler/scheduler.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/auto_reset.h" 9 #include "base/auto_reset.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 122
123 base::TimeTicks Scheduler::Now() const { 123 base::TimeTicks Scheduler::Now() const {
124 base::TimeTicks now = gfx::FrameTime::Now(); 124 base::TimeTicks now = gfx::FrameTime::Now();
125 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.now"), 125 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.now"),
126 "Scheduler::Now", 126 "Scheduler::Now",
127 "now", 127 "now",
128 now); 128 now);
129 return now; 129 return now;
130 } 130 }
131 131
132 void Scheduler::SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) {
133 authoritative_vsync_interval_ = interval;
134 if (vsync_observer_)
135 vsync_observer_->OnUpdateVSyncParameters(last_vsync_timebase_, interval);
136 }
137
132 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, 138 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
133 base::TimeDelta interval) { 139 base::TimeDelta interval) {
140 TRACE_EVENT2("cc", "Scheduler::CommitVSyncParameters", "timebase",
141 (timebase - base::TimeTicks()).InSecondsF(), "interval",
142 interval.InSecondsF());
143
134 if (authoritative_vsync_interval_ != base::TimeDelta()) { 144 if (authoritative_vsync_interval_ != base::TimeDelta()) {
135 interval = authoritative_vsync_interval_; 145 interval = authoritative_vsync_interval_;
136 } else if (interval == base::TimeDelta()) { 146 } else if (interval == base::TimeDelta()) {
137 // TODO(brianderson): We should not be receiving 0 intervals. 147 // TODO(brianderson): We should not be receiving 0 intervals.
138 interval = BeginFrameArgs::DefaultInterval(); 148 interval = BeginFrameArgs::DefaultInterval();
139 } 149 }
140 150
141 last_vsync_timebase_ = timebase; 151 last_vsync_timebase_ = timebase;
142 152
143 if (vsync_observer_) 153 if (vsync_observer_)
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 BeginImplFrameWithDeadline(adjusted_args); 390 BeginImplFrameWithDeadline(adjusted_args);
381 } 391 }
382 return true; 392 return true;
383 } 393 }
384 394
385 void Scheduler::SetChildrenNeedBeginFrames(bool children_need_begin_frames) { 395 void Scheduler::SetChildrenNeedBeginFrames(bool children_need_begin_frames) {
386 state_machine_.SetChildrenNeedBeginFrames(children_need_begin_frames); 396 state_machine_.SetChildrenNeedBeginFrames(children_need_begin_frames);
387 ProcessScheduledActions(); 397 ProcessScheduledActions();
388 } 398 }
389 399
390 void Scheduler::SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) {
391 authoritative_vsync_interval_ = interval;
392 if (vsync_observer_)
393 vsync_observer_->OnUpdateVSyncParameters(last_vsync_timebase_, interval);
394 }
395
396 void Scheduler::SetVideoNeedsBeginFrames(bool video_needs_begin_frames) { 400 void Scheduler::SetVideoNeedsBeginFrames(bool video_needs_begin_frames) {
397 state_machine_.SetVideoNeedsBeginFrames(video_needs_begin_frames); 401 state_machine_.SetVideoNeedsBeginFrames(video_needs_begin_frames);
398 ProcessScheduledActions(); 402 ProcessScheduledActions();
399 } 403 }
400 404
401 void Scheduler::OnDrawForOutputSurface() { 405 void Scheduler::OnDrawForOutputSurface() {
402 DCHECK(settings_.using_synchronous_renderer_compositor); 406 DCHECK(settings_.using_synchronous_renderer_compositor);
403 DCHECK_EQ(state_machine_.begin_impl_frame_state(), 407 DCHECK_EQ(state_machine_.begin_impl_frame_state(),
404 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); 408 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
405 DCHECK(!BeginImplFrameDeadlinePending()); 409 DCHECK(!BeginImplFrameDeadlinePending());
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 args.AsValue(), "main_thread_is_high_latency", 495 args.AsValue(), "main_thread_is_high_latency",
492 main_thread_is_in_high_latency_mode); 496 main_thread_is_in_high_latency_mode);
493 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), 497 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
494 "MainThreadLatency", main_thread_is_in_high_latency_mode); 498 "MainThreadLatency", main_thread_is_in_high_latency_mode);
495 499
496 advance_commit_state_task_.Cancel(); 500 advance_commit_state_task_.Cancel();
497 501
498 begin_impl_frame_args_ = args; 502 begin_impl_frame_args_ = args;
499 begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate(); 503 begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate();
500 504
501 if (!state_machine_.impl_latency_takes_priority() && 505 BeginImplFrame();
502 main_thread_is_in_high_latency_mode && 506 // Decide if we want skip any actions before we ProcessScheduledActions
503 CanCommitAndActivateBeforeDeadline()) { 507 // so that they take effect immediately rather than with a 1 frame delay.
508 // Prioritize skipping the main thread's latency first so we can keep the
509 // main and impl threads synchronized. Then skip an impl frame if it makes
510 // sense. This avoids skipping both at the same time to avoid strange
511 // interactions/oscillations since ShouldRecoverImplLatency() depends on
512 // whether the main thread is in a high latency mode or not.
513 if (ShouldRecoverMainLatency()) {
514 TRACE_EVENT_INSTANT1("cc", "SkipBeginMainFrameToReduceLatency",
515 TRACE_EVENT_SCOPE_THREAD, "state", AsValue());
504 state_machine_.SetSkipNextBeginMainFrameToReduceLatency(); 516 state_machine_.SetSkipNextBeginMainFrameToReduceLatency();
517 } else if (ShouldRecoverImplLatency()) {
518 TRACE_EVENT_INSTANT1("cc", "SkipNextSwapToReduceLatency",
519 TRACE_EVENT_SCOPE_THREAD, "state", AsValue());
520 state_machine_.SetSkipNextSwapToReduceLatency();
sunnyps 2015/05/21 23:42:23 Can we call FinishImplFrame here instead of going
brianderson 2015/05/22 01:12:53 That's a good idea. I'll give it a try!
505 } 521 }
506 522 ProcessScheduledActions();
sunnyps 2015/05/21 23:42:23 Any particular reason for splitting ProcessSchedul
brianderson 2015/05/22 01:12:53 SchedulerStateMachine::OnBeginImplFrame resets the
507 BeginImplFrame();
508 523
509 // The deadline will be scheduled in ProcessScheduledActions. 524 // The deadline will be scheduled in ProcessScheduledActions.
510 state_machine_.OnBeginImplFrameDeadlinePending(); 525 state_machine_.OnBeginImplFrameDeadlinePending();
511 ProcessScheduledActions(); 526 ProcessScheduledActions();
512 } 527 }
513 528
514 void Scheduler::BeginImplFrameSynchronous(const BeginFrameArgs& args) { 529 void Scheduler::BeginImplFrameSynchronous(const BeginFrameArgs& args) {
515 TRACE_EVENT1("cc,benchmark", "Scheduler::BeginImplFrame", "args", 530 TRACE_EVENT1("cc,benchmark", "Scheduler::BeginImplFrame", "args",
516 args.AsValue()); 531 args.AsValue());
517 begin_impl_frame_args_ = args; 532 begin_impl_frame_args_ = args;
518 BeginImplFrame(); 533 BeginImplFrame();
534 ProcessScheduledActions();
535
519 FinishImplFrame(); 536 FinishImplFrame();
520 } 537 }
521 538
522 void Scheduler::FinishImplFrame() { 539 void Scheduler::FinishImplFrame() {
523 state_machine_.OnBeginImplFrameIdle(); 540 state_machine_.OnBeginImplFrameIdle();
524 ProcessScheduledActions(); 541 ProcessScheduledActions();
525 542
526 client_->DidFinishImplFrame(); 543 client_->DidFinishImplFrame();
527 frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); 544 frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
528 } 545 }
529 546
530 // BeginImplFrame starts a compositor frame that will wait up until a deadline 547 // BeginImplFrame starts a compositor frame that will wait up until a deadline
531 // for a BeginMainFrame+activation to complete before it times out and draws 548 // for a BeginMainFrame+activation to complete before it times out and draws
532 // any asynchronous animation and scroll/pinch updates. 549 // any asynchronous animation and scroll/pinch updates.
533 void Scheduler::BeginImplFrame() { 550 void Scheduler::BeginImplFrame() {
534 DCHECK_EQ(state_machine_.begin_impl_frame_state(), 551 DCHECK_EQ(state_machine_.begin_impl_frame_state(),
535 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); 552 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
536 DCHECK(!BeginImplFrameDeadlinePending()); 553 DCHECK(!BeginImplFrameDeadlinePending());
537 DCHECK(state_machine_.HasInitializedOutputSurface()); 554 DCHECK(state_machine_.HasInitializedOutputSurface());
538 DCHECK(advance_commit_state_task_.IsCancelled()); 555 DCHECK(advance_commit_state_task_.IsCancelled());
539 556
540 state_machine_.OnBeginImplFrame(); 557 state_machine_.OnBeginImplFrame();
541 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_); 558 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
542 client_->WillBeginImplFrame(begin_impl_frame_args_); 559 client_->WillBeginImplFrame(begin_impl_frame_args_);
543
544 ProcessScheduledActions();
545 } 560 }
546 561
547 void Scheduler::ScheduleBeginImplFrameDeadline() { 562 void Scheduler::ScheduleBeginImplFrameDeadline() {
548 // The synchronous compositor does not post a deadline task. 563 // The synchronous compositor does not post a deadline task.
549 DCHECK(!settings_.using_synchronous_renderer_compositor); 564 DCHECK(!settings_.using_synchronous_renderer_compositor);
550 565
551 begin_impl_frame_deadline_task_.Cancel(); 566 begin_impl_frame_deadline_task_.Cancel();
552 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); 567 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
553 568
554 begin_impl_frame_deadline_mode_ = 569 begin_impl_frame_deadline_mode_ =
555 state_machine_.CurrentBeginImplFrameDeadlineMode(); 570 state_machine_.CurrentBeginImplFrameDeadlineMode();
556
557 base::TimeTicks deadline; 571 base::TimeTicks deadline;
558 switch (begin_impl_frame_deadline_mode_) { 572 switch (begin_impl_frame_deadline_mode_) {
559 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE: 573 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE:
560 // No deadline. 574 // No deadline.
561 return; 575 return;
562 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE: 576 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE:
563 // We are ready to draw a new active tree immediately. 577 // We are ready to draw a new active tree immediately.
564 // We don't use Now() here because it's somewhat expensive to call. 578 // We don't use Now() here because it's somewhat expensive to call.
565 deadline = base::TimeTicks(); 579 deadline = base::TimeTicks();
566 break; 580 break;
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
764 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); 778 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size());
765 state->SetBoolean("begin_retro_frame_task_", 779 state->SetBoolean("begin_retro_frame_task_",
766 !begin_retro_frame_task_.IsCancelled()); 780 !begin_retro_frame_task_.IsCancelled());
767 state->SetBoolean("begin_impl_frame_deadline_task_", 781 state->SetBoolean("begin_impl_frame_deadline_task_",
768 !begin_impl_frame_deadline_task_.IsCancelled()); 782 !begin_impl_frame_deadline_task_.IsCancelled());
769 state->SetBoolean("advance_commit_state_task_", 783 state->SetBoolean("advance_commit_state_task_",
770 !advance_commit_state_task_.IsCancelled()); 784 !advance_commit_state_task_.IsCancelled());
771 state->BeginDictionary("begin_impl_frame_args"); 785 state->BeginDictionary("begin_impl_frame_args");
772 begin_impl_frame_args_.AsValueInto(state); 786 begin_impl_frame_args_.AsValueInto(state);
773 state->EndDictionary(); 787 state->EndDictionary();
788 state->SetString("begin_impl_frame_deadline_mode_",
789 SchedulerStateMachine::BeginImplFrameDeadlineModeToString(
790 begin_impl_frame_deadline_mode_));
774 791
775 base::TimeTicks now = Now(); 792 base::TimeTicks now = Now();
776 base::TimeTicks frame_time = begin_impl_frame_args_.frame_time; 793 base::TimeTicks frame_time = begin_impl_frame_args_.frame_time;
777 base::TimeTicks deadline = begin_impl_frame_args_.deadline; 794 base::TimeTicks deadline = begin_impl_frame_args_.deadline;
778 base::TimeDelta interval = begin_impl_frame_args_.interval; 795 base::TimeDelta interval = begin_impl_frame_args_.interval;
779 state->BeginDictionary("major_timestamps_in_ms"); 796 state->BeginDictionary("major_timestamps_in_ms");
780 state->SetDouble("0_interval", interval.InMillisecondsF()); 797 state->SetDouble("0_interval", interval.InMillisecondsF());
781 state->SetDouble("1_now_to_deadline", (deadline - now).InMillisecondsF()); 798 state->SetDouble("1_now_to_deadline", (deadline - now).InMillisecondsF());
782 state->SetDouble("2_frame_time_to_now", (now - frame_time).InMillisecondsF()); 799 state->SetDouble("2_frame_time_to_now", (now - frame_time).InMillisecondsF());
783 state->SetDouble("3_frame_time_to_deadline", 800 state->SetDouble("3_frame_time_to_deadline",
(...skipping 12 matching lines...) Expand all
796 client_->DrawDurationEstimate().InMillisecondsF()); 813 client_->DrawDurationEstimate().InMillisecondsF());
797 state->SetDouble( 814 state->SetDouble(
798 "begin_main_frame_to_commit_duration_estimate_ms", 815 "begin_main_frame_to_commit_duration_estimate_ms",
799 client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF()); 816 client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF());
800 state->SetDouble( 817 state->SetDouble(
801 "commit_to_activate_duration_estimate_ms", 818 "commit_to_activate_duration_estimate_ms",
802 client_->CommitToActivateDurationEstimate().InMillisecondsF()); 819 client_->CommitToActivateDurationEstimate().InMillisecondsF());
803 state->EndDictionary(); 820 state->EndDictionary();
804 } 821 }
805 822
823 bool Scheduler::ShouldRecoverMainLatency() const {
824 TRACE_EVENT0("cc", "ShouldRecoverMainLatency");
825 if (!state_machine_.MainThreadIsInHighLatencyMode())
826 return false;
827
828 if (state_machine_.impl_latency_takes_priority())
829 return false;
830
831 return CanCommitAndActivateBeforeDeadline();
832 }
833
834 bool Scheduler::ShouldRecoverImplLatency() const {
835 TRACE_EVENT1("cc", "ShouldRecoverImplLatency",
836 "swaps_are_likely_high_latency",
837 state_machine_.swaps_are_likely_high_latency());
838 if (!state_machine_.swaps_are_likely_high_latency())
sunnyps 2015/05/21 23:42:22 When is swaps_are_likely_high_latency != pending_s
brianderson 2015/05/22 01:12:53 When the swap ack for a BeginImplFrame(1) comes ba
839 return false;
840
841 bool frame_time_is_before_deadline =
sunnyps 2015/05/21 23:42:23 Maybe we shouldn't adjust the deadline in begin_im
brianderson 2015/05/22 01:12:53 Are you saying the logic would be easier to follow
842 begin_impl_frame_args_.frame_time < begin_impl_frame_args_.deadline;
843
844 auto next_begin_impl_frame_deadline_mode =
sunnyps 2015/05/21 23:42:23 nit: Let's not use auto here.
brianderson 2015/05/22 01:12:53 Done.
845 state_machine_.CurrentBeginImplFrameDeadlineMode();
846 switch (next_begin_impl_frame_deadline_mode) {
847 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE:
848 return false;
849 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE:
850 return frame_time_is_before_deadline;
851 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR:
852 return frame_time_is_before_deadline;
853 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE:
854 return CanCommitAndActivateBeforeDeadline();
855 case SchedulerStateMachine::
856 BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW:
857 return false;
858 }
859 NOTREACHED();
860 return false;
861 }
862
806 bool Scheduler::CanCommitAndActivateBeforeDeadline() const { 863 bool Scheduler::CanCommitAndActivateBeforeDeadline() const {
807 // Check if the main thread computation and commit can be finished before the 864 // Check if the main thread computation and commit can be finished before the
808 // impl thread's deadline. 865 // impl thread's deadline.
809 base::TimeTicks estimated_draw_time = 866 base::TimeTicks estimated_draw_time =
810 begin_impl_frame_args_.frame_time + 867 begin_impl_frame_args_.frame_time +
811 client_->BeginMainFrameToCommitDurationEstimate() + 868 client_->BeginMainFrameToCommitDurationEstimate() +
812 client_->CommitToActivateDurationEstimate(); 869 client_->CommitToActivateDurationEstimate();
813 870
814 TRACE_EVENT2(
815 TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
816 "CanCommitAndActivateBeforeDeadline",
817 "time_left_after_drawing_ms",
818 (begin_impl_frame_args_.deadline - estimated_draw_time).InMillisecondsF(),
819 "state",
820 AsValue());
821
822 return estimated_draw_time < begin_impl_frame_args_.deadline; 871 return estimated_draw_time < begin_impl_frame_args_.deadline;
823 } 872 }
824 873
825 bool Scheduler::IsBeginMainFrameSentOrStarted() const { 874 bool Scheduler::IsBeginMainFrameSentOrStarted() const {
826 return (state_machine_.commit_state() == 875 return (state_machine_.commit_state() ==
827 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || 876 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT ||
828 state_machine_.commit_state() == 877 state_machine_.commit_state() ==
829 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); 878 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED);
830 } 879 }
831 880
832 } // namespace cc 881 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698