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

Commit d7599d83 authored by Alec Mouri's avatar Alec Mouri
Browse files

[SurfaceFlinger] Add vsync offset information to systrace.

* Trace offset values in DispSyncSource
* Trace offset type in VSyncModulator
* Refactor how offsets are stored so that refresh rate type can be
encoded in VSyncModulator
* Add locking to catch a potential race condition when updating offsets,
as phase offsets can be accessed or updated on multiple threads.

Bug: 133325345
Test: verified that correct offsets are reported in systrace
Change-Id: I38d43b722cd54728a2e4de3df7dd472aceb1de15
parent b488afaa
Loading
Loading
Loading
Loading
+19 −5
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset,
        mTraceVsync(traceVsync),
        mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
        mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)),
        mVsyncOffsetLabel(base::StringPrintf("VsyncOffset-%s", name)),
        mVsyncNegativeOffsetLabel(base::StringPrintf("VsyncNegativeOffset-%s", name)),
        mDispSync(dispSync),
        mPhaseOffset(phaseOffset),
        mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {}
@@ -41,6 +43,7 @@ DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset,
void DispSyncSource::setVSyncEnabled(bool enable) {
    std::lock_guard lock(mVsyncMutex);
    if (enable) {
        tracePhaseOffset();
        status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
                                                   static_cast<DispSync::Callback*>(this),
                                                   mLastCallbackTime);
@@ -76,6 +79,7 @@ void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) {
    const int numPeriods = phaseOffset / period;
    phaseOffset -= numPeriods * period;
    mPhaseOffset = phaseOffset;
    tracePhaseOffset();

    // If we're not enabled, we don't need to mess with the listeners
    if (!mEnabled) {
@@ -94,16 +98,26 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) {
    {
        std::lock_guard lock(mCallbackMutex);
        callback = mCallback;
    }

    if (mTraceVsync) {
        mValue = (mValue + 1) % 2;
        ATRACE_INT(mVsyncEventLabel.c_str(), mValue);
    }
    }

    if (callback != nullptr) {
        callback->onVSyncEvent(when);
    }
}

void DispSyncSource::tracePhaseOffset() {
    if (mPhaseOffset > 0) {
        ATRACE_INT(mVsyncOffsetLabel.c_str(), mPhaseOffset);
        ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), 0);
    } else {
        ATRACE_INT(mVsyncOffsetLabel.c_str(), 0);
        ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), -mPhaseOffset);
    }
}

} // namespace android
+5 −1
Original line number Diff line number Diff line
@@ -39,12 +39,16 @@ private:
    // The following method is the implementation of the DispSync::Callback.
    virtual void onDispSyncEvent(nsecs_t when);

    void tracePhaseOffset() REQUIRES(mVsyncMutex);

    const char* const mName;
    int mValue = 0;

    const bool mTraceVsync;
    const std::string mVsyncOnLabel;
    const std::string mVsyncEventLabel;
    const std::string mVsyncOffsetLabel;
    const std::string mVsyncNegativeOffsetLabel;
    nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0;

    DispSync* mDispSync;
+28 −25
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ using namespace android::sysprop;

namespace scheduler {

using RefreshRateType = RefreshRateConfigs::RefreshRateType;
PhaseOffsets::~PhaseOffsets() = default;

namespace impl {
@@ -72,25 +73,32 @@ PhaseOffsets::PhaseOffsets() {
    property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1");
    const int phaseOffsetThresholdForNextVsyncNs = atoi(value);

    mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs
                                                              : sfVsyncPhaseOffsetNs,
                                        earlyAppOffsetNs != -1 ? earlyAppOffsetNs
                                                               : vsyncPhaseOffsetNs};
    mDefaultRefreshRateOffsets.earlyGl = {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs
                                                                  : sfVsyncPhaseOffsetNs,
                                          earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs
                                                                   : vsyncPhaseOffsetNs};
    mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};

    mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
    Offsets defaultOffsets;
    Offsets highFpsOffsets;
    defaultOffsets.early = {RefreshRateType::DEFAULT,
                            earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
                            earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
    defaultOffsets.earlyGl = {RefreshRateType::DEFAULT,
                              earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
                              earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
    defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};

    highFpsOffsets.early = {RefreshRateType::PERFORMANCE,
                            highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
                                                         : highFpsLateSfOffsetNs,
                            highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
                                                          : highFpsLateAppOffsetNs};
    mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
    highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE,
                              highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
                                                             : highFpsLateSfOffsetNs,
                              highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
                                                              : highFpsLateAppOffsetNs};
    mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs};
    highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs,
                           highFpsLateAppOffsetNs};

    mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets});
    mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets});
    mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets});

    mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1
            ? phaseOffsetThresholdForNextVsyncNs
@@ -99,12 +107,7 @@ PhaseOffsets::PhaseOffsets() {

PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(
        android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const {
    switch (refreshRateType) {
        case RefreshRateConfigs::RefreshRateType::PERFORMANCE:
            return mHighRefreshRateOffsets;
        default:
            return mDefaultRefreshRateOffsets;
    }
    return mOffsets.at(refreshRateType);
}

void PhaseOffsets::dump(std::string& result) const {
+2 −5
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#pragma once

#include <cinttypes>
#include <unordered_map>

#include "RefreshRateConfigs.h"
#include "VSyncModulator.h"
@@ -79,14 +80,10 @@ public:
    void dump(std::string& result) const override;

private:
    Offsets getDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; }
    Offsets getHighRefreshRateOffsets() { return mHighRefreshRateOffsets; }

    std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType =
            RefreshRateConfigs::RefreshRateType::DEFAULT;

    Offsets mDefaultRefreshRateOffsets;
    Offsets mHighRefreshRateOffsets;
    std::unordered_map<RefreshRateConfigs::RefreshRateType, Offsets> mOffsets;
    nsecs_t mOffsetThresholdForNextVsync;
};
} // namespace impl
+61 −18
Original line number Diff line number Diff line
@@ -14,28 +14,36 @@
 * limitations under the License.
 */

#define ATRACE_TAG ATRACE_TAG_GRAPHICS

#include "VSyncModulator.h"

#include <cutils/properties.h>
#include <utils/Trace.h>

#include <cinttypes>
#include <mutex>

namespace android {

using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
VSyncModulator::VSyncModulator() {
    char value[PROPERTY_VALUE_MAX];
    property_get("debug.sf.vsync_trace_detailed_info", value, "0");
    mTraceDetailedInfo = atoi(value);
    // Populate the offset map with some default offsets.
    const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0};
    setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0);
}

void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
                                     nsecs_t thresholdForNextVsync) {
    mEarlyOffsets = early;
    mEarlyGlOffsets = earlyGl;
    mLateOffsets = late;
    std::lock_guard<std::mutex> lock(mMutex);
    mOffsetMap.insert_or_assign(OffsetType::Early, early);
    mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl);
    mOffsetMap.insert_or_assign(OffsetType::Late, late);
    mThresholdForNextVsync = thresholdForNextVsync;

    if (mSfConnectionHandle && late.sf != mOffsets.load().sf) {
        mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf);
    }

    if (mAppConnectionHandle && late.app != mOffsets.load().app) {
        mScheduler->setPhaseOffset(mAppConnectionHandle, late.app);
    }
    mOffsets = late;
    updateOffsetsLocked();
}

void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) {
@@ -93,21 +101,35 @@ void VSyncModulator::onRefreshed(bool usedRenderEngine) {
}

VSyncModulator::Offsets VSyncModulator::getOffsets() {
    std::lock_guard<std::mutex> lock(mMutex);
    return mOffsetMap.at(mOffsetType);
}

VSyncModulator::Offsets VSyncModulator::getNextOffsets() {
    return mOffsetMap.at(getNextOffsetType());
}

VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() {
    // Early offsets are used if we're in the middle of a refresh rate
    // change, or if we recently begin a transaction.
    if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 ||
        mRefreshRateChangePending) {
        return mEarlyOffsets;
        return OffsetType::Early;
    } else if (mRemainingRenderEngineUsageCount > 0) {
        return mEarlyGlOffsets;
        return OffsetType::EarlyGl;
    } else {
        return mLateOffsets;
        return OffsetType::Late;
    }
}

void VSyncModulator::updateOffsets() {
    const Offsets desired = getOffsets();
    const Offsets current = mOffsets;
    std::lock_guard<std::mutex> lock(mMutex);
    updateOffsetsLocked();
}

void VSyncModulator::updateOffsetsLocked() {
    const Offsets desired = getNextOffsets();
    const Offsets current = mOffsetMap.at(mOffsetType);

    bool changed = false;
    if (desired.sf != current.sf) {
@@ -128,8 +150,29 @@ void VSyncModulator::updateOffsets() {
    }

    if (changed) {
        mOffsets = desired;
        updateOffsetType();
    }
}

void VSyncModulator::updateOffsetType() {
    mOffsetType = getNextOffsetType();
    if (!mTraceDetailedInfo) {
        return;
    }
    OffsetType type = mOffsetType;
    Offsets offsets = mOffsetMap.at(type);
    ATRACE_INT("Vsync-EarlyOffsetsOn",
               offsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early);
    ATRACE_INT("Vsync-EarlyGLOffsetsOn",
               offsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl);
    ATRACE_INT("Vsync-LateOffsetsOn",
               offsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late);
    ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn",
               offsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early);
    ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn",
               offsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl);
    ATRACE_INT("Vsync-HighFpsLateOffsetsOn",
               offsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late);
}

} // namespace android
Loading