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