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