diff options
| author | 2019-05-22 19:58:00 -0700 | |
|---|---|---|
| committer | 2019-09-03 19:09:40 -0700 | |
| commit | 38baf72ccb8d1df176255d9756ef697cd4d2ffab (patch) | |
| tree | fe194a1886e0081c5bb7c4a34f4c6eae03432f8f | |
| parent | a9c4d556084fb3b8592063b451c72f0ab0f7a65d (diff) | |
[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
(cherry picked from commit d7599d832c96cc3ba0c2ad19653f29bdfe084284)
Merged-In: I38d43b722cd54728a2e4de3df7dd472aceb1de15
7 files changed, 150 insertions, 75 deletions
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 265b8aa47f..026b55707c 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -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,11 +98,11 @@ 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 (mTraceVsync) { + mValue = (mValue + 1) % 2; + ATRACE_INT(mVsyncEventLabel.c_str(), mValue); } if (callback != nullptr) { @@ -106,4 +110,14 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) { } } -} // namespace android
\ No newline at end of file +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 diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h index b6785c5f74..50560a5a2b 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.h +++ b/services/surfaceflinger/Scheduler/DispSyncSource.h @@ -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; @@ -58,4 +62,4 @@ private: bool mEnabled GUARDED_BY(mVsyncMutex) = false; }; -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 276bce1f89..8a2604f4a3 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -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 - : highFpsLateSfOffsetNs, - highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs - : highFpsLateAppOffsetNs}; - mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs - : highFpsLateSfOffsetNs, - highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs - : highFpsLateAppOffsetNs}; - mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}; + 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}; + highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE, + highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs + : highFpsLateSfOffsetNs, + highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs + : 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 { diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h index dc71e6eb60..2b5c2f10f1 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.h +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h @@ -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 diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp index af8f445b30..381308ab34 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp +++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp @@ -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 diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 677862e4fe..c6374be83a 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -39,13 +39,22 @@ private: const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; public: + VSyncModulator(); + // Wrapper for a collection of surfaceflinger/app offsets for a particular // configuration . struct Offsets { + scheduler::RefreshRateConfigs::RefreshRateType fpsMode; nsecs_t sf; nsecs_t app; }; + enum class OffsetType { + Early, + EarlyGl, + Late, + }; + // Sets the phase offsets // // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction @@ -57,13 +66,7 @@ public: // appEarlyGl: Like sfEarlyGl, but for the app-vsync. // appLate: The regular app vsync phase offset. void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, - nsecs_t thresholdForNextVsync); - - // Returns the configured early offsets. - Offsets getEarlyOffsets() const { return mEarlyOffsets; } - - // Returns the configured early gl offsets. - Offsets getEarlyGlOffsets() const { return mEarlyGlOffsets; } + nsecs_t thresholdForNextVsync) EXCLUDES(mMutex); // Sets handles to the SF and app event threads. void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) { @@ -100,15 +103,22 @@ public: // frame. void onRefreshed(bool usedRenderEngine); - // Returns the offsets that should be used. - Offsets getOffsets(); + // Returns the offsets that we are currently using + Offsets getOffsets() EXCLUDES(mMutex); private: - void updateOffsets(); - - Offsets mLateOffsets; - Offsets mEarlyOffsets; - Offsets mEarlyGlOffsets; + // Returns the next offsets that we should be using + Offsets getNextOffsets() REQUIRES(mMutex); + // Returns the next offset type that we should use. + OffsetType getNextOffsetType(); + // Updates offsets and persists them into the scheduler framework. + void updateOffsets() EXCLUDES(mMutex); + void updateOffsetsLocked() REQUIRES(mMutex); + // Updates the internal offset type. + void updateOffsetType() REQUIRES(mMutex); + + mutable std::mutex mMutex; + std::unordered_map<OffsetType, Offsets> mOffsetMap GUARDED_BY(mMutex); nsecs_t mThresholdForNextVsync; EventThread* mSfEventThread = nullptr; @@ -118,13 +128,15 @@ private: Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr; Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr; - std::atomic<Offsets> mOffsets; + OffsetType mOffsetType GUARDED_BY(mMutex) = OffsetType::Late; std::atomic<Scheduler::TransactionStart> mTransactionStart = Scheduler::TransactionStart::NORMAL; std::atomic<bool> mRefreshRateChangePending = false; std::atomic<int> mRemainingEarlyFrameCount = 0; std::atomic<int> mRemainingRenderEngineUsageCount = 0; + + bool mTraceDetailedInfo = false; }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h index 96121bb088..1d7501102e 100644 --- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h +++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h @@ -23,6 +23,8 @@ namespace android { namespace scheduler { +using RefreshRateType = RefreshRateConfigs::RefreshRateType; + class FakePhaseOffsets : public android::scheduler::PhaseOffsets { nsecs_t FAKE_PHASE_OFFSET_NS = 0; @@ -34,20 +36,20 @@ public: nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; } PhaseOffsets::Offsets getOffsetsForRefreshRate( - RefreshRateConfigs::RefreshRateType /*refreshRateType*/) const override { + RefreshRateType /*refreshRateType*/) const override { return getCurrentOffsets(); } // Returns early, early GL, and late offsets for Apps and SF. PhaseOffsets::Offsets getCurrentOffsets() const override { - return Offsets{{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}}; + return Offsets{{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}}; } // This function should be called when the device is switching between different // refresh rates, to properly update the offsets. - void setRefreshRateType(RefreshRateConfigs::RefreshRateType /*refreshRateType*/) override {} + void setRefreshRateType(RefreshRateType /*refreshRateType*/) override {} nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; } @@ -56,4 +58,4 @@ public: }; } // namespace scheduler -} // namespace android
\ No newline at end of file +} // namespace android |