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