Skip to content

Commit 93dcdcb

Browse files
Dominik LaskowskiAndroid (Google) Code Review
authored andcommitted
Merge "SF: Report missed frames per display" into main
2 parents 174a289 + ec0eac2 commit 93dcdcb

15 files changed

Lines changed: 295 additions & 134 deletions

services/surfaceflinger/Scheduler/Scheduler.cpp

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
2626
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
2727
#include <configstore/Utils.h>
28+
#include <ftl/concat.h>
2829
#include <ftl/enum.h>
2930
#include <ftl/fake_guard.h>
3031
#include <ftl/small_map.h>
@@ -130,8 +131,8 @@ void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId,
130131
auto [pacesetterVsyncSchedule, isNew] = [&]() FTL_FAKE_GUARD(kMainThreadContext) {
131132
std::scoped_lock lock(mDisplayLock);
132133
const bool isNew = mDisplays
133-
.emplace_or_replace(displayId, std::move(selectorPtr),
134-
std::move(schedulePtr))
134+
.emplace_or_replace(displayId, displayId, std::move(selectorPtr),
135+
std::move(schedulePtr), mFeatures)
135136
.second;
136137

137138
return std::make_pair(promotePacesetterDisplayLocked(), isNew);
@@ -171,21 +172,43 @@ void Scheduler::run() {
171172

172173
void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
173174
TimePoint expectedVsyncTime) {
174-
mPacesetterFrameTargeter.beginFrame({.frameBeginTime = SchedulerClock::now(),
175-
.vsyncId = vsyncId,
176-
.expectedVsyncTime = expectedVsyncTime,
177-
.sfWorkDuration =
178-
mVsyncModulator->getVsyncConfig().sfWorkDuration},
179-
*getVsyncSchedule());
180-
181-
if (!compositor.commit(mPacesetterFrameTargeter.target())) {
182-
return;
175+
const FrameTargeter::BeginFrameArgs beginFrameArgs =
176+
{.frameBeginTime = SchedulerClock::now(),
177+
.vsyncId = vsyncId,
178+
// TODO(b/255601557): Calculate per display.
179+
.expectedVsyncTime = expectedVsyncTime,
180+
.sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration};
181+
182+
LOG_ALWAYS_FATAL_IF(!mPacesetterDisplayId);
183+
const auto pacesetterId = *mPacesetterDisplayId;
184+
const auto pacesetterOpt = mDisplays.get(pacesetterId);
185+
186+
FrameTargeter& pacesetterTargeter = *pacesetterOpt->get().targeterPtr;
187+
pacesetterTargeter.beginFrame(beginFrameArgs, *pacesetterOpt->get().schedulePtr);
188+
189+
if (!compositor.commit(pacesetterTargeter.target())) return;
190+
191+
// TODO(b/256196556): Choose the frontrunner display.
192+
FrameTargeters targeters;
193+
targeters.try_emplace(pacesetterId, &pacesetterTargeter);
194+
195+
for (auto& [id, display] : mDisplays) {
196+
if (id == pacesetterId) continue;
197+
198+
FrameTargeter& targeter = *display.targeterPtr;
199+
targeter.beginFrame(beginFrameArgs, *display.schedulePtr);
200+
201+
targeters.try_emplace(id, &targeter);
183202
}
184203

185-
const auto compositeResult = compositor.composite(mPacesetterFrameTargeter);
204+
const auto resultsPerDisplay = compositor.composite(pacesetterId, targeters);
186205
compositor.sample();
187206

188-
mPacesetterFrameTargeter.endFrame(compositeResult);
207+
for (const auto& [id, targeter] : targeters) {
208+
const auto resultOpt = resultsPerDisplay.get(id);
209+
LOG_ALWAYS_FATAL_IF(!resultOpt);
210+
targeter->endFrame(*resultOpt);
211+
}
189212
}
190213

191214
std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
@@ -539,8 +562,16 @@ bool Scheduler::addResyncSample(PhysicalDisplayId id, nsecs_t timestamp,
539562
}
540563

541564
void Scheduler::addPresentFence(PhysicalDisplayId id, std::shared_ptr<FenceTime> fence) {
542-
auto schedule = getVsyncSchedule(id);
543-
LOG_ALWAYS_FATAL_IF(!schedule);
565+
const auto scheduleOpt =
566+
(ftl::FakeGuard(mDisplayLock), mDisplays.get(id)).and_then([](const Display& display) {
567+
return display.powerMode == hal::PowerMode::OFF
568+
? std::nullopt
569+
: std::make_optional(display.schedulePtr);
570+
});
571+
572+
if (!scheduleOpt) return;
573+
const auto& schedule = scheduleOpt->get();
574+
544575
if (const bool needMoreSignals = schedule->getController().addPresentFence(std::move(fence))) {
545576
schedule->enableHardwareVsync();
546577
} else {
@@ -750,7 +781,23 @@ void Scheduler::dump(utils::Dumper& dumper) const {
750781
mFrameRateOverrideMappings.dump(dumper);
751782
dumper.eol();
752783

753-
mPacesetterFrameTargeter.dump(dumper);
784+
{
785+
utils::Dumper::Section section(dumper, "Frame Targeting"sv);
786+
787+
std::scoped_lock lock(mDisplayLock);
788+
ftl::FakeGuard guard(kMainThreadContext);
789+
790+
for (const auto& [id, display] : mDisplays) {
791+
utils::Dumper::Section
792+
section(dumper,
793+
id == mPacesetterDisplayId
794+
? ftl::Concat("Pacesetter Display ", id.value).c_str()
795+
: ftl::Concat("Follower Display ", id.value).c_str());
796+
797+
display.targeterPtr->dump(dumper);
798+
dumper.eol();
799+
}
800+
}
754801
}
755802

756803
void Scheduler::dumpVsync(std::string& out) const {

services/surfaceflinger/Scheduler/Scheduler.h

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ class Scheduler : android::impl::MessageQueue {
222222
// otherwise.
223223
bool addResyncSample(PhysicalDisplayId, nsecs_t timestamp,
224224
std::optional<nsecs_t> hwcVsyncPeriod);
225-
void addPresentFence(PhysicalDisplayId, std::shared_ptr<FenceTime>) EXCLUDES(mDisplayLock)
225+
void addPresentFence(PhysicalDisplayId, std::shared_ptr<FenceTime>)
226226
REQUIRES(kMainThreadContext);
227227

228228
// Layers are registered on creation, and unregistered when the weak reference expires.
@@ -254,7 +254,14 @@ class Scheduler : android::impl::MessageQueue {
254254
return std::const_pointer_cast<VsyncSchedule>(std::as_const(*this).getVsyncSchedule(idOpt));
255255
}
256256

257-
const FrameTarget& pacesetterFrameTarget() { return mPacesetterFrameTargeter.target(); }
257+
TimePoint expectedPresentTimeForPacesetter() const EXCLUDES(mDisplayLock) {
258+
std::scoped_lock lock(mDisplayLock);
259+
return pacesetterDisplayLocked()
260+
.transform([](const Display& display) {
261+
return display.targeterPtr->target().expectedPresentTime();
262+
})
263+
.value_or(TimePoint());
264+
}
258265

259266
// Returns true if a given vsync timestamp is considered valid vsync
260267
// for a given uid
@@ -308,7 +315,8 @@ class Scheduler : android::impl::MessageQueue {
308315
enum class TouchState { Inactive, Active };
309316

310317
// impl::MessageQueue overrides:
311-
void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override;
318+
void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override
319+
REQUIRES(kMainThreadContext, mDisplayLock);
312320

313321
// Create a connection on the given EventThread.
314322
ConnectionHandle createConnection(std::unique_ptr<EventThread>);
@@ -434,13 +442,24 @@ class Scheduler : android::impl::MessageQueue {
434442
// must lock for writes but not reads. See also mPolicyLock for locking order.
435443
mutable std::mutex mDisplayLock;
436444

445+
using FrameTargeterPtr = std::unique_ptr<FrameTargeter>;
446+
437447
struct Display {
438-
Display(RefreshRateSelectorPtr selectorPtr, VsyncSchedulePtr schedulePtr)
439-
: selectorPtr(std::move(selectorPtr)), schedulePtr(std::move(schedulePtr)) {}
448+
Display(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
449+
VsyncSchedulePtr schedulePtr, FeatureFlags features)
450+
: displayId(displayId),
451+
selectorPtr(std::move(selectorPtr)),
452+
schedulePtr(std::move(schedulePtr)),
453+
targeterPtr(std::make_unique<
454+
FrameTargeter>(displayId,
455+
features.test(Feature::kBackpressureGpuComposition))) {}
456+
457+
const PhysicalDisplayId displayId;
440458

441459
// Effectively const except in move constructor.
442460
RefreshRateSelectorPtr selectorPtr;
443461
VsyncSchedulePtr schedulePtr;
462+
FrameTargeterPtr targeterPtr;
444463

445464
hal::PowerMode powerMode = hal::PowerMode::OFF;
446465
};
@@ -454,8 +473,6 @@ class Scheduler : android::impl::MessageQueue {
454473
ftl::Optional<PhysicalDisplayId> mPacesetterDisplayId GUARDED_BY(mDisplayLock)
455474
GUARDED_BY(kMainThreadContext);
456475

457-
FrameTargeter mPacesetterFrameTargeter{mFeatures.test(Feature::kBackpressureGpuComposition)};
458-
459476
ftl::Optional<DisplayRef> pacesetterDisplayLocked() REQUIRES(mDisplayLock) {
460477
return static_cast<const Scheduler*>(this)->pacesetterDisplayLocked().transform(
461478
[](const Display& display) { return std::ref(const_cast<Display&>(display)); });

services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <atomic>
2121
#include <memory>
2222

23+
#include <ui/DisplayId.h>
2324
#include <ui/Fence.h>
2425
#include <ui/FenceTime.h>
2526

@@ -75,16 +76,17 @@ class FrameTarget {
7576
bool didMissHwcFrame() const { return mHwcFrameMissed && !mGpuFrameMissed; }
7677

7778
protected:
79+
explicit FrameTarget(const std::string& displayLabel);
7880
~FrameTarget() = default;
7981

8082
VsyncId mVsyncId;
8183
TimePoint mFrameBeginTime;
8284
TimePoint mExpectedPresentTime;
8385

84-
TracedOrdinal<bool> mFramePending{"PrevFramePending", false};
85-
TracedOrdinal<bool> mFrameMissed{"PrevFrameMissed", false};
86-
TracedOrdinal<bool> mHwcFrameMissed{"PrevHwcFrameMissed", false};
87-
TracedOrdinal<bool> mGpuFrameMissed{"PrevGpuFrameMissed", false};
86+
TracedOrdinal<bool> mFramePending;
87+
TracedOrdinal<bool> mFrameMissed;
88+
TracedOrdinal<bool> mHwcFrameMissed;
89+
TracedOrdinal<bool> mGpuFrameMissed;
8890

8991
struct FenceWithFenceTime {
9092
sp<Fence> fence = Fence::NO_FENCE;
@@ -103,8 +105,9 @@ class FrameTarget {
103105
// Computes a display's per-frame metrics about past/upcoming targeting of present deadlines.
104106
class FrameTargeter final : private FrameTarget {
105107
public:
106-
explicit FrameTargeter(bool backpressureGpuComposition)
107-
: mBackpressureGpuComposition(backpressureGpuComposition) {}
108+
FrameTargeter(PhysicalDisplayId displayId, bool backpressureGpuComposition)
109+
: FrameTarget(to_string(displayId)),
110+
mBackpressureGpuComposition(backpressureGpuComposition) {}
108111

109112
const FrameTarget& target() const { return *this; }
110113

services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
#pragma once
1818

19+
#include <ui/DisplayId.h>
20+
#include <ui/DisplayMap.h>
21+
1922
#include <scheduler/interface/CompositionCoverage.h>
2023

2124
namespace android {
@@ -24,4 +27,6 @@ struct CompositeResult {
2427
CompositionCoverageFlags compositionCoverage;
2528
};
2629

30+
using CompositeResultsPerDisplay = ui::PhysicalDisplayMap<PhysicalDisplayId, CompositeResult>;
31+
2732
} // namespace android

services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include <cstdint>
2020

2121
#include <ftl/flags.h>
22+
#include <ui/DisplayId.h>
23+
#include <ui/DisplayMap.h>
2224

2325
namespace android {
2426

@@ -34,4 +36,14 @@ enum class CompositionCoverage : std::uint8_t {
3436

3537
using CompositionCoverageFlags = ftl::Flags<CompositionCoverage>;
3638

39+
using CompositionCoveragePerDisplay = ui::DisplayMap<DisplayId, CompositionCoverageFlags>;
40+
41+
inline CompositionCoverageFlags multiDisplayUnion(const CompositionCoveragePerDisplay& displays) {
42+
CompositionCoverageFlags coverage;
43+
for (const auto& [id, flags] : displays) {
44+
coverage |= flags;
45+
}
46+
return coverage;
47+
}
48+
3749
} // namespace android

services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
#pragma once
1818

19+
#include <ui/DisplayId.h>
20+
#include <ui/DisplayMap.h>
21+
1922
#include <scheduler/Time.h>
2023
#include <scheduler/VsyncId.h>
2124
#include <scheduler/interface/CompositeResult.h>
@@ -26,6 +29,8 @@ namespace scheduler {
2629
class FrameTarget;
2730
class FrameTargeter;
2831

32+
using FrameTargeters = ui::PhysicalDisplayMap<PhysicalDisplayId, scheduler::FrameTargeter*>;
33+
2934
} // namespace scheduler
3035

3136
struct ICompositor {
@@ -38,7 +43,8 @@ struct ICompositor {
3843

3944
// Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition
4045
// via RenderEngine and the Composer HAL, respectively.
41-
virtual CompositeResult composite(scheduler::FrameTargeter&) = 0;
46+
virtual CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId,
47+
const scheduler::FrameTargeters&) = 0;
4248

4349
// Samples the composited frame via RegionSamplingThread.
4450
virtual void sample() = 0;

services/surfaceflinger/Scheduler/src/FrameTargeter.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121

2222
namespace android::scheduler {
2323

24+
FrameTarget::FrameTarget(const std::string& displayLabel)
25+
: mFramePending("PrevFramePending " + displayLabel, false),
26+
mFrameMissed("PrevFrameMissed " + displayLabel, false),
27+
mHwcFrameMissed("PrevHwcFrameMissed " + displayLabel, false),
28+
mGpuFrameMissed("PrevGpuFrameMissed " + displayLabel, false) {}
29+
2430
TimePoint FrameTarget::pastVsyncTime(Period vsyncPeriod) const {
2531
// TODO(b/267315508): Generalize to N VSYNCs.
2632
const int shift = static_cast<int>(targetsVsyncsAhead<2>(vsyncPeriod));
@@ -130,10 +136,6 @@ FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr
130136
}
131137

132138
void FrameTargeter::dump(utils::Dumper& dumper) const {
133-
using namespace std::string_view_literals;
134-
135-
utils::Dumper::Section section(dumper, "Frame Targeting"sv);
136-
137139
// There are scripts and tests that expect this (rather than "name=value") format.
138140
dumper.dump({}, "Total missed frame count: " + std::to_string(mFrameMissedCount));
139141
dumper.dump({}, "HWC missed frame count: " + std::to_string(mHwcFrameMissedCount));

services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class FrameTargeterTest : public testing::Test {
9696
FenceToFenceTimeMap mFenceMap;
9797

9898
static constexpr bool kBackpressureGpuComposition = true;
99-
FrameTargeter mTargeter{kBackpressureGpuComposition};
99+
FrameTargeter mTargeter{PhysicalDisplayId::fromPort(13), kBackpressureGpuComposition};
100100
};
101101

102102
TEST_F(FrameTargeterTest, targetsFrames) {

0 commit comments

Comments
 (0)