1 /*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // TODO(b/129481165): remove the #pragma below and fix conversion issues
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wconversion"
20 #pragma clang diagnostic ignored "-Wextra"
21
22 #undef LOG_TAG
23 #define LOG_TAG "LibSurfaceFlingerUnittests"
24 #define LOG_NDEBUG 0
25
26 #include "Scheduler/VSyncPredictor.h"
27
28 #include <gmock/gmock.h>
29 #include <gtest/gtest.h>
30 #include <algorithm>
31 #include <chrono>
32 #include <utility>
33
34 using namespace testing;
35 using namespace std::literals;
36
37 namespace android::scheduler {
38
39 MATCHER_P2(IsCloseTo, value, tolerance, "is within tolerance") {
40 return arg <= value + tolerance && arg >= value - tolerance;
41 }
42
generateVsyncTimestamps(size_t count,nsecs_t period,nsecs_t bias)43 std::vector<nsecs_t> generateVsyncTimestamps(size_t count, nsecs_t period, nsecs_t bias) {
44 std::vector<nsecs_t> vsyncs(count);
45 std::generate(vsyncs.begin(), vsyncs.end(),
46 [&, n = 0]() mutable { return n++ * period + bias; });
47 return vsyncs;
48 }
49
50 struct VSyncPredictorTest : testing::Test {
51 nsecs_t mNow = 0;
52 nsecs_t mPeriod = 1000;
53 static constexpr size_t kHistorySize = 10;
54 static constexpr size_t kMinimumSamplesForPrediction = 6;
55 static constexpr size_t kOutlierTolerancePercent = 25;
56 static constexpr nsecs_t mMaxRoundingError = 100;
57
58 VSyncPredictor tracker{mPeriod, kHistorySize, kMinimumSamplesForPrediction,
59 kOutlierTolerancePercent};
60 };
61
TEST_F(VSyncPredictorTest,reportsAnticipatedPeriod)62 TEST_F(VSyncPredictorTest, reportsAnticipatedPeriod) {
63 auto model = tracker.getVSyncPredictionModel();
64
65 EXPECT_THAT(model.slope, Eq(mPeriod));
66 EXPECT_THAT(model.intercept, Eq(0));
67
68 auto const changedPeriod = 2000;
69 tracker.setPeriod(changedPeriod);
70 model = tracker.getVSyncPredictionModel();
71 EXPECT_THAT(model.slope, Eq(changedPeriod));
72 EXPECT_THAT(model.intercept, Eq(0));
73 }
74
TEST_F(VSyncPredictorTest,reportsSamplesNeededWhenHasNoDataPoints)75 TEST_F(VSyncPredictorTest, reportsSamplesNeededWhenHasNoDataPoints) {
76 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
77 EXPECT_TRUE(tracker.needsMoreSamples());
78 tracker.addVsyncTimestamp(mNow += mPeriod);
79 }
80 EXPECT_FALSE(tracker.needsMoreSamples());
81 }
82
TEST_F(VSyncPredictorTest,reportsSamplesNeededAfterExplicitRateChange)83 TEST_F(VSyncPredictorTest, reportsSamplesNeededAfterExplicitRateChange) {
84 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
85 tracker.addVsyncTimestamp(mNow += mPeriod);
86 }
87 EXPECT_FALSE(tracker.needsMoreSamples());
88
89 auto const changedPeriod = mPeriod * 2;
90 tracker.setPeriod(changedPeriod);
91 EXPECT_TRUE(tracker.needsMoreSamples());
92
93 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
94 EXPECT_TRUE(tracker.needsMoreSamples());
95 tracker.addVsyncTimestamp(mNow += changedPeriod);
96 }
97 EXPECT_FALSE(tracker.needsMoreSamples());
98 }
99
TEST_F(VSyncPredictorTest,transitionsToModelledPointsAfterSynthetic)100 TEST_F(VSyncPredictorTest, transitionsToModelledPointsAfterSynthetic) {
101 auto last = mNow;
102 auto const bias = 10;
103 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
104 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
105 mNow += mPeriod - bias;
106 last = mNow;
107 tracker.addVsyncTimestamp(mNow);
108 mNow += bias;
109 }
110
111 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod - bias));
112 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod - bias));
113 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 990), Eq(mNow + 2 * mPeriod - bias));
114 }
115
TEST_F(VSyncPredictorTest,uponNotifiedOfInaccuracyUsesSynthetic)116 TEST_F(VSyncPredictorTest, uponNotifiedOfInaccuracyUsesSynthetic) {
117 auto const slightlyLessPeriod = mPeriod - 10;
118 auto const changedPeriod = mPeriod - 1;
119 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
120 tracker.addVsyncTimestamp(mNow += slightlyLessPeriod);
121 }
122
123 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + slightlyLessPeriod));
124 tracker.setPeriod(changedPeriod);
125 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + changedPeriod));
126 }
127
128 // b/159882858
TEST_F(VSyncPredictorTest,updatesTimebaseForSyntheticAfterIdleTime)129 TEST_F(VSyncPredictorTest, updatesTimebaseForSyntheticAfterIdleTime) {
130 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
131 EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
132 }
133
134 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
135
136 auto const halfPeriod = mPeriod >> 2;
137 nsecs_t relativelyLongGapWithDrift = mPeriod * 100 + halfPeriod;
138
139 EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += relativelyLongGapWithDrift));
140
141 tracker.resetModel();
142 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
143 }
144
TEST_F(VSyncPredictorTest,uponBadVsyncWillSwitchToSyntheticWhileRecalibrating)145 TEST_F(VSyncPredictorTest, uponBadVsyncWillSwitchToSyntheticWhileRecalibrating) {
146 auto const slightlyMorePeriod = mPeriod + 10;
147 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
148 EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += slightlyMorePeriod));
149 }
150
151 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + slightlyMorePeriod));
152
153 auto const halfPeriod = mPeriod >> 2;
154 EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += halfPeriod));
155
156 tracker.resetModel();
157 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
158 }
159
TEST_F(VSyncPredictorTest,adaptsToFenceTimelines_60hzHighVariance)160 TEST_F(VSyncPredictorTest, adaptsToFenceTimelines_60hzHighVariance) {
161 // these are precomputed simulated 16.6s vsyncs with uniform distribution +/- 1.6ms error
162 std::vector<nsecs_t> const simulatedVsyncs{
163 15492949, 32325658, 49534984, 67496129, 84652891,
164 100332564, 117737004, 132125931, 149291099, 165199602,
165 };
166 auto constexpr idealPeriod = 16600000;
167 auto constexpr expectedPeriod = 16639242;
168 auto constexpr expectedIntercept = 1049341;
169
170 tracker.setPeriod(idealPeriod);
171 for (auto const& timestamp : simulatedVsyncs) {
172 tracker.addVsyncTimestamp(timestamp);
173 }
174 auto [slope, intercept] = tracker.getVSyncPredictionModel();
175 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
176 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
177 }
178
TEST_F(VSyncPredictorTest,adaptsToFenceTimelines_90hzLowVariance)179 TEST_F(VSyncPredictorTest, adaptsToFenceTimelines_90hzLowVariance) {
180 // these are precomputed simulated 11.1 vsyncs with uniform distribution +/- 1ms error
181 std::vector<nsecs_t> const simulatedVsyncs{
182 11167047, 22603464, 32538479, 44938134, 56321268,
183 66730346, 78062637, 88171429, 99707843, 111397621,
184 };
185 auto idealPeriod = 11110000;
186 auto expectedPeriod = 11089413;
187 auto expectedIntercept = 94421;
188
189 tracker.setPeriod(idealPeriod);
190 for (auto const& timestamp : simulatedVsyncs) {
191 tracker.addVsyncTimestamp(timestamp);
192 }
193 auto [slope, intercept] = tracker.getVSyncPredictionModel();
194 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
195 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
196 }
197
TEST_F(VSyncPredictorTest,adaptsToFenceTimelinesDiscontinuous_22hzLowVariance)198 TEST_F(VSyncPredictorTest, adaptsToFenceTimelinesDiscontinuous_22hzLowVariance) {
199 // these are 11.1s vsyncs with low variance, randomly computed, between -1 and 1ms
200 std::vector<nsecs_t> const simulatedVsyncs{
201 45259463, // 0
202 91511026, // 1
203 136307650, // 2
204 1864501714, // 40
205 1908641034, // 41
206 1955278544, // 42
207 4590180096, // 100
208 4681594994, // 102
209 5499224734, // 120
210 5591378272, // 122
211 };
212 auto idealPeriod = 45454545;
213 auto expectedPeriod = 45450152;
214 auto expectedIntercept = 469647;
215
216 tracker.setPeriod(idealPeriod);
217 for (auto const& timestamp : simulatedVsyncs) {
218 tracker.addVsyncTimestamp(timestamp);
219 }
220 auto [slope, intercept] = tracker.getVSyncPredictionModel();
221 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
222 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
223 }
224
TEST_F(VSyncPredictorTest,againstOutliersDiscontinuous_500hzLowVariance)225 TEST_F(VSyncPredictorTest, againstOutliersDiscontinuous_500hzLowVariance) {
226 std::vector<nsecs_t> const simulatedVsyncs{
227 1992548, // 0
228 4078038, // 1
229 6165794, // 2
230 7958171, // 3
231 10193537, // 4
232 2401840200, // 1200
233 2403000000, // an outlier that should be excluded (1201 and a half)
234 2405803629, // 1202
235 2408028599, // 1203
236 2410121051, // 1204
237 };
238 auto idealPeriod = 2000000;
239 auto expectedPeriod = 1999892;
240 auto expectedIntercept = 86342;
241
242 tracker.setPeriod(idealPeriod);
243 for (auto const& timestamp : simulatedVsyncs) {
244 tracker.addVsyncTimestamp(timestamp);
245 }
246
247 auto [slope, intercept] = tracker.getVSyncPredictionModel();
248 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
249 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
250 }
251
TEST_F(VSyncPredictorTest,handlesVsyncChange)252 TEST_F(VSyncPredictorTest, handlesVsyncChange) {
253 auto const fastPeriod = 100;
254 auto const fastTimeBase = 100;
255 auto const slowPeriod = 400;
256 auto const slowTimeBase = 800;
257 auto const simulatedVsyncsFast =
258 generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod, fastTimeBase);
259 auto const simulatedVsyncsSlow =
260 generateVsyncTimestamps(kMinimumSamplesForPrediction, slowPeriod, slowTimeBase);
261
262 tracker.setPeriod(fastPeriod);
263 for (auto const& timestamp : simulatedVsyncsFast) {
264 tracker.addVsyncTimestamp(timestamp);
265 }
266
267 auto const mMaxRoundingError = 100;
268 auto model = tracker.getVSyncPredictionModel();
269 EXPECT_THAT(model.slope, IsCloseTo(fastPeriod, mMaxRoundingError));
270 EXPECT_THAT(model.intercept, IsCloseTo(0, mMaxRoundingError));
271
272 tracker.setPeriod(slowPeriod);
273 for (auto const& timestamp : simulatedVsyncsSlow) {
274 tracker.addVsyncTimestamp(timestamp);
275 }
276 model = tracker.getVSyncPredictionModel();
277 EXPECT_THAT(model.slope, IsCloseTo(slowPeriod, mMaxRoundingError));
278 EXPECT_THAT(model.intercept, IsCloseTo(0, mMaxRoundingError));
279 }
280
TEST_F(VSyncPredictorTest,willBeAccurateUsingPriorResultsForRate)281 TEST_F(VSyncPredictorTest, willBeAccurateUsingPriorResultsForRate) {
282 auto const fastPeriod = 101000;
283 auto const fastTimeBase = fastPeriod - 500;
284 auto const fastPeriod2 = 99000;
285
286 auto const slowPeriod = 400000;
287 auto const slowTimeBase = 800000 - 201;
288 auto const simulatedVsyncsFast =
289 generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod, fastTimeBase);
290 auto const simulatedVsyncsSlow =
291 generateVsyncTimestamps(kMinimumSamplesForPrediction, slowPeriod, slowTimeBase);
292 auto const simulatedVsyncsFast2 =
293 generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod2, fastTimeBase);
294
295 auto idealPeriod = 100000;
296 tracker.setPeriod(idealPeriod);
297 for (auto const& timestamp : simulatedVsyncsFast) {
298 tracker.addVsyncTimestamp(timestamp);
299 }
300 auto model = tracker.getVSyncPredictionModel();
301 EXPECT_THAT(model.slope, Eq(fastPeriod));
302 EXPECT_THAT(model.intercept, Eq(0));
303
304 tracker.setPeriod(slowPeriod);
305 for (auto const& timestamp : simulatedVsyncsSlow) {
306 tracker.addVsyncTimestamp(timestamp);
307 }
308
309 // we had a model for 100ns mPeriod before, use that until the new samples are
310 // sufficiently built up
311 tracker.setPeriod(idealPeriod);
312 model = tracker.getVSyncPredictionModel();
313 EXPECT_THAT(model.slope, Eq(fastPeriod));
314 EXPECT_THAT(model.intercept, Eq(0));
315
316 for (auto const& timestamp : simulatedVsyncsFast2) {
317 tracker.addVsyncTimestamp(timestamp);
318 }
319 model = tracker.getVSyncPredictionModel();
320 EXPECT_THAT(model.slope, Eq(fastPeriod2));
321 EXPECT_THAT(model.intercept, Eq(0));
322 }
323
TEST_F(VSyncPredictorTest,idealModelPredictionsBeforeRegressionModelIsBuilt)324 TEST_F(VSyncPredictorTest, idealModelPredictionsBeforeRegressionModelIsBuilt) {
325 auto const simulatedVsyncs =
326 generateVsyncTimestamps(kMinimumSamplesForPrediction + 1, mPeriod, 0);
327 nsecs_t const mNow = 0;
328 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mPeriod));
329
330 nsecs_t const aBitOfTime = 422;
331
332 for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
333 tracker.addVsyncTimestamp(simulatedVsyncs[i]);
334 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(simulatedVsyncs[i] + aBitOfTime),
335 Eq(mPeriod + simulatedVsyncs[i]));
336 }
337
338 for (auto i = kMinimumSamplesForPrediction; i < simulatedVsyncs.size(); i++) {
339 tracker.addVsyncTimestamp(simulatedVsyncs[i]);
340 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(simulatedVsyncs[i] + aBitOfTime),
341 Eq(mPeriod + simulatedVsyncs[i]));
342 }
343 }
344
345 // See b/145667109, and comment in prod code under test.
TEST_F(VSyncPredictorTest,doesNotPredictBeforeTimePointWithHigherIntercept)346 TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) {
347 std::vector<nsecs_t> const simulatedVsyncs{
348 158929578733000,
349 158929306806205, // oldest TS in ringbuffer
350 158929650879052,
351 158929661969209,
352 158929684198847,
353 158929695268171,
354 158929706370359,
355 };
356 auto const idealPeriod = 11111111;
357 auto const expectedPeriod = 11113919;
358 auto const expectedIntercept = -1195945;
359
360 tracker.setPeriod(idealPeriod);
361 for (auto const& timestamp : simulatedVsyncs) {
362 tracker.addVsyncTimestamp(timestamp);
363 }
364
365 auto [slope, intercept] = tracker.getVSyncPredictionModel();
366 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
367 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
368
369 // (timePoint - oldestTS) % expectedPeriod works out to be: 395334
370 // (timePoint - oldestTS) / expectedPeriod works out to be: 38.96
371 // so failure to account for the offset will floor the ordinal to 38, which was in the past.
372 auto const timePoint = 158929728723871;
373 auto const prediction = tracker.nextAnticipatedVSyncTimeFrom(timePoint);
374 EXPECT_THAT(prediction, Ge(timePoint));
375 }
376
377 // See b/151146131
TEST_F(VSyncPredictorTest,hasEnoughPrecision)378 TEST_F(VSyncPredictorTest, hasEnoughPrecision) {
379 VSyncPredictor tracker{mPeriod, 20, kMinimumSamplesForPrediction, kOutlierTolerancePercent};
380 std::vector<nsecs_t> const simulatedVsyncs{840873348817, 840890049444, 840906762675,
381 840923581635, 840940161584, 840956868096,
382 840973702473, 840990256277, 841007116851,
383 841023722530, 841040452167, 841057073002,
384 841073800920, 841090474360, 841107278632,
385 841123898634, 841140750875, 841157287127,
386 841591357014, 840856664232
387
388 };
389 auto const idealPeriod = 16666666;
390 auto const expectedPeriod = 16698426;
391 auto const expectedIntercept = 58055;
392
393 tracker.setPeriod(idealPeriod);
394 for (auto const& timestamp : simulatedVsyncs) {
395 tracker.addVsyncTimestamp(timestamp);
396 }
397
398 auto [slope, intercept] = tracker.getVSyncPredictionModel();
399 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
400 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
401 }
402
TEST_F(VSyncPredictorTest,resetsWhenInstructed)403 TEST_F(VSyncPredictorTest, resetsWhenInstructed) {
404 auto const idealPeriod = 10000;
405 auto const realPeriod = 10500;
406 tracker.setPeriod(idealPeriod);
407 for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
408 tracker.addVsyncTimestamp(i * realPeriod);
409 }
410
411 EXPECT_THAT(tracker.getVSyncPredictionModel().slope, IsCloseTo(realPeriod, mMaxRoundingError));
412 tracker.resetModel();
413 EXPECT_THAT(tracker.getVSyncPredictionModel().slope, IsCloseTo(idealPeriod, mMaxRoundingError));
414 }
415
TEST_F(VSyncPredictorTest,slopeAlwaysValid)416 TEST_F(VSyncPredictorTest, slopeAlwaysValid) {
417 constexpr auto kNumVsyncs = 100;
418 auto invalidPeriod = mPeriod;
419 auto now = 0;
420 for (int i = 0; i < kNumVsyncs; i++) {
421 tracker.addVsyncTimestamp(now);
422 now += invalidPeriod;
423 invalidPeriod *= 0.9f;
424
425 auto [slope, intercept] = tracker.getVSyncPredictionModel();
426 EXPECT_THAT(slope, IsCloseTo(mPeriod, mPeriod * kOutlierTolerancePercent / 100.f));
427
428 // When VsyncPredictor returns the period it means that it doesn't know how to predict and
429 // it needs to get more samples
430 if (slope == mPeriod && intercept == 0) {
431 EXPECT_TRUE(tracker.needsMoreSamples());
432 }
433 }
434 }
435
operator ""_years(unsigned long long years)436 constexpr nsecs_t operator""_years(unsigned long long years) noexcept {
437 using namespace std::chrono_literals;
438 return years * 365 * 24 * 3600 *
439 std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
440 }
TEST_F(VSyncPredictorTest,aPhoneThatHasBeenAroundAWhileCanStillComputePeriod)441 TEST_F(VSyncPredictorTest, aPhoneThatHasBeenAroundAWhileCanStillComputePeriod) {
442 constexpr nsecs_t timeBase = 100_years;
443
444 for (auto i = 0; i < kHistorySize; i++) {
445 tracker.addVsyncTimestamp(timeBase + i * mPeriod);
446 }
447 auto [slope, intercept] = tracker.getVSyncPredictionModel();
448 EXPECT_THAT(slope, IsCloseTo(mPeriod, mMaxRoundingError));
449 EXPECT_THAT(intercept, Eq(0));
450 }
451
TEST_F(VSyncPredictorTest,isVSyncInPhase)452 TEST_F(VSyncPredictorTest, isVSyncInPhase) {
453 auto last = mNow;
454 auto const bias = 10;
455 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
456 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
457 mNow += mPeriod - bias;
458 last = mNow;
459 tracker.addVsyncTimestamp(mNow);
460 mNow += bias;
461 }
462
463 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod - bias));
464 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod - bias));
465 EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 990), Eq(mNow + 2 * mPeriod - bias));
466
467 const auto maxDivider = 5;
468 const auto maxPeriods = 15;
469 for (int divider = 1; divider < maxDivider; divider++) {
470 for (int i = 0; i < maxPeriods; i++) {
471 const bool expectedInPhase = (i % divider) == 0;
472 EXPECT_THAT(expectedInPhase,
473 tracker.isVSyncInPhase(mNow + i * mPeriod - bias,
474 Fps::fromPeriodNsecs(divider * mPeriod)))
475 << "vsync at " << mNow + (i + 1) * mPeriod - bias << " is "
476 << (expectedInPhase ? "not " : "") << "in phase for divider " << divider;
477 }
478 }
479 }
480
TEST_F(VSyncPredictorTest,inconsistentVsyncValueIsFlushedEventually)481 TEST_F(VSyncPredictorTest, inconsistentVsyncValueIsFlushedEventually) {
482 EXPECT_TRUE(tracker.addVsyncTimestamp(600));
483 EXPECT_TRUE(tracker.needsMoreSamples());
484
485 EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += mPeriod));
486
487 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
488 EXPECT_TRUE(tracker.needsMoreSamples());
489 EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
490 }
491
492 EXPECT_FALSE(tracker.needsMoreSamples());
493 }
494
TEST_F(VSyncPredictorTest,knownVsyncIsUpdated)495 TEST_F(VSyncPredictorTest, knownVsyncIsUpdated) {
496 EXPECT_TRUE(tracker.addVsyncTimestamp(600));
497 EXPECT_TRUE(tracker.needsMoreSamples());
498 EXPECT_EQ(600, tracker.nextAnticipatedVSyncTimeFrom(mNow));
499
500 EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += mPeriod));
501 EXPECT_EQ(mNow + 1000, tracker.nextAnticipatedVSyncTimeFrom(mNow));
502
503 for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
504 EXPECT_TRUE(tracker.needsMoreSamples());
505 EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
506 EXPECT_EQ(mNow + 1000, tracker.nextAnticipatedVSyncTimeFrom(mNow));
507 }
508
509 EXPECT_FALSE(tracker.needsMoreSamples());
510 EXPECT_EQ(mNow + 1000, tracker.nextAnticipatedVSyncTimeFrom(mNow));
511 }
512
TEST_F(VSyncPredictorTest,robustToDuplicateTimestamps_60hzRealTraceData)513 TEST_F(VSyncPredictorTest, robustToDuplicateTimestamps_60hzRealTraceData) {
514 // these are real vsync timestamps from b/190331974 which caused vsync predictor
515 // period to spike to 18ms due to very close timestamps
516 std::vector<nsecs_t> const simulatedVsyncs{
517 198353408177, 198370074844, 198371400000, 198374274000, 198390941000, 198407565000,
518 198540887994, 198607538588, 198624218276, 198657655939, 198674224176, 198690880955,
519 198724204319, 198740988133, 198758166681, 198790869196, 198824205052, 198840871678,
520 198857715631, 198890885797, 198924199640, 198940873834, 198974204401,
521 };
522 auto constexpr idealPeriod = 16'666'666;
523 auto constexpr expectedPeriod = 16'644'742;
524 auto constexpr expectedIntercept = 125'626;
525
526 tracker.setPeriod(idealPeriod);
527 for (auto const& timestamp : simulatedVsyncs) {
528 tracker.addVsyncTimestamp(timestamp);
529 }
530 auto [slope, intercept] = tracker.getVSyncPredictionModel();
531 EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
532 EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
533 }
534
535 } // namespace android::scheduler
536
537 // TODO(b/129481165): remove the #pragma below and fix conversion issues
538 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
539