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