#include "cc/metrics/average_lag_tracker.h"
#include <memory>
#include "base/test/metrics/histogram_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Bucket;
using testing::ElementsAre;
namespace cc {
namespace {
class AverageLagTrackerTest : public testing::Test {
public:
AverageLagTrackerTest() { ResetHistograms(); }
void ResetHistograms() {
histogram_tester_ = std::make_unique<base::HistogramTester>();
}
const base::HistogramTester& histogram_tester() { return *histogram_tester_; }
void SetUp() override {
average_lag_tracker_ = std::make_unique<AverageLagTracker>();
}
void SyntheticTouchScrollBegin(base::TimeTicks event_time,
base::TimeTicks frame_time,
float delta,
float predicted_delta = 0) {
AverageLagTracker::EventInfo event_info(
delta, predicted_delta != 0 ? predicted_delta : delta, event_time,
AverageLagTracker::EventType::kScrollbegin);
event_info.finish_timestamp = frame_time;
average_lag_tracker_->AddScrollEventInFrame(event_info);
}
void SyntheticTouchScrollUpdate(base::TimeTicks event_time,
base::TimeTicks frame_time,
float delta,
float predicted_delta = 0) {
AverageLagTracker::EventInfo event_info(
delta, predicted_delta != 0 ? predicted_delta : delta, event_time,
AverageLagTracker::EventType::kScrollupdate);
event_info.finish_timestamp = frame_time;
average_lag_tracker_->AddScrollEventInFrame(event_info);
}
void CheckScrollBeginHistograms(int bucket_value, int count) {
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.ScrollBegin.Touch.AverageLagPresentation"),
ElementsAre(Bucket(bucket_value, count)));
EXPECT_THAT(
histogram_tester().GetAllSamples("Event.Latency.ScrollBegin.Touch."
"AverageLagPresentation.NoPrediction"),
ElementsAre(Bucket(bucket_value, count)));
}
void CheckScrollUpdateWithPredictionHistograms(int bucket_value, int count) {
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.ScrollUpdate.Touch.AverageLagPresentation"),
ElementsAre(Bucket(bucket_value, count)));
}
void CheckScrollUpdateNoPredictionHistograms(int bucket_value, int count) {
EXPECT_THAT(
histogram_tester().GetAllSamples("Event.Latency.ScrollUpdate.Touch."
"AverageLagPresentation.NoPrediction"),
ElementsAre(Bucket(bucket_value, count)));
}
void CheckPredictionPositiveHistograms(int bucket_value, int count) {
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.ScrollUpdate.Touch.AverageLagPresentation."
"PredictionPositive"),
ElementsAre(Bucket(bucket_value, count)));
}
void CheckRemainingLagPercentageHistograms(int bucket_value, int count) {
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.ScrollUpdate.Touch.AverageLagPresentation."
"RemainingLagPercentage"),
ElementsAre(Bucket(bucket_value, count)));
}
void CheckPredictionNegativeHistograms(int bucket_value, int count) {
EXPECT_THAT(histogram_tester().GetAllSamples(
"Event.Latency.ScrollUpdate.Touch.AverageLagPresentation."
"PredictionNegative"),
ElementsAre(Bucket(bucket_value, count)));
}
void CheckScrollUpdateHistogramsTotalCount(int count) {
histogram_tester().ExpectTotalCount(
"Event.Latency.ScrollUpdate.Touch.AverageLagPresentation", count);
histogram_tester().ExpectTotalCount(
"Event.Latency.ScrollUpdate.Touch.AverageLagPresentation.NoPrediction",
count);
}
void CheckPredictionPositiveHistogramsTotalCount(int count) {
histogram_tester().ExpectTotalCount(
"Event.Latency.ScrollUpdate.Touch.AverageLagPresentation."
"PredictionPositive",
count);
}
void CheckPredictionNegativeHistogramsTotalCount(int count) {
histogram_tester().ExpectTotalCount(
"Event.Latency.ScrollUpdate.Touch.AverageLagPresentation."
"PredictionNegative",
count);
}
protected:
std::unique_ptr<AverageLagTracker> average_lag_tracker_;
std::unique_ptr<base::HistogramTester> histogram_tester_;
};
base::TimeTicks MillisecondsToTimeTicks(float t_ms) {
return base::TimeTicks() + base::Milliseconds(t_ms);
}
TEST_F(AverageLagTrackerTest, OneSecondInterval) {
base::TimeTicks event_time = base::TimeTicks() + base::Milliseconds(5);
base::TimeTicks frame_time = base::TimeTicks() + base::Milliseconds(10);
float scroll_delta = 10;
event_time += base::Milliseconds(10);
frame_time += base::Milliseconds(10);
SyntheticTouchScrollBegin(event_time, frame_time, scroll_delta);
const int kUpdates = 101;
for (int i = 0; i < kUpdates; i++) {
event_time += base::Milliseconds(10);
frame_time += base::Milliseconds(10);
const int sign = (i < kUpdates / 2) ? 1 : -1;
SyntheticTouchScrollUpdate(event_time, frame_time, sign * scroll_delta);
}
EXPECT_EQ(event_time, base::TimeTicks() + base::Milliseconds(1025));
EXPECT_EQ(frame_time, base::TimeTicks() + base::Milliseconds(1030));
CheckScrollBeginHistograms(12, 1);
CheckScrollUpdateWithPredictionHistograms(9, 1);
CheckScrollUpdateNoPredictionHistograms(9, 1);
CheckPredictionPositiveHistograms(0, 1);
CheckPredictionNegativeHistogramsTotalCount(0);
CheckRemainingLagPercentageHistograms(100 - 0, 1);
ResetHistograms();
event_time += base::Milliseconds(10);
frame_time += base::Milliseconds(10);
SyntheticTouchScrollBegin(event_time, frame_time, scroll_delta);
CheckScrollUpdateWithPredictionHistograms(8, 1);
CheckScrollUpdateNoPredictionHistograms(8, 1);
CheckPredictionPositiveHistograms(0, 1);
CheckPredictionNegativeHistogramsTotalCount(0);
CheckRemainingLagPercentageHistograms(100 - 0, 1);
}
TEST_F(AverageLagTrackerTest, LargerLatency) {
base::TimeTicks event_time = MillisecondsToTimeTicks(10);
base::TimeTicks frame_time = event_time + base::Milliseconds(20);
float scroll_delta = 10;
SyntheticTouchScrollBegin(event_time, frame_time, scroll_delta);
for (int i = 0; i < 2; i++) {
event_time += base::Milliseconds(10);
frame_time = event_time + base::Milliseconds(20);
SyntheticTouchScrollUpdate(event_time, frame_time, scroll_delta);
}
CheckScrollBeginHistograms(20, 1);
event_time = MillisecondsToTimeTicks(1000);
frame_time = MillisecondsToTimeTicks(1000);
SyntheticTouchScrollBegin(event_time, frame_time, scroll_delta);
CheckScrollUpdateWithPredictionHistograms(14, 1);
CheckScrollUpdateNoPredictionHistograms(14, 1);
}
TEST_F(AverageLagTrackerTest, TwoLatencyInfoInSameFrame) {
base::TimeTicks event_time = MillisecondsToTimeTicks(10);
base::TimeTicks frame_time = MillisecondsToTimeTicks(20);
SyntheticTouchScrollBegin(event_time, frame_time, -10 );
event_time = MillisecondsToTimeTicks(20);
frame_time = MillisecondsToTimeTicks(30);
SyntheticTouchScrollUpdate(event_time, frame_time, -10 );
CheckScrollBeginHistograms(14, 1);
event_time = MillisecondsToTimeTicks(25);
frame_time = MillisecondsToTimeTicks(30);
SyntheticTouchScrollUpdate(event_time, frame_time, 5 );
event_time = MillisecondsToTimeTicks(1000);
frame_time = MillisecondsToTimeTicks(1000);
SyntheticTouchScrollBegin(event_time, frame_time, 0);
CheckScrollUpdateWithPredictionHistograms(6, 1);
CheckScrollUpdateNoPredictionHistograms(6, 1);
}
TEST_F(AverageLagTrackerTest, ChangeDirectionInFrame) {
base::TimeTicks event_time = MillisecondsToTimeTicks(10);
base::TimeTicks frame_time = MillisecondsToTimeTicks(20);
SyntheticTouchScrollBegin(event_time, frame_time, 10 );
event_time = MillisecondsToTimeTicks(20);
frame_time = MillisecondsToTimeTicks(30);
SyntheticTouchScrollUpdate(event_time, frame_time, 10 );
event_time = MillisecondsToTimeTicks(30);
frame_time = MillisecondsToTimeTicks(40);
SyntheticTouchScrollUpdate(event_time, frame_time, -20 );
event_time = MillisecondsToTimeTicks(1000);
frame_time = MillisecondsToTimeTicks(1000);
SyntheticTouchScrollBegin(event_time, frame_time, 0);
CheckScrollUpdateWithPredictionHistograms(12, 1);
CheckScrollUpdateNoPredictionHistograms(12, 1);
}
TEST_F(AverageLagTrackerTest, NoScrollPrediction) {
base::TimeTicks event_time = MillisecondsToTimeTicks(5);
base::TimeTicks frame_time = MillisecondsToTimeTicks(10);
SyntheticTouchScrollBegin(event_time, frame_time, 5 );
event_time = MillisecondsToTimeTicks(15);
frame_time = MillisecondsToTimeTicks(20);
SyntheticTouchScrollUpdate(event_time, frame_time, 10 );
event_time = MillisecondsToTimeTicks(25);
frame_time = MillisecondsToTimeTicks(30);
SyntheticTouchScrollUpdate(event_time, frame_time, 10 );
event_time = MillisecondsToTimeTicks(1000);
frame_time = MillisecondsToTimeTicks(1000);
SyntheticTouchScrollBegin(event_time, frame_time, 0);
CheckScrollBeginHistograms(7, 1);
CheckScrollUpdateWithPredictionHistograms(9, 1);
CheckScrollUpdateNoPredictionHistograms(9, 1);
}
TEST_F(AverageLagTrackerTest, ScrollPrediction) {
base::TimeTicks event_time = MillisecondsToTimeTicks(5);
base::TimeTicks frame_time = MillisecondsToTimeTicks(10);
SyntheticTouchScrollBegin(event_time, frame_time, 5 ,
10 );
event_time = MillisecondsToTimeTicks(15);
frame_time = MillisecondsToTimeTicks(20);
SyntheticTouchScrollUpdate(event_time, frame_time, 10 ,
10 );
event_time = MillisecondsToTimeTicks(25);
frame_time = MillisecondsToTimeTicks(30);
SyntheticTouchScrollUpdate(event_time, frame_time, 10 ,
10 );
event_time = MillisecondsToTimeTicks(1000);
frame_time = MillisecondsToTimeTicks(1000);
SyntheticTouchScrollBegin(event_time, frame_time, 0);
CheckScrollBeginHistograms(7, 1);
CheckScrollUpdateWithPredictionHistograms(4, 1);
CheckScrollUpdateNoPredictionHistograms(9, 1);
CheckPredictionPositiveHistograms(5, 1);
CheckPredictionNegativeHistogramsTotalCount(0);
CheckRemainingLagPercentageHistograms(100 * 4.375 / 9.375, 1);
}
TEST_F(AverageLagTrackerTest, ImperfectScrollPrediction) {
base::TimeTicks event_time = MillisecondsToTimeTicks(5);
base::TimeTicks frame_time = MillisecondsToTimeTicks(10);
SyntheticTouchScrollBegin(event_time, frame_time, 5 ,
12 );
event_time = MillisecondsToTimeTicks(15);
frame_time = MillisecondsToTimeTicks(20);
SyntheticTouchScrollUpdate(event_time, frame_time, 10 ,
5 );
event_time = MillisecondsToTimeTicks(25);
frame_time = MillisecondsToTimeTicks(30);
SyntheticTouchScrollUpdate(event_time, frame_time, 10 ,
14 );
event_time = MillisecondsToTimeTicks(1000);
frame_time = MillisecondsToTimeTicks(1000);
SyntheticTouchScrollBegin(event_time, frame_time, 0);
CheckScrollBeginHistograms(7, 1);
CheckScrollUpdateWithPredictionHistograms(5, 1);
CheckScrollUpdateNoPredictionHistograms(9, 1);
CheckPredictionPositiveHistograms(4, 1);
CheckPredictionNegativeHistogramsTotalCount(0);
CheckRemainingLagPercentageHistograms(100 * 5.075 / 9.375, 1);
}
TEST_F(AverageLagTrackerTest, NegativePredictionEffect) {
base::TimeTicks event_time = MillisecondsToTimeTicks(5);
base::TimeTicks frame_time = MillisecondsToTimeTicks(10);
SyntheticTouchScrollBegin(event_time, frame_time, 5 ,
20 );
event_time = MillisecondsToTimeTicks(15);
frame_time = MillisecondsToTimeTicks(20);
SyntheticTouchScrollUpdate(event_time, frame_time, 10 ,
40 );
event_time = MillisecondsToTimeTicks(25);
frame_time = MillisecondsToTimeTicks(30);
SyntheticTouchScrollUpdate(event_time, frame_time, 10 ,
0 );
event_time = MillisecondsToTimeTicks(1000);
frame_time = MillisecondsToTimeTicks(1000);
SyntheticTouchScrollBegin(event_time, frame_time, 0);
CheckScrollBeginHistograms(7, 1);
CheckScrollUpdateWithPredictionHistograms(20, 1);
CheckScrollUpdateNoPredictionHistograms(9, 1);
CheckPredictionPositiveHistogramsTotalCount(0);
CheckPredictionNegativeHistograms(11, 1);
CheckRemainingLagPercentageHistograms(219, 1);
}
TEST_F(AverageLagTrackerTest, NoPredictionEffect) {
base::TimeTicks event_time = MillisecondsToTimeTicks(5);
base::TimeTicks frame_time = MillisecondsToTimeTicks(10);
SyntheticTouchScrollBegin(event_time, frame_time, 5 ,
25 );
event_time = MillisecondsToTimeTicks(15);
frame_time = MillisecondsToTimeTicks(20);
SyntheticTouchScrollUpdate(event_time, frame_time, 10 ,
7 );
event_time = MillisecondsToTimeTicks(25);
frame_time = MillisecondsToTimeTicks(30);
SyntheticTouchScrollUpdate(event_time, frame_time, 10 ,
5 );
event_time = MillisecondsToTimeTicks(1000);
frame_time = MillisecondsToTimeTicks(1000);
SyntheticTouchScrollBegin(event_time, frame_time, 0);
CheckScrollBeginHistograms(7, 1);
CheckScrollUpdateWithPredictionHistograms(9, 1);
CheckScrollUpdateNoPredictionHistograms(9, 1);
CheckPredictionPositiveHistograms(0, 1);
CheckPredictionNegativeHistogramsTotalCount(0);
}
TEST_F(AverageLagTrackerTest, EventOutOfOrder) {
base::TimeTicks event_time = MillisecondsToTimeTicks(5);
base::TimeTicks frame_time = MillisecondsToTimeTicks(10);
float scroll_delta = 5.f;
SyntheticTouchScrollBegin(event_time, frame_time, scroll_delta);
event_time = MillisecondsToTimeTicks(15);
frame_time = MillisecondsToTimeTicks(20);
SyntheticTouchScrollUpdate(event_time, frame_time, scroll_delta);
event_time = MillisecondsToTimeTicks(25);
frame_time = MillisecondsToTimeTicks(30);
SyntheticTouchScrollUpdate(event_time, frame_time, scroll_delta);
event_time = MillisecondsToTimeTicks(1000);
frame_time = MillisecondsToTimeTicks(1000);
SyntheticTouchScrollBegin(event_time, frame_time, 0);
CheckScrollUpdateHistogramsTotalCount(1);
base::TimeTicks earlier_event_time = MillisecondsToTimeTicks(15);
frame_time = MillisecondsToTimeTicks(1010);
SyntheticTouchScrollUpdate(earlier_event_time, frame_time, scroll_delta);
event_time = MillisecondsToTimeTicks(2000);
frame_time = MillisecondsToTimeTicks(2000);
SyntheticTouchScrollBegin(event_time, frame_time, 0);
CheckScrollUpdateHistogramsTotalCount(1);
}
}
}