Commit 8daa3cc3 authored by behdad's avatar behdad Committed by Commit Bot

Reporting the max percent dropped frame of sliding window

This change sets the max percent dropped frames of a 1 second sliding
window of frames as worst_smoothness.

Bug: 1115141
Change-Id: Iaab465289a72f1cc80a1d75a7836016a5c0ab53b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2532672
Commit-Queue: Behdad Bakhshinategh <behdadb@chromium.org>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Reviewed-by: default avatarJonathan Ross <jonross@chromium.org>
Reviewed-by: default avatarAlexei Svitkine <asvitkine@chromium.org>
Reviewed-by: default avatarJohn Chen <johnchen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#828995}
parent 957cd8a0
...@@ -4,7 +4,11 @@ ...@@ -4,7 +4,11 @@
#include "cc/metrics/dropped_frame_counter.h" #include "cc/metrics/dropped_frame_counter.h"
#include <algorithm>
#include "base/bind.h" #include "base/bind.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "cc/metrics/frame_sorter.h" #include "cc/metrics/frame_sorter.h"
#include "cc/metrics/total_frame_counter.h" #include "cc/metrics/total_frame_counter.h"
...@@ -67,11 +71,15 @@ void DroppedFrameCounter::ReportFrames() { ...@@ -67,11 +71,15 @@ void DroppedFrameCounter::ReportFrames() {
total_counter_->ComputeTotalVisibleFrames(base::TimeTicks::Now()); total_counter_->ComputeTotalVisibleFrames(base::TimeTicks::Now());
TRACE_EVENT2("cc,benchmark", "SmoothnessDroppedFrame", "total", total_frames, TRACE_EVENT2("cc,benchmark", "SmoothnessDroppedFrame", "total", total_frames,
"smoothness", total_smoothness_dropped_); "smoothness", total_smoothness_dropped_);
UMA_HISTOGRAM_PERCENTAGE(
"Graphics.Smoothness.MaxPercentDroppedFrames_1sWindow",
sliding_window_max_percent_dropped_);
if (ukm_smoothness_data_ && total_frames > 0) { if (ukm_smoothness_data_ && total_frames > 0) {
UkmSmoothnessData smoothness_data; UkmSmoothnessData smoothness_data;
smoothness_data.avg_smoothness = smoothness_data.avg_smoothness =
static_cast<double>(total_smoothness_dropped_) * 100 / total_frames; static_cast<double>(total_smoothness_dropped_) * 100 / total_frames;
smoothness_data.worst_smoothness = sliding_window_max_percent_dropped_;
ukm_smoothness_data_->seq_lock.WriteBegin(); ukm_smoothness_data_->seq_lock.WriteBegin();
device::OneWriterSeqLock::AtomicWriterMemcpy(&ukm_smoothness_data_->data, device::OneWriterSeqLock::AtomicWriterMemcpy(&ukm_smoothness_data_->data,
...@@ -91,14 +99,46 @@ void DroppedFrameCounter::Reset() { ...@@ -91,14 +99,46 @@ void DroppedFrameCounter::Reset() {
total_partial_ = 0; total_partial_ = 0;
total_dropped_ = 0; total_dropped_ = 0;
total_smoothness_dropped_ = 0; total_smoothness_dropped_ = 0;
sliding_window_max_percent_dropped_ = 0;
dropped_frame_count_in_window_ = 0;
fcp_received_ = false; fcp_received_ = false;
sliding_window_ = {};
ring_buffer_.Clear(); ring_buffer_.Clear();
frame_sorter_.Reset(); frame_sorter_.Reset();
} }
base::TimeDelta DroppedFrameCounter::ComputeCurrentWindowSize() const {
DCHECK_GT(sliding_window_.size(), 0u);
return sliding_window_.back().first.frame_time +
sliding_window_.back().first.interval -
sliding_window_.front().first.frame_time;
}
void DroppedFrameCounter::NotifyFrameResult(const viz::BeginFrameArgs& args, void DroppedFrameCounter::NotifyFrameResult(const viz::BeginFrameArgs& args,
bool is_dropped) { bool is_dropped) {
// TODO(crbug.com/1115141) The implementation of smoothness metrics. sliding_window_.push({args, is_dropped});
if (is_dropped)
dropped_frame_count_in_window_++;
if (ComputeCurrentWindowSize() < kSlidingWindowInterval)
return;
DCHECK_GE(dropped_frame_count_in_window_, 0u);
DCHECK_GE(sliding_window_.size(), dropped_frame_count_in_window_);
DCHECK_GT(kSlidingWindowInterval, args.interval);
// args.interval being lower than the window interval guarantees that queue
// would not be empty at any point in the loop below.
double percent_dropped_frame =
(dropped_frame_count_in_window_ * 100.0) / sliding_window_.size();
sliding_window_max_percent_dropped_ =
fmax(sliding_window_max_percent_dropped_, percent_dropped_frame);
while (ComputeCurrentWindowSize() >= kSlidingWindowInterval) {
if (sliding_window_.front().second) // If frame is dropped.
dropped_frame_count_in_window_--;
sliding_window_.pop();
}
} }
void DroppedFrameCounter::OnFcpReceived() { void DroppedFrameCounter::OnFcpReceived() {
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#define CC_METRICS_DROPPED_FRAME_COUNTER_H_ #define CC_METRICS_DROPPED_FRAME_COUNTER_H_
#include <stddef.h> #include <stddef.h>
#include <queue>
#include <utility>
#include "base/containers/ring_buffer.h" #include "base/containers/ring_buffer.h"
#include "cc/cc_export.h" #include "cc/cc_export.h"
...@@ -64,8 +66,18 @@ class CC_EXPORT DroppedFrameCounter { ...@@ -64,8 +66,18 @@ class CC_EXPORT DroppedFrameCounter {
total_counter_ = total_counter; total_counter_ = total_counter;
} }
double sliding_window_max_percent_dropped() const {
return sliding_window_max_percent_dropped_;
}
private: private:
void NotifyFrameResult(const viz::BeginFrameArgs& args, bool is_dropped); void NotifyFrameResult(const viz::BeginFrameArgs& args, bool is_dropped);
base::TimeDelta ComputeCurrentWindowSize() const;
const base::TimeDelta kSlidingWindowInterval =
base::TimeDelta::FromSeconds(1);
std::queue<std::pair<const viz::BeginFrameArgs, bool>> sliding_window_;
uint32_t dropped_frame_count_in_window_ = 0;
RingBufferType ring_buffer_; RingBufferType ring_buffer_;
size_t total_frames_ = 0; size_t total_frames_ = 0;
...@@ -73,6 +85,7 @@ class CC_EXPORT DroppedFrameCounter { ...@@ -73,6 +85,7 @@ class CC_EXPORT DroppedFrameCounter {
size_t total_dropped_ = 0; size_t total_dropped_ = 0;
size_t total_smoothness_dropped_ = 0; size_t total_smoothness_dropped_ = 0;
bool fcp_received_ = false; bool fcp_received_ = false;
double sliding_window_max_percent_dropped_ = 0;
UkmSmoothnessDataShared* ukm_smoothness_data_ = nullptr; UkmSmoothnessDataShared* ukm_smoothness_data_ = nullptr;
FrameSorter frame_sorter_; FrameSorter frame_sorter_;
......
...@@ -4,8 +4,11 @@ ...@@ -4,8 +4,11 @@
#include "cc/metrics/dropped_frame_counter.h" #include "cc/metrics/dropped_frame_counter.h"
#include <vector>
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h" #include "base/synchronization/waitable_event.h"
#include "base/time/time.h"
#include "cc/animation/animation_host.h" #include "cc/animation/animation_host.h"
#include "cc/test/fake_content_layer_client.h" #include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_picture_layer.h" #include "cc/test/fake_picture_layer.h"
...@@ -247,5 +250,98 @@ class DroppedFrameCounterMainDropsSmoothnessTest ...@@ -247,5 +250,98 @@ class DroppedFrameCounterMainDropsSmoothnessTest
// TODO(crbug.com/1115376) Disabled for flakiness. // TODO(crbug.com/1115376) Disabled for flakiness.
// MULTI_THREAD_TEST_F(DroppedFrameCounterMainDropsSmoothnessTest); // MULTI_THREAD_TEST_F(DroppedFrameCounterMainDropsSmoothnessTest);
class DroppedFrameCounterTest : public testing::Test {
public:
DroppedFrameCounterTest() {
dropped_frame_counter_.set_total_counter(&total_frame_counter_);
}
~DroppedFrameCounterTest() override = default;
// For each boolean in frame_states produces a frame
void SimulateFrameSequence(std::vector<bool> frame_states, int repeat) {
for (int i = 0; i < repeat; i++) {
for (auto is_dropped : frame_states) {
viz::BeginFrameArgs args_ = SimulateBeginFrameArgs();
dropped_frame_counter_.OnBeginFrame(args_);
dropped_frame_counter_.OnEndFrame(args_, is_dropped);
sequence_number_++;
frame_time_ += interval_;
}
}
}
void AdvancetimeByIntervals(int interval_count) {
frame_time_ += interval_ * interval_count;
}
double MaxPercentDroppedFrame() {
return dropped_frame_counter_.sliding_window_max_percent_dropped();
}
private:
DroppedFrameCounter dropped_frame_counter_;
TotalFrameCounter total_frame_counter_;
uint64_t sequence_number_ = 1;
uint64_t source_id_ = 1;
const base::TickClock* tick_clock_ = base::DefaultTickClock::GetInstance();
base::TimeTicks frame_time_ = tick_clock_->NowTicks();
const base::TimeDelta interval_ =
base::TimeDelta::FromMicroseconds(16667); // 16.667 ms
viz::BeginFrameArgs SimulateBeginFrameArgs() {
viz::BeginFrameId current_id_(source_id_, sequence_number_);
viz::BeginFrameArgs args = viz::BeginFrameArgs();
args.frame_id = current_id_;
args.frame_time = frame_time_;
args.interval = interval_;
return args;
}
};
TEST_F(DroppedFrameCounterTest, SimplePattern1) {
// 2 out of every 3 frames are dropped (In total 80 frames out of 120).
SimulateFrameSequence({true, true, true, false, true, false}, 20);
EXPECT_EQ(MaxPercentDroppedFrame(), 200.0 / 3);
}
TEST_F(DroppedFrameCounterTest, SimplePattern2) {
// 1 out of every 5 frames are dropped (In total 24 frames out of 120).
SimulateFrameSequence({false, false, false, false, true}, 24);
EXPECT_EQ(MaxPercentDroppedFrame(), 20.0);
}
TEST_F(DroppedFrameCounterTest, MaxPercentDroppedChanges) {
// First 60 frames have 20% dropped.
SimulateFrameSequence({false, false, false, false, true}, 12);
EXPECT_EQ(MaxPercentDroppedFrame(), 20.0);
// 30 new frames are added that have 18 dropped frames.
// and the 30 frame before that had 6 dropped frames.
// So in total in the window has 24 frames dropped out of 60 frames.
SimulateFrameSequence({false, false, true, true, true}, 6);
EXPECT_EQ(MaxPercentDroppedFrame(), 40.0);
// 30 new frames are added that have 24 dropped frames.
// and the 30 frame before that had 18 dropped frames.
// So in total in the window has 42 frames dropped out of 60 frames.
SimulateFrameSequence({false, true, true, true, true}, 6);
EXPECT_EQ(MaxPercentDroppedFrame(), 70.0);
}
TEST_F(DroppedFrameCounterTest, MaxPercentDroppedWithIdleFrames) {
// First 20 frames have 4 frames dropped (20%).
SimulateFrameSequence({false, false, false, false, true}, 4);
// Then no frames are added for 20 intervals.
AdvancetimeByIntervals(20);
// Then 20 frames have 16 frames dropped (60%).
SimulateFrameSequence({false, false, true, true, true}, 4);
// So in total, there are 40 frames in the 1 second window with 16 dropped
// frames (40% in total).
EXPECT_EQ(MaxPercentDroppedFrame(), 40.0);
}
} // namespace } // namespace
} // namespace cc } // namespace cc
...@@ -5903,6 +5903,20 @@ reviews. Googlers can read more about this at go/gwsq-gerrit. ...@@ -5903,6 +5903,20 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
</summary> </summary>
</histogram> </histogram>
<histogram name="Graphics.Smoothness.MaxPercentDroppedFrames_1sWindow"
units="%" expires_after="2021-11-12">
<owner>behdadb@chromium.org</owner>
<owner>sadrul@chromium.org</owner>
<summary>
Tracks the percent of dropped frames for in a 1 second sliding window.
PercentDroppedFrames is measured by tracking the number of frames which were
not displayed on screen out of the total number of frames expected to be
produced and displayed. In other words, the lower this number is, the
smoother experience.
</summary>
</histogram>
<histogram name="Graphics.Smoothness.MaxStale" units="ms" <histogram name="Graphics.Smoothness.MaxStale" units="ms"
expires_after="2021-11-01"> expires_after="2021-11-01">
<owner>sadrul@chromium.org</owner> <owner>sadrul@chromium.org</owner>
......
...@@ -44,6 +44,7 @@ RENDERING_BENCHMARK_UMA = [ ...@@ -44,6 +44,7 @@ RENDERING_BENCHMARK_UMA = [
'Graphics.Smoothness.PercentDroppedFrames.SlowerThread.Universal', 'Graphics.Smoothness.PercentDroppedFrames.SlowerThread.Universal',
'Graphics.Smoothness.PercentDroppedFrames.ScrollingThread.TouchScroll', 'Graphics.Smoothness.PercentDroppedFrames.ScrollingThread.TouchScroll',
'Graphics.Smoothness.PercentDroppedFrames.ScrollingThread.WheelScroll', 'Graphics.Smoothness.PercentDroppedFrames.ScrollingThread.WheelScroll',
'Graphics.Smoothness.MaxPercentDroppedFrames_1sWindow',
'Memory.GPU.PeakMemoryUsage.Scroll', 'Memory.GPU.PeakMemoryUsage.Scroll',
'Memory.GPU.PeakMemoryUsage.PageLoad', 'Memory.GPU.PeakMemoryUsage.PageLoad',
] ]
......
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