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