xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // #define LOG_NDEBUG 0
18 
19 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
20 
21 #undef LOG_TAG
22 #define LOG_TAG "PowerAdvisor"
23 
24 #include <unistd.h>
25 #include <cinttypes>
26 #include <cstdint>
27 #include <functional>
28 #include <optional>
29 
30 #include <android-base/properties.h>
31 #include <common/trace.h>
32 #include <utils/Log.h>
33 #include <utils/Mutex.h>
34 
35 #include <binder/IServiceManager.h>
36 
37 #pragma clang diagnostic push
38 #pragma clang diagnostic ignored "-Wconversion"
39 #include <powermanager/PowerHalController.h>
40 #include <powermanager/PowerHintSessionWrapper.h>
41 #pragma clang diagnostic pop
42 
43 #include <common/FlagManager.h>
44 #include "PowerAdvisor.h"
45 
46 namespace hal = aidl::android::hardware::power;
47 
48 namespace android::adpf::impl {
49 
50 using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
51 using android::hardware::EventFlag;
52 
53 using ChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
54 using MsgQueue = android::AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>;
55 using FlagQueue = android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
56 
57 PowerAdvisor::~PowerAdvisor() = default;
58 
59 namespace {
traceExpensiveRendering(bool enabled)60 void traceExpensiveRendering(bool enabled) {
61     if (enabled) {
62         SFTRACE_ASYNC_BEGIN("ExpensiveRendering", 0);
63     } else {
64         SFTRACE_ASYNC_END("ExpensiveRendering", 0);
65     }
66 }
67 
68 } // namespace
69 
PowerAdvisor(std::function<void ()> && sfDisableExpensiveFn,std::chrono::milliseconds timeout)70 PowerAdvisor::PowerAdvisor(std::function<void()>&& sfDisableExpensiveFn,
71                            std::chrono::milliseconds timeout)
72       : mPowerHal(std::make_unique<power::PowerHalController>()) {
73     if (timeout > 0ms) {
74         mScreenUpdateTimer.emplace("UpdateImminentTimer", timeout,
75                                    /* resetCallback */ nullptr,
76                                    /* timeoutCallback */
77                                    [this, disableExpensiveFn = std::move(sfDisableExpensiveFn),
78                                     timeout] {
79                                        while (true) {
80                                            auto timeSinceLastUpdate = std::chrono::nanoseconds(
81                                                    systemTime() - mLastScreenUpdatedTime.load());
82                                            if (timeSinceLastUpdate >= timeout) {
83                                                break;
84                                            }
85                                            // We may try to disable expensive rendering and allow
86                                            // for sending DISPLAY_UPDATE_IMMINENT hints too early if
87                                            // we idled very shortly after updating the screen, so
88                                            // make sure we wait enough time.
89                                            std::this_thread::sleep_for(timeout -
90                                                                        timeSinceLastUpdate);
91                                        }
92                                        mSendUpdateImminent.store(true);
93                                        disableExpensiveFn();
94                                    });
95     }
96 }
97 
init()98 void PowerAdvisor::init() {
99     // Defer starting the screen update timer until SurfaceFlinger finishes construction.
100     if (mScreenUpdateTimer) {
101         mScreenUpdateTimer->start();
102     }
103 }
104 
onBootFinished()105 void PowerAdvisor::onBootFinished() {
106     mBootFinished.store(true);
107 }
108 
setExpensiveRenderingExpected(DisplayId displayId,bool expected)109 void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
110     if (!mHasExpensiveRendering) {
111         ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
112         return;
113     }
114     if (expected) {
115         mExpensiveDisplays.insert(displayId);
116     } else {
117         mExpensiveDisplays.erase(displayId);
118     }
119 
120     const bool expectsExpensiveRendering = !mExpensiveDisplays.empty();
121     if (mNotifiedExpensiveRendering != expectsExpensiveRendering) {
122         auto ret = getPowerHal().setMode(hal::Mode::EXPENSIVE_RENDERING, expectsExpensiveRendering);
123         if (!ret.isOk()) {
124             if (ret.isUnsupported()) {
125                 mHasExpensiveRendering = false;
126             }
127             return;
128         }
129 
130         mNotifiedExpensiveRendering = expectsExpensiveRendering;
131         traceExpensiveRendering(mNotifiedExpensiveRendering);
132     }
133 }
134 
notifyCpuLoadUp()135 void PowerAdvisor::notifyCpuLoadUp() {
136     // Only start sending this notification once the system has booted so we don't introduce an
137     // early-boot dependency on Power HAL
138     if (!mBootFinished.load()) {
139         return;
140     }
141     sendHintSessionHint(hal::SessionHint::CPU_LOAD_UP);
142 }
143 
notifyDisplayUpdateImminentAndCpuReset()144 void PowerAdvisor::notifyDisplayUpdateImminentAndCpuReset() {
145     // Only start sending this notification once the system has booted so we don't introduce an
146     // early-boot dependency on Power HAL
147     if (!mBootFinished.load()) {
148         return;
149     }
150 
151     if (mSendUpdateImminent.exchange(false)) {
152         ALOGV("AIDL notifyDisplayUpdateImminentAndCpuReset");
153         sendHintSessionHint(hal::SessionHint::CPU_LOAD_RESET);
154 
155         if (!mHasDisplayUpdateImminent) {
156             ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
157         } else {
158             auto ret = getPowerHal().setBoost(hal::Boost::DISPLAY_UPDATE_IMMINENT, 0);
159             if (ret.isUnsupported()) {
160                 mHasDisplayUpdateImminent = false;
161             }
162         }
163 
164         if (mScreenUpdateTimer) {
165             mScreenUpdateTimer->reset();
166         } else {
167             // If we don't have a screen update timer, then we don't throttle power hal calls so
168             // flip this bit back to allow for calling into power hal again.
169             mSendUpdateImminent.store(true);
170         }
171     }
172 
173     if (mScreenUpdateTimer) {
174         mLastScreenUpdatedTime.store(systemTime());
175     }
176 }
177 
usePowerHintSession()178 bool PowerAdvisor::usePowerHintSession() {
179     // uses cached value since the underlying support and flag are unlikely to change at runtime
180     return mHintSessionEnabled.value_or(false) && supportsPowerHintSession();
181 }
182 
supportsPowerHintSession()183 bool PowerAdvisor::supportsPowerHintSession() {
184     if (!mSupportsHintSession.has_value()) {
185         mSupportsHintSession = getPowerHal().getHintSessionPreferredRate().isOk();
186     }
187     return *mSupportsHintSession;
188 }
189 
shouldCreateSessionWithConfig()190 bool PowerAdvisor::shouldCreateSessionWithConfig() {
191     return mSessionConfigSupported && mBootFinished &&
192             FlagManager::getInstance().adpf_use_fmq_channel();
193 }
194 
sendHintSessionHint(hal::SessionHint hint)195 void PowerAdvisor::sendHintSessionHint(hal::SessionHint hint) {
196     if (!mBootFinished || !usePowerHintSession()) {
197         ALOGV("Power hint session is not enabled, skip sending session hint");
198         return;
199     }
200     SFTRACE_CALL();
201     if (sTraceHintSessionData) SFTRACE_INT("Session hint", static_cast<int>(hint));
202     {
203         std::scoped_lock lock(mHintSessionMutex);
204         if (!ensurePowerHintSessionRunning()) {
205             ALOGV("Hint session not running and could not be started, skip sending session hint");
206             return;
207         }
208         ALOGV("Sending session hint: %d", static_cast<int>(hint));
209         if (!writeHintSessionMessage<ChannelMessageContents::Tag::hint>(&hint, 1)) {
210             auto ret = mHintSession->sendHint(hint);
211             if (!ret.isOk()) {
212                 ALOGW("Failed to send session hint with error: %s", ret.errorMessage());
213                 mHintSession = nullptr;
214             }
215         }
216     }
217 }
218 
ensurePowerHintSessionRunning()219 bool PowerAdvisor::ensurePowerHintSessionRunning() {
220     if (mHintSession == nullptr && !mHintSessionThreadIds.empty() && usePowerHintSession()) {
221         if (shouldCreateSessionWithConfig()) {
222             auto ret = getPowerHal().createHintSessionWithConfig(getpid(),
223                                                                  static_cast<int32_t>(getuid()),
224                                                                  mHintSessionThreadIds,
225                                                                  mTargetDuration.ns(),
226                                                                  hal::SessionTag::SURFACEFLINGER,
227                                                                  &mSessionConfig);
228             if (ret.isOk()) {
229                 mHintSession = ret.value();
230                 if (FlagManager::getInstance().adpf_use_fmq_channel_fixed() &&
231                     FlagManager::getInstance().adpf_fmq_sf()) {
232                     setUpFmq();
233                 }
234             }
235             // If it fails the first time we try, or ever returns unsupported, assume unsupported
236             else if (mFirstConfigSupportCheck || ret.isUnsupported()) {
237                 ALOGI("Hint session with config is unsupported, falling back to a legacy session");
238                 mSessionConfigSupported = false;
239             }
240             mFirstConfigSupportCheck = false;
241         }
242         // Immediately try original method after, in case the first way returned unsupported
243         if (mHintSession == nullptr && !shouldCreateSessionWithConfig()) {
244             auto ret = getPowerHal().createHintSession(getpid(), static_cast<int32_t>(getuid()),
245                                                        mHintSessionThreadIds, mTargetDuration.ns());
246             if (ret.isOk()) {
247                 mHintSession = ret.value();
248             }
249         }
250     }
251     return mHintSession != nullptr;
252 }
253 
setUpFmq()254 void PowerAdvisor::setUpFmq() {
255     auto&& channelRet = getPowerHal().getSessionChannel(getpid(), static_cast<int32_t>(getuid()));
256     if (!channelRet.isOk()) {
257         ALOGE("Failed to get session channel with error: %s", channelRet.errorMessage());
258         return;
259     }
260     auto& channelConfig = channelRet.value();
261     mMsgQueue = std::make_unique<MsgQueue>(std::move(channelConfig.channelDescriptor), true);
262     LOG_ALWAYS_FATAL_IF(!mMsgQueue->isValid(), "Failed to set up hint session msg queue");
263     LOG_ALWAYS_FATAL_IF(channelConfig.writeFlagBitmask <= 0,
264                         "Invalid flag bit masks found in channel config: writeBitMask(%d)",
265                         channelConfig.writeFlagBitmask);
266     mFmqWriteMask = static_cast<uint32_t>(channelConfig.writeFlagBitmask);
267     if (!channelConfig.eventFlagDescriptor.has_value()) {
268         // For FMQ v1 in Android 15 we will force using shared event flag since the default
269         // no-op FMQ impl in Power HAL v5 will always return a valid channel config with
270         // non-zero masks but no shared flag.
271         mMsgQueue = nullptr;
272         ALOGE("No event flag descriptor found in channel config");
273         return;
274     }
275     mFlagQueue = std::make_unique<FlagQueue>(std::move(*channelConfig.eventFlagDescriptor), true);
276     LOG_ALWAYS_FATAL_IF(!mFlagQueue->isValid(), "Failed to set up hint session flag queue");
277     auto status = EventFlag::createEventFlag(mFlagQueue->getEventFlagWord(), &mEventFlag);
278     LOG_ALWAYS_FATAL_IF(status != OK, "Failed to set up hint session event flag");
279 }
280 
updateTargetWorkDuration(Duration targetDuration)281 void PowerAdvisor::updateTargetWorkDuration(Duration targetDuration) {
282     if (!mBootFinished || !usePowerHintSession()) {
283         ALOGV("Power hint session is not enabled, skipping target update");
284         return;
285     }
286     SFTRACE_CALL();
287     {
288         mTargetDuration = targetDuration;
289         if (sTraceHintSessionData) SFTRACE_INT64("Time target", targetDuration.ns());
290         if (targetDuration == mLastTargetDurationSent) return;
291         std::scoped_lock lock(mHintSessionMutex);
292         if (!ensurePowerHintSessionRunning()) {
293             ALOGV("Hint session not running and could not be started, skip updating target");
294             return;
295         }
296         ALOGV("Sending target time: %" PRId64 "ns", targetDuration.ns());
297         mLastTargetDurationSent = targetDuration;
298         auto target = targetDuration.ns();
299         if (!writeHintSessionMessage<ChannelMessageContents::Tag::targetDuration>(&target, 1)) {
300             auto ret = mHintSession->updateTargetWorkDuration(targetDuration.ns());
301             if (!ret.isOk()) {
302                 ALOGW("Failed to set power hint target work duration with error: %s",
303                       ret.errorMessage());
304                 mHintSession = nullptr;
305             }
306         }
307     }
308 }
309 
reportActualWorkDuration()310 void PowerAdvisor::reportActualWorkDuration() {
311     if (!mBootFinished || !sUseReportActualDuration || !usePowerHintSession()) {
312         ALOGV("Actual work duration power hint cannot be sent, skipping");
313         return;
314     }
315     SFTRACE_CALL();
316     std::optional<hal::WorkDuration> actualDuration = estimateWorkDuration();
317     if (!actualDuration.has_value() || actualDuration->durationNanos < 0) {
318         ALOGV("Failed to send actual work duration, skipping");
319         return;
320     }
321     actualDuration->durationNanos += sTargetSafetyMargin.ns();
322     if (sTraceHintSessionData) {
323         SFTRACE_INT64("Measured duration", actualDuration->durationNanos);
324         SFTRACE_INT64("Target error term", actualDuration->durationNanos - mTargetDuration.ns());
325         SFTRACE_INT64("Reported duration", actualDuration->durationNanos);
326         if (supportsGpuReporting()) {
327             SFTRACE_INT64("Reported cpu duration", actualDuration->cpuDurationNanos);
328             SFTRACE_INT64("Reported gpu duration", actualDuration->gpuDurationNanos);
329         }
330         SFTRACE_INT64("Reported target", mLastTargetDurationSent.ns());
331         SFTRACE_INT64("Reported target error term",
332                       actualDuration->durationNanos - mLastTargetDurationSent.ns());
333     }
334 
335     ALOGV("Sending actual work duration of: %" PRId64 " with cpu: %" PRId64 " and gpu: %" PRId64
336           " on reported target: %" PRId64 " with error: %" PRId64,
337           actualDuration->durationNanos, actualDuration->cpuDurationNanos,
338           actualDuration->gpuDurationNanos, mLastTargetDurationSent.ns(),
339           actualDuration->durationNanos - mLastTargetDurationSent.ns());
340 
341     if (mTimingTestingMode) {
342         mDelayReportActualMutexAcquisitonPromise.get_future().wait();
343         mDelayReportActualMutexAcquisitonPromise = std::promise<bool>{};
344     }
345 
346     {
347         std::scoped_lock lock(mHintSessionMutex);
348         if (!ensurePowerHintSessionRunning()) {
349             ALOGV("Hint session not running and could not be started, skip reporting durations");
350             return;
351         }
352         mHintSessionQueue.push_back(*actualDuration);
353         if (!writeHintSessionMessage<
354                     ChannelMessageContents::Tag::workDuration>(mHintSessionQueue.data(),
355                                                                mHintSessionQueue.size())) {
356             auto ret = mHintSession->reportActualWorkDuration(mHintSessionQueue);
357             if (!ret.isOk()) {
358                 ALOGW("Failed to report actual work durations with error: %s", ret.errorMessage());
359                 mHintSession = nullptr;
360                 return;
361             }
362         }
363     }
364     mHintSessionQueue.clear();
365 }
366 
367 template <hal::ChannelMessage::ChannelMessageContents::Tag T, class In>
writeHintSessionMessage(In * contents,size_t count)368 bool PowerAdvisor::writeHintSessionMessage(In* contents, size_t count) {
369     if (!mMsgQueue) {
370         ALOGV("Skip using FMQ with message tag %hhd as it's not supported", T);
371         return false;
372     }
373     auto availableSize = mMsgQueue->availableToWrite();
374     if (availableSize < count) {
375         ALOGW("Skip using FMQ with message tag %hhd as there isn't enough space", T);
376         return false;
377     }
378     MsgQueue::MemTransaction tx;
379     if (!mMsgQueue->beginWrite(count, &tx)) {
380         ALOGW("Failed to begin writing message with tag %hhd", T);
381         return false;
382     }
383     for (size_t i = 0; i < count; ++i) {
384         if constexpr (T == ChannelMessageContents::Tag::workDuration) {
385             const hal::WorkDuration& duration = contents[i];
386             new (tx.getSlot(i)) hal::ChannelMessage{
387                     .sessionID = static_cast<int32_t>(mSessionConfig.id),
388                     .timeStampNanos =
389                             (i == count - 1) ? ::android::uptimeNanos() : duration.timeStampNanos,
390                     .data = ChannelMessageContents::make<ChannelMessageContents::Tag::workDuration,
391                                                          hal::WorkDurationFixedV1>({
392                             .durationNanos = duration.durationNanos,
393                             .workPeriodStartTimestampNanos = duration.workPeriodStartTimestampNanos,
394                             .cpuDurationNanos = duration.cpuDurationNanos,
395                             .gpuDurationNanos = duration.gpuDurationNanos,
396                     }),
397             };
398         } else {
399             new (tx.getSlot(i)) hal::ChannelMessage{
400                     .sessionID = static_cast<int32_t>(mSessionConfig.id),
401                     .timeStampNanos = ::android::uptimeNanos(),
402                     .data = ChannelMessageContents::make<T, In>(std::move(contents[i])),
403             };
404         }
405     }
406     if (!mMsgQueue->commitWrite(count)) {
407         ALOGW("Failed to send message with tag %hhd, fall back to binder call", T);
408         return false;
409     }
410     mEventFlag->wake(mFmqWriteMask);
411     return true;
412 }
413 
enablePowerHintSession(bool enabled)414 void PowerAdvisor::enablePowerHintSession(bool enabled) {
415     mHintSessionEnabled = enabled;
416 }
417 
startPowerHintSession(std::vector<int32_t> && threadIds)418 bool PowerAdvisor::startPowerHintSession(std::vector<int32_t>&& threadIds) {
419     mHintSessionThreadIds = threadIds;
420     if (!mBootFinished.load()) {
421         return false;
422     }
423     if (!usePowerHintSession()) {
424         ALOGI("Cannot start power hint session: disabled or unsupported");
425         return false;
426     }
427     LOG_ALWAYS_FATAL_IF(mHintSessionThreadIds.empty(),
428                         "No thread IDs provided to power hint session!");
429     {
430         std::scoped_lock lock(mHintSessionMutex);
431         if (mHintSession != nullptr) {
432             ALOGE("Cannot start power hint session: already running");
433             return false;
434         }
435         return ensurePowerHintSessionRunning();
436     }
437 }
438 
supportsGpuReporting()439 bool PowerAdvisor::supportsGpuReporting() {
440     return mBootFinished && FlagManager::getInstance().adpf_gpu_sf();
441 }
442 
setGpuStartTime(DisplayId displayId,TimePoint startTime)443 void PowerAdvisor::setGpuStartTime(DisplayId displayId, TimePoint startTime) {
444     DisplayTimingData& displayData = mDisplayTimingData[displayId];
445     if (displayData.gpuEndFenceTime) {
446         nsecs_t signalTime = displayData.gpuEndFenceTime->getSignalTime();
447         if (signalTime != Fence::SIGNAL_TIME_INVALID && signalTime != Fence::SIGNAL_TIME_PENDING) {
448             displayData.lastValidGpuStartTime = displayData.gpuStartTime;
449             displayData.lastValidGpuEndTime = TimePoint::fromNs(signalTime);
450             for (auto&& [_, otherDisplayData] : mDisplayTimingData) {
451                 if (!otherDisplayData.lastValidGpuStartTime.has_value() ||
452                     !otherDisplayData.lastValidGpuEndTime.has_value())
453                     continue;
454                 if ((*otherDisplayData.lastValidGpuStartTime < *displayData.gpuStartTime) &&
455                     (*otherDisplayData.lastValidGpuEndTime > *displayData.gpuStartTime)) {
456                     displayData.lastValidGpuStartTime = *otherDisplayData.lastValidGpuEndTime;
457                     break;
458                 }
459             }
460         }
461         displayData.gpuEndFenceTime = nullptr;
462     }
463     displayData.gpuStartTime = startTime;
464 }
465 
setGpuFenceTime(DisplayId displayId,std::unique_ptr<FenceTime> && fenceTime)466 void PowerAdvisor::setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) {
467     DisplayTimingData& displayData = mDisplayTimingData[displayId];
468     if (displayData.gpuEndFenceTime && !supportsGpuReporting()) {
469         nsecs_t signalTime = displayData.gpuEndFenceTime->getSignalTime();
470         if (signalTime != Fence::SIGNAL_TIME_INVALID && signalTime != Fence::SIGNAL_TIME_PENDING) {
471             displayData.lastValidGpuStartTime = displayData.gpuStartTime;
472             displayData.lastValidGpuEndTime = TimePoint::fromNs(signalTime);
473             for (auto&& [_, otherDisplayData] : mDisplayTimingData) {
474                 // If the previous display started before us but ended after we should have
475                 // started, then it likely delayed our start time and we must compensate for that.
476                 // Displays finishing earlier should have already made their way through this call
477                 // and swapped their timing into "lastValid" from "latest", so we check that here.
478                 if (!otherDisplayData.lastValidGpuStartTime.has_value()) continue;
479                 if ((*otherDisplayData.lastValidGpuStartTime < *displayData.gpuStartTime) &&
480                     (*otherDisplayData.lastValidGpuEndTime > *displayData.gpuStartTime)) {
481                     displayData.lastValidGpuStartTime = *otherDisplayData.lastValidGpuEndTime;
482                     break;
483                 }
484             }
485         }
486     }
487     displayData.gpuEndFenceTime = std::move(fenceTime);
488     if (!supportsGpuReporting()) {
489         displayData.gpuStartTime = TimePoint::now();
490     }
491 }
492 
setHwcValidateTiming(DisplayId displayId,TimePoint validateStartTime,TimePoint validateEndTime)493 void PowerAdvisor::setHwcValidateTiming(DisplayId displayId, TimePoint validateStartTime,
494                                         TimePoint validateEndTime) {
495     DisplayTimingData& displayData = mDisplayTimingData[displayId];
496     displayData.hwcValidateStartTime = validateStartTime;
497     displayData.hwcValidateEndTime = validateEndTime;
498 }
499 
setHwcPresentTiming(DisplayId displayId,TimePoint presentStartTime,TimePoint presentEndTime)500 void PowerAdvisor::setHwcPresentTiming(DisplayId displayId, TimePoint presentStartTime,
501                                        TimePoint presentEndTime) {
502     DisplayTimingData& displayData = mDisplayTimingData[displayId];
503     displayData.hwcPresentStartTime = presentStartTime;
504     displayData.hwcPresentEndTime = presentEndTime;
505 }
506 
setSkippedValidate(DisplayId displayId,bool skipped)507 void PowerAdvisor::setSkippedValidate(DisplayId displayId, bool skipped) {
508     mDisplayTimingData[displayId].skippedValidate = skipped;
509 }
510 
setRequiresRenderEngine(DisplayId displayId,bool requiresRenderEngine)511 void PowerAdvisor::setRequiresRenderEngine(DisplayId displayId, bool requiresRenderEngine) {
512     mDisplayTimingData[displayId].requiresRenderEngine = requiresRenderEngine;
513 }
514 
setExpectedPresentTime(TimePoint expectedPresentTime)515 void PowerAdvisor::setExpectedPresentTime(TimePoint expectedPresentTime) {
516     mExpectedPresentTimes.append(expectedPresentTime);
517 }
518 
setSfPresentTiming(TimePoint presentFenceTime,TimePoint presentEndTime)519 void PowerAdvisor::setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) {
520     mLastPresentFenceTime = presentFenceTime;
521     mLastSfPresentEndTime = presentEndTime;
522 }
523 
setFrameDelay(Duration frameDelayDuration)524 void PowerAdvisor::setFrameDelay(Duration frameDelayDuration) {
525     mFrameDelayDuration = frameDelayDuration;
526 }
527 
setHwcPresentDelayedTime(DisplayId displayId,TimePoint earliestFrameStartTime)528 void PowerAdvisor::setHwcPresentDelayedTime(DisplayId displayId, TimePoint earliestFrameStartTime) {
529     mDisplayTimingData[displayId].hwcPresentDelayedTime = earliestFrameStartTime;
530 }
531 
setCommitStart(TimePoint commitStartTime)532 void PowerAdvisor::setCommitStart(TimePoint commitStartTime) {
533     mCommitStartTimes.append(commitStartTime);
534 }
535 
setCompositeEnd(TimePoint compositeEndTime)536 void PowerAdvisor::setCompositeEnd(TimePoint compositeEndTime) {
537     mLastPostcompDuration = compositeEndTime - mLastSfPresentEndTime;
538 }
539 
setDisplays(std::vector<DisplayId> & displayIds)540 void PowerAdvisor::setDisplays(std::vector<DisplayId>& displayIds) {
541     mDisplayIds = displayIds;
542 }
543 
setTotalFrameTargetWorkDuration(Duration targetDuration)544 void PowerAdvisor::setTotalFrameTargetWorkDuration(Duration targetDuration) {
545     mTotalFrameTargetDuration = targetDuration;
546 }
547 
getOrderedDisplayIds(std::optional<TimePoint> DisplayTimingData::* sortBy)548 std::vector<DisplayId> PowerAdvisor::getOrderedDisplayIds(
549         std::optional<TimePoint> DisplayTimingData::*sortBy) {
550     std::vector<DisplayId> sortedDisplays;
551     std::copy_if(mDisplayIds.begin(), mDisplayIds.end(), std::back_inserter(sortedDisplays),
552                  [&](DisplayId id) {
553                      return mDisplayTimingData.count(id) &&
554                              (mDisplayTimingData[id].*sortBy).has_value();
555                  });
556     std::sort(sortedDisplays.begin(), sortedDisplays.end(), [&](DisplayId idA, DisplayId idB) {
557         return *(mDisplayTimingData[idA].*sortBy) < *(mDisplayTimingData[idB].*sortBy);
558     });
559     return sortedDisplays;
560 }
561 
estimateWorkDuration()562 std::optional<hal::WorkDuration> PowerAdvisor::estimateWorkDuration() {
563     if (!mExpectedPresentTimes.isFull() || !mCommitStartTimes.isFull()) {
564         return std::nullopt;
565     }
566 
567     // Tracks when we finish presenting to hwc
568     TimePoint estimatedHwcEndTime = mCommitStartTimes[0];
569 
570     // How long we spent this frame not doing anything, waiting for fences or vsync
571     Duration idleDuration = 0ns;
572 
573     // Most recent previous gpu end time in the current frame, probably from a prior display, used
574     // as the start time for the next gpu operation if it ran over time since it probably blocked
575     std::optional<TimePoint> previousValidGpuEndTime;
576 
577     // The currently estimated gpu end time for the frame,
578     // used to accumulate gpu time as we iterate over the active displays
579     std::optional<TimePoint> estimatedGpuEndTime;
580 
581     std::vector<DisplayId>&& displayIds =
582             getOrderedDisplayIds(&DisplayTimingData::hwcPresentStartTime);
583     DisplayTimeline displayTiming;
584     std::optional<GpuTimeline> firstGpuTimeline;
585 
586     // Iterate over the displays that use hwc in the same order they are presented
587     for (DisplayId displayId : displayIds) {
588         if (mDisplayTimingData.count(displayId) == 0) {
589             continue;
590         }
591 
592         auto& displayData = mDisplayTimingData.at(displayId);
593 
594         displayTiming = displayData.calculateDisplayTimeline(mLastPresentFenceTime);
595 
596         // Update predicted present finish time with this display's present time
597         estimatedHwcEndTime = displayTiming.hwcPresentEndTime;
598 
599         // Track how long we spent waiting for the fence, can be excluded from the timing estimate
600         idleDuration += displayTiming.probablyWaitsForPresentFence
601                 ? mLastPresentFenceTime - displayTiming.presentFenceWaitStartTime
602                 : 0ns;
603 
604         // Track how long we spent waiting to present, can be excluded from the timing estimate
605         idleDuration += displayTiming.hwcPresentDelayDuration;
606 
607         // Estimate the reference frame's gpu timing
608         auto gpuTiming = displayData.estimateGpuTiming(previousValidGpuEndTime);
609         if (gpuTiming.has_value()) {
610             if (!firstGpuTimeline.has_value()) {
611                 firstGpuTimeline = gpuTiming;
612             }
613             previousValidGpuEndTime = gpuTiming->startTime + gpuTiming->duration;
614 
615             // Estimate the prediction frame's gpu end time from the reference frame
616             estimatedGpuEndTime = std::max(displayTiming.hwcPresentStartTime,
617                                            estimatedGpuEndTime.value_or(TimePoint{0ns})) +
618                     gpuTiming->duration;
619         }
620     }
621 
622     TimePoint estimatedFlingerEndTime = mLastSfPresentEndTime;
623 
624     // Don't count time spent idly waiting in the estimate as we could do more work in that time
625     estimatedHwcEndTime -= idleDuration;
626     estimatedFlingerEndTime -= idleDuration;
627 
628     // We finish the frame when both present and the gpu are done, so wait for the later of the two
629     // Also add the frame delay duration since the target did not move while we were delayed
630     Duration totalDuration = mFrameDelayDuration +
631             std::max(estimatedHwcEndTime, estimatedGpuEndTime.value_or(TimePoint{0ns})) -
632             mCommitStartTimes[0];
633     Duration totalDurationWithoutGpu =
634             mFrameDelayDuration + estimatedHwcEndTime - mCommitStartTimes[0];
635 
636     // We finish SurfaceFlinger when post-composition finishes, so add that in here
637     Duration flingerDuration =
638             estimatedFlingerEndTime + mLastPostcompDuration - mCommitStartTimes[0];
639     Duration estimatedGpuDuration = firstGpuTimeline.has_value()
640             ? estimatedGpuEndTime.value_or(TimePoint{0ns}) - firstGpuTimeline->startTime
641             : Duration::fromNs(0);
642 
643     // Combine the two timings into a single normalized one
644     Duration combinedDuration = combineTimingEstimates(totalDuration, flingerDuration);
645     Duration cpuDuration = combineTimingEstimates(totalDurationWithoutGpu, flingerDuration);
646 
647     hal::WorkDuration duration{
648             .timeStampNanos = TimePoint::now().ns(),
649             .durationNanos = combinedDuration.ns(),
650             .workPeriodStartTimestampNanos = mCommitStartTimes[0].ns(),
651             .cpuDurationNanos = supportsGpuReporting() ? cpuDuration.ns() : 0,
652             .gpuDurationNanos = supportsGpuReporting() ? estimatedGpuDuration.ns() : 0,
653     };
654     if (sTraceHintSessionData) {
655         SFTRACE_INT64("Idle duration", idleDuration.ns());
656         SFTRACE_INT64("Total duration", totalDuration.ns());
657         SFTRACE_INT64("Flinger duration", flingerDuration.ns());
658     }
659     return std::make_optional(duration);
660 }
661 
combineTimingEstimates(Duration totalDuration,Duration flingerDuration)662 Duration PowerAdvisor::combineTimingEstimates(Duration totalDuration, Duration flingerDuration) {
663     Duration targetDuration{0ns};
664     targetDuration = mTargetDuration;
665     if (!mTotalFrameTargetDuration.has_value()) return flingerDuration;
666 
667     // Normalize total to the flinger target (vsync period) since that's how often we actually send
668     // hints
669     Duration normalizedTotalDuration = Duration::fromNs((targetDuration.ns() * totalDuration.ns()) /
670                                                         mTotalFrameTargetDuration->ns());
671     return std::max(flingerDuration, normalizedTotalDuration);
672 }
673 
calculateDisplayTimeline(TimePoint fenceTime)674 PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayTimeline(
675         TimePoint fenceTime) {
676     DisplayTimeline timeline;
677     // How long between calling hwc present and trying to wait on the fence
678     const Duration fenceWaitStartDelay =
679             (skippedValidate ? kFenceWaitStartDelaySkippedValidate : kFenceWaitStartDelayValidated);
680 
681     // Did our reference frame wait for an appropriate vsync before calling into hwc
682     const bool waitedOnHwcPresentTime = hwcPresentDelayedTime.has_value() &&
683             *hwcPresentDelayedTime > *hwcPresentStartTime &&
684             *hwcPresentDelayedTime < *hwcPresentEndTime;
685 
686     // Use validate start here if we skipped it because we did validate + present together
687     timeline.hwcPresentStartTime = skippedValidate ? *hwcValidateStartTime : *hwcPresentStartTime;
688 
689     // Use validate end here if we skipped it because we did validate + present together
690     timeline.hwcPresentEndTime = skippedValidate ? *hwcValidateEndTime : *hwcPresentEndTime;
691 
692     // How long hwc present was delayed waiting for the next appropriate vsync
693     timeline.hwcPresentDelayDuration =
694             (waitedOnHwcPresentTime ? *hwcPresentDelayedTime - *hwcPresentStartTime : 0ns);
695     // When we started waiting for the present fence after calling into hwc present
696     timeline.presentFenceWaitStartTime =
697             timeline.hwcPresentStartTime + timeline.hwcPresentDelayDuration + fenceWaitStartDelay;
698     timeline.probablyWaitsForPresentFence = fenceTime > timeline.presentFenceWaitStartTime &&
699             fenceTime < timeline.hwcPresentEndTime;
700 
701     // How long we ran after we finished waiting for the fence but before hwc present finished
702     timeline.postPresentFenceHwcPresentDuration = timeline.hwcPresentEndTime -
703             (timeline.probablyWaitsForPresentFence ? fenceTime
704                                                    : timeline.presentFenceWaitStartTime);
705     return timeline;
706 }
707 
estimateGpuTiming(std::optional<TimePoint> previousEndTime)708 std::optional<PowerAdvisor::GpuTimeline> PowerAdvisor::DisplayTimingData::estimateGpuTiming(
709         std::optional<TimePoint> previousEndTime) {
710     if (!(requiresRenderEngine && lastValidGpuStartTime.has_value() && gpuEndFenceTime)) {
711         return std::nullopt;
712     }
713     const TimePoint latestGpuStartTime =
714             std::max(previousEndTime.value_or(TimePoint{0ns}), *gpuStartTime);
715     const nsecs_t gpuEndFenceSignal = gpuEndFenceTime->getSignalTime();
716     Duration gpuDuration{0ns};
717     if (gpuEndFenceSignal != Fence::SIGNAL_TIME_INVALID &&
718         gpuEndFenceSignal != Fence::SIGNAL_TIME_PENDING) {
719         const TimePoint latestGpuEndTime = TimePoint::fromNs(gpuEndFenceSignal);
720 
721         // If we know how long the most recent gpu duration was, use that
722         gpuDuration = latestGpuEndTime - latestGpuStartTime;
723     } else if (lastValidGpuEndTime.has_value()) {
724         // If we don't have the fence data, use the most recent information we do have
725         gpuDuration = *lastValidGpuEndTime - *lastValidGpuStartTime;
726         if (gpuEndFenceSignal == Fence::SIGNAL_TIME_PENDING) {
727             // If pending but went over the previous duration, use current time as the end
728             gpuDuration = std::max(gpuDuration, Duration{TimePoint::now() - latestGpuStartTime});
729         }
730     }
731     return GpuTimeline{.duration = gpuDuration, .startTime = latestGpuStartTime};
732 }
733 
734 const bool PowerAdvisor::sTraceHintSessionData =
735         base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
736 
737 const Duration PowerAdvisor::sTargetSafetyMargin = std::chrono::microseconds(
738         base::GetIntProperty<int64_t>("debug.sf.hint_margin_us",
739                                       ticks<std::micro>(PowerAdvisor::kDefaultTargetSafetyMargin)));
740 
741 const bool PowerAdvisor::sUseReportActualDuration =
742         base::GetBoolProperty(std::string("debug.adpf.use_report_actual_duration"), true);
743 
getPowerHal()744 power::PowerHalController& PowerAdvisor::getPowerHal() {
745     static std::once_flag halFlag;
746     std::call_once(halFlag, [this] { mPowerHal->init(); });
747     return *mPowerHal;
748 }
749 
750 } // namespace android::adpf::impl
751