diff options
author | 2024-12-19 17:04:57 -0800 | |
---|---|---|
committer | 2025-01-08 09:45:38 -0800 | |
commit | 734f288a902abf333770f2f64f64a62b9b95edd2 (patch) | |
tree | 1354119c21a699b29b9e7fac01b18412450f4a90 | |
parent | a1635a6f52610fd4847f62c3c149dfdb73dfb5fb (diff) |
Trace critical workloads
Create a new trace track and trace all important work that happens on
the main thread. Keep track of changes in workload as transaction are
queued and committed to infer when the CPU load will increase from
the last frame. This CL only logs the workload.
Flag: EXEMPT logs
Bug: 333623207
Test: perfetto
Change-Id: Ib423d1968545adc89172bd0e40fbde2a31b46ddf
17 files changed, 392 insertions, 3 deletions
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 16425c9872..100261423a 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -302,6 +302,11 @@ struct layer_state_t { static constexpr uint64_t VISIBLE_REGION_CHANGES = layer_state_t::GEOMETRY_CHANGES | layer_state_t::HIERARCHY_CHANGES | layer_state_t::eAlphaChanged; + // Changes that force GPU composition. + static constexpr uint64_t COMPOSITION_EFFECTS = layer_state_t::eBackgroundBlurRadiusChanged | + layer_state_t::eBlurRegionsChanged | layer_state_t::eCornerRadiusChanged | + layer_state_t::eShadowRadiusChanged | layer_state_t::eStretchChanged; + bool hasValidBuffer() const; void sanitize(int32_t permissions); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 20aceb1a82..a982d3e868 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -36,6 +36,10 @@ #include <utils/RefBase.h> #include <utils/Timers.h> +namespace aidl::android::hardware::graphics::composer3 { +enum class Composition; +} + namespace android { class Fence; @@ -176,6 +180,11 @@ public: // Whether the layer should be rendered with rounded corners. virtual bool hasRoundedCorners() const = 0; virtual void setWasClientComposed(const sp<Fence>&) {} + virtual void setHwcCompositionType( + aidl::android::hardware::graphics::composer3::Composition) = 0; + virtual aidl::android::hardware::graphics::composer3::Composition getHwcCompositionType() + const = 0; + virtual const gui::LayerMetadata* getMetadata() const = 0; virtual const gui::LayerMetadata* getRelativeMetadata() const = 0; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index 272fa3eef7..7744b8bb99 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -59,6 +59,10 @@ public: MOCK_CONST_METHOD0(getMetadata, gui::LayerMetadata*()); MOCK_CONST_METHOD0(getRelativeMetadata, gui::LayerMetadata*()); MOCK_METHOD0(onPictureProfileCommitted, void()); + MOCK_METHOD(void, setHwcCompositionType, + (aidl::android::hardware::graphics::composer3::Composition), (override)); + MOCK_METHOD(aidl::android::hardware::graphics::composer3::Composition, getHwcCompositionType, + (), (const, override)); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 96b86d5a31..9b66f01789 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -867,6 +867,7 @@ void OutputLayer::writeCompositionTypeToHWC(HWC2::Layer* hwcLayer, if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType || (outputDependentState.hwc->layerSkipped && !skipLayer)) { outputDependentState.hwc->hwcCompositionType = requestedCompositionType; + getLayerFE().setHwcCompositionType(requestedCompositionType); if (auto error = hwcLayer->setCompositionType(requestedCompositionType); error != hal::Error::NONE) { @@ -964,6 +965,7 @@ void OutputLayer::applyDeviceCompositionTypeChange(Composition compositionType) } hwcState.hwcCompositionType = compositionType; + getLayerFE().setHwcCompositionType(compositionType); } void OutputLayer::prepareForDeviceLayerRequests() { diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index 42f3202f20..523ef7bfbe 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -18,12 +18,17 @@ #undef LOG_TAG #define LOG_TAG "SurfaceFlinger" -#include "LayerSnapshot.h" +#include <PowerAdvisor/Workload.h> +#include <aidl/android/hardware/graphics/composer3/Composition.h> +#include <gui/LayerState.h> + #include "Layer.h" +#include "LayerSnapshot.h" namespace android::surfaceflinger::frontend { using namespace ftl::flag_operators; +using namespace aidl::android::hardware::graphics::composer3; namespace { @@ -532,4 +537,49 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate } } +char LayerSnapshot::classifyCompositionForDebug(Composition compositionType) const { + if (!isVisible) { + return '.'; + } + + switch (compositionType) { + case Composition::INVALID: + return 'i'; + case Composition::SOLID_COLOR: + return 'c'; + case Composition::CURSOR: + return 'u'; + case Composition::SIDEBAND: + return 'd'; + case Composition::DISPLAY_DECORATION: + return 'a'; + case Composition::REFRESH_RATE_INDICATOR: + return 'r'; + case Composition::CLIENT: + case Composition::DEVICE: + break; + } + + char code = '.'; // Default to invisible + if (hasBufferOrSidebandStream()) { + code = 'b'; + } else if (fillsColor()) { + code = 'c'; // Solid color + } else if (hasBlur()) { + code = 'l'; // Blur + } else if (hasProtectedContent) { + code = 'p'; // Protected content + } else if (drawShadows()) { + code = 's'; // Shadow + } else if (roundedCorner.hasRoundedCorners()) { + code = 'r'; // Rounded corners + } + + if (compositionType == Composition::CLIENT) { + return static_cast<char>(std::toupper(code)); + } else { + return code; + } +} + } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 68b13959a8..04b9f3b448 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -16,6 +16,7 @@ #pragma once +#include <PowerAdvisor/Workload.h> #include <compositionengine/LayerFECompositionState.h> #include <renderengine/LayerSettings.h> #include "DisplayHardware/ComposerHal.h" @@ -159,6 +160,10 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { friend std::ostream& operator<<(std::ostream& os, const LayerSnapshot& obj); void merge(const RequestedLayerState& requested, bool forceUpdate, bool displayChanges, bool forceFullDamage, uint32_t displayRotationFlags); + // Returns a char summarizing the composition request + // This function tries to maintain parity with planner::Plan chars. + char classifyCompositionForDebug( + aidl::android::hardware::graphics::composer3::Composition compositionType) const; }; } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index dbb1ed3a9f..617dfbe9c0 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -427,4 +427,14 @@ ftl::Future<FenceResult> LayerFE::createReleaseFenceFuture() { LayerFE::ReleaseFencePromiseStatus LayerFE::getReleaseFencePromiseStatus() { return mReleaseFencePromiseStatus; } + +void LayerFE::setHwcCompositionType( + aidl::android::hardware::graphics::composer3::Composition type) { + mLastHwcCompositionType = type; +} + +aidl::android::hardware::graphics::composer3::Composition LayerFE::getHwcCompositionType() const { + return mLastHwcCompositionType; +} + } // namespace android diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h index 9483aebafa..64ec27862d 100644 --- a/services/surfaceflinger/LayerFE.h +++ b/services/surfaceflinger/LayerFE.h @@ -59,6 +59,9 @@ public: void setReleaseFence(const FenceResult& releaseFence) override; LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() override; void onPictureProfileCommitted() override; + void setHwcCompositionType(aidl::android::hardware::graphics::composer3::Composition) override; + aidl::android::hardware::graphics::composer3::Composition getHwcCompositionType() + const override; std::unique_ptr<surfaceflinger::frontend::LayerSnapshot> mSnapshot; @@ -90,6 +93,8 @@ private: std::string mName; std::promise<FenceResult> mReleaseFence; ReleaseFencePromiseStatus mReleaseFencePromiseStatus = ReleaseFencePromiseStatus::UNINITIALIZED; + aidl::android::hardware::graphics::composer3::Composition mLastHwcCompositionType = + aidl::android::hardware::graphics::composer3::Composition::INVALID; }; } // namespace android diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp index ff452723d5..cd7210c627 100644 --- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp +++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp @@ -29,7 +29,9 @@ #include <android-base/properties.h> #include <android/binder_libbinder.h> +#include <common/WorkloadTracer.h> #include <common/trace.h> +#include <ftl/concat.h> #include <utils/Log.h> #include <utils/Mutex.h> @@ -44,6 +46,7 @@ namespace android::adpf::impl { +using namespace android::ftl::flag_operators; using aidl::android::hardware::common::fmq::SynchronizedReadWrite; using android::hardware::EventFlag; @@ -62,6 +65,8 @@ void traceExpensiveRendering(bool enabled) { } } +static constexpr ftl::Flags<Workload> TRIGGER_LOAD_CHANGE_HINTS = Workload::EFFECTS | + Workload::VISIBLE_REGION | Workload::DISPLAY_CHANGES | Workload::SCREENSHOT; } // namespace PowerAdvisor::PowerAdvisor(std::function<void()>&& sfDisableExpensiveFn, @@ -756,4 +761,58 @@ power::PowerHalController& PowerAdvisor::getPowerHal() { return *mPowerHal; } +void PowerAdvisor::setQueuedWorkload(ftl::Flags<Workload> queued) { + queued &= TRIGGER_LOAD_CHANGE_HINTS; + if (!(queued).get()) return; + uint32_t previousQueuedWorkload = mQueuedWorkload.fetch_or(queued.get()); + + uint32_t newHints = (previousQueuedWorkload ^ queued.get()) & queued.get(); + if (newHints) { + SFTRACE_INSTANT_FOR_TRACK(WorkloadTracer::TRACK_NAME, + ftl::Concat("QueuedWorkload: ", + ftl::truncated<20>(ftl::Flags<Workload>(newHints) + .string() + .c_str())) + .c_str()); + } + if (!previousQueuedWorkload) { + // TODO(b/385028458) maybe load up hint if close to wake up + } +} + +void PowerAdvisor::setScreenshotWorkload() { + mCommittedWorkload |= Workload::SCREENSHOT; +} + +void PowerAdvisor::setCommittedWorkload(ftl::Flags<Workload> workload) { + workload &= TRIGGER_LOAD_CHANGE_HINTS; + uint32_t queued = mQueuedWorkload.exchange(0); + mCommittedWorkload |= workload; + + bool cancelLoadupHint = queued && !mCommittedWorkload.get(); + if (cancelLoadupHint) { + SFTRACE_INSTANT_FOR_TRACK(WorkloadTracer::TRACK_NAME, + ftl::Concat("UncommittedQueuedWorkload: ", + ftl::truncated<20>(ftl::Flags<Workload>(queued) + .string() + .c_str())) + .c_str()); + // TODO(b/385028458) cancel load up hint + } + + bool increasedWorkload = queued == 0 && mCommittedWorkload.get() != 0; + if (increasedWorkload) { + SFTRACE_INSTANT_FOR_TRACK(WorkloadTracer::TRACK_NAME, + ftl::Concat("CommittedWorkload: ", + ftl::truncated<20>(mCommittedWorkload.string())) + .c_str()); + + // TODO(b/385028458) load up hint + } +} + +void PowerAdvisor::setCompositedWorkload(ftl::Flags<Workload> composited) { + composited &= TRIGGER_LOAD_CHANGE_HINTS; + mCommittedWorkload = composited; +} } // namespace android::adpf::impl diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h index 43fc21093f..540a9df2ca 100644 --- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h +++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h @@ -32,9 +32,12 @@ #include <fmq/AidlMessageQueue.h> #pragma clang diagnostic pop +#include <common/trace.h> +#include <ftl/flags.h> #include <scheduler/Time.h> #include <ui/DisplayIdentification.h> #include "../Scheduler/OneShotTimer.h" +#include "Workload.h" #include "SessionManager.h" @@ -109,6 +112,26 @@ public: // Get the session manager, if it exists virtual std::shared_ptr<SessionManager> getSessionManager() = 0; + // --- Track per frame workloads to use for load up hint heuristics + // Track queued workload from transactions as they are queued from the binder thread. + // The workload is accumulated and reset on frame commit. The queued workload may be + // relevant for the next frame so can be used as an early load up hint. Note this is + // only a hint because the transaction can remain in the queue and not be applied on + // the next frame. + virtual void setQueuedWorkload(ftl::Flags<Workload> workload) = 0; + // Track additional workload dur to a screenshot request for load up hint heuristics. This + // would indicate an immediate increase in GPU workload. + virtual void setScreenshotWorkload() = 0; + // Track committed workload from transactions that are applied on the main thread. + // This workload is determined from the applied transactions. This can provide a high + // confidence that the CPU and or GPU workload will increase immediately. + virtual void setCommittedWorkload(ftl::Flags<Workload> workload) = 0; + // Update committed workload with the actual workload from post composition. This is + // used to update the baseline workload so we can detect increases in workloads on the + // next commit. We use composite instead of commit to update the baseline to account + // for optimizations like caching which may reduce the workload. + virtual void setCompositedWorkload(ftl::Flags<Workload> workload) = 0; + // --- The following methods may run on threads besides SF main --- // Send a hint about an upcoming increase in the CPU workload virtual void notifyCpuLoadUp() = 0; @@ -158,6 +181,11 @@ public: void setTotalFrameTargetWorkDuration(Duration targetDuration) override; std::shared_ptr<SessionManager> getSessionManager() override; + void setQueuedWorkload(ftl::Flags<Workload> workload) override; + void setScreenshotWorkload() override; + void setCommittedWorkload(ftl::Flags<Workload> workload) override; + void setCompositedWorkload(ftl::Flags<Workload> workload) override; + // --- The following methods may run on threads besides SF main --- void notifyCpuLoadUp() override; void notifyDisplayUpdateImminentAndCpuReset() override; @@ -332,6 +360,11 @@ private: static constexpr const Duration kFenceWaitStartDelayValidated{150us}; static constexpr const Duration kFenceWaitStartDelaySkippedValidate{250us}; + // Track queued and committed workloads per frame. Queued workload is atomic because it's + // updated on both binder and the main thread. + std::atomic<uint32_t> mQueuedWorkload; + ftl::Flags<Workload> mCommittedWorkload; + void sendHintSessionHint(aidl::android::hardware::power::SessionHint hint); template <aidl::android::hardware::power::ChannelMessage::ChannelMessageContents::Tag T, diff --git a/services/surfaceflinger/PowerAdvisor/Workload.h b/services/surfaceflinger/PowerAdvisor/Workload.h new file mode 100644 index 0000000000..70023579f8 --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/Workload.h @@ -0,0 +1,44 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <ftl/flags.h> +#include <stdint.h> + +namespace android::adpf { +// Additional composition workload that can increase cpu load. +enum class Workload : uint32_t { + NONE = 0, + // Layer effects like blur and shadows which forces client composition + EFFECTS = 1 << 0, + + // Geometry changes which requires HWC to validate and share composition strategy + VISIBLE_REGION = 1 << 1, + + // Diplay changes which can cause geometry changes + DISPLAY_CHANGES = 1 << 2, + + // Changes in sf duration which can shorten the deadline for sf to composite the frame + WAKEUP = 1 << 3, + + // Increases in refresh rates can cause the deadline for sf to composite to be shorter + REFRESH_RATE_INCREASE = 1 << 4, + + // Screenshot requests increase both the cpu and gpu workload + SCREENSHOT = 1 << 5 +}; +} // namespace android::adpf diff --git a/services/surfaceflinger/QueuedTransactionState.h b/services/surfaceflinger/QueuedTransactionState.h index af40c026a0..86683da26c 100644 --- a/services/surfaceflinger/QueuedTransactionState.h +++ b/services/surfaceflinger/QueuedTransactionState.h @@ -21,7 +21,9 @@ #include "FrontEnd/LayerCreationArgs.h" #include "renderengine/ExternalTexture.h" +#include <PowerAdvisor/Workload.h> #include <common/FlagManager.h> +#include <ftl/flags.h> #include <gui/LayerState.h> #include <system/window.h> @@ -148,6 +150,7 @@ struct QueuedTransactionState { uint64_t id; bool sentFenceTimeoutWarning = false; std::vector<uint64_t> mergedTransactionIds; + ftl::Flags<adpf::Workload> workloadHint; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1c185b1dd1..578d7d6a3a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -44,6 +44,7 @@ #include <com_android_graphics_libgui_flags.h> #include <com_android_graphics_surfaceflinger_flags.h> #include <common/FlagManager.h> +#include <common/WorkloadTracer.h> #include <common/trace.h> #include <compositionengine/CompositionEngine.h> #include <compositionengine/CompositionRefreshArgs.h> @@ -156,6 +157,7 @@ #include "MutexUtils.h" #include "NativeWindowSurface.h" #include "PowerAdvisor/PowerAdvisor.h" +#include "PowerAdvisor/Workload.h" #include "RegionSamplingThread.h" #include "RenderAreaBuilder.h" #include "Scheduler/EventThread.h" @@ -2458,6 +2460,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, bool flushTransactions, bool& outTransactionsAreEmpty) { using Changes = frontend::RequestedLayerState::Changes; SFTRACE_CALL(); + SFTRACE_NAME_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Transaction Handling"); frontend::Update update; if (flushTransactions) { SFTRACE_NAME("TransactionHandler:flushTransactions"); @@ -2484,8 +2487,20 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, mDestroyedHandles.clear(); } + size_t addedLayers = update.newLayers.size(); mLayerLifecycleManager.addLayers(std::move(update.newLayers)); update.transactions = mTransactionHandler.flushTransactions(); + ftl::Flags<adpf::Workload> committedWorkload; + for (auto& transaction : update.transactions) { + committedWorkload |= transaction.workloadHint; + } + SFTRACE_INSTANT_FOR_TRACK(WorkloadTracer::TRACK_NAME, + ftl::Concat("Layers: +", addedLayers, " -", + update.destroyedHandles.size(), + " txns:", update.transactions.size()) + .c_str()); + + mPowerAdvisor->setCommittedWorkload(committedWorkload); if (mTransactionTracing) { mTransactionTracing->addCommittedTransactions(ftl::to_underlying(vsyncId), frameTimeNs, update, mFrontEndDisplayInfos, @@ -2686,7 +2701,7 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, return false; } } - + SFTRACE_NAME_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Commit"); const Period vsyncPeriod = mScheduler->getVsyncSchedule()->period(); // Save this once per commit + composite to ensure consistency @@ -2760,6 +2775,7 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, // Hold mStateLock as chooseRefreshRateForContent promotes wp<Layer> to sp<Layer> // and may eventually call to ~Layer() if it holds the last reference { + SFTRACE_NAME_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Refresh Rate Selection"); bool updateAttachedChoreographer = mUpdateAttachedChoreographer; mUpdateAttachedChoreographer = false; @@ -2786,6 +2802,8 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, CompositeResultsPerDisplay SurfaceFlinger::composite( PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters& frameTargeters) { + SFTRACE_ASYNC_FOR_TRACK_BEGIN(WorkloadTracer::TRACK_NAME, "Composition", + WorkloadTracer::COMPOSITION_TRACE_COOKIE); const scheduler::FrameTarget& pacesetterTarget = frameTargeters.get(pacesetterId)->get()->target(); @@ -2948,10 +2966,34 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( } mCompositionEngine->present(refreshArgs); - moveSnapshotsFromCompositionArgs(refreshArgs, layers); + ftl::Flags<adpf::Workload> compositedWorkload; + if (refreshArgs.updatingGeometryThisFrame || refreshArgs.updatingOutputGeometryThisFrame) { + compositedWorkload |= adpf::Workload::VISIBLE_REGION; + } + if (mFrontEndDisplayInfosChanged) { + compositedWorkload |= adpf::Workload::DISPLAY_CHANGES; + SFTRACE_INSTANT_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Display Changes"); + } + int index = 0; + std::array<char, WorkloadTracer::COMPOSITION_SUMMARY_SIZE> compositionSummary = {0}; + auto lastLayerStack = ui::INVALID_LAYER_STACK; for (auto& [layer, layerFE] : layers) { CompositionResult compositionResult{layerFE->stealCompositionResult()}; + if (index < compositionSummary.size()) { + if (lastLayerStack != ui::INVALID_LAYER_STACK && + lastLayerStack != layerFE->mSnapshot->outputFilter.layerStack) { + // add a space to separate displays + compositionSummary[index++] = ' '; + } + lastLayerStack = layerFE->mSnapshot->outputFilter.layerStack; + compositionSummary[index++] = layerFE->mSnapshot->classifyCompositionForDebug( + layerFE->getHwcCompositionType()); + if (layerFE->mSnapshot->hasEffect()) { + compositedWorkload |= adpf::Workload::EFFECTS; + } + } + if (compositionResult.lastClientCompositionFence) { layer->setWasClientComposed(compositionResult.lastClientCompositionFence); } @@ -2960,6 +3002,20 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( } } + // Concisely describe the layers composited this frame using single chars. GPU composited layers + // are uppercase, DPU composited are lowercase. Special chars denote effects (blur, shadow, + // etc.). This provides a snapshot of the compositing workload. + SFTRACE_INSTANT_FOR_TRACK(WorkloadTracer::TRACK_NAME, + ftl::Concat("Layers: ", layers.size(), " ", + ftl::truncated<WorkloadTracer::COMPOSITION_SUMMARY_SIZE>( + compositionSummary.data())) + .c_str()); + + mPowerAdvisor->setCompositedWorkload(compositedWorkload); + moveSnapshotsFromCompositionArgs(refreshArgs, layers); + SFTRACE_ASYNC_FOR_TRACK_END(WorkloadTracer::TRACK_NAME, + WorkloadTracer::COMPOSITION_TRACE_COOKIE); + SFTRACE_NAME_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Post Composition"); SFTRACE_NAME("postComposition"); mTimeStats->recordFrameDuration(pacesetterTarget.frameBeginTime().ns(), systemTime()); @@ -4874,8 +4930,15 @@ status_t SurfaceFlinger::setTransactionState( const int originPid = ipc->getCallingPid(); const int originUid = ipc->getCallingUid(); uint32_t permissions = LayerStatePermissions::getTransactionPermissions(originPid, originUid); + ftl::Flags<adpf::Workload> queuedWorkload; for (auto& composerState : states) { composerState.state.sanitize(permissions); + if (composerState.state.what & layer_state_t::COMPOSITION_EFFECTS) { + queuedWorkload |= adpf::Workload::EFFECTS; + } + if (composerState.state.what & layer_state_t::VISIBLE_REGION_CHANGES) { + queuedWorkload |= adpf::Workload::VISIBLE_REGION; + } } for (DisplayState& display : displays) { @@ -4898,6 +4961,10 @@ status_t SurfaceFlinger::setTransactionState( flags &= ~(eEarlyWakeupStart | eEarlyWakeupEnd); } } + if (flags & eEarlyWakeupStart) { + queuedWorkload |= adpf::Workload::WAKEUP; + } + mPowerAdvisor->setQueuedWorkload(queuedWorkload); const int64_t postTime = systemTime(); @@ -4961,6 +5028,7 @@ status_t SurfaceFlinger::setTransactionState( originUid, transactionId, mergedTransactionIds}; + state.workloadHint = queuedWorkload; if (mTransactionTracing) { mTransactionTracing->addQueuedTransaction(state); @@ -7394,6 +7462,8 @@ std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getSnapsho std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) { return mScheduler ->schedule([=, this, &renderAreaBuilder, &layers]() REQUIRES(kMainThreadContext) { + SFTRACE_NAME_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Screenshot"); + mPowerAdvisor->setScreenshotWorkload(); SFTRACE_NAME("getSnapshotsFromMainThread"); layers = getLayerSnapshotsFn(); // Non-threaded RenderEngine eventually returns to the main thread a 2nd time diff --git a/services/surfaceflinger/common/include/common/WorkloadTracer.h b/services/surfaceflinger/common/include/common/WorkloadTracer.h new file mode 100644 index 0000000000..39b6fa1bf4 --- /dev/null +++ b/services/surfaceflinger/common/include/common/WorkloadTracer.h @@ -0,0 +1,29 @@ + +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <ftl/flags.h> +#include <stdint.h> +namespace android::WorkloadTracer { + +static constexpr int32_t COMPOSITION_TRACE_COOKIE = 1; +static constexpr int32_t POST_COMPOSITION_TRACE_COOKIE = 2; +static constexpr size_t COMPOSITION_SUMMARY_SIZE = 20; +static constexpr const char* TRACK_NAME = "CriticalWorkload"; + +} // namespace android::WorkloadTracer
\ No newline at end of file diff --git a/services/surfaceflinger/common/include/common/trace.h b/services/surfaceflinger/common/include/common/trace.h index dc5716ba05..9a7e97feba 100644 --- a/services/surfaceflinger/common/include/common/trace.h +++ b/services/surfaceflinger/common/include/common/trace.h @@ -65,6 +65,8 @@ #define SFTRACE_NAME(name) ::android::ScopedTrace PASTE(___tracer, __LINE__)(name) // SFTRACE_CALL is an SFTRACE_NAME that uses the current function name. #define SFTRACE_CALL() SFTRACE_NAME(__FUNCTION__) +#define SFTRACE_NAME_FOR_TRACK(trackName, name) \ + ::android::ScopedTraceForTrack PASTE(___tracer, __LINE__)(trackName, name) #define SFTRACE_FORMAT(fmt, ...) \ ::android::ScopedTrace PASTE(___tracer, __LINE__)(fmt, ##__VA_ARGS__) @@ -87,4 +89,21 @@ public: inline ~ScopedTrace() { SFTRACE_END(); } }; +class ScopedTraceForTrack { +public: + inline ScopedTraceForTrack(const char* trackName, const char* name) + : mCookie(getUniqueCookie()), mTrackName(trackName) { + SFTRACE_ASYNC_FOR_TRACK_BEGIN(mTrackName, name, mCookie); + } + inline ~ScopedTraceForTrack() { SFTRACE_ASYNC_FOR_TRACK_END(mTrackName, mCookie); } + +private: + static int32_t getUniqueCookie() { + static std::atomic<int32_t> sUniqueCookie = 1000; + return sUniqueCookie++; + } + int32_t mCookie; + const char* mTrackName; +}; + } // namespace android diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp index 5c25f34ae7..d7f7bdb9db 100644 --- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp +++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp @@ -39,6 +39,7 @@ using namespace android::hardware::power; using namespace std::chrono_literals; using namespace testing; using namespace android::power; +using namespace ftl::flag_operators; namespace android::adpf::impl { @@ -54,6 +55,8 @@ public: void setTimingTestingMode(bool testinMode); void allowReportActualToAcquireMutex(); bool sessionExists(); + ftl::Flags<Workload> getCommittedWorkload() const; + ftl::Flags<Workload> getQueuedWorkload() const; int64_t toNanos(Duration d); struct GpuTestConfig { @@ -315,6 +318,14 @@ Duration PowerAdvisorTest::getErrorMargin() { return mPowerAdvisor->sTargetSafetyMargin; } +ftl::Flags<Workload> PowerAdvisorTest::getCommittedWorkload() const { + return mPowerAdvisor->mCommittedWorkload; +} + +ftl::Flags<Workload> PowerAdvisorTest::getQueuedWorkload() const { + return ftl::Flags<Workload>{mPowerAdvisor->mQueuedWorkload.load()}; +} + namespace { TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) { @@ -842,5 +853,32 @@ TEST_F(PowerAdvisorTest, fmq_sendHint_queueFull) { ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP); } +TEST_F(PowerAdvisorTest, trackQueuedWorkloads) { + mPowerAdvisor->setQueuedWorkload(ftl::Flags<Workload>()); + ASSERT_EQ(getQueuedWorkload(), ftl::Flags<Workload>()); + + // verify workloads are queued + mPowerAdvisor->setQueuedWorkload(ftl::Flags<Workload>(Workload::VISIBLE_REGION)); + ASSERT_EQ(getQueuedWorkload(), ftl::Flags<Workload>(Workload::VISIBLE_REGION)); + + mPowerAdvisor->setQueuedWorkload(ftl::Flags<Workload>(Workload::EFFECTS)); + ASSERT_EQ(getQueuedWorkload(), Workload::VISIBLE_REGION | Workload::EFFECTS); + + // verify queued workloads are cleared after commit + mPowerAdvisor->setCommittedWorkload(ftl::Flags<Workload>()); + ASSERT_EQ(getQueuedWorkload(), ftl::Flags<Workload>()); +} + +TEST_F(PowerAdvisorTest, trackCommittedWorkloads) { + // verify queued workloads are cleared after commit + mPowerAdvisor->setCommittedWorkload(Workload::SCREENSHOT | Workload::VISIBLE_REGION); + ASSERT_EQ(getCommittedWorkload(), Workload::SCREENSHOT | Workload::VISIBLE_REGION); + + // on composite, verify we update the committed workload so we track workload increases for the + // next frame accurately + mPowerAdvisor->setCompositedWorkload(Workload::VISIBLE_REGION | Workload::DISPLAY_CHANGES); + ASSERT_EQ(getCommittedWorkload(), Workload::VISIBLE_REGION | Workload::DISPLAY_CHANGES); +} + } // namespace } // namespace android::adpf::impl diff --git a/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h index fd55597d7a..5abee16bd0 100644 --- a/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h +++ b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h @@ -65,6 +65,10 @@ public: MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (Duration targetDuration), (override)); MOCK_METHOD(std::shared_ptr<SessionManager>, getSessionManager, (), (override)); MOCK_METHOD(sp<IBinder>, getOrCreateSessionManagerForBinder, (uid_t uid), (override)); + MOCK_METHOD(void, setQueuedWorkload, (ftl::Flags<Workload> workload), (override)); + MOCK_METHOD(void, setScreenshotWorkload, (), (override)); + MOCK_METHOD(void, setCommittedWorkload, (ftl::Flags<Workload> workload), (override)); + MOCK_METHOD(void, setCompositedWorkload, (ftl::Flags<Workload> workload), (override)); }; } // namespace android::adpf::mock |