[go: nahoru, domu]

blob: a684c455f08f7526712a81a690bba0c5ad45ead7 [file] [log] [blame]
Ella Ge792e4f12019-04-05 17:32:151// 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/latency/average_lag_tracker.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
11using base::Bucket;
12using testing::ElementsAre;
13
14namespace ui {
15namespace {
16
17class AverageLagTrackerTest : public testing::Test {
18 public:
19 AverageLagTrackerTest() { ResetHistograms(); }
20
21 void ResetHistograms() {
22 histogram_tester_.reset(new base::HistogramTester());
23 }
24
25 const base::HistogramTester& histogram_tester() { return *histogram_tester_; }
26
27 void SetUp() override {
28 average_lag_tracker_ = std::make_unique<AverageLagTracker>();
29 }
30
31 void SyntheticTouchScrollBeginLatencyInfo(base::TimeTicks event_time,
32 base::TimeTicks frame_time,
Ella Ge7d1d3be202019-04-08 16:47:5933 float delta,
34 float predicted_delta = 0) {
Ella Ge792e4f12019-04-05 17:32:1535 ui::LatencyInfo touch_latency(ui::SourceEventType::TOUCH);
36 touch_latency.set_scroll_update_delta(delta);
Ella Ge7d1d3be202019-04-08 16:47:5937 touch_latency.set_predicted_scroll_update_delta(
38 predicted_delta != 0 ? predicted_delta : delta);
39
Ella Ge792e4f12019-04-05 17:32:1540 touch_latency.AddLatencyNumberWithTimestamp(
41 ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
42 event_time, 1);
43 touch_latency.AddLatencyNumberWithTimestamp(
44 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT, event_time,
45 1);
46 average_lag_tracker_->AddLatencyInFrame(touch_latency, frame_time,
47 "ScrollBegin");
48 }
49
50 void SyntheticTouchScrollUpdateLatencyInfo(base::TimeTicks event_time,
51 base::TimeTicks frame_time,
Ella Ge7d1d3be202019-04-08 16:47:5952 float delta,
53 float predicted_delta = 0) {
Ella Ge792e4f12019-04-05 17:32:1554 ui::LatencyInfo touch_latency(ui::SourceEventType::TOUCH);
55 touch_latency.set_scroll_update_delta(delta);
Ella Ge7d1d3be202019-04-08 16:47:5956 touch_latency.set_predicted_scroll_update_delta(
57 predicted_delta != 0 ? predicted_delta : delta);
Ella Ge792e4f12019-04-05 17:32:1558 touch_latency.AddLatencyNumberWithTimestamp(
59 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, event_time,
60 1);
61 touch_latency.AddLatencyNumberWithTimestamp(
62 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_LAST_EVENT_COMPONENT, event_time,
63 1);
64 average_lag_tracker_->AddLatencyInFrame(touch_latency, frame_time,
65 "ScrollUpdate");
66 }
67
68 protected:
69 std::unique_ptr<AverageLagTracker> average_lag_tracker_;
70
71 std::unique_ptr<base::HistogramTester> histogram_tester_;
72};
73
74base::TimeTicks MillisecondsToTimeTicks(float t_ms) {
75 return base::TimeTicks() + base::TimeDelta::FromMilliseconds(t_ms);
76}
77
78// Simulate a simple situation that events at every 10ms and start at t=15ms,
79// frame swaps at every 10ms too and start at t=20ms and test we record one
80// UMA for ScrollUpdate in one second.
81TEST_F(AverageLagTrackerTest, OneSecondInterval) {
82 base::TimeTicks event_time =
83 base::TimeTicks() + base::TimeDelta::FromMilliseconds(5);
84 base::TimeTicks frame_time =
85 base::TimeTicks() + base::TimeDelta::FromMilliseconds(10);
86 float scroll_delta = 10;
87
88 // ScrollBegin
89 event_time += base::TimeDelta::FromMilliseconds(10); // 15ms
90 frame_time += base::TimeDelta::FromMilliseconds(10); // 20ms
91 SyntheticTouchScrollBeginLatencyInfo(event_time, frame_time, scroll_delta);
92
93 // Send 101 ScrollUpdate events to verify that there is 1 AverageLag record
94 // per 1 second.
95 const int kUpdates = 101;
96 for (int i = 0; i < kUpdates; i++) {
97 event_time += base::TimeDelta::FromMilliseconds(10);
98 frame_time += base::TimeDelta::FromMilliseconds(10);
99 // First 50 has positive delta, others negetive delta.
100 const int sign = (i < kUpdates / 2) ? 1 : -1;
101 SyntheticTouchScrollUpdateLatencyInfo(event_time, frame_time,
102 sign * scroll_delta);
103 }
104
105 // ScrollBegin report_time is at 20ms, so the next ScrollUpdate report_time is
106 // at 1020ms. The last event_time that finish this report should be later than
107 // 1020ms.
108 EXPECT_EQ(event_time,
109 base::TimeTicks() + base::TimeDelta::FromMilliseconds(1025));
110 EXPECT_EQ(frame_time,
111 base::TimeTicks() + base::TimeDelta::FromMilliseconds(1030));
112
113 // ScrollBegin AverageLag are the area between the event original component
114 // (time=15ms, delta=10px) to the frame swap time (time=20ms, expect finger
115 // position at delta=15px). The AverageLag scaled to 1 second is
116 // (0.5*(10px+15px)*5ms)/5ms = 12.5px.
117 EXPECT_THAT(histogram_tester().GetAllSamples(
118 "Event.Latency.ScrollBegin.Touch.AverageLag"),
119 ElementsAre(Bucket(12, 1)));
120 // This ScrollUpdate AverageLag are calculated as the finger uniformly scroll
121 // 10px each frame. For scroll up/down frame, the Lag at the last frame swap
122 // is 5px, and Lag at this frame swap is 15px. For the one changing direction,
123 // the Lag is from 5 to 10 and down to 5 again. So total LagArea is 99 * 100,
124 // plus 75. the AverageLag in 1 second is 9.975px.
125 EXPECT_THAT(histogram_tester().GetAllSamples(
126 "Event.Latency.ScrollUpdate.Touch.AverageLag"),
127 ElementsAre(Bucket(9, 1)));
128 ResetHistograms();
129
130 // Send another ScrollBegin to end the unfinished ScrollUpdate report.
131 event_time += base::TimeDelta::FromMilliseconds(10);
132 frame_time += base::TimeDelta::FromMilliseconds(10);
133 SyntheticTouchScrollBeginLatencyInfo(event_time, frame_time, scroll_delta);
134
135 // The last ScrollUpdate's lag is 8.75px and truncated to 8.
136 EXPECT_THAT(histogram_tester().GetAllSamples(
137 "Event.Latency.ScrollUpdate.Touch.AverageLag"),
138 ElementsAre(Bucket(8, 1)));
139}
140
141// Test the case that event's frame swap time is later than next event's
142// creation time. (i.e, event at t=10ms will be dispatch at t=30ms, while next
143// event is at t=20ms).
144TEST_F(AverageLagTrackerTest, LargerLatency) {
145 base::TimeTicks event_time = MillisecondsToTimeTicks(10);
146 base::TimeTicks frame_time =
147 event_time + base::TimeDelta::FromMilliseconds(20);
148 float scroll_delta = 10;
149
150 SyntheticTouchScrollBeginLatencyInfo(event_time, frame_time, scroll_delta);
151
152 // Send 2 ScrollUpdate. The second one will record AverageLag.ScrollBegin as
153 // it's event_time is larger or equal to ScrollBegin's frame_time.
154 for (int i = 0; i < 2; i++) {
155 event_time += base::TimeDelta::FromMilliseconds(10);
156 frame_time = event_time + base::TimeDelta::FromMilliseconds(20);
157 SyntheticTouchScrollUpdateLatencyInfo(event_time, frame_time, scroll_delta);
158 }
159
160 // ScrollBegin AveragLag are from t=10ms to t=30ms, with absolute scroll
161 // position from 10 to 30. The AverageLag should be:
162 // (0.5*(10px + 30px)*20ms/20ms) = 20px.
163 EXPECT_THAT(histogram_tester().GetAllSamples(
164 "Event.Latency.ScrollBegin.Touch.AverageLag"),
165 ElementsAre(Bucket(20, 1)));
166
167 // Another ScrollBegin to flush unfinished frames.
168 // event_time doesn't matter here because the previous frames' lag are
169 // compute from their frame_time.
170 event_time = MillisecondsToTimeTicks(1000);
171 frame_time = MillisecondsToTimeTicks(1000);
172 SyntheticTouchScrollBeginLatencyInfo(event_time, frame_time, scroll_delta);
173 // The to unfinished frames' lag are (finger_positon-rendered_position)*time,
174 // AverageLag is ((30px-10px)*10ms+(30px-20px)*10ms)/20ms = 15px.
175 EXPECT_THAT(histogram_tester().GetAllSamples(
176 "Event.Latency.ScrollUpdate.Touch.AverageLag"),
177 ElementsAre(Bucket(14, 1)));
178}
179
180// Test that multiple latency being flush in the same frame swap.
181TEST_F(AverageLagTrackerTest, TwoLatencyInfoInSameFrame) {
182 // ScrollBegin
183 base::TimeTicks event_time = MillisecondsToTimeTicks(10);
184 base::TimeTicks frame_time = MillisecondsToTimeTicks(20);
185 SyntheticTouchScrollBeginLatencyInfo(event_time, frame_time,
186 -10 /* scroll_delta */);
187
188 // ScrollUpdate with event_time >= ScrollBegin frame_time will generate
189 // a histogram for AverageLag.ScrollBegin.
190 event_time = MillisecondsToTimeTicks(20);
191 frame_time = MillisecondsToTimeTicks(30);
192 SyntheticTouchScrollUpdateLatencyInfo(event_time, frame_time,
193 -10 /* scroll_delta */);
194
195 // Absolute position from -10 to -20. The AverageLag should be:
196 // (0.5*(10px + 20px)*10ms/10ms) = 15px.
197 EXPECT_THAT(histogram_tester().GetAllSamples(
198 "Event.Latency.ScrollBegin.Touch.AverageLag"),
199 ElementsAre(Bucket(14, 1)));
200
201 event_time = MillisecondsToTimeTicks(25);
202 frame_time = MillisecondsToTimeTicks(30);
203 SyntheticTouchScrollUpdateLatencyInfo(event_time, frame_time,
204 5 /* scroll_delta */);
205
206 // Another ScrollBegin to flush unfinished frames.
207 event_time = MillisecondsToTimeTicks(1000);
208 frame_time = MillisecondsToTimeTicks(1000);
209 SyntheticTouchScrollBeginLatencyInfo(event_time, frame_time, 0);
210
211 // The ScrollUpdates are at t=20ms, finger_pos=-20px, rendered_pos=-10px,
212 // at t=25ms, finger_pos=-15px, rendered_pos=-10px;
213 // To t=30ms both events get flush.
214 // AverageLag is (0.5*(10px+5px)*5ms + 5px*5ms)/10ms = 6.25px
215 EXPECT_THAT(histogram_tester().GetAllSamples(
216 "Event.Latency.ScrollUpdate.Touch.AverageLag"),
217 ElementsAre(Bucket(6, 1)));
218}
219
220// Test the case that switching direction causes lag at current frame
221// time and previous frame time are in different direction.
222TEST_F(AverageLagTrackerTest, ChangeDirectionInFrame) {
223 // ScrollBegin
224 base::TimeTicks event_time = MillisecondsToTimeTicks(10);
225 base::TimeTicks frame_time = MillisecondsToTimeTicks(20);
226 SyntheticTouchScrollBeginLatencyInfo(event_time, frame_time,
227 10 /* scroll_delta */);
228
229 // At t=20, lag = 10px.
230 event_time = MillisecondsToTimeTicks(20);
231 frame_time = MillisecondsToTimeTicks(30);
232 SyntheticTouchScrollUpdateLatencyInfo(event_time, frame_time,
233 10 /* scroll_delta */);
234
235 // At t=30, lag = -10px.
236 event_time = MillisecondsToTimeTicks(30);
237 frame_time = MillisecondsToTimeTicks(40);
238 SyntheticTouchScrollUpdateLatencyInfo(event_time, frame_time,
239 -20 /* scroll_delta */);
240
241 // Another ScrollBegin to flush unfinished frames.
242 event_time = MillisecondsToTimeTicks(1000);
243 frame_time = MillisecondsToTimeTicks(1000);
244 SyntheticTouchScrollBeginLatencyInfo(event_time, frame_time, 0);
245
246 // From t=20 to t=30, lag_area=2*(0.5*10px*5ms)=50px*ms.
247 // From t=30 to t=40, lag_area=20px*10ms=200px*ms
248 // AverageLag = (50+200)/20 = 12.5px.
249 EXPECT_THAT(histogram_tester().GetAllSamples(
250 "Event.Latency.ScrollUpdate.Touch.AverageLag"),
251 ElementsAre(Bucket(12, 1)));
252}
253
Ella Ge7d1d3be202019-04-08 16:47:59254// A simple case without scroll prediction to compare with the two with
255// prediction cases below.
256TEST_F(AverageLagTrackerTest, NoScrollPrediction) {
257 // ScrollBegin, at t=5, finter_pos=5px.
258 base::TimeTicks event_time = MillisecondsToTimeTicks(5);
259 base::TimeTicks frame_time = MillisecondsToTimeTicks(10);
260 SyntheticTouchScrollBeginLatencyInfo(event_time, frame_time,
261 5 /* scroll_delta */);
262
263 // ScrollUpdate, at t=15, finger_pos=15px.
264 event_time = MillisecondsToTimeTicks(15);
265 frame_time = MillisecondsToTimeTicks(20);
266 SyntheticTouchScrollUpdateLatencyInfo(event_time, frame_time,
267 10 /* scroll_delta */);
268
269 // ScrollUpdate, at t=25, finger_pos=25px.
270 event_time = MillisecondsToTimeTicks(25);
271 frame_time = MillisecondsToTimeTicks(30);
272 SyntheticTouchScrollUpdateLatencyInfo(event_time, frame_time,
273 10 /* scroll_delta */);
274
275 // Another ScrollBegin to flush unfinished frames.
276 event_time = MillisecondsToTimeTicks(1000);
277 frame_time = MillisecondsToTimeTicks(1000);
278 SyntheticTouchScrollBeginLatencyInfo(event_time, frame_time, 0);
279
280 // Prediction hasn't take affect on ScrollBegin so it'll stay the same.
281 EXPECT_THAT(histogram_tester().GetAllSamples(
282 "Event.Latency.ScrollBegin.Touch.AverageLag"),
283 ElementsAre(Bucket(7, 1)));
284 // At t=10, finger_pos = 10px, rendered_pos = 5px.
285 // At t=20, finger_pos = 20px, rendered_pos = 15px.
286 // At t=30, finger_pos = 25px, rendered_pos = 25px.
287 // AverageLag = ((5px+15px)*10ms/2 + (5px+10px)*5ms/2 + 10px*5ms)/20ms
288 // = 9.375
289 EXPECT_THAT(histogram_tester().GetAllSamples(
290 "Event.Latency.ScrollUpdate.Touch.AverageLag"),
291 ElementsAre(Bucket(9, 1)));
292}
293
294// Test AverageLag with perfect scroll prediction.
295TEST_F(AverageLagTrackerTest, ScrollPrediction) {
296 // ScrollBegin, at t=5, finter_pos=5px.
297 // Predict frame_time=10, predicted_pos = 10px.
298 base::TimeTicks event_time = MillisecondsToTimeTicks(5);
299 base::TimeTicks frame_time = MillisecondsToTimeTicks(10);
300 SyntheticTouchScrollBeginLatencyInfo(
301 event_time, frame_time, 5 /* scroll_delta */, 10 /* predicted_delta */);
302
303 // ScrollUpdate, at t=15, finger_pos=15px.
304 // Predict frame_time=20, predicted_pos = 20px.
305 event_time = MillisecondsToTimeTicks(15);
306 frame_time = MillisecondsToTimeTicks(20);
307 SyntheticTouchScrollUpdateLatencyInfo(
308 event_time, frame_time, 10 /* scroll_delta */, 10 /* predicted_delta */);
309
310 // ScrollUpdate, at t=25, finger_pos=25px.
311 // Predict frame_time=30, predicted_pos = 30px.
312 event_time = MillisecondsToTimeTicks(25);
313 frame_time = MillisecondsToTimeTicks(30);
314 SyntheticTouchScrollUpdateLatencyInfo(
315 event_time, frame_time, 10 /* scroll_delta */, 10 /* predicted_delta */);
316
317 // Another ScrollBegin to flush unfinished frames.
318 event_time = MillisecondsToTimeTicks(1000);
319 frame_time = MillisecondsToTimeTicks(1000);
320 SyntheticTouchScrollBeginLatencyInfo(event_time, frame_time, 0);
321
322 // Prediction hasn't take affect on ScrollBegin so it'll stay the same.
323 EXPECT_THAT(histogram_tester().GetAllSamples(
324 "Event.Latency.ScrollBegin.Touch.AverageLag"),
325 ElementsAre(Bucket(7, 1)));
326 // At t=10, finger_pos = 10px, rendered_pos = 10px.
327 // At t=20, finger_pos = 20px, rendered_pos = 20px.
328 // At t=30, finger_pos = 25px, rendered_pos = 30px.
329 // AverageLag = ((0px+10px)*10ms/2 + (0px+5px)*10ms/2 + 5px*5ms)/20ms
330 // = 4.375px
331 EXPECT_THAT(histogram_tester().GetAllSamples(
332 "Event.Latency.ScrollUpdate.Touch.AverageLag"),
333 ElementsAre(Bucket(4, 1)));
334}
335
336// Test AverageLag with imperfect scroll prediction.
337TEST_F(AverageLagTrackerTest, ImperfectScrollPrediction) {
338 // ScrollBegin, at t=5, finter_pos=5px.
339 // Predict frame_time=10, predicted_pos(over) = 12px.
340 base::TimeTicks event_time = MillisecondsToTimeTicks(5);
341 base::TimeTicks frame_time = MillisecondsToTimeTicks(10);
342 SyntheticTouchScrollBeginLatencyInfo(
343 event_time, frame_time, 5 /* scroll_delta */, 12 /* predicted_delta */);
344
345 // ScrollUpdate, at t=15, finger_pos=15px.
346 // Predict frame_time=20, predicted_pos(under) = 17px.
347 event_time = MillisecondsToTimeTicks(15);
348 frame_time = MillisecondsToTimeTicks(20);
349 SyntheticTouchScrollUpdateLatencyInfo(
350 event_time, frame_time, 10 /* scroll_delta */, 5 /* predicted_delta */);
351
352 // ScrollUpdate, at t=25, finger_pos=25px.
353 // Predict frame_time=30, predicted_pos(over) = 31px.
354 event_time = MillisecondsToTimeTicks(25);
355 frame_time = MillisecondsToTimeTicks(30);
356 SyntheticTouchScrollUpdateLatencyInfo(
357 event_time, frame_time, 10 /* scroll_delta */, 14 /* predicted_delta */);
358
359 // Another ScrollBegin to flush unfinished frames.
360 event_time = MillisecondsToTimeTicks(1000);
361 frame_time = MillisecondsToTimeTicks(1000);
362 SyntheticTouchScrollBeginLatencyInfo(event_time, frame_time, 0);
363
364 EXPECT_THAT(histogram_tester().GetAllSamples(
365 "Event.Latency.ScrollBegin.Touch.AverageLag"),
366 ElementsAre(Bucket(7, 1)));
367 // AverageLag = ((2px*2ms/2+8px*8ms/2)+ ((3px+8px)*5ms/2+8px*5ms))/20ms
368 // = 5.075px
369 EXPECT_THAT(histogram_tester().GetAllSamples(
370 "Event.Latency.ScrollUpdate.Touch.AverageLag"),
371 ElementsAre(Bucket(5, 1)));
372}
373
Ella Ge792e4f12019-04-05 17:32:15374} // namespace
375} // namespace ui