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