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 <processgroup/processgroup.h>
26 #include <sys/syscall.h>
27 #include <utils/Trace.h>
28
29 namespace aidl {
30 namespace google {
31 namespace hardware {
32 namespace power {
33 namespace impl {
34 namespace pixel {
35
36 using ::android::perfmgr::AdpfConfig;
37 using ::android::perfmgr::HintManager;
38
39 namespace {
40 /* there is no glibc or bionic wrapper */
41 struct sched_attr {
42 __u32 size;
43 __u32 sched_policy;
44 __u64 sched_flags;
45 __s32 sched_nice;
46 __u32 sched_priority;
47 __u64 sched_runtime;
48 __u64 sched_deadline;
49 __u64 sched_period;
50 __u32 sched_util_min;
51 __u32 sched_util_max;
52 };
53
sched_setattr(int pid,struct sched_attr * attr,unsigned int flags)54 static int sched_setattr(int pid, struct sched_attr *attr, unsigned int flags) {
55 if (!HintManager::GetInstance()->GetAdpfProfile()->mUclampMinOn) {
56 ALOGV("PowerSessionManager:%s: skip", __func__);
57 return 0;
58 }
59 return syscall(__NR_sched_setattr, pid, attr, flags);
60 }
61
set_uclamp_min(int tid,int min)62 static void set_uclamp_min(int tid, int min) {
63 static constexpr int32_t kMaxUclampValue = 1024;
64 min = std::max(0, min);
65 min = std::min(min, kMaxUclampValue);
66
67 sched_attr attr = {};
68 attr.size = sizeof(attr);
69
70 attr.sched_flags = (SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP_MIN);
71 attr.sched_util_min = min;
72
73 int ret = sched_setattr(tid, &attr, 0);
74 if (ret) {
75 if (errno == ESRCH) {
76 ALOGV("sched_setattr failed for thread %d, err=%d", tid, errno);
77 } else {
78 ALOGW("sched_setattr failed for thread %d, err=%d", tid, errno);
79 }
80 }
81 }
82 } // namespace
83
updateHintMode(const std::string & mode,bool enabled)84 void PowerSessionManager::updateHintMode(const std::string &mode, bool enabled) {
85 ALOGV("PowerSessionManager::updateHintMode: mode: %s, enabled: %d", mode.c_str(), enabled);
86 if (enabled && mode.compare(0, 8, "REFRESH_") == 0) {
87 if (mode.compare("REFRESH_120FPS") == 0) {
88 mDisplayRefreshRate = 120;
89 } else if (mode.compare("REFRESH_90FPS") == 0) {
90 mDisplayRefreshRate = 90;
91 } else if (mode.compare("REFRESH_60FPS") == 0) {
92 mDisplayRefreshRate = 60;
93 }
94 }
95 if (HintManager::GetInstance()->GetAdpfProfile()) {
96 HintManager::GetInstance()->SetAdpfProfile(mode);
97 }
98 }
99
updateHintBoost(const std::string & boost,int32_t durationMs)100 void PowerSessionManager::updateHintBoost(const std::string &boost, int32_t durationMs) {
101 ATRACE_CALL();
102 ALOGV("PowerSessionManager::updateHintBoost: boost: %s, durationMs: %d", boost.c_str(),
103 durationMs);
104 }
105
getDisplayRefreshRate()106 int PowerSessionManager::getDisplayRefreshRate() {
107 return mDisplayRefreshRate;
108 }
109
addPowerSession(PowerHintSession * session)110 void PowerSessionManager::addPowerSession(PowerHintSession *session) {
111 std::lock_guard<std::mutex> guard(mLock);
112 mSessions.insert(session);
113 addThreadsFromPowerSessionLocked(session);
114 }
115
removePowerSession(PowerHintSession * session)116 void PowerSessionManager::removePowerSession(PowerHintSession *session) {
117 std::lock_guard<std::mutex> guard(mLock);
118 mSessions.erase(session);
119 removeThreadsFromPowerSessionLocked(session);
120 }
121
addThreadsFromPowerSession(PowerHintSession * session)122 void PowerSessionManager::addThreadsFromPowerSession(PowerHintSession *session) {
123 std::lock_guard<std::mutex> guard(mLock);
124 addThreadsFromPowerSessionLocked(session);
125 }
126
addThreadsFromPowerSessionLocked(PowerHintSession * session)127 void PowerSessionManager::addThreadsFromPowerSessionLocked(PowerHintSession *session) {
128 for (auto t : session->getTidList()) {
129 if (mTidSessionListMap[t].empty()) {
130 if (!SetTaskProfiles(t, {"ResetUclampGrp"})) {
131 ALOGW("Failed to set ResetUclampGrp task profile for tid:%d", t);
132 }
133 }
134 mTidSessionListMap[t].insert(session);
135 }
136 }
137
removeThreadsFromPowerSession(PowerHintSession * session)138 void PowerSessionManager::removeThreadsFromPowerSession(PowerHintSession *session) {
139 std::lock_guard<std::mutex> guard(mLock);
140 removeThreadsFromPowerSessionLocked(session);
141 }
142
removeThreadsFromPowerSessionLocked(PowerHintSession * session)143 void PowerSessionManager::removeThreadsFromPowerSessionLocked(PowerHintSession *session) {
144 for (auto t : session->getTidList()) {
145 size_t cnt = mTidSessionListMap[t].erase(session);
146 if (cnt != 0 && mTidSessionListMap[t].empty()) {
147 if (!SetTaskProfiles(t, {"NoResetUclampGrp"})) {
148 ALOGW("Failed to set NoResetUclampGrp task profile for tid:%d", t);
149 }
150 }
151 }
152 }
153
setUclampMin(PowerHintSession * session,int val)154 void PowerSessionManager::setUclampMin(PowerHintSession *session, int val) {
155 std::lock_guard<std::mutex> guard(mLock);
156 setUclampMinLocked(session, val);
157 }
158
setUclampMinLocked(PowerHintSession * session,int val)159 void PowerSessionManager::setUclampMinLocked(PowerHintSession *session, int val) {
160 for (auto t : session->getTidList()) {
161 // Get thex max uclamp.min across sessions which include the tid.
162 int tidMax = 0;
163 for (PowerHintSession *s : mTidSessionListMap[t]) {
164 if (!s->isActive() || s->isTimeout())
165 continue;
166 tidMax = std::max(tidMax, s->getUclampMin());
167 }
168 set_uclamp_min(t, std::max(val, tidMax));
169 }
170 }
171
isAnyAppSessionActive()172 std::optional<bool> PowerSessionManager::isAnyAppSessionActive() {
173 std::lock_guard<std::mutex> guard(mLock);
174 bool active = false;
175 for (PowerHintSession *s : mSessions) {
176 // session active and not stale is actually active.
177 if (s->isActive() && !s->isTimeout() && s->isAppSession()) {
178 active = true;
179 break;
180 }
181 }
182 if (active == mActive) {
183 return std::nullopt;
184 } else {
185 mActive = active;
186 }
187
188 return active;
189 }
190
handleMessage(const Message &)191 void PowerSessionManager::handleMessage(const Message &) {
192 auto active = isAnyAppSessionActive();
193 if (!active.has_value()) {
194 return;
195 }
196 if (active.value()) {
197 disableSystemTopAppBoost();
198 } else {
199 enableSystemTopAppBoost();
200 }
201 }
202
dumpToFd(int fd)203 void PowerSessionManager::dumpToFd(int fd) {
204 std::ostringstream dump_buf;
205 std::lock_guard<std::mutex> guard(mLock);
206 dump_buf << "========== Begin PowerSessionManager ADPF list ==========\n";
207 for (PowerHintSession *s : mSessions) {
208 s->dumpToStream(dump_buf);
209 dump_buf << " Tid:Ref[";
210 for (size_t i = 0, len = s->getTidList().size(); i < len; i++) {
211 int t = s->getTidList()[i];
212 dump_buf << t << ":" << mTidSessionListMap[t].size();
213 if (i < len - 1) {
214 dump_buf << ", ";
215 }
216 }
217 dump_buf << "]\n";
218 }
219 dump_buf << "========== End PowerSessionManager ADPF list ==========\n";
220 if (!::android::base::WriteStringToFd(dump_buf.str(), fd)) {
221 ALOGE("Failed to dump one of session list to fd:%d", fd);
222 }
223 }
224
enableSystemTopAppBoost()225 void PowerSessionManager::enableSystemTopAppBoost() {
226 if (HintManager::GetInstance()->IsHintSupported(kDisableBoostHintName)) {
227 ALOGV("PowerSessionManager::enableSystemTopAppBoost!!");
228 HintManager::GetInstance()->EndHint(kDisableBoostHintName);
229 }
230 }
231
disableSystemTopAppBoost()232 void PowerSessionManager::disableSystemTopAppBoost() {
233 if (HintManager::GetInstance()->IsHintSupported(kDisableBoostHintName)) {
234 ALOGV("PowerSessionManager::disableSystemTopAppBoost!!");
235 HintManager::GetInstance()->DoHint(kDisableBoostHintName);
236 }
237 }
238
239 // =========== PowerHintMonitor implementation start from here ===========
start()240 void PowerHintMonitor::start() {
241 if (!isRunning()) {
242 run("PowerHintMonitor", ::android::PRIORITY_HIGHEST);
243 }
244 }
245
threadLoop()246 bool PowerHintMonitor::threadLoop() {
247 while (true) {
248 mLooper->pollOnce(-1);
249 }
250 return true;
251 }
252
getLooper()253 sp<Looper> PowerHintMonitor::getLooper() {
254 return mLooper;
255 }
256
257 } // namespace pixel
258 } // namespace impl
259 } // namespace power
260 } // namespace hardware
261 } // namespace google
262 } // namespace aidl
263