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