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