• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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