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