1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "socperf_handler.h"
16 #include <cstdio> // for FILE
17 #include <cstdint> // for int32_t
18 #include <climits> // for PATH_MAX
19 #include <list> // for list, __list_iterator, operator!=
20 #include <new> // for operator delete, operator new
21 #include <cstdlib> // for realpath
22 #include <string> // for basic_string, to_string
23 #include <unordered_map> // for unordered_map, operator==, operator!=
24 #include <utility> // for pair
25 #include <vector> // for vector
26 #include <unistd.h> // for open, write
27 #include <fcntl.h> // for O_RDWR, O_CLOEXEC
28 #include "socperf_common.h" // for ResStatus, ResAction, ResNode, INVALID_V...
29
30 namespace OHOS {
31 namespace SOCPERF {
SocPerfHandler(const std::shared_ptr<AppExecFwk::EventRunner> & runner)32 SocPerfHandler::SocPerfHandler(
33 const std::shared_ptr<AppExecFwk::EventRunner>& runner) : AppExecFwk::EventHandler(runner)
34 {
35 }
36
~SocPerfHandler()37 SocPerfHandler::~SocPerfHandler()
38 {
39 }
40
ProcessEvent(const AppExecFwk::InnerEvent::Pointer & event)41 void SocPerfHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
42 {
43 if (event == nullptr) {
44 return;
45 }
46 switch (event->GetInnerEventId()) {
47 case INNER_EVENT_ID_INIT_RES_NODE_INFO: {
48 auto resNode = event->GetSharedObject<ResNode>();
49 if (resNode != nullptr) {
50 resNodeInfo.insert(std::pair<int32_t, std::shared_ptr<ResNode>>(resNode->id, resNode));
51 WriteNode(resNode->path, std::to_string(resNode->def));
52 auto resStatus = std::make_shared<ResStatus>(resNode->def);
53 resStatusInfo.insert(std::pair<int32_t, std::shared_ptr<ResStatus>>(resNode->id, resStatus));
54 }
55 break;
56 }
57 case INNER_EVENT_ID_INIT_GOV_RES_NODE_INFO: {
58 auto govResNode = event->GetSharedObject<GovResNode>();
59 if (govResNode != nullptr) {
60 govResNodeInfo.insert(std::pair<int32_t, std::shared_ptr<GovResNode>>(govResNode->id, govResNode));
61 for (int32_t i = 0; i < (int32_t)govResNode->paths.size(); i++) {
62 WriteNode(govResNode->paths[i], govResNode->levelToStr[govResNode->def][i]);
63 }
64 auto resStatus = std::make_shared<ResStatus>(govResNode->def);
65 resStatusInfo.insert(std::pair<int32_t, std::shared_ptr<ResStatus>>(govResNode->id, resStatus));
66 }
67 break;
68 }
69 case INNER_EVENT_ID_DO_FREQ_ACTION: {
70 int32_t resId = event->GetParam();
71 if (!IsValidResId(resId)) {
72 return;
73 }
74 std::shared_ptr<ResAction> resAction = event->GetSharedObject<ResAction>();
75 if (resAction != nullptr) {
76 UpdateResActionList(resId, resAction, false);
77 }
78 break;
79 }
80 case INNER_EVENT_ID_DO_FREQ_ACTION_DELAYED: {
81 int32_t resId = event->GetParam();
82 if (!IsValidResId(resId)) {
83 return;
84 }
85 std::shared_ptr<ResAction> resAction = event->GetSharedObject<ResAction>();
86 if (resAction != nullptr) {
87 UpdateResActionList(resId, resAction, true);
88 }
89 break;
90 }
91 case INNER_EVENT_ID_POWER_LIMIT_BOOST_FREQ: {
92 powerLimitBoost = event->GetParam() == 1;
93 for (auto iter = resStatusInfo.begin(); iter != resStatusInfo.end(); ++iter) {
94 ArbitrateCandidate(iter->first);
95 }
96 break;
97 }
98 case INNER_EVENT_ID_THERMAL_LIMIT_BOOST_FREQ: {
99 thermalLimitBoost = event->GetParam() == 1;
100 for (auto iter = resStatusInfo.begin(); iter != resStatusInfo.end(); ++iter) {
101 ArbitrateCandidate(iter->first);
102 }
103 break;
104 }
105 default: {
106 break;
107 }
108 }
109 }
110
UpdateResActionList(int32_t resId,std::shared_ptr<ResAction> resAction,bool delayed)111 void SocPerfHandler::UpdateResActionList(int32_t resId, std::shared_ptr<ResAction> resAction, bool delayed)
112 {
113 std::shared_ptr<ResStatus> resStatus = resStatusInfo[resId];
114 int32_t type = resAction->type;
115
116 if (delayed) {
117 for (auto iter = resStatus->resActionList[type].begin();
118 iter != resStatus->resActionList[type].end(); ++iter) {
119 if (resAction == *iter) {
120 resStatus->resActionList[type].erase(iter);
121 UpdateCandidatesValue(resId, type);
122 break;
123 }
124 }
125 } else {
126 switch (resAction->onOff) {
127 case EVENT_INVALID: {
128 resStatus->resActionList[type].push_back(resAction);
129 UpdateCandidatesValue(resId, type);
130 auto event = AppExecFwk::InnerEvent::Get(
131 INNER_EVENT_ID_DO_FREQ_ACTION_DELAYED, resAction, resId);
132 this->SendEvent(event, resAction->duration);
133 break;
134 }
135 case EVENT_ON: {
136 if (resAction->duration == 0) {
137 for (auto iter = resStatus->resActionList[type].begin();
138 iter != resStatus->resActionList[type].end(); ++iter) {
139 if (resAction->TotalSame(*iter)) {
140 resStatus->resActionList[type].erase(iter);
141 break;
142 }
143 }
144 resStatus->resActionList[type].push_back(resAction);
145 UpdateCandidatesValue(resId, type);
146 } else {
147 resStatus->resActionList[type].push_back(resAction);
148 UpdateCandidatesValue(resId, type);
149 auto event = AppExecFwk::InnerEvent::Get(
150 INNER_EVENT_ID_DO_FREQ_ACTION_DELAYED, resAction, resId);
151 this->SendEvent(event, resAction->duration);
152 }
153 break;
154 }
155 case EVENT_OFF: {
156 for (auto iter = resStatus->resActionList[type].begin();
157 iter != resStatus->resActionList[type].end(); ++iter) {
158 if (resAction->PartSame(*iter) && (*iter)->onOff == EVENT_ON) {
159 resStatus->resActionList[type].erase(iter);
160 UpdateCandidatesValue(resId, type);
161 break;
162 }
163 }
164 break;
165 }
166 default: {
167 break;
168 }
169 }
170 }
171 }
172
UpdateCandidatesValue(int32_t resId,int32_t type)173 void SocPerfHandler::UpdateCandidatesValue(int32_t resId, int32_t type)
174 {
175 std::shared_ptr<ResStatus> resStatus = resStatusInfo[resId];
176 int64_t prev = resStatus->candidates[type];
177
178 if (resStatus->resActionList[type].empty()) {
179 resStatus->candidates[type] = INVALID_VALUE;
180 } else {
181 if (type == ACTION_TYPE_PERF) {
182 int64_t res = MIN_INT_VALUE;
183 for (auto iter = resStatus->resActionList[type].begin();
184 iter != resStatus->resActionList[type].end(); ++iter) {
185 res = Max(res, (*iter)->value);
186 }
187 resStatus->candidates[type] = res;
188 } else {
189 int64_t res = MAX_INT_VALUE;
190 for (auto iter = resStatus->resActionList[type].begin();
191 iter != resStatus->resActionList[type].end(); ++iter) {
192 res = Min(res, (*iter)->value);
193 }
194 resStatus->candidates[type] = res;
195 }
196 }
197
198 if (resStatus->candidates[type] != prev) {
199 ArbitrateCandidate(resId);
200 }
201 }
202
ArbitrateCandidate(int32_t resId)203 void SocPerfHandler::ArbitrateCandidate(int32_t resId)
204 {
205 std::shared_ptr<ResStatus> resStatus = resStatusInfo[resId];
206 int64_t candidatePerf = resStatus->candidates[ACTION_TYPE_PERF];
207 int64_t candidatePower = resStatus->candidates[ACTION_TYPE_POWER];
208 int64_t candidateThermal = resStatus->candidates[ACTION_TYPE_THERMAL];
209
210 if (ExistNoCandidate(resId, resStatus, candidatePerf, candidatePower, candidateThermal)) {
211 return;
212 }
213
214 if (!powerLimitBoost && !thermalLimitBoost) {
215 if (candidatePerf != INVALID_VALUE) {
216 resStatus->candidate = Max(candidatePerf, candidatePower, candidateThermal);
217 } else {
218 resStatus->candidate =
219 (candidatePower == INVALID_VALUE) ? candidateThermal :
220 ((candidateThermal == INVALID_VALUE) ? candidatePower : Min(candidatePower, candidateThermal));
221 }
222 } else if (!powerLimitBoost && thermalLimitBoost) {
223 resStatus->candidate =
224 (candidateThermal != INVALID_VALUE) ? candidateThermal : Max(candidatePerf, candidatePower);
225 } else if (powerLimitBoost && !thermalLimitBoost) {
226 resStatus->candidate =
227 (candidatePower != INVALID_VALUE) ? candidatePower : Max(candidatePerf, candidateThermal);
228 } else {
229 if (candidatePower == INVALID_VALUE && candidateThermal == INVALID_VALUE) {
230 resStatus->candidate = candidatePerf;
231 } else {
232 resStatus->candidate =
233 (candidatePower == INVALID_VALUE) ? candidateThermal :
234 ((candidateThermal == INVALID_VALUE) ? candidatePower : Min(candidatePower, candidateThermal));
235 }
236 }
237
238 ArbitratePairRes(resId);
239 }
240
ArbitratePairRes(int32_t resId)241 void SocPerfHandler::ArbitratePairRes(int32_t resId)
242 {
243 if (IsGovResId(resId)) {
244 UpdateCurrentValue(resId, resStatusInfo[resId]->candidate);
245 return;
246 }
247
248 int32_t pairResId = resNodeInfo[resId]->pair;
249 if (pairResId == INVALID_VALUE) {
250 UpdateCurrentValue(resId, resStatusInfo[resId]->candidate);
251 return;
252 }
253
254 if (resNodeInfo[resId]->mode == 1) {
255 if (resStatusInfo[resId]->candidate < resStatusInfo[pairResId]->candidate) {
256 if (powerLimitBoost || thermalLimitBoost) {
257 UpdatePairResValue(pairResId,
258 resStatusInfo[resId]->candidate, resId, resStatusInfo[resId]->candidate);
259 } else {
260 UpdatePairResValue(pairResId,
261 resStatusInfo[pairResId]->candidate, resId, resStatusInfo[pairResId]->candidate);
262 }
263 } else {
264 UpdatePairResValue(pairResId,
265 resStatusInfo[pairResId]->candidate, resId, resStatusInfo[resId]->candidate);
266 }
267 } else {
268 if (resStatusInfo[resId]->candidate > resStatusInfo[pairResId]->candidate) {
269 if (powerLimitBoost || thermalLimitBoost) {
270 UpdatePairResValue(resId,
271 resStatusInfo[pairResId]->candidate, pairResId, resStatusInfo[pairResId]->candidate);
272 } else {
273 UpdatePairResValue(resId,
274 resStatusInfo[resId]->candidate, pairResId, resStatusInfo[resId]->candidate);
275 }
276 } else {
277 UpdatePairResValue(resId,
278 resStatusInfo[resId]->candidate, pairResId, resStatusInfo[pairResId]->candidate);
279 }
280 }
281 }
282
UpdatePairResValue(int32_t minResId,int64_t minResValue,int32_t maxResId,int64_t maxResValue)283 void SocPerfHandler::UpdatePairResValue(int32_t minResId, int64_t minResValue, int32_t maxResId, int64_t maxResValue)
284 {
285 WriteNode(resNodeInfo[minResId]->path, std::to_string(resNodeInfo[minResId]->def));
286 WriteNode(resNodeInfo[maxResId]->path, std::to_string(resNodeInfo[maxResId]->def));
287 UpdateCurrentValue(minResId, minResValue);
288 UpdateCurrentValue(maxResId, maxResValue);
289 }
290
UpdateCurrentValue(int32_t resId,int64_t currValue)291 void SocPerfHandler::UpdateCurrentValue(int32_t resId, int64_t currValue)
292 {
293 resStatusInfo[resId]->current = currValue;
294 if (IsGovResId(resId)) {
295 if (govResNodeInfo[resId]->levelToStr.find(currValue) != govResNodeInfo[resId]->levelToStr.end()) {
296 std::vector<std::string> targetStrs = govResNodeInfo[resId]->levelToStr[resStatusInfo[resId]->current];
297 for (int32_t i = 0; i < (int32_t)govResNodeInfo[resId]->paths.size(); i++) {
298 WriteNode(govResNodeInfo[resId]->paths[i], targetStrs[i]);
299 }
300 }
301 } else if (IsResId(resId)) {
302 WriteNode(resNodeInfo[resId]->path, std::to_string(resStatusInfo[resId]->current));
303 }
304 }
305
WriteNode(std::string filePath,std::string value)306 void SocPerfHandler::WriteNode(std::string filePath, std::string value)
307 {
308 int32_t fd = GetFdForFilePath(filePath);
309 if (fd < 0) {
310 return;
311 }
312 write(fd, value.c_str(), value.size());
313 }
314
GetFdForFilePath(std::string filePath)315 int32_t SocPerfHandler::GetFdForFilePath(std::string filePath)
316 {
317 if (fdInfo.find(filePath) != fdInfo.end()) {
318 return fdInfo[filePath];
319 }
320 char path[PATH_MAX + 1] = {0};
321 if (filePath.size() == 0 || filePath.size() > PATH_MAX || !realpath(filePath.c_str(), path)) {
322 return -1;
323 }
324 int32_t fd = open(path, O_RDWR | O_CLOEXEC);
325 if (fd < 0) {
326 return fd;
327 }
328 fdInfo.insert(std::pair<std::string, int32_t>(filePath, fd));
329 return fdInfo[filePath];
330 }
331
ExistNoCandidate(int32_t resId,std::shared_ptr<ResStatus> resStatus,int64_t perf,int64_t power,int64_t thermal)332 bool SocPerfHandler::ExistNoCandidate(
333 int32_t resId, std::shared_ptr<ResStatus> resStatus, int64_t perf, int64_t power, int64_t thermal)
334 {
335 if (perf == INVALID_VALUE && power == INVALID_VALUE && thermal == INVALID_VALUE) {
336 if (IsGovResId(resId)) {
337 resStatus->candidate = govResNodeInfo[resId]->def;
338 } else if (IsResId(resId)) {
339 resStatus->candidate = resNodeInfo[resId]->def;
340 }
341 ArbitratePairRes(resId);
342 return true;
343 }
344 return false;
345 }
346
IsGovResId(int32_t resId)347 bool SocPerfHandler::IsGovResId(int32_t resId)
348 {
349 if (resNodeInfo.find(resId) == resNodeInfo.end()
350 && govResNodeInfo.find(resId) != govResNodeInfo.end()) {
351 return true;
352 }
353 return false;
354 }
355
IsResId(int32_t resId)356 bool SocPerfHandler::IsResId(int32_t resId)
357 {
358 if (govResNodeInfo.find(resId) == govResNodeInfo.end()
359 && resNodeInfo.find(resId) != resNodeInfo.end()) {
360 return true;
361 }
362 return false;
363 }
364
IsValidResId(int32_t resId)365 bool SocPerfHandler::IsValidResId(int32_t resId)
366 {
367 if (resNodeInfo.find(resId) == resNodeInfo.end()
368 && govResNodeInfo.find(resId) == govResNodeInfo.end()) {
369 return false;
370 }
371 if (resStatusInfo.find(resId) == resStatusInfo.end()) {
372 return false;
373 }
374 return true;
375 }
376 } // namespace SOCPERF
377 } // namespace OHOS
378