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
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 20aceb1..a982d3e 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 @@
// 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 272fa3e..7744b8b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -59,6 +59,10 @@
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 96b86d5..9b66f01 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -867,6 +867,7 @@
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 @@
}
hwcState.hwcCompositionType = compositionType;
+ getLayerFE().setHwcCompositionType(compositionType);
}
void OutputLayer::prepareForDeviceLayerRequests() {
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 42f3202..523ef7b 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 @@
}
}
+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 68b1395..04b9f3b 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 @@
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 dbb1ed3..617dfbe 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -427,4 +427,14 @@
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 9483aeb..64ec278 100644
--- a/services/surfaceflinger/LayerFE.h
+++ b/services/surfaceflinger/LayerFE.h
@@ -59,6 +59,9 @@
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 @@
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 ff45272..cd7210c 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 @@
}
}
+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 @@
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 43fc210..540a9df 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 @@
// 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 @@
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 @@
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 0000000..7002357
--- /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 af40c02..86683da 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 @@
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 1c185b1..578d7d6 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 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 @@
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 @@
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 @@
// 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 @@
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 @@
}
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 @@
}
}
+ // 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 @@
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 @@
flags &= ~(eEarlyWakeupStart | eEarlyWakeupEnd);
}
}
+ if (flags & eEarlyWakeupStart) {
+ queuedWorkload |= adpf::Workload::WAKEUP;
+ }
+ mPowerAdvisor->setQueuedWorkload(queuedWorkload);
const int64_t postTime = systemTime();
@@ -4961,6 +5028,7 @@
originUid,
transactionId,
mergedTransactionIds};
+ state.workloadHint = queuedWorkload;
if (mTransactionTracing) {
mTransactionTracing->addQueuedTransaction(state);
@@ -7394,6 +7462,8 @@
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 0000000..39b6fa1
--- /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 dc5716b..9a7e97f 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 @@
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 5c25f34..d7f7bdb 100644
--- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
@@ -39,6 +39,7 @@
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 @@
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 @@
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 @@
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 fd55597..5abee16 100644
--- a/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h
@@ -65,6 +65,10 @@
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