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 <perfmgr/HintManager.h>
25 #include <private/android_filesystem_config.h>
26 #include <processgroup/processgroup.h>
27 #include <sys/syscall.h>
28 #include <utils/Trace.h>
29
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 using ::android::perfmgr::HintManager;
42 constexpr char kGameModeName[] = "GAME";
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 && HintManager::GetInstance()->GetAdpfProfileFromDoHint()) {
89 HintManager::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,const ProcessTag procTag)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, const ProcessTag procTag) {
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.lastUpdatedTime = timeNow;
116 sve.votes = std::make_shared<Votes>();
117 sve.sessionTrace = sessionTrace;
118 sve.votes->add(
119 static_cast<std::underlying_type_t<AdpfVoteType>>(AdpfVoteType::CPU_VOTE_DEFAULT),
120 CpuVote(false, timeNow, sessionDescriptor->targetNs, kUclampMin, kUclampMax));
121
122 bool addedRes = false;
123 {
124 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
125 addedRes = mSessionTaskMap.add(sessionDescriptor->sessionId, sve, {});
126 }
127 if (!addedRes) {
128 ALOGE("sessionTaskMap failed to add power session: %" PRId64, sessionDescriptor->sessionId);
129 }
130
131 setThreadsFromPowerSession(sessionDescriptor->sessionId, threadIds, procTag);
132 }
133
134 template <class HintManagerT>
removePowerSession(int64_t sessionId,const ProcessTag procTag)135 void PowerSessionManager<HintManagerT>::removePowerSession(int64_t sessionId,
136 const ProcessTag procTag) {
137 // To remove a session we also need to undo the effects the session
138 // has on currently enabled votes which means setting vote to inactive
139 // and then forceing a uclamp update to occur
140 forceSessionActive(sessionId, false);
141
142 std::vector<pid_t> addedThreads;
143 std::vector<pid_t> removedThreads;
144
145 {
146 // Wait till end to remove session because it needs to be around for apply U clamp
147 // to work above since applying the uclamp needs a valid session id
148 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
149 mSessionTaskMap.replace(sessionId, {}, &addedThreads, &removedThreads);
150 mSessionTaskMap.remove(sessionId);
151 }
152
153 if (procTag == ProcessTag::SYSTEM_UI) {
154 for (auto tid : removedThreads) {
155 if (!SetTaskProfiles(tid, {"SCHED_QOS_SENSITIVE_EXTREME_CLEAR"})) {
156 ALOGE("Failed to set SCHED_QOS_SENSITIVE_EXTREME_CLEAR task profile for tid:%d",
157 tid);
158 }
159 }
160 } else {
161 for (auto tid : removedThreads) {
162 if (!SetTaskProfiles(tid, {"SCHED_QOS_SENSITIVE_STANDARD_CLEAR"})) {
163 ALOGE("Failed to set SCHED_QOS_SENSITIVE_STANDARD_CLEAR task profile for tid:%d",
164 tid);
165 }
166 }
167 }
168
169 unregisterSession(sessionId);
170 }
171
172 template <class HintManagerT>
setThreadsFromPowerSession(int64_t sessionId,const std::vector<int32_t> & threadIds,const ProcessTag procTag)173 void PowerSessionManager<HintManagerT>::setThreadsFromPowerSession(
174 int64_t sessionId, const std::vector<int32_t> &threadIds, const ProcessTag procTag) {
175 std::vector<pid_t> addedThreads;
176 std::vector<pid_t> removedThreads;
177 forceSessionActive(sessionId, false);
178 {
179 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
180 mSessionTaskMap.replace(sessionId, threadIds, &addedThreads, &removedThreads);
181 }
182 if (procTag == ProcessTag::SYSTEM_UI) {
183 for (auto tid : addedThreads) {
184 if (!SetTaskProfiles(tid, {"SCHED_QOS_SENSITIVE_EXTREME_SET"})) {
185 ALOGE("Failed to set SCHED_QOS_SENSITIVE_EXTREME_SET task profile for tid:%d", tid);
186 }
187 }
188 } else {
189 for (auto tid : addedThreads) {
190 if (!SetTaskProfiles(tid, {"SCHED_QOS_SENSITIVE_STANDARD_SET"})) {
191 ALOGE("Failed to set SCHED_QOS_SENSITIVE_STANDARD_SET task profile for tid:%d",
192 tid);
193 }
194 }
195 }
196 if (procTag == ProcessTag::SYSTEM_UI) {
197 for (auto tid : removedThreads) {
198 if (!SetTaskProfiles(tid, {"SCHED_QOS_SENSITIVE_EXTREME_CLEAR"})) {
199 ALOGE("Failed to set SCHED_QOS_SENSITIVE_EXTREME_CLEAR task profile for tid:%d",
200 tid);
201 }
202 }
203 } else {
204 for (auto tid : removedThreads) {
205 if (!SetTaskProfiles(tid, {"SCHED_QOS_SENSITIVE_STANDARD_CLEAR"})) {
206 ALOGE("Failed to set SCHED_QOS_SENSITIVE_STANDARD_CLEAR task profile for tid:%d",
207 tid);
208 }
209 }
210 }
211 forceSessionActive(sessionId, true);
212 }
213
214 template <class HintManagerT>
isAnyAppSessionActive()215 std::optional<bool> PowerSessionManager<HintManagerT>::isAnyAppSessionActive() {
216 bool isAnyAppSessionActive = false;
217 {
218 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
219 isAnyAppSessionActive =
220 mSessionTaskMap.isAnyAppSessionActive(std::chrono::steady_clock::now());
221 }
222 return isAnyAppSessionActive;
223 }
224
225 template <class HintManagerT>
updateUniversalBoostMode()226 void PowerSessionManager<HintManagerT>::updateUniversalBoostMode() {
227 const auto active = isAnyAppSessionActive();
228 if (!active.has_value()) {
229 return;
230 }
231 if (active.value()) {
232 disableSystemTopAppBoost();
233 } else {
234 enableSystemTopAppBoost();
235 }
236 }
237
238 template <class HintManagerT>
dumpToFd(int fd)239 void PowerSessionManager<HintManagerT>::dumpToFd(int fd) {
240 std::ostringstream dump_buf;
241 dump_buf << "========== Begin PowerSessionManager ADPF list ==========\n";
242 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
243 mSessionTaskMap.forEachSessionValTasks(
244 [&](auto /* sessionId */, const auto &sessionVal, const auto &tasks) {
245 sessionVal.dump(dump_buf);
246 dump_buf << " Tid:Ref[";
247
248 size_t tasksLen = tasks.size();
249 for (auto taskId : tasks) {
250 dump_buf << taskId << ":";
251 const auto &sessionIds = mSessionTaskMap.getSessionIds(taskId);
252 if (!sessionIds.empty()) {
253 dump_buf << sessionIds.size();
254 }
255 if (tasksLen > 0) {
256 dump_buf << ", ";
257 --tasksLen;
258 }
259 }
260 dump_buf << "]\n";
261 });
262 dump_buf << "========== End PowerSessionManager ADPF list ==========\n";
263 if (!::android::base::WriteStringToFd(dump_buf.str(), fd)) {
264 ALOGE("Failed to dump one of session list to fd:%d", fd);
265 }
266 }
267
268 template <class HintManagerT>
pause(int64_t sessionId)269 void PowerSessionManager<HintManagerT>::pause(int64_t sessionId) {
270 {
271 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
272 auto sessValPtr = mSessionTaskMap.findSession(sessionId);
273 if (nullptr == sessValPtr) {
274 ALOGW("Pause failed, session is null %" PRId64, sessionId);
275 return;
276 }
277
278 if (!sessValPtr->isActive) {
279 ALOGW("Sess(%" PRId64 "), cannot pause, already inActive", sessionId);
280 return;
281 }
282 sessValPtr->isActive = false;
283 }
284 applyCpuAndGpuVotes(sessionId, std::chrono::steady_clock::now());
285 updateUniversalBoostMode();
286 }
287
288 template <class HintManagerT>
resume(int64_t sessionId)289 void PowerSessionManager<HintManagerT>::resume(int64_t sessionId) {
290 {
291 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
292 auto sessValPtr = mSessionTaskMap.findSession(sessionId);
293 if (nullptr == sessValPtr) {
294 ALOGW("Resume failed, session is null %" PRId64, sessionId);
295 return;
296 }
297
298 if (sessValPtr->isActive) {
299 ALOGW("Sess(%" PRId64 "), cannot resume, already active", sessionId);
300 return;
301 }
302 sessValPtr->isActive = true;
303 }
304 applyCpuAndGpuVotes(sessionId, std::chrono::steady_clock::now());
305 updateUniversalBoostMode();
306 }
307
308 template <class HintManagerT>
updateTargetWorkDuration(int64_t sessionId,AdpfVoteType voteId,std::chrono::nanoseconds durationNs)309 void PowerSessionManager<HintManagerT>::updateTargetWorkDuration(
310 int64_t sessionId, AdpfVoteType voteId, std::chrono::nanoseconds durationNs) {
311 int voteIdInt = static_cast<std::underlying_type_t<AdpfVoteType>>(voteId);
312 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
313 auto sessValPtr = mSessionTaskMap.findSession(sessionId);
314 if (nullptr == sessValPtr) {
315 ALOGE("Failed to updateTargetWorkDuration, session val is null id: %" PRId64, sessionId);
316 return;
317 }
318
319 sessValPtr->votes->updateDuration(voteIdInt, durationNs);
320 // Note, for now we are not recalculating and applying uclamp because
321 // that maintains behavior from before. In the future we may want to
322 // revisit that decision.
323 }
324
325 template <typename T>
shouldScheduleTimeout(Votes const & votes,int vote_id,std::chrono::time_point<T> deadline)326 auto shouldScheduleTimeout(Votes const &votes, int vote_id, std::chrono::time_point<T> deadline)
327 -> bool {
328 return !votes.voteIsActive(vote_id) || deadline < votes.voteTimeout(vote_id);
329 }
330
331 template <class HintManagerT>
voteSet(int64_t sessionId,AdpfVoteType voteId,int uclampMin,int uclampMax,std::chrono::steady_clock::time_point startTime,std::chrono::nanoseconds durationNs)332 void PowerSessionManager<HintManagerT>::voteSet(int64_t sessionId, AdpfVoteType voteId,
333 int uclampMin, int uclampMax,
334 std::chrono::steady_clock::time_point startTime,
335 std::chrono::nanoseconds durationNs) {
336 const int voteIdInt = static_cast<std::underlying_type_t<AdpfVoteType>>(voteId);
337 const auto timeoutDeadline = startTime + durationNs;
338 bool scheduleTimeout = false;
339
340 {
341 std::lock_guard lock(mSessionTaskMapMutex);
342 auto session = mSessionTaskMap.findSession(sessionId);
343 if (!session) {
344 // Because of the async nature of some events an event for a session
345 // that has been removed is a possibility
346 return;
347 }
348 scheduleTimeout = shouldScheduleTimeout(*session->votes, voteIdInt, timeoutDeadline),
349 mSessionTaskMap.addVote(sessionId, voteIdInt, uclampMin, uclampMax, startTime, durationNs);
350 if (ATRACE_ENABLED()) {
351 ATRACE_INT(session->sessionTrace->trace_votes[voteIdInt].c_str(), uclampMin);
352 }
353 session->lastUpdatedTime = startTime;
354 applyUclampLocked(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>
voteSet(int64_t sessionId,AdpfVoteType voteId,Cycles capacity,std::chrono::steady_clock::time_point startTime,std::chrono::nanoseconds durationNs)365 void PowerSessionManager<HintManagerT>::voteSet(int64_t sessionId, AdpfVoteType voteId,
366 Cycles capacity,
367 std::chrono::steady_clock::time_point startTime,
368 std::chrono::nanoseconds durationNs) {
369 const int voteIdInt = static_cast<std::underlying_type_t<AdpfVoteType>>(voteId);
370 const auto timeoutDeadline = startTime + durationNs;
371 bool scheduleTimeout = false;
372
373 {
374 std::lock_guard lock(mSessionTaskMapMutex);
375 auto session = mSessionTaskMap.findSession(sessionId);
376 if (!session) {
377 return;
378 }
379 scheduleTimeout = shouldScheduleTimeout(*session->votes, voteIdInt, timeoutDeadline),
380 mSessionTaskMap.addGpuVote(sessionId, voteIdInt, capacity, startTime, durationNs);
381 if (ATRACE_ENABLED()) {
382 ATRACE_INT(session->sessionTrace->trace_votes[voteIdInt].c_str(),
383 static_cast<int>(capacity));
384 }
385 session->lastUpdatedTime = startTime;
386 applyGpuVotesLocked(sessionId, startTime);
387 }
388
389 if (scheduleTimeout) {
390 mEventSessionTimeoutWorker.schedule(
391 {.timeStamp = startTime, .sessionId = sessionId, .voteId = voteIdInt},
392 timeoutDeadline);
393 }
394 }
395
396 template <class HintManagerT>
disableBoosts(int64_t sessionId)397 void PowerSessionManager<HintManagerT>::disableBoosts(int64_t sessionId) {
398 {
399 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
400 auto sessValPtr = mSessionTaskMap.findSession(sessionId);
401 if (nullptr == sessValPtr) {
402 // Because of the async nature of some events an event for a session
403 // that has been removed is a possibility
404 return;
405 }
406
407 // sessValPtr->disableBoosts();
408 for (auto vid : {AdpfVoteType::CPU_LOAD_UP, AdpfVoteType::CPU_LOAD_RESET,
409 AdpfVoteType::CPU_LOAD_RESUME, AdpfVoteType::VOTE_POWER_EFFICIENCY,
410 AdpfVoteType::GPU_LOAD_UP, AdpfVoteType::GPU_LOAD_RESET}) {
411 auto vint = static_cast<std::underlying_type_t<AdpfVoteType>>(vid);
412 sessValPtr->votes->setUseVote(vint, false);
413 if (ATRACE_ENABLED()) {
414 ATRACE_INT(sessValPtr->sessionTrace->trace_votes[vint].c_str(), 0);
415 }
416 }
417 }
418 }
419
420 template <class HintManagerT>
enableSystemTopAppBoost()421 void PowerSessionManager<HintManagerT>::enableSystemTopAppBoost() {
422 if (HintManagerT::GetInstance()->IsHintSupported(kDisableBoostHintName)) {
423 ALOGV("PowerSessionManager::enableSystemTopAppBoost!!");
424 HintManagerT::GetInstance()->EndHint(kDisableBoostHintName);
425 }
426 }
427
428 template <class HintManagerT>
disableSystemTopAppBoost()429 void PowerSessionManager<HintManagerT>::disableSystemTopAppBoost() {
430 if (HintManagerT::GetInstance()->IsHintSupported(kDisableBoostHintName)) {
431 ALOGV("PowerSessionManager::disableSystemTopAppBoost!!");
432 HintManagerT::GetInstance()->DoHint(kDisableBoostHintName);
433 }
434 }
435
436 template <class HintManagerT>
handleEvent(const EventSessionTimeout & eventTimeout)437 void PowerSessionManager<HintManagerT>::handleEvent(const EventSessionTimeout &eventTimeout) {
438 bool recalcUclamp = false;
439 const auto tNow = std::chrono::steady_clock::now();
440 {
441 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
442 auto sessValPtr = mSessionTaskMap.findSession(eventTimeout.sessionId);
443 if (nullptr == sessValPtr) {
444 // It is ok for session timeouts to fire after a session has been
445 // removed
446 return;
447 }
448
449 // To minimize the number of events pushed into the queue, we are using
450 // the following logic to make use of a single timeout event which will
451 // requeue itself if the timeout has been changed since it was added to
452 // the work queue. Requeue Logic:
453 // if vote active and vote timeout <= sched time
454 // then deactivate vote and recalc uclamp (near end of function)
455 // if vote active and vote timeout > sched time
456 // then requeue timeout event for new deadline (which is vote timeout)
457 const bool voteIsActive = sessValPtr->votes->voteIsActive(eventTimeout.voteId);
458 const auto voteTimeout = sessValPtr->votes->voteTimeout(eventTimeout.voteId);
459
460 if (voteIsActive) {
461 if (voteTimeout <= tNow) {
462 sessValPtr->votes->setUseVote(eventTimeout.voteId, false);
463 recalcUclamp = true;
464 if (ATRACE_ENABLED()) {
465 ATRACE_INT(sessValPtr->sessionTrace->trace_votes[eventTimeout.voteId].c_str(),
466 0);
467 }
468 } else {
469 // Can unlock sooner than we do
470 auto eventTimeout2 = eventTimeout;
471 mEventSessionTimeoutWorker.schedule(eventTimeout2, voteTimeout);
472 }
473 }
474 }
475
476 if (!recalcUclamp) {
477 return;
478 }
479
480 // It is important to use the correct time here, time now is more reasonable
481 // than trying to use the event's timestamp which will be slightly off given
482 // the background priority queue introduces latency
483 applyCpuAndGpuVotes(eventTimeout.sessionId, tNow);
484 updateUniversalBoostMode();
485 }
486
487 template <class HintManagerT>
applyUclampLocked(int64_t sessionId,std::chrono::steady_clock::time_point timePoint)488 void PowerSessionManager<HintManagerT>::applyUclampLocked(
489 int64_t sessionId, std::chrono::steady_clock::time_point timePoint) {
490 auto config = HintManagerT::GetInstance()->GetAdpfProfile();
491 {
492 // TODO(kevindubois) un-indent this in followup patch to reduce churn.
493 auto sessValPtr = mSessionTaskMap.findSession(sessionId);
494 if (nullptr == sessValPtr) {
495 return;
496 }
497
498 if (!config->mUclampMinOn) {
499 ALOGV("PowerSessionManager::set_uclamp: skip");
500 } else {
501 auto &threadList = mSessionTaskMap.getTaskIds(sessionId);
502 auto tidIter = threadList.begin();
503 while (tidIter != threadList.end()) {
504 UclampRange uclampRange;
505 mSessionTaskMap.getTaskVoteRange(*tidIter, timePoint, uclampRange,
506 config->mUclampMaxEfficientBase,
507 config->mUclampMaxEfficientOffset);
508 int stat = set_uclamp(*tidIter, uclampRange);
509 if (stat == ESRCH) {
510 ALOGV("Removing dead thread %d from hint session %s.", *tidIter,
511 sessValPtr->idString.c_str());
512 if (mSessionTaskMap.removeDeadTaskSessionMap(sessionId, *tidIter)) {
513 ALOGV("Removed dead thread-session map.");
514 }
515 tidIter = threadList.erase(tidIter);
516 } else {
517 tidIter++;
518 }
519 }
520 }
521
522 sessValPtr->lastUpdatedTime = timePoint;
523 }
524 }
525
526 template <class HintManagerT>
applyGpuVotesLocked(int64_t sessionId,std::chrono::steady_clock::time_point timePoint)527 void PowerSessionManager<HintManagerT>::applyGpuVotesLocked(
528 int64_t sessionId, std::chrono::steady_clock::time_point timePoint) {
529 auto const sessValPtr = mSessionTaskMap.findSession(sessionId);
530 if (!sessValPtr) {
531 return;
532 }
533
534 auto const gpuVotingOn = HintManagerT::GetInstance()->GetAdpfProfile()->mGpuBoostOn;
535 if (mGpuCapacityNode && gpuVotingOn) {
536 auto const capacity = mSessionTaskMap.getSessionsGpuCapacity(timePoint);
537 (*mGpuCapacityNode)->set_gpu_capacity(capacity);
538 }
539
540 sessValPtr->lastUpdatedTime = timePoint;
541 }
542
543 template <class HintManagerT>
applyCpuAndGpuVotes(int64_t sessionId,std::chrono::steady_clock::time_point timePoint)544 void PowerSessionManager<HintManagerT>::applyCpuAndGpuVotes(
545 int64_t sessionId, std::chrono::steady_clock::time_point timePoint) {
546 std::lock_guard lock(mSessionTaskMapMutex);
547 applyUclampLocked(sessionId, timePoint);
548 applyGpuVotesLocked(sessionId, timePoint);
549 }
550
551 template <class HintManagerT>
gpuFrequency() const552 std::optional<Frequency> PowerSessionManager<HintManagerT>::gpuFrequency() const {
553 if (mGpuCapacityNode) {
554 return (*mGpuCapacityNode)->gpu_frequency();
555 }
556 return {};
557 }
558
559 template <class HintManagerT>
forceSessionActive(int64_t sessionId,bool isActive)560 void PowerSessionManager<HintManagerT>::forceSessionActive(int64_t sessionId, bool isActive) {
561 {
562 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
563 auto sessValPtr = mSessionTaskMap.findSession(sessionId);
564 if (nullptr == sessValPtr) {
565 return;
566 }
567 sessValPtr->isActive = isActive;
568 }
569
570 // As currently written, call needs to occur synchronously so as to ensure
571 // that the SessionId remains valid and mapped to the proper threads/tasks
572 // which enables apply u clamp to work correctly
573 applyCpuAndGpuVotes(sessionId, std::chrono::steady_clock::now());
574 updateUniversalBoostMode();
575 }
576
577 template <class HintManagerT>
setPreferPowerEfficiency(int64_t sessionId,bool enabled)578 void PowerSessionManager<HintManagerT>::setPreferPowerEfficiency(int64_t sessionId, bool enabled) {
579 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
580 auto sessValPtr = mSessionTaskMap.findSession(sessionId);
581 if (nullptr == sessValPtr) {
582 return;
583 }
584 if (enabled != sessValPtr->isPowerEfficient) {
585 sessValPtr->isPowerEfficient = enabled;
586 applyUclampLocked(sessionId, std::chrono::steady_clock::now());
587 }
588 }
589
590 template <class HintManagerT>
registerSession(std::shared_ptr<void> session,int64_t sessionId)591 void PowerSessionManager<HintManagerT>::registerSession(std::shared_ptr<void> session,
592 int64_t sessionId) {
593 std::lock_guard<std::mutex> lock(mSessionMapMutex);
594 mSessionMap[sessionId] = session;
595 }
596
597 template <class HintManagerT>
unregisterSession(int64_t sessionId)598 void PowerSessionManager<HintManagerT>::unregisterSession(int64_t sessionId) {
599 std::lock_guard<std::mutex> lock(mSessionMapMutex);
600 mSessionMap.erase(sessionId);
601 }
602
603 template <class HintManagerT>
getSession(int64_t sessionId)604 std::shared_ptr<void> PowerSessionManager<HintManagerT>::getSession(int64_t sessionId) {
605 std::scoped_lock lock(mSessionMapMutex);
606 auto ptr = mSessionMap.find(sessionId);
607 if (ptr == mSessionMap.end()) {
608 return nullptr;
609 }
610 std::shared_ptr<void> out = ptr->second.lock();
611 if (!out) {
612 mSessionMap.erase(sessionId);
613 return nullptr;
614 }
615 return out;
616 }
617
618 template <class HintManagerT>
clear()619 void PowerSessionManager<HintManagerT>::clear() {
620 std::scoped_lock lock(mSessionMapMutex);
621 mSessionMap.clear();
622 }
623
624 template <class HintManagerT>
updateFrameBuckets(int64_t sessionId,const FrameBuckets & lastReportedFrames)625 void PowerSessionManager<HintManagerT>::updateFrameBuckets(int64_t sessionId,
626 const FrameBuckets &lastReportedFrames) {
627 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
628 auto sessValPtr = mSessionTaskMap.findSession(sessionId);
629 if (nullptr == sessValPtr) {
630 return;
631 }
632
633 sessValPtr->sessFrameBuckets.addUpNewFrames(lastReportedFrames);
634 }
635
636 template <class HintManagerT>
updateHboostStatistics(int64_t sessionId,SessionJankyLevel jankyLevel,int32_t numOfFrames)637 void PowerSessionManager<HintManagerT>::updateHboostStatistics(int64_t sessionId,
638 SessionJankyLevel jankyLevel,
639 int32_t numOfFrames) {
640 std::lock_guard<std::mutex> lock(mSessionTaskMapMutex);
641 auto sessValPtr = mSessionTaskMap.findSession(sessionId);
642 if (nullptr == sessValPtr) {
643 return;
644 }
645 switch (jankyLevel) {
646 case SessionJankyLevel::LIGHT:
647 sessValPtr->hBoostModeDist.lightModeFrames += numOfFrames;
648 break;
649 case SessionJankyLevel::MODERATE:
650 sessValPtr->hBoostModeDist.moderateModeFrames += numOfFrames;
651 break;
652 case SessionJankyLevel::SEVERE:
653 sessValPtr->hBoostModeDist.severeModeFrames += numOfFrames;
654 break;
655 default:
656 ALOGW("Unknown janky level during updateHboostStatistics");
657 }
658 }
659
660 template class PowerSessionManager<>;
661 template class PowerSessionManager<testing::NiceMock<mock::pixel::MockHintManager>>;
662
663 } // namespace pixel
664 } // namespace impl
665 } // namespace power
666 } // namespace hardware
667 } // namespace google
668 } // namespace aidl
669