Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6db6d622 authored by Alec Mouri's avatar Alec Mouri
Browse files

When adding event listener, use fuzzy window for last event time.

* We track the last callback time anyways, so there's no risk of
double-firing
* Without this we might risk missing a dispsync event. E.g., if vsyncs
are at T and T+11, and we're considering SF events with +1 offset, then
SF will fire at T+1. If we immediately deregister the SF listener, then
re-register later at T+13, we miss the event at T+12. But we would
probably be ok to fire at T+13 anyways.

Note that the old last event time inference did allow for this.
See change I742b30a8d28780a44592c4d3077f33d23cf65789...

listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase - mWakeupLatency;

...with +2/+6 offsets and 16.6ms period, then if SF registers at +7ms
after vsync, then last event time is inferred to be T-1.3ms, and with
reference time T-16.6ms, then the next computed event time ends up being
(floor(((T-1.3) - (T-16.6) - 6)/16.6) + 1)* 16.6 + 6 + T-16.6, which ends up
being T+6ms, which would immediately cause a wakeup. So this change
reintroduces that behavior while keeping the math right.

Bug: 128918820
Test: systrace
Change-Id: If45be5a579628045ba3d9bfe282bf8831fdb5275
parent 5e1371af
Loading
Loading
Loading
Loading
+11 −10
Original line number Diff line number Diff line
@@ -211,13 +211,14 @@ public:
            const nsecs_t numPeriodsSinceReference = baseTime / mPeriod;
            const nsecs_t predictedReference = mReferenceTime + numPeriodsSinceReference * mPeriod;
            const nsecs_t phaseCorrection = mPhase + listener.mPhase;
            const nsecs_t predictedLastEventTime = predictedReference + phaseCorrection;
            if (predictedLastEventTime >= now) {
                // Make sure that the last event time does not exceed the current time.
                // If it would, then back the last event time by a period.
                listener.mLastEventTime = predictedLastEventTime - mPeriod;
            } else {
                listener.mLastEventTime = predictedLastEventTime;
            listener.mLastEventTime = predictedReference + phaseCorrection;
            // If we're very close in time to the predicted last event time,
            // then we need to back up the last event time so that we can
            // attempt to fire an event immediately.
            //
            // Otherwise, keep the last event time that we predicted.
            if (isShorterThanPeriod(now - listener.mLastEventTime)) {
                listener.mLastEventTime -= mPeriod;
            }
        } else {
            listener.mLastEventTime = now + mPhase - mWakeupLatency;
@@ -314,7 +315,7 @@ private:

    // Sanity check that the duration is close enough in length to a period without
    // falling into double-rate vsyncs.
    bool isCloseToPeriod(nsecs_t duration) {
    bool isShorterThanPeriod(nsecs_t duration) {
        // Ratio of 3/5 is arbitrary, but it must be greater than 1/2.
        return duration < (3 * mPeriod) / 5;
    }
@@ -330,7 +331,7 @@ private:
            nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);

            if (t < now) {
                if (isCloseToPeriod(now - eventListener.mLastCallbackTime)) {
                if (isShorterThanPeriod(now - eventListener.mLastCallbackTime)) {
                    eventListener.mLastEventTime = t;
                    eventListener.mLastCallbackTime = now;
                    ALOGV("[%s] [%s] Skipping event due to model error", mName,
@@ -391,7 +392,7 @@ private:

        // Check that it's been slightly more than half a period since the last
        // event so that we don't accidentally fall into double-rate vsyncs
        if (isCloseToPeriod(t - listener.mLastEventTime)) {
        if (isShorterThanPeriod(t - listener.mLastEventTime)) {
            t += mPeriod;
            ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
        }