• 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 constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
51 
52 struct VSyncPredictorTest : testing::Test {
53     nsecs_t mNow = 0;
54     nsecs_t mPeriod = 1000;
55     static constexpr size_t kHistorySize = 10;
56     static constexpr size_t kMinimumSamplesForPrediction = 6;
57     static constexpr size_t kOutlierTolerancePercent = 25;
58     static constexpr nsecs_t mMaxRoundingError = 100;
59 
60     VSyncPredictor tracker{DEFAULT_DISPLAY_ID, mPeriod, kHistorySize, kMinimumSamplesForPrediction,
61                            kOutlierTolerancePercent};
62 };
63 
TEST_F(VSyncPredictorTest,reportsAnticipatedPeriod)64 TEST_F(VSyncPredictorTest, reportsAnticipatedPeriod) {
65     auto model = tracker.getVSyncPredictionModel();
66 
67     EXPECT_THAT(model.slope, Eq(mPeriod));
68     EXPECT_THAT(model.intercept, Eq(0));
69 
70     auto const changedPeriod = 2000;
71     tracker.setPeriod(changedPeriod);
72     model = tracker.getVSyncPredictionModel();
73     EXPECT_THAT(model.slope, Eq(changedPeriod));
74     EXPECT_THAT(model.intercept, Eq(0));
75 }
76 
TEST_F(VSyncPredictorTest,reportsSamplesNeededWhenHasNoDataPoints)77 TEST_F(VSyncPredictorTest, reportsSamplesNeededWhenHasNoDataPoints) {
78     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
79         EXPECT_TRUE(tracker.needsMoreSamples());
80         tracker.addVsyncTimestamp(mNow += mPeriod);
81     }
82     EXPECT_FALSE(tracker.needsMoreSamples());
83 }
84 
TEST_F(VSyncPredictorTest,reportsSamplesNeededAfterExplicitRateChange)85 TEST_F(VSyncPredictorTest, reportsSamplesNeededAfterExplicitRateChange) {
86     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
87         tracker.addVsyncTimestamp(mNow += mPeriod);
88     }
89     EXPECT_FALSE(tracker.needsMoreSamples());
90 
91     auto const changedPeriod = mPeriod * 2;
92     tracker.setPeriod(changedPeriod);
93     EXPECT_TRUE(tracker.needsMoreSamples());
94 
95     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
96         EXPECT_TRUE(tracker.needsMoreSamples());
97         tracker.addVsyncTimestamp(mNow += changedPeriod);
98     }
99     EXPECT_FALSE(tracker.needsMoreSamples());
100 }
101 
TEST_F(VSyncPredictorTest,transitionsToModelledPointsAfterSynthetic)102 TEST_F(VSyncPredictorTest, transitionsToModelledPointsAfterSynthetic) {
103     auto last = mNow;
104     auto const bias = 10;
105     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
106         EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
107         mNow += mPeriod - bias;
108         last = mNow;
109         tracker.addVsyncTimestamp(mNow);
110         mNow += bias;
111     }
112 
113     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod - bias));
114     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod - bias));
115     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 990), Eq(mNow + 2 * mPeriod - bias));
116 }
117 
TEST_F(VSyncPredictorTest,uponNotifiedOfInaccuracyUsesSynthetic)118 TEST_F(VSyncPredictorTest, uponNotifiedOfInaccuracyUsesSynthetic) {
119     auto const slightlyLessPeriod = mPeriod - 10;
120     auto const changedPeriod = mPeriod - 1;
121     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
122         tracker.addVsyncTimestamp(mNow += slightlyLessPeriod);
123     }
124 
125     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + slightlyLessPeriod));
126     tracker.setPeriod(changedPeriod);
127     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + changedPeriod));
128 }
129 
130 // b/159882858
TEST_F(VSyncPredictorTest,updatesTimebaseForSyntheticAfterIdleTime)131 TEST_F(VSyncPredictorTest, updatesTimebaseForSyntheticAfterIdleTime) {
132     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
133         EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
134     }
135 
136     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
137 
138     auto const halfPeriod = mPeriod >> 2;
139     nsecs_t relativelyLongGapWithDrift = mPeriod * 100 + halfPeriod;
140 
141     EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += relativelyLongGapWithDrift));
142 
143     tracker.resetModel();
144     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
145 }
146 
TEST_F(VSyncPredictorTest,uponBadVsyncWillSwitchToSyntheticWhileRecalibrating)147 TEST_F(VSyncPredictorTest, uponBadVsyncWillSwitchToSyntheticWhileRecalibrating) {
148     auto const slightlyMorePeriod = mPeriod + 10;
149     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
150         EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += slightlyMorePeriod));
151     }
152 
153     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + slightlyMorePeriod));
154 
155     auto const halfPeriod = mPeriod >> 2;
156     EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += halfPeriod));
157 
158     tracker.resetModel();
159     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
160 }
161 
TEST_F(VSyncPredictorTest,adaptsToFenceTimelines_60hzHighVariance)162 TEST_F(VSyncPredictorTest, adaptsToFenceTimelines_60hzHighVariance) {
163     // these are precomputed simulated 16.6s vsyncs with uniform distribution +/- 1.6ms error
164     std::vector<nsecs_t> const simulatedVsyncs{
165             15492949,  32325658,  49534984,  67496129,  84652891,
166             100332564, 117737004, 132125931, 149291099, 165199602,
167     };
168     auto constexpr idealPeriod = 16600000;
169     auto constexpr expectedPeriod = 16639242;
170     auto constexpr expectedIntercept = 1049341;
171 
172     tracker.setPeriod(idealPeriod);
173     for (auto const& timestamp : simulatedVsyncs) {
174         tracker.addVsyncTimestamp(timestamp);
175     }
176     auto [slope, intercept] = tracker.getVSyncPredictionModel();
177     EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
178     EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
179 }
180 
TEST_F(VSyncPredictorTest,adaptsToFenceTimelines_90hzLowVariance)181 TEST_F(VSyncPredictorTest, adaptsToFenceTimelines_90hzLowVariance) {
182     // these are precomputed simulated 11.1 vsyncs with uniform distribution +/- 1ms error
183     std::vector<nsecs_t> const simulatedVsyncs{
184             11167047, 22603464, 32538479, 44938134, 56321268,
185             66730346, 78062637, 88171429, 99707843, 111397621,
186     };
187     auto idealPeriod = 11110000;
188     auto expectedPeriod = 11089413;
189     auto expectedIntercept = 94421;
190 
191     tracker.setPeriod(idealPeriod);
192     for (auto const& timestamp : simulatedVsyncs) {
193         tracker.addVsyncTimestamp(timestamp);
194     }
195     auto [slope, intercept] = tracker.getVSyncPredictionModel();
196     EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
197     EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
198 }
199 
TEST_F(VSyncPredictorTest,adaptsToFenceTimelinesDiscontinuous_22hzLowVariance)200 TEST_F(VSyncPredictorTest, adaptsToFenceTimelinesDiscontinuous_22hzLowVariance) {
201     // these are 11.1s vsyncs with low variance, randomly computed, between -1 and 1ms
202     std::vector<nsecs_t> const simulatedVsyncs{
203             45259463,   // 0
204             91511026,   // 1
205             136307650,  // 2
206             1864501714, // 40
207             1908641034, // 41
208             1955278544, // 42
209             4590180096, // 100
210             4681594994, // 102
211             5499224734, // 120
212             5591378272, // 122
213     };
214     auto idealPeriod = 45454545;
215     auto expectedPeriod = 45450152;
216     auto expectedIntercept = 469647;
217 
218     tracker.setPeriod(idealPeriod);
219     for (auto const& timestamp : simulatedVsyncs) {
220         tracker.addVsyncTimestamp(timestamp);
221     }
222     auto [slope, intercept] = tracker.getVSyncPredictionModel();
223     EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
224     EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
225 }
226 
TEST_F(VSyncPredictorTest,againstOutliersDiscontinuous_500hzLowVariance)227 TEST_F(VSyncPredictorTest, againstOutliersDiscontinuous_500hzLowVariance) {
228     std::vector<nsecs_t> const simulatedVsyncs{
229             1992548,    // 0
230             4078038,    // 1
231             6165794,    // 2
232             7958171,    // 3
233             10193537,   // 4
234             2401840200, // 1200
235             2403000000, // an outlier that should be excluded (1201 and a half)
236             2405803629, // 1202
237             2408028599, // 1203
238             2410121051, // 1204
239     };
240     auto idealPeriod = 2000000;
241     auto expectedPeriod = 1999892;
242     auto expectedIntercept = 86342;
243 
244     tracker.setPeriod(idealPeriod);
245     for (auto const& timestamp : simulatedVsyncs) {
246         tracker.addVsyncTimestamp(timestamp);
247     }
248 
249     auto [slope, intercept] = tracker.getVSyncPredictionModel();
250     EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
251     EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
252 }
253 
TEST_F(VSyncPredictorTest,handlesVsyncChange)254 TEST_F(VSyncPredictorTest, handlesVsyncChange) {
255     auto const fastPeriod = 100;
256     auto const fastTimeBase = 100;
257     auto const slowPeriod = 400;
258     auto const slowTimeBase = 800;
259     auto const simulatedVsyncsFast =
260             generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod, fastTimeBase);
261     auto const simulatedVsyncsSlow =
262             generateVsyncTimestamps(kMinimumSamplesForPrediction, slowPeriod, slowTimeBase);
263 
264     tracker.setPeriod(fastPeriod);
265     for (auto const& timestamp : simulatedVsyncsFast) {
266         tracker.addVsyncTimestamp(timestamp);
267     }
268 
269     auto const mMaxRoundingError = 100;
270     auto model = tracker.getVSyncPredictionModel();
271     EXPECT_THAT(model.slope, IsCloseTo(fastPeriod, mMaxRoundingError));
272     EXPECT_THAT(model.intercept, IsCloseTo(0, mMaxRoundingError));
273 
274     tracker.setPeriod(slowPeriod);
275     for (auto const& timestamp : simulatedVsyncsSlow) {
276         tracker.addVsyncTimestamp(timestamp);
277     }
278     model = tracker.getVSyncPredictionModel();
279     EXPECT_THAT(model.slope, IsCloseTo(slowPeriod, mMaxRoundingError));
280     EXPECT_THAT(model.intercept, IsCloseTo(0, mMaxRoundingError));
281 }
282 
TEST_F(VSyncPredictorTest,willBeAccurateUsingPriorResultsForRate)283 TEST_F(VSyncPredictorTest, willBeAccurateUsingPriorResultsForRate) {
284     auto const fastPeriod = 101000;
285     auto const fastTimeBase = fastPeriod - 500;
286     auto const fastPeriod2 = 99000;
287 
288     auto const slowPeriod = 400000;
289     auto const slowTimeBase = 800000 - 201;
290     auto const simulatedVsyncsFast =
291             generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod, fastTimeBase);
292     auto const simulatedVsyncsSlow =
293             generateVsyncTimestamps(kMinimumSamplesForPrediction, slowPeriod, slowTimeBase);
294     auto const simulatedVsyncsFast2 =
295             generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod2, fastTimeBase);
296 
297     auto idealPeriod = 100000;
298     tracker.setPeriod(idealPeriod);
299     for (auto const& timestamp : simulatedVsyncsFast) {
300         tracker.addVsyncTimestamp(timestamp);
301     }
302     auto model = tracker.getVSyncPredictionModel();
303     EXPECT_THAT(model.slope, Eq(fastPeriod));
304     EXPECT_THAT(model.intercept, Eq(0));
305 
306     tracker.setPeriod(slowPeriod);
307     for (auto const& timestamp : simulatedVsyncsSlow) {
308         tracker.addVsyncTimestamp(timestamp);
309     }
310 
311     // we had a model for 100ns mPeriod before, use that until the new samples are
312     // sufficiently built up
313     tracker.setPeriod(idealPeriod);
314     model = tracker.getVSyncPredictionModel();
315     EXPECT_THAT(model.slope, Eq(fastPeriod));
316     EXPECT_THAT(model.intercept, Eq(0));
317 
318     for (auto const& timestamp : simulatedVsyncsFast2) {
319         tracker.addVsyncTimestamp(timestamp);
320     }
321     model = tracker.getVSyncPredictionModel();
322     EXPECT_THAT(model.slope, Eq(fastPeriod2));
323     EXPECT_THAT(model.intercept, Eq(0));
324 }
325 
TEST_F(VSyncPredictorTest,idealModelPredictionsBeforeRegressionModelIsBuilt)326 TEST_F(VSyncPredictorTest, idealModelPredictionsBeforeRegressionModelIsBuilt) {
327     auto const simulatedVsyncs =
328             generateVsyncTimestamps(kMinimumSamplesForPrediction + 1, mPeriod, 0);
329     nsecs_t const mNow = 0;
330     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mPeriod));
331 
332     nsecs_t const aBitOfTime = 422;
333 
334     for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
335         tracker.addVsyncTimestamp(simulatedVsyncs[i]);
336         EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(simulatedVsyncs[i] + aBitOfTime),
337                     Eq(mPeriod + simulatedVsyncs[i]));
338     }
339 
340     for (auto i = kMinimumSamplesForPrediction; i < simulatedVsyncs.size(); i++) {
341         tracker.addVsyncTimestamp(simulatedVsyncs[i]);
342         EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(simulatedVsyncs[i] + aBitOfTime),
343                     Eq(mPeriod + simulatedVsyncs[i]));
344     }
345 }
346 
347 // See b/145667109, and comment in prod code under test.
TEST_F(VSyncPredictorTest,doesNotPredictBeforeTimePointWithHigherIntercept)348 TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) {
349     std::vector<nsecs_t> const simulatedVsyncs{
350             158929578733000,
351             158929306806205, // oldest TS in ringbuffer
352             158929650879052,
353             158929661969209,
354             158929684198847,
355             158929695268171,
356             158929706370359,
357     };
358     auto const idealPeriod = 11111111;
359     auto const expectedPeriod = 11113919;
360     auto const expectedIntercept = -1195945;
361 
362     tracker.setPeriod(idealPeriod);
363     for (auto const& timestamp : simulatedVsyncs) {
364         tracker.addVsyncTimestamp(timestamp);
365     }
366 
367     auto [slope, intercept] = tracker.getVSyncPredictionModel();
368     EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
369     EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
370 
371     // (timePoint - oldestTS) % expectedPeriod works out to be: 395334
372     // (timePoint - oldestTS) / expectedPeriod works out to be: 38.96
373     // so failure to account for the offset will floor the ordinal to 38, which was in the past.
374     auto const timePoint = 158929728723871;
375     auto const prediction = tracker.nextAnticipatedVSyncTimeFrom(timePoint);
376     EXPECT_THAT(prediction, Ge(timePoint));
377 }
378 
379 // See b/151146131
TEST_F(VSyncPredictorTest,hasEnoughPrecision)380 TEST_F(VSyncPredictorTest, hasEnoughPrecision) {
381     VSyncPredictor tracker{DEFAULT_DISPLAY_ID, mPeriod, 20, kMinimumSamplesForPrediction,
382                            kOutlierTolerancePercent};
383     std::vector<nsecs_t> const simulatedVsyncs{840873348817, 840890049444, 840906762675,
384                                                840923581635, 840940161584, 840956868096,
385                                                840973702473, 840990256277, 841007116851,
386                                                841023722530, 841040452167, 841057073002,
387                                                841073800920, 841090474360, 841107278632,
388                                                841123898634, 841140750875, 841157287127,
389                                                841591357014, 840856664232
390 
391     };
392     auto const idealPeriod = 16666666;
393     auto const expectedPeriod = 16698426;
394     auto const expectedIntercept = 58055;
395 
396     tracker.setPeriod(idealPeriod);
397     for (auto const& timestamp : simulatedVsyncs) {
398         tracker.addVsyncTimestamp(timestamp);
399     }
400 
401     auto [slope, intercept] = tracker.getVSyncPredictionModel();
402     EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
403     EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
404 }
405 
TEST_F(VSyncPredictorTest,resetsWhenInstructed)406 TEST_F(VSyncPredictorTest, resetsWhenInstructed) {
407     auto const idealPeriod = 10000;
408     auto const realPeriod = 10500;
409     tracker.setPeriod(idealPeriod);
410     for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
411         tracker.addVsyncTimestamp(i * realPeriod);
412     }
413 
414     EXPECT_THAT(tracker.getVSyncPredictionModel().slope, IsCloseTo(realPeriod, mMaxRoundingError));
415     tracker.resetModel();
416     EXPECT_THAT(tracker.getVSyncPredictionModel().slope, IsCloseTo(idealPeriod, mMaxRoundingError));
417 }
418 
TEST_F(VSyncPredictorTest,slopeAlwaysValid)419 TEST_F(VSyncPredictorTest, slopeAlwaysValid) {
420     constexpr auto kNumVsyncs = 100;
421     auto invalidPeriod = mPeriod;
422     auto now = 0;
423     for (int i = 0; i < kNumVsyncs; i++) {
424         tracker.addVsyncTimestamp(now);
425         now += invalidPeriod;
426         invalidPeriod *= 0.9f;
427 
428         auto [slope, intercept] = tracker.getVSyncPredictionModel();
429         EXPECT_THAT(slope, IsCloseTo(mPeriod, mPeriod * kOutlierTolerancePercent / 100.f));
430 
431         // When VsyncPredictor returns the period it means that it doesn't know how to predict and
432         // it needs to get more samples
433         if (slope == mPeriod && intercept == 0) {
434             EXPECT_TRUE(tracker.needsMoreSamples());
435         }
436     }
437 }
438 
operator ""_years(unsigned long long years)439 constexpr nsecs_t operator""_years(unsigned long long years) noexcept {
440     using namespace std::chrono_literals;
441     return years * 365 * 24 * 3600 *
442             std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
443 }
TEST_F(VSyncPredictorTest,aPhoneThatHasBeenAroundAWhileCanStillComputePeriod)444 TEST_F(VSyncPredictorTest, aPhoneThatHasBeenAroundAWhileCanStillComputePeriod) {
445     constexpr nsecs_t timeBase = 100_years;
446 
447     for (auto i = 0; i < kHistorySize; i++) {
448         tracker.addVsyncTimestamp(timeBase + i * mPeriod);
449     }
450     auto [slope, intercept] = tracker.getVSyncPredictionModel();
451     EXPECT_THAT(slope, IsCloseTo(mPeriod, mMaxRoundingError));
452     EXPECT_THAT(intercept, Eq(0));
453 }
454 
TEST_F(VSyncPredictorTest,isVSyncInPhase)455 TEST_F(VSyncPredictorTest, isVSyncInPhase) {
456     auto last = mNow;
457     auto const bias = 10;
458     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
459         EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
460         mNow += mPeriod - bias;
461         last = mNow;
462         tracker.addVsyncTimestamp(mNow);
463         mNow += bias;
464     }
465 
466     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod - bias));
467     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod - bias));
468     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 990), Eq(mNow + 2 * mPeriod - bias));
469 
470     const auto maxDivisor = 5;
471     const auto maxPeriods = 15;
472     for (int divisor = 1; divisor < maxDivisor; divisor++) {
473         for (int i = 0; i < maxPeriods; i++) {
474             const bool expectedInPhase = ((kMinimumSamplesForPrediction - 1 + i) % divisor) == 0;
475             EXPECT_THAT(expectedInPhase,
476                         tracker.isVSyncInPhase(mNow + i * mPeriod - bias,
477                                                Fps::fromPeriodNsecs(divisor * mPeriod)))
478                     << "vsync at " << mNow + (i + 1) * mPeriod - bias << " is "
479                     << (expectedInPhase ? "not " : "") << "in phase for divisor " << divisor;
480         }
481     }
482 }
483 
TEST_F(VSyncPredictorTest,isVSyncInPhaseForDivisors)484 TEST_F(VSyncPredictorTest, isVSyncInPhaseForDivisors) {
485     auto last = mNow;
486     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
487         EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
488         mNow += mPeriod;
489         last = mNow;
490         tracker.addVsyncTimestamp(mNow);
491     }
492 
493     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
494 
495     EXPECT_TRUE(tracker.isVSyncInPhase(mNow + 1 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 2)));
496     EXPECT_FALSE(tracker.isVSyncInPhase(mNow + 2 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 2)));
497     EXPECT_TRUE(tracker.isVSyncInPhase(mNow + 3 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 2)));
498 
499     EXPECT_FALSE(tracker.isVSyncInPhase(mNow + 5 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 4)));
500     EXPECT_TRUE(tracker.isVSyncInPhase(mNow + 3 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 4)));
501     EXPECT_FALSE(tracker.isVSyncInPhase(mNow + 4 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 4)));
502     EXPECT_FALSE(tracker.isVSyncInPhase(mNow + 6 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 4)));
503     EXPECT_TRUE(tracker.isVSyncInPhase(mNow + 7 * mPeriod, Fps::fromPeriodNsecs(mPeriod * 4)));
504 }
505 
TEST_F(VSyncPredictorTest,inconsistentVsyncValueIsFlushedEventually)506 TEST_F(VSyncPredictorTest, inconsistentVsyncValueIsFlushedEventually) {
507     EXPECT_TRUE(tracker.addVsyncTimestamp(600));
508     EXPECT_TRUE(tracker.needsMoreSamples());
509 
510     EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += mPeriod));
511 
512     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
513         EXPECT_TRUE(tracker.needsMoreSamples());
514         EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
515     }
516 
517     EXPECT_FALSE(tracker.needsMoreSamples());
518 }
519 
TEST_F(VSyncPredictorTest,knownVsyncIsUpdated)520 TEST_F(VSyncPredictorTest, knownVsyncIsUpdated) {
521     EXPECT_TRUE(tracker.addVsyncTimestamp(600));
522     EXPECT_TRUE(tracker.needsMoreSamples());
523     EXPECT_EQ(600, tracker.nextAnticipatedVSyncTimeFrom(mNow));
524 
525     EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += mPeriod));
526     EXPECT_EQ(mNow + 1000, tracker.nextAnticipatedVSyncTimeFrom(mNow));
527 
528     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
529         EXPECT_TRUE(tracker.needsMoreSamples());
530         EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
531         EXPECT_EQ(mNow + 1000, tracker.nextAnticipatedVSyncTimeFrom(mNow));
532     }
533 
534     EXPECT_FALSE(tracker.needsMoreSamples());
535     EXPECT_EQ(mNow + 1000, tracker.nextAnticipatedVSyncTimeFrom(mNow));
536 }
537 
TEST_F(VSyncPredictorTest,robustToDuplicateTimestamps_60hzRealTraceData)538 TEST_F(VSyncPredictorTest, robustToDuplicateTimestamps_60hzRealTraceData) {
539     // these are real vsync timestamps from b/190331974 which caused vsync predictor
540     // period to spike to 18ms due to very close timestamps
541     std::vector<nsecs_t> const simulatedVsyncs{
542             198353408177, 198370074844, 198371400000, 198374274000, 198390941000, 198407565000,
543             198540887994, 198607538588, 198624218276, 198657655939, 198674224176, 198690880955,
544             198724204319, 198740988133, 198758166681, 198790869196, 198824205052, 198840871678,
545             198857715631, 198890885797, 198924199640, 198940873834, 198974204401,
546     };
547     auto constexpr idealPeriod = 16'666'666;
548     auto constexpr expectedPeriod = 16'644'742;
549     auto constexpr expectedIntercept = 125'626;
550 
551     tracker.setPeriod(idealPeriod);
552     for (auto const& timestamp : simulatedVsyncs) {
553         tracker.addVsyncTimestamp(timestamp);
554     }
555     auto [slope, intercept] = tracker.getVSyncPredictionModel();
556     EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
557     EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
558 }
559 
TEST_F(VSyncPredictorTest,setRenderRateIsRespected)560 TEST_F(VSyncPredictorTest, setRenderRateIsRespected) {
561     auto last = mNow;
562     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
563         EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
564         mNow += mPeriod;
565         last = mNow;
566         tracker.addVsyncTimestamp(mNow);
567     }
568 
569     tracker.setRenderRate(Fps::fromPeriodNsecs(3 * mPeriod));
570 
571     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
572     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod));
573     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1100), Eq(mNow + 4 * mPeriod));
574     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 2100), Eq(mNow + 4 * mPeriod));
575     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 3100), Eq(mNow + 4 * mPeriod));
576     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 4100), Eq(mNow + 7 * mPeriod));
577     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 5100), Eq(mNow + 7 * mPeriod));
578 }
579 
TEST_F(VSyncPredictorTest,setRenderRateOfDivisorIsInPhase)580 TEST_F(VSyncPredictorTest, setRenderRateOfDivisorIsInPhase) {
581     auto last = mNow;
582     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
583         EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
584         mNow += mPeriod;
585         last = mNow;
586         tracker.addVsyncTimestamp(mNow);
587     }
588 
589     const auto refreshRate = Fps::fromPeriodNsecs(mPeriod);
590 
591     tracker.setRenderRate(refreshRate / 4);
592     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + 3 * mPeriod));
593     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 3 * mPeriod), Eq(mNow + 7 * mPeriod));
594     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 7 * mPeriod), Eq(mNow + 11 * mPeriod));
595 
596     tracker.setRenderRate(refreshRate / 2);
597     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + 1 * mPeriod));
598     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1 * mPeriod), Eq(mNow + 3 * mPeriod));
599     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 3 * mPeriod), Eq(mNow + 5 * mPeriod));
600     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 5 * mPeriod), Eq(mNow + 7 * mPeriod));
601     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 7 * mPeriod), Eq(mNow + 9 * mPeriod));
602     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 9 * mPeriod), Eq(mNow + 11 * mPeriod));
603 
604     tracker.setRenderRate(refreshRate / 6);
605     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + 1 * mPeriod));
606     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1 * mPeriod), Eq(mNow + 7 * mPeriod));
607 }
608 
TEST_F(VSyncPredictorTest,setRenderRateIsIgnoredIfNotDivisor)609 TEST_F(VSyncPredictorTest, setRenderRateIsIgnoredIfNotDivisor) {
610     auto last = mNow;
611     for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
612         EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
613         mNow += mPeriod;
614         last = mNow;
615         tracker.addVsyncTimestamp(mNow);
616     }
617 
618     tracker.setRenderRate(Fps::fromPeriodNsecs(3.5f * mPeriod));
619 
620     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
621     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod));
622     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1100), Eq(mNow + 2 * mPeriod));
623     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 2100), Eq(mNow + 3 * mPeriod));
624     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 3100), Eq(mNow + 4 * mPeriod));
625     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 4100), Eq(mNow + 5 * mPeriod));
626     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 5100), Eq(mNow + 6 * mPeriod));
627 }
628 
629 } // namespace android::scheduler
630 
631 // TODO(b/129481165): remove the #pragma below and fix conversion issues
632 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
633