1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/base/prediction/prediction_metrics_handler.h"
6
7 #include "base/test/metrics/histogram_tester.h"
8 #include "testing/gmock/include/gmock/gmock.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/base/prediction/input_predictor_unittest_helpers.h"
11 #include "ui/base/prediction/prediction_unittest_helpers.h"
12
13 using base::Bucket;
14 using testing::ElementsAre;
15
16 namespace ui {
17 namespace test {
18 namespace {
19
MillisecondsToTestTimeTicks(int64_t ms)20 base::TimeTicks MillisecondsToTestTimeTicks(int64_t ms) {
21 return PredictionUnittestHelpers::GetStaticTimeStampForTests() +
22 base::TimeDelta::FromMilliseconds(ms);
23 }
24
25 } // namespace
26
27 class PredictionMetricsHandlerTest : public testing::Test {
28 public:
PredictionMetricsHandlerTest()29 explicit PredictionMetricsHandlerTest() {}
30
SetUp()31 void SetUp() override {
32 metrics_handler_ = std::make_unique<PredictionMetricsHandler>(
33 "Event.InputEventPrediction.Scroll");
34 histogram_tester_ = std::make_unique<base::HistogramTester>();
35 }
36
37 DISALLOW_COPY_AND_ASSIGN(PredictionMetricsHandlerTest);
38
GetInterpolatedEventForPredictedEvent(const base::TimeTicks & timestamp,gfx::PointF * interpolated)39 int GetInterpolatedEventForPredictedEvent(const base::TimeTicks& timestamp,
40 gfx::PointF* interpolated) {
41 return metrics_handler_->GetInterpolatedEventForPredictedEvent(
42 timestamp, interpolated);
43 }
44
HistogramSizeEq(const char * histogram_name,int size)45 ::testing::AssertionResult HistogramSizeEq(const char* histogram_name,
46 int size) {
47 uint64_t histogram_size =
48 histogram_tester_->GetAllSamples(histogram_name).size();
49 if (static_cast<uint64_t>(size) == histogram_size) {
50 return ::testing::AssertionSuccess();
51 } else {
52 return ::testing::AssertionFailure()
53 << histogram_name << " expected " << size << " entries, but had "
54 << histogram_size;
55 }
56 }
57
HasPredictionHistograms()58 bool HasPredictionHistograms() {
59 uint64_t histogram_size =
60 histogram_tester_
61 ->GetAllSamples("Event.InputEventPrediction.Scroll.WrongDirection")
62 .size();
63 return histogram_size > 0u;
64 }
65
Reset()66 void Reset() {
67 histogram_tester_.reset(new base::HistogramTester());
68 metrics_handler_->Reset();
69 }
70
histogram_tester()71 const base::HistogramTester& histogram_tester() { return *histogram_tester_; }
72
73 protected:
74 std::unique_ptr<PredictionMetricsHandler> metrics_handler_;
75 std::unique_ptr<base::HistogramTester> histogram_tester_;
76 };
77
TEST_F(PredictionMetricsHandlerTest,CanComputeMetricsTest)78 TEST_F(PredictionMetricsHandlerTest, CanComputeMetricsTest) {
79 base::TimeTicks start_time =
80 PredictionUnittestHelpers::GetStaticTimeStampForTests();
81 base::TimeDelta dt = base::TimeDelta::FromMilliseconds(8);
82
83 // Need at least 2 real events to start comput metrics.
84 {
85 metrics_handler_->AddRealEvent(gfx::PointF(0, 0), start_time + 3 * dt,
86 start_time);
87 metrics_handler_->AddPredictedEvent(gfx::PointF(0, 0), start_time + 3 * dt,
88 start_time);
89 metrics_handler_->EvaluatePrediction();
90 EXPECT_FALSE(HasPredictionHistograms());
91 }
92
93 // Need at least a real event strictly after the second predicted event.
94 Reset();
95 {
96 metrics_handler_->AddRealEvent(gfx::PointF(0, 0), start_time, start_time);
97 metrics_handler_->AddRealEvent(gfx::PointF(0, 0), start_time + dt,
98 start_time);
99 metrics_handler_->AddPredictedEvent(gfx::PointF(0, 0), start_time + 2 * dt,
100 start_time);
101 metrics_handler_->AddPredictedEvent(gfx::PointF(0, 0), start_time + 3 * dt,
102 start_time);
103 metrics_handler_->EvaluatePrediction();
104 EXPECT_FALSE(HasPredictionHistograms());
105
106 metrics_handler_->AddRealEvent(gfx::PointF(0, 0), start_time + 3 * dt,
107 start_time);
108 metrics_handler_->EvaluatePrediction();
109 EXPECT_FALSE(HasPredictionHistograms());
110
111 metrics_handler_->AddRealEvent(gfx::PointF(0, 0), start_time + 3.1 * dt,
112 start_time);
113 metrics_handler_->EvaluatePrediction();
114 EXPECT_TRUE(HasPredictionHistograms());
115 }
116 }
117
TEST_F(PredictionMetricsHandlerTest,InterpolationTest)118 TEST_F(PredictionMetricsHandlerTest, InterpolationTest) {
119 base::TimeTicks start_time =
120 PredictionUnittestHelpers::GetStaticTimeStampForTests();
121 base::TimeDelta dt = base::TimeDelta::FromMilliseconds(8);
122 gfx::PointF interpolated;
123
124 metrics_handler_->AddRealEvent(gfx::PointF(2, 2), start_time + 1 * dt,
125 start_time);
126 metrics_handler_->AddRealEvent(gfx::PointF(3, 3), start_time + 2 * dt,
127 start_time);
128 metrics_handler_->AddRealEvent(gfx::PointF(5, 5), start_time + 3 * dt,
129 start_time);
130 metrics_handler_->AddRealEvent(gfx::PointF(8, 8), start_time + 4 * dt,
131 start_time);
132
133 EXPECT_EQ(0, GetInterpolatedEventForPredictedEvent(start_time + 1.5 * dt,
134 &interpolated));
135 EXPECT_EQ(interpolated, gfx::PointF(2.5, 2.5));
136
137 EXPECT_EQ(2, GetInterpolatedEventForPredictedEvent(start_time + 3.5 * dt,
138 &interpolated));
139 EXPECT_EQ(interpolated, gfx::PointF(6.5, 6.5));
140 }
141 // For test purpose and simplify, we are predicted in the middle of 2 real
142 // events, which is also the frame time (i.e. a prediction of 4 ms)
AddEvents(PredictionMetricsHandler * metrics_handler)143 void AddEvents(PredictionMetricsHandler* metrics_handler) {
144 metrics_handler->AddRealEvent(gfx::PointF(1, 1),
145 MillisecondsToTestTimeTicks(8),
146 MillisecondsToTestTimeTicks(12)); // R0
147 metrics_handler->AddRealEvent(gfx::PointF(2, 2),
148 MillisecondsToTestTimeTicks(16),
149 MillisecondsToTestTimeTicks(20)); // R1
150 metrics_handler->AddRealEvent(gfx::PointF(4, 4),
151 MillisecondsToTestTimeTicks(24),
152 MillisecondsToTestTimeTicks(28)); // R2
153 metrics_handler->AddRealEvent(gfx::PointF(7, 7),
154 MillisecondsToTestTimeTicks(32),
155 MillisecondsToTestTimeTicks(36)); // R3
156 metrics_handler->AddRealEvent(gfx::PointF(5, 5),
157 MillisecondsToTestTimeTicks(40),
158 MillisecondsToTestTimeTicks(44)); // R4
159 metrics_handler->AddRealEvent(gfx::PointF(3, 3),
160 MillisecondsToTestTimeTicks(48),
161 MillisecondsToTestTimeTicks(54)); // R5
162
163 // P0 | Interpolation from R0-R1 is (1.5,1.5)
164 // UnderPrediction
165 metrics_handler->AddPredictedEvent(gfx::PointF(1, 1),
166 MillisecondsToTestTimeTicks(12),
167 MillisecondsToTestTimeTicks(12));
168 // P1 | Interpolation from R1-R2 is (3,3)
169 // OverPrediction | RightDirection
170 metrics_handler->AddPredictedEvent(gfx::PointF(3.5, 3.5),
171 MillisecondsToTestTimeTicks(20),
172 MillisecondsToTestTimeTicks(20));
173 // P2 | Interpolation from R2-R3 is (5.5,5.5)
174 // UnderPrediction | RightDirection
175 metrics_handler->AddPredictedEvent(gfx::PointF(5, 5),
176 MillisecondsToTestTimeTicks(28),
177 MillisecondsToTestTimeTicks(28));
178 // P3 | Interpolation from R3-R4 is (6,6)
179 // UnderPrediction | WrongDirection
180 metrics_handler->AddPredictedEvent(gfx::PointF(7, 7),
181 MillisecondsToTestTimeTicks(36),
182 MillisecondsToTestTimeTicks(36));
183 // P4 | Interpolation from R4-R5 is (4,4)
184 // OverPrediction | RightDirection
185 metrics_handler->AddPredictedEvent(gfx::PointF(3, 3),
186 MillisecondsToTestTimeTicks(44),
187 MillisecondsToTestTimeTicks(44));
188 }
189
TEST_F(PredictionMetricsHandlerTest,PredictionMetricTest)190 TEST_F(PredictionMetricsHandlerTest, PredictionMetricTest) {
191 AddEvents(metrics_handler_.get());
192 metrics_handler_->EvaluatePrediction();
193
194 EXPECT_THAT(histogram_tester().GetAllSamples(
195 "Event.InputEventPrediction.Scroll.OverPrediction"),
196 ElementsAre(Bucket(0, 1), Bucket(1, 1)));
197
198 EXPECT_THAT(histogram_tester().GetAllSamples(
199 "Event.InputEventPrediction.Scroll.UnderPrediction"),
200 ElementsAre(Bucket(0, 2), Bucket(1, 1)));
201
202 EXPECT_THAT(histogram_tester().GetAllSamples(
203 "Event.InputEventPrediction.Scroll.WrongDirection"),
204 ElementsAre(Bucket(0, 3), Bucket(1, 1)));
205
206 EXPECT_THAT(histogram_tester().GetAllSamples(
207 "Event.InputEventPrediction.Scroll.PredictionJitter"),
208 ElementsAre(Bucket(1, 2), Bucket(2, 2)));
209
210 EXPECT_THAT(histogram_tester().GetAllSamples(
211 "Event.InputEventPrediction.Scroll.VisualJitter"),
212 ElementsAre(Bucket(1, 2), Bucket(2, 2)));
213 }
214
215 // Test that it doesn't crash when predicted event is prior to first real event.
TEST_F(PredictionMetricsHandlerTest,PredictedTimePriorToReal)216 TEST_F(PredictionMetricsHandlerTest, PredictedTimePriorToReal) {
217 metrics_handler_->AddRealEvent(gfx::PointF(1, 1),
218 MillisecondsToTestTimeTicks(8),
219 MillisecondsToTestTimeTicks(12));
220 metrics_handler_->AddRealEvent(gfx::PointF(2, 2),
221 MillisecondsToTestTimeTicks(10),
222 MillisecondsToTestTimeTicks(12));
223
224 metrics_handler_->AddPredictedEvent(gfx::PointF(0, 0),
225 MillisecondsToTestTimeTicks(7),
226 MillisecondsToTestTimeTicks(12));
227 metrics_handler_->EvaluatePrediction();
228 // No prediction metrics result.
229 EXPECT_TRUE(
230 HistogramSizeEq("Event.InputEventPrediction.Scroll.PredictionJitter", 0));
231 }
232
233 } // namespace test
234 } // namespace ui
235