blob: a0351de1e00d6a6faa67b3334df6639eb3553a87 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/metrics/scroll_jank_v4_histogram_emitter.h"
#include <memory>
#include <utility>
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "cc/base/features.h"
#include "cc/metrics/event_metrics.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
namespace {
constexpr JankReasonArray<int> MakeMissedVsyncCounts(
std::initializer_list<std::pair<JankReason, int>> values) {
JankReasonArray<int> result = {}; // Default initialize to 0
for (const auto& [reason, missed_vsyncs] : values) {
result[static_cast<int>(reason)] += missed_vsyncs;
}
return result;
}
constexpr JankReasonArray<int> kNonJankyFrame = {};
void ExpectNoScrollJankHistograms(
const base::HistogramTester& histogram_tester) {
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll", 0);
}
} // namespace
class ScrollJankV4HistogramEmitterTest : public testing::Test {
public:
void SetUp() override {
histogram_emitter_ = std::make_unique<ScrollJankV4HistogramEmitter>();
}
void TearDown() override { histogram_emitter_ = nullptr; }
protected:
std::unique_ptr<ScrollJankV4HistogramEmitter> histogram_emitter_;
};
TEST_F(ScrollJankV4HistogramEmitterTest,
EmitsFixedWindowHistogramsEvery64Frames) {
// First window: NO histograms should be emitted for the first 64 frames. Note
// that the first fixed window contains 65 frames to compensate for the fact
// that the very first frame can never be janky.
{
base::HistogramTester histogram_tester;
// Frames 1-10: Non-janky.
for (int i = 1; i <= 10; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// Frame 11: Janky for ALL reasons.
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDueToDeceleratingInputFrameDelivery, 1},
{JankReason::kMissedVsyncDuringFastScroll, 2},
{JankReason::kMissedVsyncAtStartOfFling, 3},
{JankReason::kMissedVsyncDuringFling, 4},
}));
// Frames 12-20: Non-janky.
for (int i = 12; i <= 20; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// Frames 21-22: Janky due to violating the running consistency rule.
for (int i = 21; i <= 22; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDueToDeceleratingInputFrameDelivery, 1},
}));
}
// Frames 23-30: Non-janky.
for (int i = 23; i <= 30; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// Frame 31-33: Janky due to violating the fast scroll continuity rule.
for (int i = 31; i <= 33; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDuringFastScroll, 1},
}));
}
// Frames 34-40: Non-janky.
for (int i = 34; i <= 40; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// Frame 41-44: Janky due to violating the fling continuity rule at the
// transition from a fast scroll.
for (int i = 41; i <= 44; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncAtStartOfFling, 1},
}));
}
// Frames 45-50: Non-janky.
for (int i = 45; i <= 50; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// Frames 51-55: Janky due to violating the fling continuity rule in the
// middle of a fling.
for (int i = 51; i <= 55; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDuringFling, 1},
}));
}
// Frames 56-64: Non-janky.
for (int i = 56; i <= 64; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
ExpectNoScrollJankHistograms(histogram_tester);
}
// UMA histograms SHOULD be emitted for the 65th frame.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow",
15 * 100 / 64 /* Frames 11, 21-22, 31-33, 41-44 & 51-55 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
3 * 100 / 64 /* Frames 11 & 21-22 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
4 * 100 / 64 /* Frames 11 & 31-33 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
5 * 100 / 64 /* Frames 11 & 41-44 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
6 * 100 / 64 /* Frames 11 & 51-55 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow",
4 + 1 + 2 + 3 + 4 + 5 /* Frames 11, 21-22, 31-33, 41-44 & 51-55 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 4 /* Frame 11 */, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll", 0);
}
// Second window: NO histograms should be emitted for the next 63 frames.
{
base::HistogramTester histogram_tester;
for (int i = 1; i <= 63; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
ExpectNoScrollJankHistograms(histogram_tester);
}
// UMA histograms SHOULD be emitted for the 64th frame.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow", 0, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
0, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
0, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow", 0, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 0, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll", 0);
}
}
TEST_F(ScrollJankV4HistogramEmitterTest,
EmitsPerScrollHistogramsAtStartOfNextScrollWhenFeatureDisabled) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature(
features::kEmitPerScrollJankV4MetricAtEndOfScroll);
// NO histograms for the first scroll should be emitted before the second
// scroll begins.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollStarted(); // First scroll.
// 1 non-janky frame.
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
// 5 janky frames.
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDueToDeceleratingInputFrameDelivery, 1},
{JankReason::kMissedVsyncDuringFastScroll, 2},
{JankReason::kMissedVsyncAtStartOfFling, 3},
{JankReason::kMissedVsyncDuringFling, 4},
}));
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDueToDeceleratingInputFrameDelivery, 1},
}));
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDuringFastScroll, 1},
}));
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncAtStartOfFling, 1},
}));
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDuringFling, 1},
}));
// 1 non-janky frame.
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
histogram_emitter_->OnScrollEnded(); // First scroll.
ExpectNoScrollJankHistograms(histogram_tester);
}
// UMA histograms for the first scroll SHOULD be emitted when the second
// scroll starts.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollStarted(); // Second scroll.
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll", 5 * 100 / 7, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 0);
}
// NO histograms for the second scroll should be emitted before the third
// scroll starts.
{
base::HistogramTester histogram_tester;
for (int i = 1; i <= 10; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// Robustness test: Under normal circumstances, the histogram emitter should
// have received a scroll end event for the second scroll, but it didn't for
// some unexpected reason. The histogram emitter should be able to handle
// this situation.
ExpectNoScrollJankHistograms(histogram_tester);
}
// UMA histograms for the second scroll SHOULD be emitted when the third
// scroll starts.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollStarted(); // Third scroll.
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll", 0, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 0);
}
// NO histograms should be emitted for the third scroll, even after the fourth
// scroll begins, because it was empty. NO histograms should also be emitted
// for the fourth scroll before the histogram emitter is destroyed.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollEnded(); // Third scroll.
histogram_emitter_->OnScrollStarted(); // Fourth scroll.
// 1 non-janky frame.
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
// 1 janky frame.
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDuringFastScroll, 4},
{JankReason::kMissedVsyncDuringFling, 2},
}));
// 1 non-janky frame.
histogram_emitter_->OnFrameWithScrollUpdates(
kNonJankyFrame); // Fourth scroll.
ExpectNoScrollJankHistograms(histogram_tester);
}
// UMA histograms for the fourth scroll SHOULD be emitted when the histogram
// emitter is destroyed.
{
base::HistogramTester histogram_tester;
delete histogram_emitter_.release();
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll", 1 * 100 / 3, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 0);
}
}
TEST_F(ScrollJankV4HistogramEmitterTest,
EmitsPerScrollHistogramsAtEndOfScrollWhenFeaturEnabled) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
features::kEmitPerScrollJankV4MetricAtEndOfScroll);
// NO histograms for the first scroll should be emitted before it ends.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollStarted(); // First scroll.
// 1 non-janky frame.
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
// 5 janky frames.
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDueToDeceleratingInputFrameDelivery, 1},
{JankReason::kMissedVsyncDuringFastScroll, 2},
{JankReason::kMissedVsyncAtStartOfFling, 3},
{JankReason::kMissedVsyncDuringFling, 4},
}));
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDueToDeceleratingInputFrameDelivery, 1},
}));
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDuringFastScroll, 1},
}));
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncAtStartOfFling, 1},
}));
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDuringFling, 1},
}));
// 1 non-janky frame.
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
ExpectNoScrollJankHistograms(histogram_tester);
}
// UMA histograms for the first scroll SHOULD be emitted when it ends.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollEnded(); // First scroll.
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll", 5 * 100 / 7, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 0);
}
// NO histograms for the second scroll should be emitted before it ends.
{
base::HistogramTester histogram_tester;
// Robustness test: Under normal circumstances, the histogram emitter should
// have received a scroll begin event for the second scroll, but it didn't
// for some unexpected reason. The histogram emitter should be able to
// handle this situation, using the fact that the first scroll has just
// ended.
for (int i = 1; i <= 10; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
ExpectNoScrollJankHistograms(histogram_tester);
}
// UMA histograms for the second scroll SHOULD be emitted when the third
// scroll begins.
{
base::HistogramTester histogram_tester;
// Robustness test: Under normal circumstances, the histogram emitter should
// have received a scroll end event for the second scroll, but it didn't for
// some unexpected reason. The histogram emitter should be able to handle
// this situation, by falling back to emitting UMA histograms for the second
// scroll when the third scroll begins.
histogram_emitter_->OnScrollStarted(); // Third scroll.
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll", 0, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 0);
}
// NO histograms should be emitted for the third scroll, even after it ends,
// because it was empty. NO histograms should also be emitted for the fourth
// scroll before the histogram emitter is destroyed.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollEnded(); // Third scroll.
histogram_emitter_->OnScrollStarted(); // Fourth scroll.
// 1 non-janky frame.
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
// 1 janky frame.
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDuringFastScroll, 4},
{JankReason::kMissedVsyncDuringFling, 2},
}));
// 1 non-janky frame.
histogram_emitter_->OnFrameWithScrollUpdates(
kNonJankyFrame); // Fourth scroll.
ExpectNoScrollJankHistograms(histogram_tester);
}
// UMA histograms for the fourth scroll SHOULD be emitted when the histogram
// emitter is destroyed.
{
base::HistogramTester histogram_tester;
delete histogram_emitter_.release();
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll", 1 * 100 / 3, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 0);
}
}
/*
A combined scenario which tests that the histogram emitter emits both fixed
window and per-scroll UMA histograms. This test also verifies that the emission
of fixed window and per-scroll histograms is independent (e.g. a scroll ending
in the middle of a fixed window shouldn't affect the fixed window calculation
and vice versa).
Presented frame: :1 33:34 65:66 97:98 129:
Fixed windows: |<-------window 1------>|<-------window 2------>|
Scrolls: |<scroll 1->|<------scroll 2------->|<scroll 3->|
Delayed frames: : 1 : 2 : 4 : 8 :
*/
TEST_F(ScrollJankV4HistogramEmitterTest,
EmitsBothFixedWindowAndPerScrollHistogramsIndependently) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
features::kEmitPerScrollJankV4MetricAtEndOfScroll);
// Start of scroll 1, frames 1-32: NO histograms should be emitted.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollStarted();
// Frames 1-10: Non-janky.
for (int i = 1; i <= 10; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// Frame 11: Janky for ALL reasons.
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDueToDeceleratingInputFrameDelivery, 1},
{JankReason::kMissedVsyncDuringFastScroll, 2},
{JankReason::kMissedVsyncAtStartOfFling, 3},
{JankReason::kMissedVsyncDuringFling, 4},
}));
// Frames 12-33: Non-janky.
for (int i = 12; i <= 33; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
ExpectNoScrollJankHistograms(histogram_tester);
}
// End of scroll 1: Per-scroll histogram should be emitted.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollEnded();
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll",
1 * 100 / 33 /* Frame 11 */, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 0);
}
// Start of scroll 2, frames 33-64: NO histograms should be emitted.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollStarted();
// Frames 34-50: Non-janky.
for (int i = 34; i <= 50; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// Frames 51-52: Janky due to violating the running consistency rule.
for (int i = 51; i <= 52; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDueToDeceleratingInputFrameDelivery, 1},
}));
}
// Frames 53-64: Non-janky.
for (int i = 53; i <= 64; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
ExpectNoScrollJankHistograms(histogram_tester);
}
// Frame 65: Fixed window histograms SHOULD be emitted.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow",
3 * 100 / 64 /* Frames 11 & 51-52 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
3 * 100 / 64 /* Frames 11 & 51-52 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
1 * 100 / 64 /* Frame 11 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
1 * 100 / 64 /* Frame 11 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
1 * 100 / 64 /* Frame 11 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow",
4 + 2 /* Frames 11 & 51-52 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 4 /* Frame 11 */, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll", 0);
}
// Frames 66-97: NO histograms should be emitted.
{
base::HistogramTester histogram_tester;
// Frames 66-80: Non-janky.
for (int i = 66; i <= 80; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// Frames 81-84: Janky due to violating the fast scroll continuity rule.
for (int i = 81; i <= 84; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncDuringFastScroll, 17},
}));
}
// Frames 85-97: Non-janky.
for (int i = 85; i <= 97; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
ExpectNoScrollJankHistograms(histogram_tester);
}
// End of scroll 2: Per-scroll histograms SHOULD be emitted.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollEnded();
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll",
6 * 100 / 64 /* Frame 51-52 & 81-84 */, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 0);
}
// Start of scroll 3, frames 98-128: NO histograms should be emitted.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollStarted();
// Frames 98-110: Non-janky.
for (int i = 98; i <= 110; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// Frame 111-118: Janky due to violating the fling continuity rule at the
// transition from a fast scroll.
for (int i = 111; i <= 118; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts({
{JankReason::kMissedVsyncAtStartOfFling, 19},
}));
}
// Frames 119-128: Non-janky.
for (int i = 119; i <= 128; i++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
ExpectNoScrollJankHistograms(histogram_tester);
}
// Frame 129: Fixed window histograms SHOULD be emitted.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow",
12 * 100 / 64 /* Frames 81-84 & 111-118 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
4 * 100 / 64 /* Frames 81-84 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
8 * 100 / 64 /* Frames 111-118 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow",
4 * 17 + 8 * 19 /* Frames 81-84 & 111-118 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow",
19 /* Frames 111-118 */, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll", 0);
}
// End of scroll 3: Per-scroll histograms SHOULD be emitted.
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollEnded();
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll",
8 * 100 / 32 /* Frames 111-118 */, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 0);
}
}
TEST_F(ScrollJankV4HistogramEmitterTest,
FramesWhichDoNotCountTowardsHistogramFrameCount) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
features::kEmitPerScrollJankV4MetricAtEndOfScroll);
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollStarted();
for (int frame = 1; frame <= 10; frame++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// A non-janky frame which doesn't count towards the histogram frame count
// followed by non-janky frame 11 which counts towards the histogram frame
// count.
histogram_emitter_->OnFrameWithScrollUpdates(
kNonJankyFrame, /* counts_towards_histogram_frame_count= */ false);
for (int frame = 11; frame <= 20; frame++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// A non-janky frame which doesn't count towards the histogram frame count
// followed by janky frame 21 which counts towards the histogram frame
// count.
histogram_emitter_->OnFrameWithScrollUpdates(
kNonJankyFrame, /* counts_towards_histogram_frame_count= */ false);
histogram_emitter_->OnFrameWithScrollUpdates(MakeMissedVsyncCounts(
{{JankReason::kMissedVsyncDueToDeceleratingInputFrameDelivery, 2}}));
for (int frame = 22; frame <= 30; frame++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// A janky frame which doesn't count towards the histogram frame count
// followed by non-janky frame 31 which counts towards the histogram frame
// count.
histogram_emitter_->OnFrameWithScrollUpdates(
MakeMissedVsyncCounts({{JankReason::kMissedVsyncDuringFastScroll, 3}}),
/* counts_towards_histogram_frame_count= */ false);
for (int frame = 31; frame <= 40; frame++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// A janky frame which doesn't count towards the histogram frame count
// followed by janky frame 41 which counts towards the histogram frame
// count.
histogram_emitter_->OnFrameWithScrollUpdates(
MakeMissedVsyncCounts({{JankReason::kMissedVsyncAtStartOfFling, 5}}),
/* counts_towards_histogram_frame_count= */ false);
histogram_emitter_->OnFrameWithScrollUpdates(
MakeMissedVsyncCounts({{JankReason::kMissedVsyncDuringFling, 4}}));
ExpectNoScrollJankHistograms(histogram_tester);
}
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollEnded();
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll",
3 * 100 / 41 /* Frames 21, 31 & 41 */, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 0);
}
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollStarted();
for (int frame = 42; frame <= 50; frame++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// A janky frame which doesn't count towards the histogram frame count.
// Since there won't be any more frames before the end of the scroll, this
// jank will end up "lost".
histogram_emitter_->OnFrameWithScrollUpdates(
MakeMissedVsyncCounts(
{{JankReason::kMissedVsyncDuringFastScroll, 1000}}),
/* counts_towards_histogram_frame_count= */ false);
ExpectNoScrollJankHistograms(histogram_tester);
}
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollEnded();
// Note that the "lost" janky frame above doesn't count towards the
// per-scroll histogram.
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll", 0, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow", 0);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 0);
}
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnScrollStarted();
for (int frame = 51; frame <= 60; frame++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
// Multiple frames which don't count towards the histogram frame count
// followed by non-janky frame 61 which counts towards the histogram frame
// count.
histogram_emitter_->OnFrameWithScrollUpdates(
MakeMissedVsyncCounts(
{{JankReason::kMissedVsyncDueToDeceleratingInputFrameDelivery, 8}}),
/* counts_towards_histogram_frame_count= */ false);
histogram_emitter_->OnFrameWithScrollUpdates(
kNonJankyFrame,
/* counts_towards_histogram_frame_count= */ false);
histogram_emitter_->OnFrameWithScrollUpdates(
MakeMissedVsyncCounts({{JankReason::kMissedVsyncDuringFastScroll, 9}}),
/* counts_towards_histogram_frame_count= */ false);
histogram_emitter_->OnFrameWithScrollUpdates(
kNonJankyFrame,
/* counts_towards_histogram_frame_count= */ false);
for (int frame = 61; frame <= 64; frame++) {
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
}
ExpectNoScrollJankHistograms(histogram_tester);
}
{
base::HistogramTester histogram_tester;
histogram_emitter_->OnFrameWithScrollUpdates(kNonJankyFrame);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow",
4 * 100 / 64 /* Frames 21, 31, 41 & 61 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDueToDeceleratingInputFrameDelivery",
2 * 100 / 64 /* Frames 21 & 61 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFastScroll",
2 * 100 / 64 /* Frames 31 & 61 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncAtStartOfFling",
1 * 100 / 64 /* Frame 41 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.DelayedFramesPercentage4.FixedWindow."
"MissedVsyncDuringFling",
1 * 100 / 64 /* Frame 41 */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.MissedVsyncsSum4.FixedWindow",
2 + 3 + 4 + 5 + 8 + 9 /* Frames 21, 31, 41 (2x) & 61 (2x) */, 1);
histogram_tester.ExpectUniqueSample(
"Event.ScrollJank.MissedVsyncsMax4.FixedWindow", 9 /* Frame 61 */, 1);
histogram_tester.ExpectTotalCount(
"Event.ScrollJank.DelayedFramesPercentage4.PerScroll", 0);
}
}
} // namespace cc