Tweak wakeup time for OneShotTimer to reduce jank
Power optimizations for OneShotTimer from change
I83f968042395857237875aab8dca0e6b90d392cb accidentally relaxed the
practical timing requirements for OneShotTimer by allowing for waiting
on a semaphore longer than intended - the optimiation amounted to
throttling the number of sem_post calls, and relying on the idle timeout
thread to check if the timer reset on wakeup before either re-entering
the reset loop or entering the idle loop. But that requires adjusting
the timeout for waiting on the semaphore by the idle timeout thread,
which did not happen. So it was possible to delay moving into an idle
state by up to double what a OneShotTimer was configured to do so. The net effect is that when a device wakes up from an idle state, it may delay learning the vsync cadence if the kernel dropped the refresh rate under the scenes, which causes noticeable jank over the first few frames.
This patch resolves this discepancy by shortening the interval that the
idle timeout thread waits on the semphore for, based on the last time
OneShotTimer::reset was called.
Bug: 233713246
Test: UIBench jank tests
Change-Id: I915822ab71ea3595a02ffbebe16e591a622fcd80
diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index 597e5e7..aafc323 100644
--- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -130,6 +130,40 @@
EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
}
+// TODO(b/186417847) This test is new and passes locally, but may be flaky
+TEST_F(OneShotTimerTest, DISABLED_resetBackToBackSlowAdvanceTest) {
+ fake::FakeClock* clock = new fake::FakeClock();
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
+ mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable(),
+ std::unique_ptr<fake::FakeClock>(clock));
+ mIdleTimer->start();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+
+ mIdleTimer->reset();
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+
+ clock->advanceTime(200us);
+ mIdleTimer->reset();
+
+ // Normally we would check that the timer callbacks weren't invoked here
+ // after resetting the timer, but we need to precisely control the timing of
+ // this test, and checking that callbacks weren't invoked requires non-zero
+ // time.
+
+ clock->advanceTime(1500us);
+ EXPECT_TRUE(mExpiredTimerCallback.waitForCall(1100us).has_value());
+ mIdleTimer->reset();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+
+ mIdleTimer->stop();
+ clock->advanceTime(2ms);
+ // Final quick check that no more callback were observed.
+ EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
+}
+
TEST_F(OneShotTimerTest, startNotCalledTest) {
fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,