• 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 "PowerSessionManager.h"
21 
22 #include <android-base/file.h>
23 #include <android-base/stringprintf.h>
24 #include <log/log.h>
25 #include <perfmgr/HintManager.h>
26 #include <private/android_filesystem_config.h>
27 #include <processgroup/processgroup.h>
28 #include <sys/syscall.h>
29 #include <utils/Trace.h>
30 
31 #include "AdpfTypes.h"
32 #include "AppDescriptorTrace.h"
33 #include "AppHintDesc.h"
34 #include "tests/mocks/MockHintManager.h"
35 
36 namespace aidl {
37 namespace google {
38 namespace hardware {
39 namespace power {
40 namespace impl {
41 namespace pixel {
42 
43 using ::android::perfmgr::HintManager;
44 
45 namespace {
46 /* there is no glibc or bionic wrapper */
47 struct sched_attr {
48     __u32 size;
49     __u32 sched_policy;
50     __u64 sched_flags;
51     __s32 sched_nice;
52     __u32 sched_priority;
53     __u64 sched_runtime;
54     __u64 sched_deadline;
55     __u64 sched_period;
56     __u32 sched_util_min;
57     __u32 sched_util_max;
58 };
59 
set_uclamp(int tid,UclampRange range)60 static int set_uclamp(int tid, UclampRange range) {
61     // Ensure min and max are bounded by the range limits and each other
62     range.uclampMin = std::min(std::max(kUclampMin, range.uclampMin), kUclampMax);
63     range.uclampMax = std::min(std::max(range.uclampMax, range.uclampMin), kUclampMax);
64     sched_attr attr = {};
65     attr.size = sizeof(attr);
66 
67     attr.sched_flags =
68             (SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP_MIN | SCHED_FLAG_UTIL_CLAMP_MAX);
69     attr.sched_util_min = range.uclampMin;
70     attr.sched_util_max = range.uclampMax;
71 
72     const int ret = syscall(__NR_sched_setattr, tid, attr, 0);
73     if (ret) {
74         ALOGW("sched_setattr failed for thread %d, err=%d", tid, errno);
75         return errno;
76     }
77     return 0;
78 }
79 }  // namespace
80 
81 template <class HintManagerT>
updateHintMode(const std::string & mode,bool enabled)82 void PowerSessionManager<HintManagerT>::updateHintMode(const std::string &mode, bool enabled) {
83     if (enabled && mode.compare(0, 8, "REFRESH_") == 0) {
84         if (mode.compare("REFRESH_120FPS") == 0) {
85             mDisplayRefreshRate = 120;
86         } else if (mode.compare("REFRESH_90FPS") == 0) {
87             mDisplayRefreshRate = 90;
88         } else if (mode.compare("REFRESH_60FPS") == 0) {
89             mDisplayRefreshRate = 60;
90         }
91     }
92     if (HintManager::GetInstance()->GetAdpfProfile()) {
93         HintManager::GetInstance()->SetAdpfProfile(mode);
94     }
95 }
96 
97 template <class HintManagerT>
updateHintBoost(const std::string & boost,int32_t durationMs)98 void PowerSessionManager<HintManagerT>::updateHintBoost(const std::string &boost,
99                                                         int32_t durationMs) {
100     ATRACE_CALL();
101     ALOGV("PowerSessionManager::updateHintBoost: boost: %s, durationMs: %d", boost.c_str(),
102           durationMs);
103 }
104 
105 template <class HintManagerT>
getDisplayRefreshRate()106 int PowerSessionManager<HintManagerT>::getDisplayRefreshRate() {
107     return mDisplayRefreshRate;
108 }
109 
110 template <class HintManagerT>
addPowerSession(const std::string & idString,const std::shared_ptr<AppHintDesc> & sessionDescriptor,const std::shared_ptr<AppDescriptorTrace> & sessionTrace,const std::vector<int32_t> & threadIds)111 void PowerSessionManager<HintManagerT>::addPowerSession(
112         const std::string &idString, const std::shared_ptr<AppHintDesc> &sessionDescriptor,
113         const std::shared_ptr<AppDescriptorTrace> &sessionTrace,
114         const std::vector<int32_t> &threadIds) {
115     if (!sessionDescriptor) {
116         ALOGE("sessionDescriptor is null. PowerSessionManager failed to add power session: %s",
117               idString.c_str());
118         return;
119     }
120     const auto timeNow = std::chrono::steady_clock::now();
121     SessionValueEntry sve;
122     sve.tgid = sessionDescriptor->tgid;
123     sve.uid = sessionDescriptor->uid;
124     sve.idString = idString;
125     sve.isActive = sessionDescriptor->is_active;
126     sve.isAppSession = sessionDescriptor->uid >= AID_APP_START;
127     sve.lastUpdatedTime = timeNow;
128     sve.votes = std::make_shared<Votes>();
129     sve.sessionTrace = sessionTrace;
130     sve.votes->add(
131             static_cast<std::underlying_type_t<AdpfVoteType>>(AdpfVoteType::CPU_VOTE_DEFAULT),
132             CpuVote(false, timeNow, sessionDescriptor->targetNs, kUclampMin, kUclampMax));
133 
134     bool addedRes = false;
135     {
136         std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
137         addedRes = mSessionTaskMap.add(sessionDescriptor->sessionId, sve, {});
138     }
139     if (!addedRes) {
140         ALOGE("sessionTaskMap failed to add power session: %" PRId64, sessionDescriptor->sessionId);
141     }
142 
143     setThreadsFromPowerSession(sessionDescriptor->sessionId, threadIds);
144 }
145 
146 template <class HintManagerT>
removePowerSession(int64_t sessionId)147 void PowerSessionManager<HintManagerT>::removePowerSession(int64_t sessionId) {
148     // To remove a session we also need to undo the effects the session
149     // has on currently enabled votes which means setting vote to inactive
150     // and then forceing a uclamp update to occur
151     forceSessionActive(sessionId, false);
152 
153     std::vector<pid_t> addedThreads;
154     std::vector<pid_t> removedThreads;
155 
156     {
157         // Wait till end to remove session because it needs to be around for apply U clamp
158         // to work above since applying the uclamp needs a valid session id
159         std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
160         mSessionTaskMap.replace(sessionId, {}, &addedThreads, &removedThreads);
161         mSessionTaskMap.remove(sessionId);
162     }
163 
164     for (auto tid : removedThreads) {
165         if (!SetTaskProfiles(tid, {"NoResetUclampGrp"})) {
166             ALOGE("Failed to set NoResetUclampGrp task profile for tid:%d", tid);
167         }
168     }
169 
170     unregisterSession(sessionId);
171 }
172 
173 template <class HintManagerT>
setThreadsFromPowerSession(int64_t sessionId,const std::vector<int32_t> & threadIds)174 void PowerSessionManager<HintManagerT>::setThreadsFromPowerSession(
175         int64_t sessionId, const std::vector<int32_t> &threadIds) {
176     std::vector<pid_t> addedThreads;
177     std::vector<pid_t> removedThreads;
178     forceSessionActive(sessionId, false);
179     {
180         std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
181         mSessionTaskMap.replace(sessionId, threadIds, &addedThreads, &removedThreads);
182     }
183     for (auto tid : addedThreads) {
184         if (!SetTaskProfiles(tid, {"ResetUclampGrp"})) {
185             ALOGE("Failed to set ResetUclampGrp task profile for tid:%d", tid);
186         }
187     }
188     for (auto tid : removedThreads) {
189         if (!SetTaskProfiles(tid, {"NoResetUclampGrp"})) {
190             ALOGE("Failed to set NoResetUclampGrp task profile for tid:%d", tid);
191         }
192     }
193     forceSessionActive(sessionId, true);
194 }
195 
196 template <class HintManagerT>
isAnyAppSessionActive()197 std::optional<bool> PowerSessionManager<HintManagerT>::isAnyAppSessionActive() {
198     bool isAnyAppSessionActive = false;
199     {
200         std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
201         isAnyAppSessionActive =
202                 mSessionTaskMap.isAnyAppSessionActive(std::chrono::steady_clock::now());
203     }
204     return isAnyAppSessionActive;
205 }
206 
207 template <class HintManagerT>
updateUniversalBoostMode()208 void PowerSessionManager<HintManagerT>::updateUniversalBoostMode() {
209     const auto active = isAnyAppSessionActive();
210     if (!active.has_value()) {
211         return;
212     }
213     if (active.value()) {
214         disableSystemTopAppBoost();
215     } else {
216         enableSystemTopAppBoost();
217     }
218 }
219 
220 template <class HintManagerT>
dumpToFd(int fd)221 void PowerSessionManager<HintManagerT>::dumpToFd(int fd) {
222     std::ostringstream dump_buf;
223     dump_buf << "========== Begin PowerSessionManager ADPF list ==========\n";
224     std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
225     mSessionTaskMap.forEachSessionValTasks(
226             [&](auto /* sessionId */, const auto &sessionVal, const auto &tasks) {
227                 sessionVal.dump(dump_buf);
228                 dump_buf << " Tid:Ref[";
229 
230                 size_t tasksLen = tasks.size();
231                 for (auto taskId : tasks) {
232                     dump_buf << taskId << ":";
233                     const auto &sessionIds = mSessionTaskMap.getSessionIds(taskId);
234                     if (!sessionIds.empty()) {
235                         dump_buf << sessionIds.size();
236                     }
237                     if (tasksLen > 0) {
238                         dump_buf << ", ";
239                         --tasksLen;
240                     }
241                 }
242                 dump_buf << "]\n";
243             });
244     dump_buf << "========== End PowerSessionManager ADPF list ==========\n";
245     if (!::android::base::WriteStringToFd(dump_buf.str(), fd)) {
246         ALOGE("Failed to dump one of session list to fd:%d", fd);
247     }
248 }
249 
250 template <class HintManagerT>
pause(int64_t sessionId)251 void PowerSessionManager<HintManagerT>::pause(int64_t sessionId) {
252     {
253         std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
254         auto sessValPtr = mSessionTaskMap.findSession(sessionId);
255         if (nullptr == sessValPtr) {
256             ALOGW("Pause failed, session is null %" PRId64, sessionId);
257             return;
258         }
259 
260         if (!sessValPtr->isActive) {
261             ALOGW("Sess(%" PRId64 "), cannot pause, already inActive", sessionId);
262             return;
263         }
264         sessValPtr->isActive = false;
265     }
266     applyCpuAndGpuVotes(sessionId, std::chrono::steady_clock::now());
267     updateUniversalBoostMode();
268 }
269 
270 template <class HintManagerT>
resume(int64_t sessionId)271 void PowerSessionManager<HintManagerT>::resume(int64_t sessionId) {
272     {
273         std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
274         auto sessValPtr = mSessionTaskMap.findSession(sessionId);
275         if (nullptr == sessValPtr) {
276             ALOGW("Resume failed, session is null %" PRId64, sessionId);
277             return;
278         }
279 
280         if (sessValPtr->isActive) {
281             ALOGW("Sess(%" PRId64 "), cannot resume, already active", sessionId);
282             return;
283         }
284         sessValPtr->isActive = true;
285     }
286     applyCpuAndGpuVotes(sessionId, std::chrono::steady_clock::now());
287     updateUniversalBoostMode();
288 }
289 
290 template <class HintManagerT>
updateTargetWorkDuration(int64_t sessionId,AdpfVoteType voteId,std::chrono::nanoseconds durationNs)291 void PowerSessionManager<HintManagerT>::updateTargetWorkDuration(
292         int64_t sessionId, AdpfVoteType voteId, std::chrono::nanoseconds durationNs) {
293     int voteIdInt = static_cast<std::underlying_type_t<AdpfVoteType>>(voteId);
294     std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
295     auto sessValPtr = mSessionTaskMap.findSession(sessionId);
296     if (nullptr == sessValPtr) {
297         ALOGE("Failed to updateTargetWorkDuration, session val is null id: %" PRId64, sessionId);
298         return;
299     }
300 
301     sessValPtr->votes->updateDuration(voteIdInt, durationNs);
302     // Note, for now we are not recalculating and applying uclamp because
303     // that maintains behavior from before.  In the future we may want to
304     // revisit that decision.
305 }
306 
307 template <typename T>
shouldScheduleTimeout(Votes const & votes,int vote_id,std::chrono::time_point<T> deadline)308 auto shouldScheduleTimeout(Votes const &votes, int vote_id, std::chrono::time_point<T> deadline)
309         -> bool {
310     return !votes.voteIsActive(vote_id) || deadline < votes.voteTimeout(vote_id);
311 }
312 
313 template <class HintManagerT>
voteSet(int64_t sessionId,AdpfVoteType voteId,int uclampMin,int uclampMax,std::chrono::steady_clock::time_point startTime,std::chrono::nanoseconds durationNs)314 void PowerSessionManager<HintManagerT>::voteSet(int64_t sessionId, AdpfVoteType voteId,
315                                                 int uclampMin, int uclampMax,
316                                                 std::chrono::steady_clock::time_point startTime,
317                                                 std::chrono::nanoseconds durationNs) {
318     const int voteIdInt = static_cast<std::underlying_type_t<AdpfVoteType>>(voteId);
319     const auto timeoutDeadline = startTime + durationNs;
320     bool scheduleTimeout = false;
321 
322     {
323         std::lock_guard lock(mSessionTaskMapMutex);
324         auto session = mSessionTaskMap.findSession(sessionId);
325         if (!session) {
326             // Because of the async nature of some events an event for a session
327             // that has been removed is a possibility
328             return;
329         }
330         scheduleTimeout = shouldScheduleTimeout(*session->votes, voteIdInt, timeoutDeadline),
331         mSessionTaskMap.addVote(sessionId, voteIdInt, uclampMin, uclampMax, startTime, durationNs);
332         if (ATRACE_ENABLED()) {
333             ATRACE_INT(session->sessionTrace->trace_votes[voteIdInt].c_str(), uclampMin);
334         }
335         session->lastUpdatedTime = startTime;
336         applyUclampLocked(sessionId, startTime);
337     }
338 
339     if (scheduleTimeout) {
340         mEventSessionTimeoutWorker.schedule(
341                 {.timeStamp = startTime, .sessionId = sessionId, .voteId = voteIdInt},
342                 timeoutDeadline);
343     }
344 }
345 
346 template <class HintManagerT>
voteSet(int64_t sessionId,AdpfVoteType voteId,Cycles capacity,std::chrono::steady_clock::time_point startTime,std::chrono::nanoseconds durationNs)347 void PowerSessionManager<HintManagerT>::voteSet(int64_t sessionId, AdpfVoteType voteId,
348                                                 Cycles capacity,
349                                                 std::chrono::steady_clock::time_point startTime,
350                                                 std::chrono::nanoseconds durationNs) {
351     const int voteIdInt = static_cast<std::underlying_type_t<AdpfVoteType>>(voteId);
352     const auto timeoutDeadline = startTime + durationNs;
353     bool scheduleTimeout = false;
354 
355     {
356         std::lock_guard lock(mSessionTaskMapMutex);
357         auto session = mSessionTaskMap.findSession(sessionId);
358         if (!session) {
359             return;
360         }
361         scheduleTimeout = shouldScheduleTimeout(*session->votes, voteIdInt, timeoutDeadline),
362         mSessionTaskMap.addGpuVote(sessionId, voteIdInt, capacity, startTime, durationNs);
363         if (ATRACE_ENABLED()) {
364             ATRACE_INT(session->sessionTrace->trace_votes[voteIdInt].c_str(),
365                        static_cast<int>(capacity));
366         }
367         session->lastUpdatedTime = startTime;
368         applyGpuVotesLocked(sessionId, startTime);
369     }
370 
371     if (scheduleTimeout) {
372         mEventSessionTimeoutWorker.schedule(
373                 {.timeStamp = startTime, .sessionId = sessionId, .voteId = voteIdInt},
374                 timeoutDeadline);
375     }
376 }
377 
378 template <class HintManagerT>
disableBoosts(int64_t sessionId)379 void PowerSessionManager<HintManagerT>::disableBoosts(int64_t sessionId) {
380     {
381         std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
382         auto sessValPtr = mSessionTaskMap.findSession(sessionId);
383         if (nullptr == sessValPtr) {
384             // Because of the async nature of some events an event for a session
385             // that has been removed is a possibility
386             return;
387         }
388 
389         // sessValPtr->disableBoosts();
390         for (auto vid : {AdpfVoteType::CPU_LOAD_UP, AdpfVoteType::CPU_LOAD_RESET,
391                          AdpfVoteType::CPU_LOAD_RESUME, AdpfVoteType::VOTE_POWER_EFFICIENCY,
392                          AdpfVoteType::GPU_LOAD_UP, AdpfVoteType::GPU_LOAD_RESET}) {
393             auto vint = static_cast<std::underlying_type_t<AdpfVoteType>>(vid);
394             sessValPtr->votes->setUseVote(vint, false);
395             if (ATRACE_ENABLED()) {
396                 ATRACE_INT(sessValPtr->sessionTrace->trace_votes[vint].c_str(), 0);
397             }
398         }
399     }
400 }
401 
402 template <class HintManagerT>
enableSystemTopAppBoost()403 void PowerSessionManager<HintManagerT>::enableSystemTopAppBoost() {
404     if (HintManager::GetInstance()->IsHintSupported(kDisableBoostHintName)) {
405         ALOGV("PowerSessionManager::enableSystemTopAppBoost!!");
406         HintManager::GetInstance()->EndHint(kDisableBoostHintName);
407     }
408 }
409 
410 template <class HintManagerT>
disableSystemTopAppBoost()411 void PowerSessionManager<HintManagerT>::disableSystemTopAppBoost() {
412     if (HintManager::GetInstance()->IsHintSupported(kDisableBoostHintName)) {
413         ALOGV("PowerSessionManager::disableSystemTopAppBoost!!");
414         HintManager::GetInstance()->DoHint(kDisableBoostHintName);
415     }
416 }
417 
418 template <class HintManagerT>
handleEvent(const EventSessionTimeout & eventTimeout)419 void PowerSessionManager<HintManagerT>::handleEvent(const EventSessionTimeout &eventTimeout) {
420     bool recalcUclamp = false;
421     const auto tNow = std::chrono::steady_clock::now();
422     {
423         std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
424         auto sessValPtr = mSessionTaskMap.findSession(eventTimeout.sessionId);
425         if (nullptr == sessValPtr) {
426             // It is ok for session timeouts to fire after a session has been
427             // removed
428             return;
429         }
430 
431         // To minimize the number of events pushed into the queue, we are using
432         // the following logic to make use of a single timeout event which will
433         // requeue itself if the timeout has been changed since it was added to
434         // the work queue.  Requeue Logic:
435         // if vote active and vote timeout <= sched time
436         //    then deactivate vote and recalc uclamp (near end of function)
437         // if vote active and vote timeout > sched time
438         //    then requeue timeout event for new deadline (which is vote timeout)
439         const bool voteIsActive = sessValPtr->votes->voteIsActive(eventTimeout.voteId);
440         const auto voteTimeout = sessValPtr->votes->voteTimeout(eventTimeout.voteId);
441 
442         if (voteIsActive) {
443             if (voteTimeout <= tNow) {
444                 sessValPtr->votes->setUseVote(eventTimeout.voteId, false);
445                 recalcUclamp = true;
446                 if (ATRACE_ENABLED()) {
447                     ATRACE_INT(sessValPtr->sessionTrace->trace_votes[eventTimeout.voteId].c_str(),
448                                0);
449                 }
450             } else {
451                 // Can unlock sooner than we do
452                 auto eventTimeout2 = eventTimeout;
453                 mEventSessionTimeoutWorker.schedule(eventTimeout2, voteTimeout);
454             }
455         }
456     }
457 
458     if (!recalcUclamp) {
459         return;
460     }
461 
462     // It is important to use the correct time here, time now is more reasonable
463     // than trying to use the event's timestamp which will be slightly off given
464     // the background priority queue introduces latency
465     applyCpuAndGpuVotes(eventTimeout.sessionId, tNow);
466     updateUniversalBoostMode();
467 }
468 
469 template <class HintManagerT>
applyUclampLocked(int64_t sessionId,std::chrono::steady_clock::time_point timePoint)470 void PowerSessionManager<HintManagerT>::applyUclampLocked(
471         int64_t sessionId, std::chrono::steady_clock::time_point timePoint) {
472     auto config = HintManager::GetInstance()->GetAdpfProfile();
473     {
474         // TODO(kevindubois) un-indent this in followup patch to reduce churn.
475         auto sessValPtr = mSessionTaskMap.findSession(sessionId);
476         if (nullptr == sessValPtr) {
477             return;
478         }
479 
480         if (!config->mUclampMinOn) {
481             ALOGV("PowerSessionManager::set_uclamp: skip");
482         } else {
483             auto &threadList = mSessionTaskMap.getTaskIds(sessionId);
484             auto tidIter = threadList.begin();
485             while (tidIter != threadList.end()) {
486                 UclampRange uclampRange;
487                 mSessionTaskMap.getTaskVoteRange(*tidIter, timePoint, uclampRange,
488                                                  config->mUclampMaxEfficientBase,
489                                                  config->mUclampMaxEfficientOffset);
490                 int stat = set_uclamp(*tidIter, uclampRange);
491                 if (stat == ESRCH) {
492                     ALOGV("Removing dead thread %d from hint session %s.", *tidIter,
493                           sessValPtr->idString.c_str());
494                     if (mSessionTaskMap.removeDeadTaskSessionMap(sessionId, *tidIter)) {
495                         ALOGV("Removed dead thread-session map.");
496                     }
497                     tidIter = threadList.erase(tidIter);
498                 } else {
499                     tidIter++;
500                 }
501             }
502         }
503 
504         sessValPtr->lastUpdatedTime = timePoint;
505     }
506 }
507 
508 template <class HintManagerT>
applyGpuVotesLocked(int64_t sessionId,std::chrono::steady_clock::time_point timePoint)509 void PowerSessionManager<HintManagerT>::applyGpuVotesLocked(
510         int64_t sessionId, std::chrono::steady_clock::time_point timePoint) {
511     auto const sessValPtr = mSessionTaskMap.findSession(sessionId);
512     if (!sessValPtr) {
513         return;
514     }
515 
516     auto const gpuVotingOn = HintManager::GetInstance()->GetAdpfProfile()->mGpuBoostOn;
517     if (mGpuCapacityNode && gpuVotingOn) {
518         auto const capacity = mSessionTaskMap.getSessionsGpuCapacity(timePoint);
519         (*mGpuCapacityNode)->set_gpu_capacity(capacity);
520     }
521 
522     sessValPtr->lastUpdatedTime = timePoint;
523 }
524 
525 template <class HintManagerT>
applyCpuAndGpuVotes(int64_t sessionId,std::chrono::steady_clock::time_point timePoint)526 void PowerSessionManager<HintManagerT>::applyCpuAndGpuVotes(
527         int64_t sessionId, std::chrono::steady_clock::time_point timePoint) {
528     std::lock_guard lock(mSessionTaskMapMutex);
529     applyUclampLocked(sessionId, timePoint);
530     applyGpuVotesLocked(sessionId, timePoint);
531 }
532 
533 template <class HintManagerT>
gpuFrequency() const534 std::optional<Frequency> PowerSessionManager<HintManagerT>::gpuFrequency() const {
535     if (mGpuCapacityNode) {
536         return (*mGpuCapacityNode)->gpu_frequency();
537     }
538     return {};
539 }
540 
541 template <class HintManagerT>
forceSessionActive(int64_t sessionId,bool isActive)542 void PowerSessionManager<HintManagerT>::forceSessionActive(int64_t sessionId, bool isActive) {
543     {
544         std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
545         auto sessValPtr = mSessionTaskMap.findSession(sessionId);
546         if (nullptr == sessValPtr) {
547             return;
548         }
549         sessValPtr->isActive = isActive;
550     }
551 
552     // As currently written, call needs to occur synchronously so as to ensure
553     // that the SessionId remains valid and mapped to the proper threads/tasks
554     // which enables apply u clamp to work correctly
555     applyCpuAndGpuVotes(sessionId, std::chrono::steady_clock::now());
556     updateUniversalBoostMode();
557 }
558 
559 template <class HintManagerT>
setPreferPowerEfficiency(int64_t sessionId,bool enabled)560 void PowerSessionManager<HintManagerT>::setPreferPowerEfficiency(int64_t sessionId, bool enabled) {
561     std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
562     auto sessValPtr = mSessionTaskMap.findSession(sessionId);
563     if (nullptr == sessValPtr) {
564         return;
565     }
566     if (enabled != sessValPtr->isPowerEfficient) {
567         sessValPtr->isPowerEfficient = enabled;
568         applyUclampLocked(sessionId, std::chrono::steady_clock::now());
569     }
570 }
571 
572 template <class HintManagerT>
registerSession(std::shared_ptr<void> session,int64_t sessionId)573 void PowerSessionManager<HintManagerT>::registerSession(std::shared_ptr<void> session,
574                                                         int64_t sessionId) {
575     std::lock_guard<std::mutex> lock(mSessionMapMutex);
576     mSessionMap[sessionId] = session;
577 }
578 
579 template <class HintManagerT>
unregisterSession(int64_t sessionId)580 void PowerSessionManager<HintManagerT>::unregisterSession(int64_t sessionId) {
581     std::lock_guard<std::mutex> lock(mSessionMapMutex);
582     mSessionMap.erase(sessionId);
583 }
584 
585 template <class HintManagerT>
getSession(int64_t sessionId)586 std::shared_ptr<void> PowerSessionManager<HintManagerT>::getSession(int64_t sessionId) {
587     std::scoped_lock lock(mSessionMapMutex);
588     auto ptr = mSessionMap.find(sessionId);
589     if (ptr == mSessionMap.end()) {
590         return nullptr;
591     }
592     std::shared_ptr<void> out = ptr->second.lock();
593     if (!out) {
594         mSessionMap.erase(sessionId);
595         return nullptr;
596     }
597     return out;
598 }
599 
600 template <class HintManagerT>
clear()601 void PowerSessionManager<HintManagerT>::clear() {
602     std::scoped_lock lock(mSessionMapMutex);
603     mSessionMap.clear();
604 }
605 
606 template class PowerSessionManager<>;
607 template class PowerSessionManager<testing::NiceMock<mock::pixel::MockHintManager>>;
608 
609 }  // namespace pixel
610 }  // namespace impl
611 }  // namespace power
612 }  // namespace hardware
613 }  // namespace google
614 }  // namespace aidl
615