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