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 ALOGW("sched_setattr failed for thread %d, err=%d", tid, errno);
76 }
77 }
78 } // namespace
79
updateHintMode(const std::string & mode,bool enabled)80 void PowerSessionManager::updateHintMode(const std::string &mode, bool enabled) {
81 ALOGV("PowerSessionManager::updateHintMode: mode: %s, enabled: %d", mode.c_str(), enabled);
82 if (enabled && mode.compare(0, 8, "REFRESH_") == 0) {
83 if (mode.compare("REFRESH_120FPS") == 0) {
84 mDisplayRefreshRate = 120;
85 } else if (mode.compare("REFRESH_90FPS") == 0) {
86 mDisplayRefreshRate = 90;
87 } else if (mode.compare("REFRESH_60FPS") == 0) {
88 mDisplayRefreshRate = 60;
89 }
90 }
91 if (HintManager::GetInstance()->GetAdpfProfile()) {
92 HintManager::GetInstance()->SetAdpfProfile(mode);
93 }
94 }
95
updateHintBoost(const std::string & boost,int32_t durationMs)96 void PowerSessionManager::updateHintBoost(const std::string &boost, int32_t durationMs) {
97 ATRACE_CALL();
98 ALOGV("PowerSessionManager::updateHintBoost: boost: %s, durationMs: %d", boost.c_str(),
99 durationMs);
100 if (boost.compare("DISPLAY_UPDATE_IMMINENT") == 0) {
101 PowerHintMonitor::getInstance()->getLooper()->sendMessage(mWakeupHandler, NULL);
102 }
103 }
104
wakeSessions()105 void PowerSessionManager::wakeSessions() {
106 std::lock_guard<std::mutex> guard(mLock);
107 std::shared_ptr<AdpfConfig> adpfConfig = HintManager::GetInstance()->GetAdpfProfile();
108 std::unordered_set<PowerHintSession *> wakeupList;
109 const int wakeupBoostValue = static_cast<int>(adpfConfig->mUclampMinInit);
110 for (auto &it : mTidSessionListMap) {
111 int tid = it.first;
112 int maxboost = -1;
113 // Find the max boost value among all the sessions that include the same TID.
114 for (PowerHintSession *s : it.second) {
115 if (!s->isActive())
116 continue;
117 // all active sessions need to be awakened.
118 wakeupList.insert(s);
119 if (s->isTimeout()) {
120 maxboost = std::max(maxboost, s->getUclampMin());
121 }
122 }
123 // Found the max boost and actally set to the task.
124 if (maxboost != -1) {
125 set_uclamp_min(tid, std::max(maxboost, wakeupBoostValue));
126 }
127 }
128 for (PowerHintSession *s : wakeupList) {
129 s->wakeup();
130 }
131 }
132
getDisplayRefreshRate()133 int PowerSessionManager::getDisplayRefreshRate() {
134 return mDisplayRefreshRate;
135 }
136
addPowerSession(PowerHintSession * session)137 void PowerSessionManager::addPowerSession(PowerHintSession *session) {
138 std::lock_guard<std::mutex> guard(mLock);
139 for (auto t : session->getTidList()) {
140 mTidSessionListMap[t].insert(session);
141 if (mTidRefCountMap.find(t) == mTidRefCountMap.end()) {
142 if (!SetTaskProfiles(t, {"ResetUclampGrp"})) {
143 ALOGW("Failed to set ResetUclampGrp task profile for tid:%d", t);
144 } else {
145 mTidRefCountMap[t] = 1;
146 }
147 continue;
148 }
149 if (mTidRefCountMap[t] <= 0) {
150 ALOGE("Error! Unexpected zero/negative RefCount:%d for tid:%d", mTidRefCountMap[t], t);
151 continue;
152 }
153 mTidRefCountMap[t]++;
154 }
155 mSessions.insert(session);
156 }
157
removePowerSession(PowerHintSession * session)158 void PowerSessionManager::removePowerSession(PowerHintSession *session) {
159 std::lock_guard<std::mutex> guard(mLock);
160 for (auto t : session->getTidList()) {
161 if (mTidRefCountMap.find(t) == mTidRefCountMap.end()) {
162 ALOGE("Unexpected Error! Failed to look up tid:%d in TidRefCountMap", t);
163 continue;
164 }
165 mTidSessionListMap[t].erase(session);
166 mTidRefCountMap[t]--;
167 if (mTidRefCountMap[t] <= 0) {
168 if (!SetTaskProfiles(t, {"NoResetUclampGrp"})) {
169 ALOGW("Failed to set NoResetUclampGrp task profile for tid:%d", t);
170 }
171 mTidRefCountMap.erase(t);
172 }
173 }
174 mSessions.erase(session);
175 }
176
setUclampMin(PowerHintSession * session,int val)177 void PowerSessionManager::setUclampMin(PowerHintSession *session, int val) {
178 std::lock_guard<std::mutex> guard(mLock);
179 setUclampMinLocked(session, val);
180 }
181
setUclampMinLocked(PowerHintSession * session,int val)182 void PowerSessionManager::setUclampMinLocked(PowerHintSession *session, int val) {
183 for (auto t : session->getTidList()) {
184 // Get thex max uclamp.min across sessions which include the tid.
185 int tidMax = 0;
186 for (PowerHintSession *s : mTidSessionListMap[t]) {
187 if (!s->isActive() || s->isTimeout())
188 continue;
189 tidMax = std::max(tidMax, s->getUclampMin());
190 }
191 set_uclamp_min(t, std::max(val, tidMax));
192 }
193 }
194
isAnyAppSessionActive()195 std::optional<bool> PowerSessionManager::isAnyAppSessionActive() {
196 std::lock_guard<std::mutex> guard(mLock);
197 bool active = false;
198 for (PowerHintSession *s : mSessions) {
199 // session active and not stale is actually active.
200 if (s->isActive() && !s->isTimeout() && s->isAppSession()) {
201 active = true;
202 break;
203 }
204 }
205 if (active == mActive) {
206 return std::nullopt;
207 } else {
208 mActive = active;
209 }
210
211 return active;
212 }
213
handleMessage(const Message &)214 void PowerSessionManager::handleMessage(const Message &) {
215 auto active = isAnyAppSessionActive();
216 if (!active.has_value()) {
217 return;
218 }
219 if (active.value()) {
220 disableSystemTopAppBoost();
221 } else {
222 enableSystemTopAppBoost();
223 }
224 }
225
handleMessage(const Message &)226 void PowerSessionManager::WakeupHandler::handleMessage(const Message &) {
227 PowerSessionManager::getInstance()->wakeSessions();
228 }
229
dumpToFd(int fd)230 void PowerSessionManager::dumpToFd(int fd) {
231 std::ostringstream dump_buf;
232 std::lock_guard<std::mutex> guard(mLock);
233 dump_buf << "========== Begin PowerSessionManager ADPF list ==========\n";
234 for (PowerHintSession *s : mSessions) {
235 s->dumpToStream(dump_buf);
236 dump_buf << " Tid:Ref[";
237 for (size_t i = 0, len = s->getTidList().size(); i < len; i++) {
238 int t = s->getTidList()[i];
239 dump_buf << t << ":" << mTidSessionListMap[t].size();
240 if (i < len - 1) {
241 dump_buf << ", ";
242 }
243 }
244 dump_buf << "]\n";
245 }
246 dump_buf << "========== End PowerSessionManager ADPF list ==========\n";
247 if (!::android::base::WriteStringToFd(dump_buf.str(), fd)) {
248 ALOGE("Failed to dump one of session list to fd:%d", fd);
249 }
250 }
251
enableSystemTopAppBoost()252 void PowerSessionManager::enableSystemTopAppBoost() {
253 if (HintManager::GetInstance()->IsHintSupported(kDisableBoostHintName)) {
254 ALOGV("PowerSessionManager::enableSystemTopAppBoost!!");
255 HintManager::GetInstance()->EndHint(kDisableBoostHintName);
256 }
257 }
258
disableSystemTopAppBoost()259 void PowerSessionManager::disableSystemTopAppBoost() {
260 if (HintManager::GetInstance()->IsHintSupported(kDisableBoostHintName)) {
261 ALOGV("PowerSessionManager::disableSystemTopAppBoost!!");
262 HintManager::GetInstance()->DoHint(kDisableBoostHintName);
263 }
264 }
265
266 // =========== PowerHintMonitor implementation start from here ===========
start()267 void PowerHintMonitor::start() {
268 if (!isRunning()) {
269 run("PowerHintMonitor", ::android::PRIORITY_HIGHEST);
270 }
271 }
272
threadLoop()273 bool PowerHintMonitor::threadLoop() {
274 while (true) {
275 mLooper->pollOnce(-1);
276 }
277 return true;
278 }
279
getLooper()280 sp<Looper> PowerHintMonitor::getLooper() {
281 return mLooper;
282 }
283
284 } // namespace pixel
285 } // namespace impl
286 } // namespace power
287 } // namespace hardware
288 } // namespace google
289 } // namespace aidl
290