• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 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 #include "SessionTaskMap.h"
18 
19 #include <algorithm>
20 #include <sstream>
21 
22 namespace aidl {
23 namespace google {
24 namespace hardware {
25 namespace power {
26 namespace impl {
27 namespace pixel {
28 
add(int64_t sessionId,const SessionValueEntry & sv,const std::vector<pid_t> & taskIds)29 bool SessionTaskMap::add(int64_t sessionId, const SessionValueEntry &sv,
30                          const std::vector<pid_t> &taskIds) {
31     if (mSessions.find(sessionId) != mSessions.end()) {
32         return false;
33     }
34 
35     auto sessValPtr = std::make_shared<SessionValueEntry>();
36     (*sessValPtr) = sv;
37     sessValPtr->sessionId = sessionId;
38 
39     auto &sessEntry = mSessions[sessionId];
40     sessEntry.val = sessValPtr;
41     sessEntry.linkedTasks = taskIds;
42 
43     for (auto taskId : taskIds) {
44         mTasks[taskId].push_back(sessValPtr);
45     }
46     return true;
47 }
48 
addVote(int64_t sessionId,int voteId,int uclampMin,int uclampMax,std::chrono::steady_clock::time_point startTime,std::chrono::nanoseconds durationNs)49 void SessionTaskMap::addVote(int64_t sessionId, int voteId, int uclampMin, int uclampMax,
50                              std::chrono::steady_clock::time_point startTime,
51                              std::chrono::nanoseconds durationNs) {
52     auto sessItr = mSessions.find(sessionId);
53     if (sessItr == mSessions.end()) {
54         return;
55     }
56 
57     sessItr->second.val->votes->add(voteId,
58                                     CpuVote(true, startTime, durationNs, uclampMin, uclampMax));
59 }
60 
addGpuVote(int64_t sessionId,int voteId,Cycles capacity,std::chrono::steady_clock::time_point startTime,std::chrono::nanoseconds durationNs)61 void SessionTaskMap::addGpuVote(int64_t sessionId, int voteId, Cycles capacity,
62                                 std::chrono::steady_clock::time_point startTime,
63                                 std::chrono::nanoseconds durationNs) {
64     auto sessItr = mSessions.find(sessionId);
65     if (sessItr == mSessions.end()) {
66         return;
67     }
68 
69     sessItr->second.val->votes->add(voteId, GpuVote(true, startTime, durationNs, capacity));
70 }
71 
findSession(int64_t sessionId) const72 std::shared_ptr<SessionValueEntry> SessionTaskMap::findSession(int64_t sessionId) const {
73     auto sessItr = mSessions.find(sessionId);
74     if (sessItr == mSessions.end()) {
75         return nullptr;
76     }
77     return sessItr->second.val;
78 }
79 
getTaskVoteRange(pid_t taskId,std::chrono::steady_clock::time_point timeNow,UclampRange & range,std::optional<int32_t> & uclampMaxEfficientBase,std::optional<int32_t> & uclampMaxEfficientOffset) const80 void SessionTaskMap::getTaskVoteRange(pid_t taskId, std::chrono::steady_clock::time_point timeNow,
81                                       UclampRange &range,
82                                       std::optional<int32_t> &uclampMaxEfficientBase,
83                                       std::optional<int32_t> &uclampMaxEfficientOffset) const {
84     auto taskItr = mTasks.find(taskId);
85     if (taskItr == mTasks.end()) {
86         // Assign to default range
87         range = {};
88         return;
89     }
90 
91     for (const auto &sessInTask : taskItr->second) {
92         if (!sessInTask->isActive) {
93             continue;
94         }
95         sessInTask->votes->getUclampRange(range, timeNow);
96         if (sessInTask->isPowerEfficient && uclampMaxEfficientBase.has_value()) {
97             range.uclampMax = std::min(range.uclampMax,
98                                        sessInTask->votes->allTimedOut(timeNow)
99                                                ? *uclampMaxEfficientBase
100                                                : range.uclampMin + *uclampMaxEfficientOffset);
101         }
102     }
103 }
104 
getSessionsGpuCapacity(std::chrono::steady_clock::time_point time_point) const105 Cycles SessionTaskMap::getSessionsGpuCapacity(
106         std::chrono::steady_clock::time_point time_point) const {
107     Cycles max(0);
108     for (auto const &[_, session] : mSessions) {
109         max = std::max(max,
110                        session.val->votes->getGpuCapacityRequest(time_point).value_or(Cycles(0)));
111     }
112     return max;
113 }
114 
getSessionIds(pid_t taskId) const115 std::vector<int64_t> SessionTaskMap::getSessionIds(pid_t taskId) const {
116     auto itr = mTasks.find(taskId);
117     if (itr == mTasks.end()) {
118         static const std::vector<int64_t> emptySessionIdVec;
119         return emptySessionIdVec;
120     }
121     std::vector<int64_t> res;
122     res.reserve(itr->second.size());
123     for (const auto &i : itr->second) {
124         res.push_back(i->sessionId);
125     }
126     return res;
127 }
128 
getTaskIds(int64_t sessionId)129 std::vector<pid_t> &SessionTaskMap::getTaskIds(int64_t sessionId) {
130     auto taskItr = mSessions.find(sessionId);
131     if (taskItr == mSessions.end()) {
132         static std::vector<pid_t> emptyTaskIdVec;
133         return emptyTaskIdVec;
134     }
135     return taskItr->second.linkedTasks;
136 }
137 
isAnyAppSessionActive(std::chrono::steady_clock::time_point timePoint) const138 bool SessionTaskMap::isAnyAppSessionActive(std::chrono::steady_clock::time_point timePoint) const {
139     for (auto &sessionVal : mSessions) {
140         if (!sessionVal.second.val->isAppSession) {
141             continue;
142         }
143         if (!sessionVal.second.val->isActive) {
144             continue;
145         }
146         if (!sessionVal.second.val->votes->allTimedOut(timePoint)) {
147             return true;
148         }
149     }
150     return false;
151 }
152 
remove(int64_t sessionId)153 bool SessionTaskMap::remove(int64_t sessionId) {
154     auto sessItr = mSessions.find(sessionId);
155     if (sessItr == mSessions.end()) {
156         return false;
157     }
158 
159     // For each task id in linked tasks need to remove the corresponding
160     // task to session mapping in the task map
161     for (const auto taskId : sessItr->second.linkedTasks) {
162         // Used linked task ids to cleanup
163         auto taskItr = mTasks.find(taskId);
164         if (taskItr == mTasks.end()) {
165             // Inconsisent state
166             continue;
167         }
168 
169         // Now lookup session id in task's set
170         auto taskSessItr =
171                 std::find(taskItr->second.begin(), taskItr->second.end(), sessItr->second.val);
172         if (taskSessItr == taskItr->second.end()) {
173             // Should not happen
174             continue;
175         }
176 
177         // Remove session id from task map
178         taskItr->second.erase(taskSessItr);
179         if (taskItr->second.empty()) {
180             mTasks.erase(taskItr);
181         }
182     }
183 
184     // Now we can safely remove session entirely since there are no more
185     // mappings in task to session id
186     mSessions.erase(sessItr);
187     return true;
188 }
189 
removeDeadTaskSessionMap(int64_t sessionId,pid_t taskId)190 bool SessionTaskMap::removeDeadTaskSessionMap(int64_t sessionId, pid_t taskId) {
191     auto sessItr = mSessions.find(sessionId);
192     if (sessItr == mSessions.end()) {
193         return false;
194     }
195 
196     auto taskItr = mTasks.find(taskId);
197     if (taskItr == mTasks.end()) {
198         // Inconsisent state
199         return false;
200     }
201 
202     // Now lookup session id in task's set
203     auto taskSessItr =
204             std::find(taskItr->second.begin(), taskItr->second.end(), sessItr->second.val);
205     if (taskSessItr == taskItr->second.end()) {
206         // Should not happen
207         return false;
208     }
209 
210     // Remove session id from task map
211     taskItr->second.erase(taskSessItr);
212     if (taskItr->second.empty()) {
213         mTasks.erase(taskItr);
214     }
215 
216     return true;
217 }
218 
replace(int64_t sessionId,const std::vector<pid_t> & taskIds,std::vector<pid_t> * addedThreads,std::vector<pid_t> * removedThreads)219 bool SessionTaskMap::replace(int64_t sessionId, const std::vector<pid_t> &taskIds,
220                              std::vector<pid_t> *addedThreads, std::vector<pid_t> *removedThreads) {
221     auto itr = mSessions.find(sessionId);
222     if (itr == mSessions.end()) {
223         return false;
224     }
225 
226     // Make copies of val and threads
227     auto svTmp = itr->second.val;
228     const auto previousTaskIds = itr->second.linkedTasks;
229 
230     // Determine newly added threads
231     if (addedThreads) {
232         for (auto tid : taskIds) {
233             auto taskSessItr = mTasks.find(tid);
234             if (taskSessItr == mTasks.end()) {
235                 addedThreads->push_back(tid);
236             }
237         }
238     }
239 
240     // Remove session from mappings
241     remove(sessionId);
242     // Add session value and task mappings
243     add(sessionId, *svTmp, taskIds);
244 
245     // Determine completely removed threads
246     if (removedThreads) {
247         for (auto tid : previousTaskIds) {
248             auto taskSessItr = mTasks.find(tid);
249             if (taskSessItr == mTasks.end()) {
250                 removedThreads->push_back(tid);
251             }
252         }
253     }
254 
255     return true;
256 }
257 
sizeSessions() const258 size_t SessionTaskMap::sizeSessions() const {
259     return mSessions.size();
260 }
261 
sizeTasks() const262 size_t SessionTaskMap::sizeTasks() const {
263     return mTasks.size();
264 }
265 
idString(int64_t sessionId) const266 const std::string &SessionTaskMap::idString(int64_t sessionId) const {
267     auto sessItr = mSessions.find(sessionId);
268     if (sessItr == mSessions.end()) {
269         static const std::string emptyString;
270         return emptyString;
271     }
272     return sessItr->second.val->idString;
273 }
274 
isAppSession(int64_t sessionId) const275 bool SessionTaskMap::isAppSession(int64_t sessionId) const {
276     auto sessItr = mSessions.find(sessionId);
277     if (sessItr == mSessions.end()) {
278         return false;
279     }
280 
281     return sessItr->second.val->isAppSession;
282 }
283 
284 }  // namespace pixel
285 }  // namespace impl
286 }  // namespace power
287 }  // namespace hardware
288 }  // namespace google
289 }  // namespace aidl
290