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