• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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