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