Commit 81c90819 authored by Sadrul Habib Chowdhury's avatar Sadrul Habib Chowdhury Committed by Commit Bot

[cc/metrics] Create reporters for skipped frames.

The display compositor (viz) can skip over some frames for various
reasons, e.g. if the client is non-responsive, or if the gpu is busy
processing previous frames, etc. For these skipped frames, no
corresponding CompositorFrameReporter object is created. As a result,
there are no PipelineReporter trace events, which can make it confusing
when looking for dropped frames. To fix this, for every started frame,
create reporters for any earlier frames that were skipped over by viz.

BUG=1138086

Change-Id: I0b7f90de19d1148ccdb4e1877ee2e56e7ffad717
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2469777
Commit-Queue: Mingjing Zhang <mjzhang@chromium.org>
Reviewed-by: default avatarMingjing Zhang <mjzhang@chromium.org>
Auto-Submit: Sadrul Chowdhury <sadrul@chromium.org>
Cr-Commit-Position: refs/heads/master@{#817182}
parent eac8e059
......@@ -61,8 +61,19 @@ bool CompositorFrameReportingController::HasReporterAt(
return !!reporters_[stage].get();
}
void CompositorFrameReportingController::ProcessSkippedFramesIfNecessary(
const viz::BeginFrameArgs& args) {
if (previous_frame_.IsValid() &&
previous_frame_.frame_id.source_id == args.frame_id.source_id) {
CreateReportersForDroppedFrames(previous_frame_, args);
}
previous_frame_ = args;
}
void CompositorFrameReportingController::WillBeginImplFrame(
const viz::BeginFrameArgs& args) {
ProcessSkippedFramesIfNecessary(args);
base::TimeTicks begin_time = Now();
if (reporters_[PipelineStage::kBeginImplFrame]) {
auto& reporter = reporters_[PipelineStage::kBeginImplFrame];
......@@ -363,6 +374,7 @@ void CompositorFrameReportingController::OnStoppedRequestingBeginFrames() {
now);
}
}
previous_frame_ = {};
}
void CompositorFrameReportingController::SetBlinkBreakdown(
......@@ -466,4 +478,31 @@ CompositorFrameReportingController::GetSmoothThread() const {
: SmoothThread::kSmoothNone;
}
void CompositorFrameReportingController::CreateReportersForDroppedFrames(
const viz::BeginFrameArgs& old_args,
const viz::BeginFrameArgs& new_args) const {
DCHECK_EQ(new_args.frame_id.source_id, old_args.frame_id.source_id);
DCHECK_GE(new_args.frame_id.sequence_number,
old_args.frame_id.sequence_number);
const uint32_t interval =
new_args.frame_id.sequence_number - old_args.frame_id.sequence_number;
auto timestamp = old_args.frame_time + old_args.interval;
for (uint32_t i = 1; i < interval; ++i, timestamp += old_args.interval) {
auto args = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE, old_args.frame_id.source_id,
old_args.frame_id.sequence_number + i, timestamp,
timestamp + old_args.interval, old_args.interval,
viz::BeginFrameArgs::NORMAL);
auto reporter = std::make_unique<CompositorFrameReporter>(
active_trackers_, args, latency_ukm_reporter_.get(),
should_report_metrics_, GetSmoothThread(), layer_tree_host_id_);
reporter->set_tick_clock(tick_clock_);
reporter->StartStage(StageType::kBeginImplFrameToSendBeginMainFrame,
timestamp);
reporter->SetDroppedFrameCounter(dropped_frame_counter_);
reporter->TerminateFrame(FrameTerminationStatus::kDidNotPresentFrame,
args.deadline);
}
}
} // namespace cc
......@@ -119,6 +119,16 @@ class CC_EXPORT CompositorFrameReportingController {
const viz::BeginFrameId& id);
CompositorFrameReporter::SmoothThread GetSmoothThread() const;
// If the display-compositor skips over some frames (e.g. when the gpu is
// busy, or the client is non-responsive), then it will not issue any
// |BeginFrameArgs| for those frames. However, |CompositorFrameReporter|
// instances should still be created for these frames. The following
// functions accomplish this.
void ProcessSkippedFramesIfNecessary(const viz::BeginFrameArgs& args);
void CreateReportersForDroppedFrames(
const viz::BeginFrameArgs& old_args,
const viz::BeginFrameArgs& new_args) const;
const bool should_report_metrics_;
const int layer_tree_host_id_;
......@@ -145,6 +155,9 @@ class CC_EXPORT CompositorFrameReportingController {
// outlive the objects in |submitted_compositor_frames_|.
base::circular_deque<SubmittedCompositorFrame> submitted_compositor_frames_;
// The latest frame that was started.
viz::BeginFrameArgs previous_frame_;
const base::TickClock* tick_clock_ = base::DefaultTickClock::GetInstance();
DroppedFrameCounter* dropped_frame_counter_ = nullptr;
......
......@@ -139,6 +139,7 @@ class CompositorFrameReportingControllerTest : public testing::Test {
args_.frame_id = frame_id;
args_.frame_time = AdvanceNowByMs(10);
args_.interval = base::TimeDelta::FromMilliseconds(16);
current_id_ = frame_id;
return args_;
}
......@@ -1338,5 +1339,45 @@ TEST_F(CompositorFrameReportingControllerTest,
reporting_controller_.SetDroppedFrameCounter(nullptr);
}
TEST_F(CompositorFrameReportingControllerTest,
SkippedFramesFromDisplayCompositorAreDropped) {
DroppedFrameCounter dropped_counter;
reporting_controller_.SetDroppedFrameCounter(&dropped_counter);
// Submit and present two compositor frames.
SimulatePresentCompositorFrame();
EXPECT_EQ(1u, dropped_counter.total_frames());
EXPECT_EQ(0u, dropped_counter.total_main_dropped());
EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
SimulatePresentCompositorFrame();
EXPECT_EQ(2u, dropped_counter.total_frames());
EXPECT_EQ(0u, dropped_counter.total_main_dropped());
EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
// Now skip over a few frames, and submit + present another frame.
const uint32_t kSkipFrames = 5;
for (uint32_t i = 0; i < kSkipFrames; ++i)
IncrementCurrentId();
SimulatePresentCompositorFrame();
EXPECT_EQ(3u + kSkipFrames, dropped_counter.total_frames());
EXPECT_EQ(0u, dropped_counter.total_main_dropped());
EXPECT_EQ(kSkipFrames, dropped_counter.total_compositor_dropped());
// Stop requesting frames, skip over a few frames, and submit + present
// another frame. There should no new dropped frames.
dropped_counter.Reset();
reporting_controller_.OnStoppedRequestingBeginFrames();
for (uint32_t i = 0; i < kSkipFrames; ++i)
IncrementCurrentId();
SimulatePresentCompositorFrame();
EXPECT_EQ(1u, dropped_counter.total_frames());
EXPECT_EQ(0u, dropped_counter.total_main_dropped());
EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
reporting_controller_.ResetReporters();
reporting_controller_.SetDroppedFrameCounter(nullptr);
}
} // namespace
} // namespace cc
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