• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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_TAG "powerhal-libperfmgr"
18 #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
19 
20 #include "PowerHintSession.h"
21 
22 #include <android-base/logging.h>
23 #include <android-base/parsedouble.h>
24 #include <android-base/properties.h>
25 #include <android-base/stringprintf.h>
26 #include <perfmgr/AdpfConfig.h>
27 #include <private/android_filesystem_config.h>
28 #include <sys/syscall.h>
29 #include <time.h>
30 #include <utils/Trace.h>
31 
32 #include <atomic>
33 
34 #include "GpuCalculationHelpers.h"
35 #include "tests/mocks/MockHintManager.h"
36 #include "tests/mocks/MockPowerSessionManager.h"
37 
38 namespace aidl {
39 namespace google {
40 namespace hardware {
41 namespace power {
42 namespace impl {
43 namespace pixel {
44 
45 using ::android::base::StringPrintf;
46 using ::android::perfmgr::AdpfConfig;
47 using std::chrono::duration_cast;
48 using std::chrono::nanoseconds;
49 
50 using std::operator""ms;
51 
52 namespace {
53 
54 static std::atomic<int64_t> sSessionIDCounter{0};
55 
ns_to_100us(int64_t ns)56 static inline int64_t ns_to_100us(int64_t ns) {
57     return ns / 100000;
58 }
59 
60 }  // namespace
61 
62 template <class HintManagerT, class PowerSessionManagerT>
convertWorkDurationToBoostByPid(const std::vector<WorkDuration> & actualDurations)63 int64_t PowerHintSession<HintManagerT, PowerSessionManagerT>::convertWorkDurationToBoostByPid(
64         const std::vector<WorkDuration> &actualDurations) {
65     std::shared_ptr<AdpfConfig> adpfConfig = HintManagerT::GetInstance()->GetAdpfProfile();
66     const nanoseconds &targetDuration = mDescriptor->targetNs;
67     int64_t &integral_error = mDescriptor->integral_error;
68     int64_t &previous_error = mDescriptor->previous_error;
69     uint64_t samplingWindowP = adpfConfig->mSamplingWindowP;
70     uint64_t samplingWindowI = adpfConfig->mSamplingWindowI;
71     uint64_t samplingWindowD = adpfConfig->mSamplingWindowD;
72     int64_t targetDurationNanos = (int64_t)targetDuration.count();
73     int64_t length = actualDurations.size();
74     int64_t p_start =
75             samplingWindowP == 0 || samplingWindowP > length ? 0 : length - samplingWindowP;
76     int64_t i_start =
77             samplingWindowI == 0 || samplingWindowI > length ? 0 : length - samplingWindowI;
78     int64_t d_start =
79             samplingWindowD == 0 || samplingWindowD > length ? 0 : length - samplingWindowD;
80     int64_t dt = ns_to_100us(targetDurationNanos);
81     int64_t err_sum = 0;
82     int64_t derivative_sum = 0;
83     for (int64_t i = std::min({p_start, i_start, d_start}); i < length; i++) {
84         int64_t actualDurationNanos = actualDurations[i].durationNanos;
85         if (std::abs(actualDurationNanos) > targetDurationNanos * 20) {
86             ALOGW("The actual duration is way far from the target (%" PRId64 " >> %" PRId64 ")",
87                   actualDurationNanos, targetDurationNanos);
88         }
89         // PID control algorithm
90         int64_t error = ns_to_100us(actualDurationNanos - targetDurationNanos);
91         if (i >= d_start) {
92             derivative_sum += error - previous_error;
93         }
94         if (i >= p_start) {
95             err_sum += error;
96         }
97         if (i >= i_start) {
98             integral_error += error * dt;
99             integral_error = std::min(adpfConfig->getPidIHighDivI(), integral_error);
100             integral_error = std::max(adpfConfig->getPidILowDivI(), integral_error);
101         }
102         previous_error = error;
103     }
104 
105     auto pid_pu_active = adpfConfig->mPidPu;
106     if (adpfConfig->mHeuristicBoostOn.has_value() && adpfConfig->mHeuristicBoostOn.value()) {
107         pid_pu_active = mHeuristicBoostActive
108                                 ? adpfConfig->mPidPu * adpfConfig->mHBoostPidPuFactor.value()
109                                 : adpfConfig->mPidPu;
110     }
111     int64_t pOut = static_cast<int64_t>((err_sum > 0 ? adpfConfig->mPidPo : pid_pu_active) *
112                                         err_sum / (length - p_start));
113     int64_t iOut = static_cast<int64_t>(adpfConfig->mPidI * integral_error);
114     int64_t dOut =
115             static_cast<int64_t>((derivative_sum > 0 ? adpfConfig->mPidDo : adpfConfig->mPidDu) *
116                                  derivative_sum / dt / (length - d_start));
117 
118     int64_t output = pOut + iOut + dOut;
119     ATRACE_INT(mAppDescriptorTrace->trace_pid_err.c_str(), err_sum / (length - p_start));
120     ATRACE_INT(mAppDescriptorTrace->trace_pid_integral.c_str(), integral_error);
121     ATRACE_INT(mAppDescriptorTrace->trace_pid_derivative.c_str(),
122                derivative_sum / dt / (length - d_start));
123     ATRACE_INT(mAppDescriptorTrace->trace_pid_pOut.c_str(), pOut);
124     ATRACE_INT(mAppDescriptorTrace->trace_pid_iOut.c_str(), iOut);
125     ATRACE_INT(mAppDescriptorTrace->trace_pid_dOut.c_str(), dOut);
126     ATRACE_INT(mAppDescriptorTrace->trace_pid_output.c_str(), output);
127     return output;
128 }
129 
130 template <class HintManagerT, class PowerSessionManagerT>
PowerHintSession(int32_t tgid,int32_t uid,const std::vector<int32_t> & threadIds,int64_t durationNs,SessionTag tag)131 PowerHintSession<HintManagerT, PowerSessionManagerT>::PowerHintSession(
132         int32_t tgid, int32_t uid, const std::vector<int32_t> &threadIds, int64_t durationNs,
133         SessionTag tag)
134     : mPSManager(PowerSessionManagerT::getInstance()),
135       mSessionId(++sSessionIDCounter),
136       mIdString(StringPrintf("%" PRId32 "-%" PRId32 "-%" PRId64, tgid, uid, mSessionId)),
137       mDescriptor(std::make_shared<AppHintDesc>(mSessionId, tgid, uid, threadIds, tag,
138                                                 std::chrono::nanoseconds(durationNs))),
139       mAppDescriptorTrace(std::make_shared<AppDescriptorTrace>(mIdString)),
140       mTag(tag),
141       mSessionRecords(
142               HintManagerT::GetInstance()->GetAdpfProfile()->mHeuristicBoostOn.has_value() &&
143                               HintManagerT::GetInstance()
144                                       ->GetAdpfProfile()
145                                       ->mHeuristicBoostOn.value()
146                       ? std::make_unique<SessionRecords>(HintManagerT::GetInstance()
147                                                                  ->GetAdpfProfile()
148                                                                  ->mMaxRecordsNum.value(),
149                                                          HintManagerT::GetInstance()
150                                                                  ->GetAdpfProfile()
151                                                                  ->mJankCheckTimeFactor.value())
152                       : nullptr) {
153     ATRACE_CALL();
154     ATRACE_INT(mAppDescriptorTrace->trace_target.c_str(), mDescriptor->targetNs.count());
155     ATRACE_INT(mAppDescriptorTrace->trace_active.c_str(), mDescriptor->is_active.load());
156 
157     mLastUpdatedTime = std::chrono::steady_clock::now();
158     mPSManager->addPowerSession(mIdString, mDescriptor, mAppDescriptorTrace, threadIds);
159     // init boost
160     auto adpfConfig = HintManagerT::GetInstance()->GetAdpfProfile();
161     mPSManager->voteSet(
162             mSessionId, AdpfVoteType::CPU_LOAD_RESET, adpfConfig->mUclampMinLoadReset, kUclampMax,
163             std::chrono::steady_clock::now(),
164             duration_cast<nanoseconds>(mDescriptor->targetNs * adpfConfig->mStaleTimeFactor / 2.0));
165 
166     mPSManager->voteSet(mSessionId, AdpfVoteType::CPU_VOTE_DEFAULT, adpfConfig->mUclampMinInit,
167                         kUclampMax, std::chrono::steady_clock::now(), mDescriptor->targetNs);
168     ALOGV("PowerHintSession created: %s", mDescriptor->toString().c_str());
169 }
170 
171 template <class HintManagerT, class PowerSessionManagerT>
~PowerHintSession()172 PowerHintSession<HintManagerT, PowerSessionManagerT>::~PowerHintSession() {
173     ATRACE_CALL();
174     close();
175     ALOGV("PowerHintSession deleted: %s", mDescriptor->toString().c_str());
176     ATRACE_INT(mAppDescriptorTrace->trace_target.c_str(), 0);
177     ATRACE_INT(mAppDescriptorTrace->trace_actl_last.c_str(), 0);
178     ATRACE_INT(mAppDescriptorTrace->trace_active.c_str(), 0);
179 }
180 
181 template <class HintManagerT, class PowerSessionManagerT>
isAppSession()182 bool PowerHintSession<HintManagerT, PowerSessionManagerT>::isAppSession() {
183     // Check if uid is in range reserved for applications
184     return mDescriptor->uid >= AID_APP_START;
185 }
186 
187 template <class HintManagerT, class PowerSessionManagerT>
updatePidControlVariable(int pidControlVariable,bool updateVote)188 void PowerHintSession<HintManagerT, PowerSessionManagerT>::updatePidControlVariable(
189         int pidControlVariable, bool updateVote) {
190     mDescriptor->pidControlVariable = pidControlVariable;
191     if (updateVote) {
192         auto adpfConfig = HintManagerT::GetInstance()->GetAdpfProfile();
193         mPSManager->voteSet(mSessionId, AdpfVoteType::CPU_VOTE_DEFAULT, pidControlVariable,
194                             kUclampMax, std::chrono::steady_clock::now(),
195                             std::max(duration_cast<nanoseconds>(mDescriptor->targetNs *
196                                                                 adpfConfig->mStaleTimeFactor),
197                                      nanoseconds(adpfConfig->mReportingRateLimitNs) * 2));
198     }
199     ATRACE_INT(mAppDescriptorTrace->trace_min.c_str(), pidControlVariable);
200 }
201 
202 template <class HintManagerT, class PowerSessionManagerT>
tryToSendPowerHint(std::string hint)203 void PowerHintSession<HintManagerT, PowerSessionManagerT>::tryToSendPowerHint(std::string hint) {
204     if (!mSupportedHints[hint].has_value()) {
205         mSupportedHints[hint] = HintManagerT::GetInstance()->IsHintSupported(hint);
206     }
207     if (mSupportedHints[hint].value()) {
208         HintManagerT::GetInstance()->DoHint(hint);
209     }
210 }
211 
212 template <class HintManagerT, class PowerSessionManagerT>
dumpToStream(std::ostream & stream)213 void PowerHintSession<HintManagerT, PowerSessionManagerT>::dumpToStream(std::ostream &stream) {
214     std::scoped_lock lock{mPowerHintSessionLock};
215     stream << "ID.Min.Act.Timeout(" << mIdString;
216     stream << ", " << mDescriptor->pidControlVariable;
217     stream << ", " << mDescriptor->is_active;
218     stream << ", " << isTimeout() << ")";
219 }
220 
221 template <class HintManagerT, class PowerSessionManagerT>
pause()222 ndk::ScopedAStatus PowerHintSession<HintManagerT, PowerSessionManagerT>::pause() {
223     std::scoped_lock lock{mPowerHintSessionLock};
224     if (mSessionClosed) {
225         ALOGE("Error: session is dead");
226         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
227     }
228     if (!mDescriptor->is_active.load())
229         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
230     // Reset to default uclamp value.
231     mPSManager->setThreadsFromPowerSession(mSessionId, {});
232     mDescriptor->is_active.store(false);
233     mPSManager->pause(mSessionId);
234     ATRACE_INT(mAppDescriptorTrace->trace_active.c_str(), false);
235     ATRACE_INT(mAppDescriptorTrace->trace_min.c_str(), 0);
236     return ndk::ScopedAStatus::ok();
237 }
238 
239 template <class HintManagerT, class PowerSessionManagerT>
resume()240 ndk::ScopedAStatus PowerHintSession<HintManagerT, PowerSessionManagerT>::resume() {
241     std::scoped_lock lock{mPowerHintSessionLock};
242     if (mSessionClosed) {
243         ALOGE("Error: session is dead");
244         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
245     }
246     if (mDescriptor->is_active.load()) {
247         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
248     }
249     mPSManager->setThreadsFromPowerSession(mSessionId, mDescriptor->thread_ids);
250     mDescriptor->is_active.store(true);
251     // resume boost
252     mPSManager->resume(mSessionId);
253     ATRACE_INT(mAppDescriptorTrace->trace_active.c_str(), true);
254     ATRACE_INT(mAppDescriptorTrace->trace_min.c_str(), mDescriptor->pidControlVariable);
255     return ndk::ScopedAStatus::ok();
256 }
257 
258 template <class HintManagerT, class PowerSessionManagerT>
close()259 ndk::ScopedAStatus PowerHintSession<HintManagerT, PowerSessionManagerT>::close() {
260     std::scoped_lock lock{mPowerHintSessionLock};
261     if (mSessionClosed) {
262         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
263     }
264     mSessionClosed = true;
265     // Remove the session from PowerSessionManager first to avoid racing.
266     mPSManager->removePowerSession(mSessionId);
267     mDescriptor->is_active.store(false);
268     ATRACE_INT(mAppDescriptorTrace->trace_min.c_str(), 0);
269     return ndk::ScopedAStatus::ok();
270 }
271 
272 template <class HintManagerT, class PowerSessionManagerT>
updateTargetWorkDuration(int64_t targetDurationNanos)273 ndk::ScopedAStatus PowerHintSession<HintManagerT, PowerSessionManagerT>::updateTargetWorkDuration(
274         int64_t targetDurationNanos) {
275     std::scoped_lock lock{mPowerHintSessionLock};
276     if (mSessionClosed) {
277         ALOGE("Error: session is dead");
278         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
279     }
280     if (targetDurationNanos <= 0) {
281         ALOGE("Error: targetDurationNanos(%" PRId64 ") should bigger than 0", targetDurationNanos);
282         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
283     }
284     targetDurationNanos =
285             targetDurationNanos * HintManagerT::GetInstance()->GetAdpfProfile()->mTargetTimeFactor;
286 
287     mDescriptor->targetNs = std::chrono::nanoseconds(targetDurationNanos);
288     mPSManager->updateTargetWorkDuration(mSessionId, AdpfVoteType::CPU_VOTE_DEFAULT,
289                                          mDescriptor->targetNs);
290     ATRACE_INT(mAppDescriptorTrace->trace_target.c_str(), targetDurationNanos);
291 
292     return ndk::ScopedAStatus::ok();
293 }
294 
295 template <class HintManagerT, class PowerSessionManagerT>
updateHeuristicBoost()296 bool PowerHintSession<HintManagerT, PowerSessionManagerT>::updateHeuristicBoost() {
297     auto maxDurationUs = mSessionRecords->getMaxDuration();  // micro seconds
298     auto avgDurationUs = mSessionRecords->getAvgDuration();  // micro seconds
299     auto numOfReportedDurations = mSessionRecords->getNumOfRecords();
300     auto numOfMissedCycles = mSessionRecords->getNumOfMissedCycles();
301 
302     if (!maxDurationUs.has_value() || !avgDurationUs.has_value()) {
303         return false;
304     }
305 
306     double maxToAvgRatio;
307     if (numOfReportedDurations <= 0) {
308         maxToAvgRatio = maxDurationUs.value() * 1.0 / (mDescriptor->targetNs.count() / 1000);
309     } else {
310         maxToAvgRatio = maxDurationUs.value() / avgDurationUs.value();
311     }
312 
313     auto adpfConfig = HintManagerT::GetInstance()->GetAdpfProfile();
314 
315     if (mSessionRecords->isLowFrameRate(adpfConfig->mLowFrameRateThreshold.value())) {
316         // Turn off the boost when the FPS drops to a low value,
317         // since usually this is because of ui changing to low rate scenarios.
318         // Extra boost is not needed in these scenarios.
319         mHeuristicBoostActive = false;
320     } else if (numOfMissedCycles >= adpfConfig->mHBoostOnMissedCycles.value()) {
321         mHeuristicBoostActive = true;
322     } else if (numOfMissedCycles <= adpfConfig->mHBoostOffMissedCycles.value() &&
323                maxToAvgRatio < adpfConfig->mHBoostOffMaxAvgRatio.value()) {
324         mHeuristicBoostActive = false;
325     }
326     ATRACE_INT(mAppDescriptorTrace->trace_heuristic_boost_active.c_str(), mHeuristicBoostActive);
327     ATRACE_INT(mAppDescriptorTrace->trace_missed_cycles.c_str(), numOfMissedCycles);
328     ATRACE_INT(mAppDescriptorTrace->trace_avg_duration.c_str(), avgDurationUs.value());
329     ATRACE_INT(mAppDescriptorTrace->trace_max_duration.c_str(), maxDurationUs.value());
330     ATRACE_INT(mAppDescriptorTrace->trace_low_frame_rate.c_str(),
331                mSessionRecords->isLowFrameRate(adpfConfig->mLowFrameRateThreshold.value()));
332     return mHeuristicBoostActive;
333 }
334 
335 template <class HintManagerT, class PowerSessionManagerT>
reportActualWorkDuration(const std::vector<WorkDuration> & actualDurations)336 ndk::ScopedAStatus PowerHintSession<HintManagerT, PowerSessionManagerT>::reportActualWorkDuration(
337         const std::vector<WorkDuration> &actualDurations) {
338     std::scoped_lock lock{mPowerHintSessionLock};
339     if (mSessionClosed) {
340         ALOGE("Error: session is dead");
341         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
342     }
343     if (mDescriptor->targetNs.count() == 0LL) {
344         ALOGE("Expect to call updateTargetWorkDuration() first.");
345         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
346     }
347     if (actualDurations.empty()) {
348         ALOGE("Error: durations shouldn't be empty.");
349         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
350     }
351     if (!mDescriptor->is_active.load()) {
352         ALOGE("Error: shouldn't report duration during pause state.");
353         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
354     }
355 
356     auto adpfConfig = HintManagerT::GetInstance()->GetAdpfProfile();
357     mDescriptor->update_count++;
358     bool isFirstFrame = isTimeout();
359     ATRACE_INT(mAppDescriptorTrace->trace_batch_size.c_str(), actualDurations.size());
360     ATRACE_INT(mAppDescriptorTrace->trace_actl_last.c_str(), actualDurations.back().durationNanos);
361     ATRACE_INT(mAppDescriptorTrace->trace_target.c_str(), mDescriptor->targetNs.count());
362     ATRACE_INT(mAppDescriptorTrace->trace_hint_count.c_str(), mDescriptor->update_count);
363     ATRACE_INT(mAppDescriptorTrace->trace_hint_overtime.c_str(),
364                actualDurations.back().durationNanos - mDescriptor->targetNs.count() > 0);
365     ATRACE_INT(mAppDescriptorTrace->trace_is_first_frame.c_str(), (isFirstFrame) ? (1) : (0));
366     ATRACE_INT(mAppDescriptorTrace->trace_cpu_duration.c_str(),
367                actualDurations.back().cpuDurationNanos);
368     ATRACE_INT(mAppDescriptorTrace->trace_gpu_duration.c_str(),
369                actualDurations.back().gpuDurationNanos);
370 
371     mLastUpdatedTime = std::chrono::steady_clock::now();
372     if (isFirstFrame) {
373         if (isAppSession()) {
374             tryToSendPowerHint("ADPF_FIRST_FRAME");
375         }
376 
377         mPSManager->updateUniversalBoostMode();
378     }
379 
380     mPSManager->disableBoosts(mSessionId);
381 
382     if (!adpfConfig->mPidOn) {
383         updatePidControlVariable(adpfConfig->mUclampMinHigh);
384         return ndk::ScopedAStatus::ok();
385     }
386 
387     if (adpfConfig->mHeuristicBoostOn.has_value() && adpfConfig->mHeuristicBoostOn.value()) {
388         mSessionRecords->addReportedDurations(actualDurations, mDescriptor->targetNs.count());
389         updateHeuristicBoost();
390     }
391 
392     int64_t output = convertWorkDurationToBoostByPid(actualDurations);
393 
394     // Apply to all the threads in the group
395     auto uclampMinCeiling = adpfConfig->mUclampMinHigh;
396     if (adpfConfig->mHeuristicBoostOn.has_value() && adpfConfig->mHeuristicBoostOn.value()) {
397         uclampMinCeiling = mHeuristicBoostActive ? adpfConfig->mHBoostUclampMin.value()
398                                                  : adpfConfig->mUclampMinHigh;
399     }
400 
401     int next_min = std::min(static_cast<int>(uclampMinCeiling),
402                             mDescriptor->pidControlVariable + static_cast<int>(output));
403     next_min = std::max(static_cast<int>(adpfConfig->mUclampMinLow), next_min);
404 
405     updatePidControlVariable(next_min);
406 
407     if (!adpfConfig->mGpuBoostOn.value_or(false) || !adpfConfig->mGpuBoostCapacityMax ||
408         !actualDurations.back().gpuDurationNanos) {
409         return ndk::ScopedAStatus::ok();
410     }
411 
412     auto const gpu_freq = mPSManager->gpuFrequency();
413     if (!gpu_freq) {
414         return ndk::ScopedAStatus::ok();
415     }
416     auto const additional_gpu_capacity =
417             calculate_capacity(actualDurations.back(), mDescriptor->targetNs, *gpu_freq);
418     ATRACE_INT(mAppDescriptorTrace->trace_gpu_capacity.c_str(),
419                static_cast<int>(additional_gpu_capacity));
420 
421     auto const additional_gpu_capacity_clamped = std::clamp(
422             additional_gpu_capacity, Cycles(0), Cycles(*adpfConfig->mGpuBoostCapacityMax));
423 
424     mPSManager->voteSet(
425             mSessionId, AdpfVoteType::GPU_CAPACITY, additional_gpu_capacity_clamped,
426             std::chrono::steady_clock::now(),
427             duration_cast<nanoseconds>(mDescriptor->targetNs * adpfConfig->mStaleTimeFactor));
428 
429     return ndk::ScopedAStatus::ok();
430 }
431 
432 template <class HintManagerT, class PowerSessionManagerT>
sendHint(SessionHint hint)433 ndk::ScopedAStatus PowerHintSession<HintManagerT, PowerSessionManagerT>::sendHint(
434         SessionHint hint) {
435     std::scoped_lock lock{mPowerHintSessionLock};
436     if (mSessionClosed) {
437         ALOGE("Error: session is dead");
438         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
439     }
440     if (mDescriptor->targetNs.count() == 0LL) {
441         ALOGE("Expect to call updateTargetWorkDuration() first.");
442         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
443     }
444     auto adpfConfig = HintManagerT::GetInstance()->GetAdpfProfile();
445 
446     switch (hint) {
447         case SessionHint::CPU_LOAD_UP:
448             updatePidControlVariable(mDescriptor->pidControlVariable);
449             mPSManager->voteSet(mSessionId, AdpfVoteType::CPU_LOAD_UP, adpfConfig->mUclampMinLoadUp,
450                                 kUclampMax, std::chrono::steady_clock::now(),
451                                 mDescriptor->targetNs * 2);
452             break;
453         case SessionHint::CPU_LOAD_DOWN:
454             updatePidControlVariable(adpfConfig->mUclampMinLow);
455             break;
456         case SessionHint::CPU_LOAD_RESET:
457             updatePidControlVariable(
458                     std::max(adpfConfig->mUclampMinInit,
459                              static_cast<uint32_t>(mDescriptor->pidControlVariable)),
460                     false);
461             mPSManager->voteSet(mSessionId, AdpfVoteType::CPU_LOAD_RESET,
462                                 adpfConfig->mUclampMinLoadReset, kUclampMax,
463                                 std::chrono::steady_clock::now(),
464                                 duration_cast<nanoseconds>(mDescriptor->targetNs *
465                                                            adpfConfig->mStaleTimeFactor / 2.0));
466             break;
467         case SessionHint::CPU_LOAD_RESUME:
468             mPSManager->voteSet(mSessionId, AdpfVoteType::CPU_LOAD_RESUME,
469                                 mDescriptor->pidControlVariable, kUclampMax,
470                                 std::chrono::steady_clock::now(),
471                                 duration_cast<nanoseconds>(mDescriptor->targetNs *
472                                                            adpfConfig->mStaleTimeFactor / 2.0));
473             break;
474         case SessionHint::POWER_EFFICIENCY:
475             setMode(SessionMode::POWER_EFFICIENCY, true);
476             break;
477         case SessionHint::GPU_LOAD_UP:
478             mPSManager->voteSet(mSessionId, AdpfVoteType::GPU_LOAD_UP,
479                                 Cycles(adpfConfig->mGpuCapacityLoadUpHeadroom),
480                                 std::chrono::steady_clock::now(), mDescriptor->targetNs);
481             break;
482         case SessionHint::GPU_LOAD_DOWN:
483             // TODO(kevindubois): add impl
484             break;
485         case SessionHint::GPU_LOAD_RESET:
486             // TODO(kevindubois): add impl
487             break;
488         default:
489             ALOGE("Error: hint is invalid");
490             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
491     }
492     tryToSendPowerHint(toString(hint));
493     mLastUpdatedTime = std::chrono::steady_clock::now();
494     return ndk::ScopedAStatus::ok();
495 }
496 
497 template <class HintManagerT, class PowerSessionManagerT>
setMode(SessionMode mode,bool enabled)498 ndk::ScopedAStatus PowerHintSession<HintManagerT, PowerSessionManagerT>::setMode(SessionMode mode,
499                                                                                  bool enabled) {
500     std::scoped_lock lock{mPowerHintSessionLock};
501     if (mSessionClosed) {
502         ALOGE("Error: session is dead");
503         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
504     }
505 
506     switch (mode) {
507         case SessionMode::POWER_EFFICIENCY:
508             mPSManager->setPreferPowerEfficiency(mSessionId, enabled);
509             break;
510         default:
511             ALOGE("Error: mode is invalid");
512             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
513     }
514 
515     mModes[static_cast<size_t>(mode)] = enabled;
516     ATRACE_INT(mAppDescriptorTrace->trace_modes[static_cast<size_t>(mode)].c_str(), enabled);
517     mLastUpdatedTime = std::chrono::steady_clock::now();
518     return ndk::ScopedAStatus::ok();
519 }
520 
521 template <class HintManagerT, class PowerSessionManagerT>
setThreads(const std::vector<int32_t> & threadIds)522 ndk::ScopedAStatus PowerHintSession<HintManagerT, PowerSessionManagerT>::setThreads(
523         const std::vector<int32_t> &threadIds) {
524     std::scoped_lock lock{mPowerHintSessionLock};
525     if (mSessionClosed) {
526         ALOGE("Error: session is dead");
527         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
528     }
529     if (threadIds.empty()) {
530         ALOGE("Error: threadIds should not be empty");
531         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
532     }
533     mDescriptor->thread_ids = threadIds;
534     mPSManager->setThreadsFromPowerSession(mSessionId, threadIds);
535     // init boost
536     updatePidControlVariable(HintManagerT::GetInstance()->GetAdpfProfile()->mUclampMinInit);
537     return ndk::ScopedAStatus::ok();
538 }
539 
540 template <class HintManagerT, class PowerSessionManagerT>
getSessionConfig(SessionConfig * _aidl_return)541 ndk::ScopedAStatus PowerHintSession<HintManagerT, PowerSessionManagerT>::getSessionConfig(
542         SessionConfig *_aidl_return) {
543     _aidl_return->id = mSessionId;
544     return ndk::ScopedAStatus::ok();
545 }
546 
547 template <class HintManagerT, class PowerSessionManagerT>
getSessionTag() const548 SessionTag PowerHintSession<HintManagerT, PowerSessionManagerT>::getSessionTag() const {
549     return mTag;
550 }
551 
toString() const552 std::string AppHintDesc::toString() const {
553     std::string out = StringPrintf("session %" PRId64 "\n", sessionId);
554     out.append(
555             StringPrintf("  duration: %" PRId64 " ns\n", static_cast<int64_t>(targetNs.count())));
556     out.append(StringPrintf("  uclamp.min: %d \n", pidControlVariable));
557     out.append(StringPrintf("  uid: %d, tgid: %d\n", uid, tgid));
558     return out;
559 }
560 
561 template <class HintManagerT, class PowerSessionManagerT>
isTimeout()562 bool PowerHintSession<HintManagerT, PowerSessionManagerT>::isTimeout() {
563     auto now = std::chrono::steady_clock::now();
564     time_point<steady_clock> staleTime =
565             mLastUpdatedTime +
566             nanoseconds(static_cast<int64_t>(
567                     mDescriptor->targetNs.count() *
568                     HintManagerT::GetInstance()->GetAdpfProfile()->mStaleTimeFactor));
569     return now >= staleTime;
570 }
571 
572 template class PowerHintSession<>;
573 template class PowerHintSession<testing::NiceMock<mock::pixel::MockHintManager>,
574                                 testing::NiceMock<mock::pixel::MockPowerSessionManager>>;
575 template class PowerHintSession<
576         testing::NiceMock<mock::pixel::MockHintManager>,
577         PowerSessionManager<testing::NiceMock<mock::pixel::MockHintManager>>>;
578 }  // namespace pixel
579 }  // namespace impl
580 }  // namespace power
581 }  // namespace hardware
582 }  // namespace google
583 }  // namespace aidl
584