Commit 1607d912 authored by Sunny Sachanandani's avatar Sunny Sachanandani Committed by Commit Bot

Reland "cc: Throttle incoming begin frames in scheduler"

This is a reland of 6beef1e6

Removed incorrect DCHECKs that were added in the original change.

Original change's description:
> cc: Throttle incoming begin frames in scheduler
>
> Unlike PostTask from IO thread to compositor thread in Chrome IPC, mojo
> polls for messages on the compositor thread which means it can dequeue a
> large number of begin frame messages after the compositor thread has
> been busy for some time. All but the last begin frame cancels the
> previous begin frame, and is essentially a nop, but it still ticks
> animations. When a page has a large number of animations each begin
> frame can take a long time and push out other tasks such as tile manager
> callbacks stalling the pipeline.
>
> Throttling the begin frames in viz doesn't fully solve the problem
> because we have to allow at least two begin frames in flight for
> pipelining, and so the client can still process two begin frames back to
> back.
>
> Throttling in AsyncLTFS causes issues with LTFS lifetime and ordering
> with respect to other messages.
>
> Saving incoming begin frame in scheduler and posting a task works and
> ensures that only one begin frame is outstanding at any time.
>
> R=danakj
> BUG=782002
>
> Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;master.tryserver.blink:linux_trusty_blink_rel
> Change-Id: I247a87ad7475d33f878a215ce87056d20482f88c
> Reviewed-on: https://chromium-review.googlesource.com/1130082
> Commit-Queue: Sunny Sachanandani <sunnyps@chromium.org>
> Reviewed-by: danakj <danakj@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#577046}

TBR=danakj
BUG=782002

Change-Id: Iec7bd9e421bdb372f101ecebc6cb71835dcb27bf
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;master.tryserver.blink:linux_trusty_blink_rel
Reviewed-on: https://chromium-review.googlesource.com/1147082
Commit-Queue: Sunny Sachanandani <sunnyps@chromium.org>
Reviewed-by: default avatarSunny Sachanandani <sunnyps@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577332}
parent 2a37c011
This diff is collapsed.
...@@ -193,6 +193,7 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { ...@@ -193,6 +193,7 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
std::unique_ptr<CompositorTimingHistory> compositor_timing_history_; std::unique_ptr<CompositorTimingHistory> compositor_timing_history_;
// What the latest deadline was, and when it was scheduled.
SchedulerStateMachine::BeginImplFrameDeadlineMode SchedulerStateMachine::BeginImplFrameDeadlineMode
begin_impl_frame_deadline_mode_ = begin_impl_frame_deadline_mode_ =
SchedulerStateMachine::BeginImplFrameDeadlineMode::NONE; SchedulerStateMachine::BeginImplFrameDeadlineMode::NONE;
...@@ -202,9 +203,18 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { ...@@ -202,9 +203,18 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
BeginFrameTracker begin_impl_frame_tracker_; BeginFrameTracker begin_impl_frame_tracker_;
viz::BeginFrameArgs begin_main_frame_args_; viz::BeginFrameArgs begin_main_frame_args_;
base::Closure begin_impl_frame_deadline_closure_; // Task posted for the deadline or drawing phase of the scheduler. This task
base::CancelableClosure begin_impl_frame_deadline_task_; // can be rescheduled e.g. when the condition for the deadline is met, it is
base::CancelableClosure missed_begin_frame_task_; // scheduled to run immediately.
// NOTE: Scheduler weak ptrs are not necessary if CancelableCallback is used.
base::CancelableOnceClosure begin_impl_frame_deadline_task_;
// This is used for queueing begin frames while scheduler is waiting for
// previous frame's deadline, or if it's inside ProcessScheduledActions().
// Only one such task is posted at any time, but the args are updated as we
// get new begin frames.
viz::BeginFrameArgs pending_begin_frame_args_;
base::CancelableOnceClosure pending_begin_frame_task_;
SchedulerStateMachine state_machine_; SchedulerStateMachine state_machine_;
bool inside_process_scheduled_actions_ = false; bool inside_process_scheduled_actions_ = false;
...@@ -215,11 +225,32 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { ...@@ -215,11 +225,32 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
bool stopped_ = false; bool stopped_ = false;
private: private:
// Posts the deadline task if needed by checking
// SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode(). This only
// happens when the scheduler is processing a begin frame
// (BeginImplFrameState::INSIDE_BEGIN_FRAME).
void ScheduleBeginImplFrameDeadline(); void ScheduleBeginImplFrameDeadline();
void ScheduleBeginImplFrameDeadlineIfNeeded();
// Starts or stops begin frames as needed by checking
// SchedulerStateMachine::BeginFrameNeeded(). This only happens when the
// scheduler is not processing a begin frame (BeginImplFrameState::IDLE).
void StartOrStopBeginFrames();
// This will only post a task if the args are valid and there's no existing
// task. That implies that we're still expecting begin frames. If begin frames
// aren't needed this will be a nop. This only happens when the scheduler is
// not processing a begin frame (BeginImplFrameState::IDLE).
void PostPendingBeginFrameTask();
// Use |pending_begin_frame_args_| to begin a new frame like it was received
// in OnBeginFrameDerivedImpl().
void HandlePendingBeginFrame();
// Used to drop the pending begin frame before we go idle.
void CancelPendingBeginFrameTask();
void BeginImplFrameNotExpectedSoon(); void BeginImplFrameNotExpectedSoon();
void BeginMainFrameNotExpectedUntil(base::TimeTicks time); void BeginMainFrameNotExpectedUntil(base::TimeTicks time);
void SetupNextBeginFrameIfNeeded();
void DrawIfPossible(); void DrawIfPossible();
void DrawForced(); void DrawForced();
void ProcessScheduledActions(); void ProcessScheduledActions();
...@@ -235,6 +266,7 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { ...@@ -235,6 +266,7 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
base::TimeTicks now) const; base::TimeTicks now) const;
void AdvanceCommitStateIfPossible(); void AdvanceCommitStateIfPossible();
bool IsBeginMainFrameSentOrStarted() const; bool IsBeginMainFrameSentOrStarted() const;
void BeginImplFrameWithDeadline(const viz::BeginFrameArgs& args); void BeginImplFrameWithDeadline(const viz::BeginFrameArgs& args);
void BeginImplFrameSynchronous(const viz::BeginFrameArgs& args); void BeginImplFrameSynchronous(const viz::BeginFrameArgs& args);
void BeginImplFrame(const viz::BeginFrameArgs& args, base::TimeTicks now); void BeginImplFrame(const viz::BeginFrameArgs& args, base::TimeTicks now);
...@@ -250,8 +282,6 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase { ...@@ -250,8 +282,6 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
return inside_action_ == action; return inside_action_ == action;
} }
base::WeakPtrFactory<Scheduler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(Scheduler); DISALLOW_COPY_AND_ASSIGN(Scheduler);
}; };
......
...@@ -1076,12 +1076,18 @@ void SchedulerStateMachine::OnBeginImplFrameIdle() { ...@@ -1076,12 +1076,18 @@ void SchedulerStateMachine::OnBeginImplFrameIdle() {
SchedulerStateMachine::BeginImplFrameDeadlineMode SchedulerStateMachine::BeginImplFrameDeadlineMode
SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const { SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const {
if (settings_.using_synchronous_renderer_compositor) { const bool outside_begin_frame =
// No deadline for synchronous compositor. begin_impl_frame_state_ != BeginImplFrameState::INSIDE_BEGIN_FRAME;
if (settings_.using_synchronous_renderer_compositor || outside_begin_frame) {
// No deadline for synchronous compositor, or when outside the begin frame.
return BeginImplFrameDeadlineMode::NONE; return BeginImplFrameDeadlineMode::NONE;
} else if (ShouldBlockDeadlineIndefinitely()) { } else if (ShouldBlockDeadlineIndefinitely()) {
// We do not want to wait for a deadline because we're waiting for full
// pipeline to be flushed for headless.
return BeginImplFrameDeadlineMode::BLOCKED; return BeginImplFrameDeadlineMode::BLOCKED;
} else if (ShouldTriggerBeginImplFrameDeadlineImmediately()) { } else if (ShouldTriggerBeginImplFrameDeadlineImmediately()) {
// We are ready to draw a new active tree immediately because there's no
// commit expected or we're prioritizing active tree latency.
return BeginImplFrameDeadlineMode::IMMEDIATE; return BeginImplFrameDeadlineMode::IMMEDIATE;
} else if (needs_redraw_) { } else if (needs_redraw_) {
// We have an animation or fast input path on the impl thread that wants // We have an animation or fast input path on the impl thread that wants
...@@ -1089,7 +1095,7 @@ SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const { ...@@ -1089,7 +1095,7 @@ SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const {
return BeginImplFrameDeadlineMode::REGULAR; return BeginImplFrameDeadlineMode::REGULAR;
} else { } else {
// The impl thread doesn't have anything it wants to draw and we are just // The impl thread doesn't have anything it wants to draw and we are just
// waiting for a new active tree. In short we are blocked. // waiting for a new active tree.
return BeginImplFrameDeadlineMode::LATE; return BeginImplFrameDeadlineMode::LATE;
} }
} }
......
...@@ -69,12 +69,18 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -69,12 +69,18 @@ class CC_EXPORT SchedulerStateMachine {
}; };
static const char* BeginImplFrameStateToString(BeginImplFrameState state); static const char* BeginImplFrameStateToString(BeginImplFrameState state);
// The scheduler uses a deadline to wait for main thread updates before
// submitting a compositor frame. BeginImplFrameDeadlineMode specifies when
// the deadline should run.
enum class BeginImplFrameDeadlineMode { enum class BeginImplFrameDeadlineMode {
NONE, NONE, // No deadline should be scheduled e.g. for synchronous compositor.
IMMEDIATE, IMMEDIATE, // Deadline should be scheduled to run immediately.
REGULAR, REGULAR, // Deadline should be scheduled to run at the deadline provided by
LATE, // in the BeginFrameArgs.
BLOCKED, LATE, // Deadline should be scheduled run when the next frame is expected
// to arrive.
BLOCKED, // Deadline should be blocked indefinitely until the next frame
// arrives.
}; };
static const char* BeginImplFrameDeadlineModeToString( static const char* BeginImplFrameDeadlineModeToString(
BeginImplFrameDeadlineMode mode); BeginImplFrameDeadlineMode mode);
...@@ -168,6 +174,8 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -168,6 +174,8 @@ class CC_EXPORT SchedulerStateMachine {
BeginImplFrameState begin_impl_frame_state() const { BeginImplFrameState begin_impl_frame_state() const {
return begin_impl_frame_state_; return begin_impl_frame_state_;
} }
// Returns BeginImplFrameDeadlineMode computed based on current state.
BeginImplFrameDeadlineMode CurrentBeginImplFrameDeadlineMode() const; BeginImplFrameDeadlineMode CurrentBeginImplFrameDeadlineMode() const;
// If the main thread didn't manage to produce a new frame in time for the // If the main thread didn't manage to produce a new frame in time for the
...@@ -320,13 +328,20 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -320,13 +328,20 @@ class CC_EXPORT SchedulerStateMachine {
bool BeginFrameNeededForVideo() const; bool BeginFrameNeededForVideo() const;
bool ProactiveBeginFrameWanted() const; bool ProactiveBeginFrameWanted() const;
// Indicates if we should post the deadline to draw immediately. This is true
// when we aren't expecting a commit or activation, or we're prioritizing
// active tree draw (see ImplLatencyTakesPriority()).
bool ShouldTriggerBeginImplFrameDeadlineImmediately() const;
// Indicates if we shouldn't schedule a deadline. Used to defer drawing until
// the entire pipeline is flushed and active tree is ready to draw for
// headless.
bool ShouldBlockDeadlineIndefinitely() const;
bool ShouldPerformImplSideInvalidation() const; bool ShouldPerformImplSideInvalidation() const;
bool CouldCreatePendingTree() const; bool CouldCreatePendingTree() const;
bool ShouldDeferInvalidatingForMainFrame() const; bool ShouldDeferInvalidatingForMainFrame() const;
bool ShouldTriggerBeginImplFrameDeadlineImmediately() const;
bool ShouldBlockDeadlineIndefinitely() const;
bool ShouldAbortCurrentFrame() const; bool ShouldAbortCurrentFrame() const;
bool ShouldBeginLayerTreeFrameSinkCreation() const; bool ShouldBeginLayerTreeFrameSinkCreation() const;
......
...@@ -511,6 +511,9 @@ class SchedulerTest : public testing::Test { ...@@ -511,6 +511,9 @@ class SchedulerTest : public testing::Test {
if (scheduler_->begin_frame_source() == if (scheduler_->begin_frame_source() ==
fake_external_begin_frame_source_.get()) { fake_external_begin_frame_source_.get()) {
EXPECT_TRUE(scheduler_->begin_frames_expected()); EXPECT_TRUE(scheduler_->begin_frames_expected());
// Run the deadline first if we're inside the previous frame.
if (client_->IsInsideBeginImplFrame())
task_runner_->RunPendingTasks();
SendNextBeginFrame(animate_only); SendNextBeginFrame(animate_only);
} else { } else {
task_runner_->RunTasksWhile(client_->FrameHasNotAdvancedCallback()); task_runner_->RunTasksWhile(client_->FrameHasNotAdvancedCallback());
...@@ -3678,10 +3681,11 @@ TEST_F(SchedulerTest, BeginFrameAckForBeginFrameBeforeLastDeadline) { ...@@ -3678,10 +3681,11 @@ TEST_F(SchedulerTest, BeginFrameAckForBeginFrameBeforeLastDeadline) {
client_->Reset(); client_->Reset();
// Send the next BeginFrame before the previous one's deadline was executed. // Send the next BeginFrame before the previous one's deadline was executed.
// This should trigger the previous BeginFrame's deadline synchronously, // This should post the previous BeginFrame's deadline, during which tiles
// during which tiles will be prepared. As a result of that, no further // will be prepared. As a result of that, no further BeginFrames will be
// BeginFrames will be needed, and the new BeginFrame should be dropped. // needed, and the new BeginFrame should be dropped.
viz::BeginFrameArgs args = SendNextBeginFrame(); viz::BeginFrameArgs args = SendNextBeginFrame();
task_runner_->RunPendingTasks(); // Run posted deadline.
EXPECT_ACTIONS("ScheduledActionPrepareTiles", "RemoveObserver(this)"); EXPECT_ACTIONS("ScheduledActionPrepareTiles", "RemoveObserver(this)");
EXPECT_FALSE(client_->IsInsideBeginImplFrame()); EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_FALSE(scheduler_->begin_frames_expected()); EXPECT_FALSE(scheduler_->begin_frames_expected());
...@@ -3748,6 +3752,7 @@ TEST_F(SchedulerTest, BeginFrameAckForLateMissedBeginFrame) { ...@@ -3748,6 +3752,7 @@ TEST_F(SchedulerTest, BeginFrameAckForLateMissedBeginFrame) {
task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval()); task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
EXPECT_GT(task_runner_->NowTicks(), args.deadline); EXPECT_GT(task_runner_->NowTicks(), args.deadline);
fake_external_begin_frame_source_->TestOnBeginFrame(args); fake_external_begin_frame_source_->TestOnBeginFrame(args);
task_runner_->RunPendingTasks();
EXPECT_NO_ACTION(); EXPECT_NO_ACTION();
EXPECT_FALSE(client_->IsInsideBeginImplFrame()); EXPECT_FALSE(client_->IsInsideBeginImplFrame());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment