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