• 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 <set>               // for set
23 #include <string>            // for basic_string, to_string
24 #include <unordered_map>     // for unordered_map, operator==, operator!=
25 #include <utility>           // for pair
26 #include <vector>            // for vector
27 #include <unistd.h>          // for open, write
28 #include <fcntl.h>           // for O_RDWR, O_CLOEXEC
29 #include "socperf_common.h"  // for ResStatus, ResAction, ResNode, INVALID_V...
30 
31 namespace OHOS {
32 namespace SOCPERF {
SocPerfHandler(const std::shared_ptr<AppExecFwk::EventRunner> & runner)33 SocPerfHandler::SocPerfHandler(
34     const std::shared_ptr<AppExecFwk::EventRunner>& runner) : AppExecFwk::EventHandler(runner)
35 {
36 }
37 
~SocPerfHandler()38 SocPerfHandler::~SocPerfHandler()
39 {
40 }
41 
ProcessEvent(const AppExecFwk::InnerEvent::Pointer & event)42 void SocPerfHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
43 {
44     if (event == nullptr) {
45         return;
46     }
47     switch (event->GetInnerEventId()) {
48         case INNER_EVENT_ID_INIT_RES_NODE_INFO: {
49             auto resNode = event->GetSharedObject<ResNode>();
50             if (resNode != nullptr) {
51                 resNodeInfo.insert(std::pair<int32_t, std::shared_ptr<ResNode>>(resNode->id, resNode));
52                 WriteNode(resNode->path, std::to_string(resNode->def));
53                 auto resStatus = std::make_shared<ResStatus>(resNode->def);
54                 resStatusInfo.insert(std::pair<int32_t, std::shared_ptr<ResStatus>>(resNode->id, resStatus));
55             }
56             break;
57         }
58         case INNER_EVENT_ID_INIT_GOV_RES_NODE_INFO: {
59             auto govResNode = event->GetSharedObject<GovResNode>();
60             if (govResNode != nullptr) {
61                 govResNodeInfo.insert(std::pair<int32_t, std::shared_ptr<GovResNode>>(govResNode->id, govResNode));
62                 for (int32_t i = 0; i < (int32_t)govResNode->paths.size(); i++) {
63                     WriteNode(govResNode->paths[i], govResNode->levelToStr[govResNode->def][i]);
64                 }
65                 auto resStatus = std::make_shared<ResStatus>(govResNode->def);
66                 resStatusInfo.insert(std::pair<int32_t, std::shared_ptr<ResStatus>>(govResNode->id, resStatus));
67             }
68             break;
69         }
70         case INNER_EVENT_ID_DO_FREQ_ACTION: {
71             int32_t resId = event->GetParam();
72             if (!IsValidResId(resId)) {
73                 return;
74             }
75             std::shared_ptr<ResAction> resAction = event->GetSharedObject<ResAction>();
76             if (resAction != nullptr) {
77                 UpdateResActionList(resId, resAction, false);
78             }
79             break;
80         }
81         case INNER_EVENT_ID_DO_FREQ_ACTION_PACK: {
82             std::shared_ptr<ResActionItem> head = event->GetSharedObject<ResActionItem>();
83             while (head) {
84                 if (IsValidResId(head->resId)) {
85                     UpdateResActionList(head->resId, head->resAction, false);
86                 }
87                 auto temp = head->next;
88                 head->next = nullptr;
89                 head = temp;
90             }
91             break;
92         }
93         case INNER_EVENT_ID_DO_FREQ_ACTION_DELAYED: {
94             int32_t resId = event->GetParam();
95             if (!IsValidResId(resId)) {
96                 return;
97             }
98             std::shared_ptr<ResAction> resAction = event->GetSharedObject<ResAction>();
99             if (resAction != nullptr) {
100                 UpdateResActionList(resId, resAction, true);
101             }
102             break;
103         }
104         case INNER_EVENT_ID_POWER_LIMIT_BOOST_FREQ: {
105             powerLimitBoost = event->GetParam() == 1;
106             for (auto iter = resStatusInfo.begin(); iter != resStatusInfo.end(); ++iter) {
107                 ArbitrateCandidate(iter->first);
108             }
109             break;
110         }
111         case INNER_EVENT_ID_THERMAL_LIMIT_BOOST_FREQ: {
112             thermalLimitBoost = event->GetParam() == 1;
113             for (auto iter = resStatusInfo.begin(); iter != resStatusInfo.end(); ++iter) {
114                 ArbitrateCandidate(iter->first);
115             }
116             break;
117         }
118         case INNER_EVENT_ID_DO_FREQ_ACTION_LEVEL: {
119             HandleDoFreqActionLevel(event->GetParam(), event->GetSharedObject<ResAction>());
120             break;
121         }
122         default: {
123             break;
124         }
125     }
126 }
127 
HandleDoFreqActionLevel(int32_t resId,std::shared_ptr<ResAction> resAction)128 void SocPerfHandler::HandleDoFreqActionLevel(int32_t resId, std::shared_ptr<ResAction> resAction)
129 {
130     int32_t realResId = resId - RES_ID_ADDITION;
131     if (!IsValidResId(realResId) || !resAction) {
132         return;
133     }
134     int32_t level = (int32_t)resAction->value;
135     if (!GetResValueByLevel(realResId, level, resAction->value)) {
136         return;
137     }
138     UpdateResActionList(realResId, resAction, false);
139 }
140 
GetResValueByLevel(int32_t resId,int32_t level,int64_t & resValue)141 bool SocPerfHandler::GetResValueByLevel(int32_t resId, int32_t level, int64_t& resValue)
142 {
143     if (resNodeInfo.find(resId) == resNodeInfo.end()
144         || resNodeInfo[resId]->available.empty()) {
145         SOC_PERF_LOGE("resId[%{public}d] is not valid.", resId);
146         return false;
147     }
148     if (level < 0) {
149         return false;
150     }
151 
152     std::set<int64_t> available;
153     for (auto a : resNodeInfo[resId]->available) {
154         available.insert(a);
155     }
156     int32_t len = (int32_t)available.size();
157     auto iter = available.begin();
158     if (level < len) {
159         std::advance(iter, len - 1 - level);
160     }
161     resValue = *iter;
162     return true;
163 }
164 
UpdateResActionList(int32_t resId,std::shared_ptr<ResAction> resAction,bool delayed)165 void SocPerfHandler::UpdateResActionList(int32_t resId, std::shared_ptr<ResAction> resAction, bool delayed)
166 {
167     std::shared_ptr<ResStatus> resStatus = resStatusInfo[resId];
168     int32_t type = resAction->type;
169 
170     if (delayed) {
171         for (auto iter = resStatus->resActionList[type].begin();
172             iter != resStatus->resActionList[type].end(); ++iter) {
173             if (resAction == *iter) {
174                 resStatus->resActionList[type].erase(iter);
175                 UpdateCandidatesValue(resId, type);
176                 break;
177             }
178         }
179     } else {
180         switch (resAction->onOff) {
181             case EVENT_INVALID: {
182                 resStatus->resActionList[type].push_back(resAction);
183                 UpdateCandidatesValue(resId, type);
184                 auto event = AppExecFwk::InnerEvent::Get(
185                     INNER_EVENT_ID_DO_FREQ_ACTION_DELAYED, resAction, resId);
186                 this->SendEvent(event, resAction->duration);
187                 break;
188             }
189             case EVENT_ON: {
190                 if (resAction->duration == 0) {
191                     for (auto iter = resStatus->resActionList[type].begin();
192                         iter != resStatus->resActionList[type].end(); ++iter) {
193                         if (resAction->TotalSame(*iter)) {
194                             resStatus->resActionList[type].erase(iter);
195                             break;
196                         }
197                     }
198                     resStatus->resActionList[type].push_back(resAction);
199                     UpdateCandidatesValue(resId, type);
200                 } else {
201                     resStatus->resActionList[type].push_back(resAction);
202                     UpdateCandidatesValue(resId, type);
203                     auto event = AppExecFwk::InnerEvent::Get(
204                         INNER_EVENT_ID_DO_FREQ_ACTION_DELAYED, resAction, resId);
205                     this->SendEvent(event, resAction->duration);
206                 }
207                 break;
208             }
209             case EVENT_OFF: {
210                 for (auto iter = resStatus->resActionList[type].begin();
211                     iter != resStatus->resActionList[type].end(); ++iter) {
212                     if (resAction->PartSame(*iter) && (*iter)->onOff == EVENT_ON) {
213                         resStatus->resActionList[type].erase(iter);
214                         UpdateCandidatesValue(resId, type);
215                         break;
216                     }
217                 }
218                 break;
219             }
220             default: {
221                 break;
222             }
223         }
224     }
225 }
226 
UpdateCandidatesValue(int32_t resId,int32_t type)227 void SocPerfHandler::UpdateCandidatesValue(int32_t resId, int32_t type)
228 {
229     std::shared_ptr<ResStatus> resStatus = resStatusInfo[resId];
230     int64_t prev = resStatus->candidates[type];
231 
232     if (resStatus->resActionList[type].empty()) {
233         resStatus->candidates[type] = INVALID_VALUE;
234     } else {
235         if (type == ACTION_TYPE_PERF) {
236             int64_t res = MIN_INT_VALUE;
237             for (auto iter = resStatus->resActionList[type].begin();
238                 iter != resStatus->resActionList[type].end(); ++iter) {
239                 res = Max(res, (*iter)->value);
240             }
241             resStatus->candidates[type] = res;
242         } else {
243             int64_t res = MAX_INT_VALUE;
244             for (auto iter = resStatus->resActionList[type].begin();
245                 iter != resStatus->resActionList[type].end(); ++iter) {
246                 res = Min(res, (*iter)->value);
247             }
248             resStatus->candidates[type] = res;
249         }
250     }
251 
252     if (resStatus->candidates[type] != prev) {
253         ArbitrateCandidate(resId);
254     }
255 }
256 
ArbitrateCandidate(int32_t resId)257 void SocPerfHandler::ArbitrateCandidate(int32_t resId)
258 {
259     std::shared_ptr<ResStatus> resStatus = resStatusInfo[resId];
260     int64_t candidatePerf = resStatus->candidates[ACTION_TYPE_PERF];
261     int64_t candidatePower = resStatus->candidates[ACTION_TYPE_POWER];
262     int64_t candidateThermal = resStatus->candidates[ACTION_TYPE_THERMAL];
263 
264     if (ExistNoCandidate(resId, resStatus, candidatePerf, candidatePower, candidateThermal)) {
265         return;
266     }
267 
268     if (!powerLimitBoost && !thermalLimitBoost) {
269         if (candidatePerf != INVALID_VALUE) {
270             resStatus->candidate = Max(candidatePerf, candidatePower, candidateThermal);
271         } else {
272             resStatus->candidate =
273                 (candidatePower == INVALID_VALUE) ? candidateThermal :
274                     ((candidateThermal == INVALID_VALUE) ? candidatePower : Min(candidatePower, candidateThermal));
275         }
276     } else if (!powerLimitBoost && thermalLimitBoost) {
277         resStatus->candidate =
278             (candidateThermal != INVALID_VALUE) ? candidateThermal : Max(candidatePerf, candidatePower);
279     } else if (powerLimitBoost && !thermalLimitBoost) {
280         resStatus->candidate =
281             (candidatePower != INVALID_VALUE) ? candidatePower : Max(candidatePerf, candidateThermal);
282     } else {
283         if (candidatePower == INVALID_VALUE && candidateThermal == INVALID_VALUE) {
284             resStatus->candidate = candidatePerf;
285         } else {
286             resStatus->candidate =
287                 (candidatePower == INVALID_VALUE) ? candidateThermal :
288                     ((candidateThermal == INVALID_VALUE) ? candidatePower : Min(candidatePower, candidateThermal));
289         }
290     }
291 
292     ArbitratePairRes(resId);
293 }
294 
ArbitratePairRes(int32_t resId)295 void SocPerfHandler::ArbitratePairRes(int32_t resId)
296 {
297     if (IsGovResId(resId)) {
298         UpdateCurrentValue(resId, resStatusInfo[resId]->candidate);
299         return;
300     }
301 
302     int32_t pairResId = resNodeInfo[resId]->pair;
303     if (pairResId == INVALID_VALUE) {
304         UpdateCurrentValue(resId, resStatusInfo[resId]->candidate);
305         return;
306     }
307 
308     if (resNodeInfo[resId]->mode == 1) {
309         if (resStatusInfo[resId]->candidate < resStatusInfo[pairResId]->candidate) {
310             if (powerLimitBoost || thermalLimitBoost) {
311                 UpdatePairResValue(pairResId,
312                     resStatusInfo[resId]->candidate, resId, resStatusInfo[resId]->candidate);
313             } else {
314                 UpdatePairResValue(pairResId,
315                     resStatusInfo[pairResId]->candidate, resId, resStatusInfo[pairResId]->candidate);
316             }
317         } else {
318             UpdatePairResValue(pairResId,
319                 resStatusInfo[pairResId]->candidate, resId, resStatusInfo[resId]->candidate);
320         }
321     } else {
322         if (resStatusInfo[resId]->candidate > resStatusInfo[pairResId]->candidate) {
323             if (powerLimitBoost || thermalLimitBoost) {
324                 UpdatePairResValue(resId,
325                     resStatusInfo[pairResId]->candidate, pairResId, resStatusInfo[pairResId]->candidate);
326             } else {
327                 UpdatePairResValue(resId,
328                     resStatusInfo[resId]->candidate, pairResId, resStatusInfo[resId]->candidate);
329             }
330         } else {
331             UpdatePairResValue(resId,
332                 resStatusInfo[resId]->candidate, pairResId, resStatusInfo[pairResId]->candidate);
333         }
334     }
335 }
336 
UpdatePairResValue(int32_t minResId,int64_t minResValue,int32_t maxResId,int64_t maxResValue)337 void SocPerfHandler::UpdatePairResValue(int32_t minResId, int64_t minResValue, int32_t maxResId, int64_t maxResValue)
338 {
339     WriteNode(resNodeInfo[minResId]->path, std::to_string(resNodeInfo[minResId]->def));
340     WriteNode(resNodeInfo[maxResId]->path, std::to_string(resNodeInfo[maxResId]->def));
341     UpdateCurrentValue(minResId, minResValue);
342     UpdateCurrentValue(maxResId, maxResValue);
343 }
344 
UpdateCurrentValue(int32_t resId,int64_t currValue)345 void SocPerfHandler::UpdateCurrentValue(int32_t resId, int64_t currValue)
346 {
347     resStatusInfo[resId]->current = currValue;
348     if (IsGovResId(resId)) {
349         if (govResNodeInfo[resId]->levelToStr.find(currValue) != govResNodeInfo[resId]->levelToStr.end()) {
350             std::vector<std::string> targetStrs = govResNodeInfo[resId]->levelToStr[resStatusInfo[resId]->current];
351             for (int32_t i = 0; i < (int32_t)govResNodeInfo[resId]->paths.size(); i++) {
352                 WriteNode(govResNodeInfo[resId]->paths[i], targetStrs[i]);
353             }
354         }
355     } else if (IsResId(resId)) {
356         WriteNode(resNodeInfo[resId]->path, std::to_string(resStatusInfo[resId]->current));
357     }
358 }
359 
WriteNode(std::string filePath,std::string value)360 void SocPerfHandler::WriteNode(std::string filePath, std::string value)
361 {
362     int32_t fd = GetFdForFilePath(filePath);
363     if (fd < 0) {
364         return;
365     }
366     write(fd, value.c_str(), value.size());
367 }
368 
GetFdForFilePath(std::string filePath)369 int32_t SocPerfHandler::GetFdForFilePath(std::string filePath)
370 {
371     if (fdInfo.find(filePath) != fdInfo.end()) {
372         return fdInfo[filePath];
373     }
374     char path[PATH_MAX + 1] = {0};
375     if (filePath.size() == 0 || filePath.size() > PATH_MAX || !realpath(filePath.c_str(), path)) {
376         return -1;
377     }
378     int32_t fd = open(path, O_RDWR | O_CLOEXEC);
379     if (fd < 0) {
380         return fd;
381     }
382     fdInfo.insert(std::pair<std::string, int32_t>(filePath, fd));
383     return fdInfo[filePath];
384 }
385 
ExistNoCandidate(int32_t resId,std::shared_ptr<ResStatus> resStatus,int64_t perf,int64_t power,int64_t thermal)386 bool SocPerfHandler::ExistNoCandidate(
387     int32_t resId, std::shared_ptr<ResStatus> resStatus, int64_t perf, int64_t power, int64_t thermal)
388 {
389     if (perf == INVALID_VALUE && power == INVALID_VALUE && thermal == INVALID_VALUE) {
390         if (IsGovResId(resId)) {
391             resStatus->candidate = govResNodeInfo[resId]->def;
392         } else if (IsResId(resId)) {
393             resStatus->candidate = resNodeInfo[resId]->def;
394         }
395         ArbitratePairRes(resId);
396         return true;
397     }
398     return false;
399 }
400 
IsGovResId(int32_t resId)401 bool SocPerfHandler::IsGovResId(int32_t resId)
402 {
403     if (resNodeInfo.find(resId) == resNodeInfo.end()
404         && govResNodeInfo.find(resId) != govResNodeInfo.end()) {
405         return true;
406     }
407     return false;
408 }
409 
IsResId(int32_t resId)410 bool SocPerfHandler::IsResId(int32_t resId)
411 {
412     if (govResNodeInfo.find(resId) == govResNodeInfo.end()
413         && resNodeInfo.find(resId) != resNodeInfo.end()) {
414         return true;
415     }
416     return false;
417 }
418 
IsValidResId(int32_t resId)419 bool SocPerfHandler::IsValidResId(int32_t resId)
420 {
421     if (resNodeInfo.find(resId) == resNodeInfo.end()
422         && govResNodeInfo.find(resId) == govResNodeInfo.end()) {
423         return false;
424     }
425     if (resStatusInfo.find(resId) == resStatusInfo.end()) {
426         return false;
427     }
428     return true;
429 }
430 } // namespace SOCPERF
431 } // namespace OHOS
432