1 /*
2 * Copyright (c) 2024 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_thread_wrap.h"
16
17 #include <set> // for set
18 #include <unistd.h> // for open, write
19 #include <fcntl.h> // for O_RDWR, O_CLOEXEC
20
21 #include "res_exe_type.h"
22 #include "res_sched_exe_client.h"
23 #include "socperf.h"
24 #include "socperf_trace.h"
25
26 namespace OHOS {
27 namespace SOCPERF {
28
SocPerfThreadWrap()29 SocPerfThreadWrap::SocPerfThreadWrap() : socperfQueue_("socperf", ffrt::queue_attr().qos(ffrt::qos_user_interactive))
30 {
31 }
32
~SocPerfThreadWrap()33 SocPerfThreadWrap::~SocPerfThreadWrap()
34 {
35 }
36
InitResourceNodeInfo()37 void SocPerfThreadWrap::InitResourceNodeInfo()
38 {
39 std::function<void()>&& initResourceNodeInfoFunc = [this]() {
40 for (auto iter = socPerfConfig_.resourceNodeInfo_.begin();
41 iter != socPerfConfig_.resourceNodeInfo_.end(); ++iter) {
42 std::shared_ptr<ResourceNode> resourceNode = iter->second;
43 if (resourceNode == nullptr) {
44 continue;
45 }
46 auto resStatus = std::make_shared<ResStatus>();
47 resStatusInfo_.insert(std::pair<int32_t, std::shared_ptr<ResStatus>>(resourceNode->id, resStatus));
48 }
49 InitResStatus();
50 };
51 socperfQueue_.submit(initResourceNodeInfoFunc);
52 }
53
DoFreqActionPack(std::shared_ptr<ResActionItem> head)54 void SocPerfThreadWrap::DoFreqActionPack(std::shared_ptr<ResActionItem> head)
55 {
56 if (head == nullptr) {
57 return;
58 }
59 std::function<void()>&& doFreqActionPackFunc = [this, head]() {
60 std::shared_ptr<ResActionItem> queueHead = head;
61 while (queueHead) {
62 if (socPerfConfig_.IsValidResId(queueHead->resId)) {
63 UpdateResActionList(queueHead->resId, queueHead->resAction, false);
64 }
65 queueHead = queueHead->next;
66 }
67 SendResStatus();
68 };
69 socperfQueue_.submit(doFreqActionPackFunc);
70 }
71
UpdatePowerLimitBoostFreq(bool powerLimitBoost)72 void SocPerfThreadWrap::UpdatePowerLimitBoostFreq(bool powerLimitBoost)
73 {
74 std::function<void()>&& updatePowerLimitBoostFreqFunc = [this, powerLimitBoost]() {
75 this->powerLimitBoost_ = powerLimitBoost;
76 for (auto iter = resStatusInfo_.begin(); iter != resStatusInfo_.end(); ++iter) {
77 if (resStatusInfo_[iter->first] == nullptr) {
78 continue;
79 }
80 ArbitrateCandidate(iter->first);
81 }
82 SendResStatus();
83 };
84 socperfQueue_.submit(updatePowerLimitBoostFreqFunc);
85 }
86
UpdateThermalLimitBoostFreq(bool thermalLimitBoost)87 void SocPerfThreadWrap::UpdateThermalLimitBoostFreq(bool thermalLimitBoost)
88 {
89 std::function<void()>&& updateThermalLimitBoostFreqFunc = [this, thermalLimitBoost]() {
90 this->thermalLimitBoost_ = thermalLimitBoost;
91 for (auto iter = resStatusInfo_.begin(); iter != resStatusInfo_.end(); ++iter) {
92 if (resStatusInfo_[iter->first] == nullptr) {
93 continue;
94 }
95 ArbitrateCandidate(iter->first);
96 }
97 SendResStatus();
98 };
99 socperfQueue_.submit(updateThermalLimitBoostFreqFunc);
100 }
101
UpdateLimitStatus(int32_t eventId,std::shared_ptr<ResAction> resAction,int32_t resId)102 void SocPerfThreadWrap::UpdateLimitStatus(int32_t eventId, std::shared_ptr<ResAction> resAction, int32_t resId)
103 {
104 if (resAction == nullptr) {
105 return;
106 }
107 std::function<void()>&& updateLimitStatusFunc = [this, eventId, resId, resAction]() {
108 if (eventId == INNER_EVENT_ID_DO_FREQ_ACTION) {
109 DoFreqAction(resId, resAction);
110 } else if (eventId == INNER_EVENT_ID_DO_FREQ_ACTION_LEVEL) {
111 DoFreqActionLevel(resId, resAction);
112 }
113 SendResStatus();
114 if (resAction->onOff && resStatusInfo_[resId] != nullptr) {
115 HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::RSS, "LIMIT_REQUEST",
116 OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
117 "CLIENT_ID", resAction->type,
118 "RES_ID", resId,
119 "CONFIG", resStatusInfo_[resId]->candidate);
120 }
121 };
122 socperfQueue_.submit(updateLimitStatusFunc);
123 }
124
ClearAllAliveRequest()125 void SocPerfThreadWrap::ClearAllAliveRequest()
126 {
127 std::function<void()>&& updateLimitStatusFunc = [this]() {
128 for (const auto& item : this->resStatusInfo_) {
129 if (item.second == nullptr) {
130 continue;
131 }
132 std::list<std::shared_ptr<ResAction>>& resActionList = item.second->resActionList[ACTION_TYPE_PERF];
133 resActionList.clear();
134 UpdateCandidatesValue(item.first, ACTION_TYPE_PERF);
135 }
136 SendResStatus();
137 };
138 socperfQueue_.submit(updateLimitStatusFunc);
139 }
140
DoFreqAction(int32_t resId,std::shared_ptr<ResAction> resAction)141 void SocPerfThreadWrap::DoFreqAction(int32_t resId, std::shared_ptr<ResAction> resAction)
142 {
143 if (!socPerfConfig_.IsValidResId(resId) || resAction == nullptr) {
144 return;
145 }
146 UpdateResActionList(resId, resAction, false);
147 }
148
InitResStatus()149 void SocPerfThreadWrap::InitResStatus()
150 {
151 std::vector<int32_t> qosId;
152 std::vector<int64_t> value;
153 std::vector<int64_t> endTime;
154 std::vector<int32_t> qosIdToRssEx;
155 std::vector<int64_t> valueToRssEx;
156 std::vector<int64_t> endTimeToRssEx;
157 for (auto iter = resStatusInfo_.begin(); iter != resStatusInfo_.end(); ++iter) {
158 int32_t resId = iter->first;
159 if (socPerfConfig_.resourceNodeInfo_.find(resId) != socPerfConfig_.resourceNodeInfo_.end()) {
160 if (socPerfConfig_.resourceNodeInfo_[resId]->persistMode == REPORT_TO_PERFSO) {
161 qosId.push_back(resId);
162 value.push_back(NODE_DEFAULT_VALUE);
163 endTime.push_back(MAX_INT_VALUE);
164 } else {
165 qosIdToRssEx.push_back(resId);
166 valueToRssEx.push_back(NODE_DEFAULT_VALUE);
167 endTimeToRssEx.push_back(MAX_INT_VALUE);
168 }
169 }
170 }
171 ReportToPerfSo(qosId, value, endTime);
172 ReportToRssExe(qosIdToRssEx, valueToRssEx, endTimeToRssEx);
173 }
174
SetWeakInteractionStatus(bool enable)175 void SocPerfThreadWrap::SetWeakInteractionStatus(bool enable)
176 {
177 std::function<void()>&& weakInteractionFunc = [this, enable]() {
178 std::string trace_str("SetWeakInteractionStatus");
179 trace_str.append("[").append(enable ? "true" : "false").append("]");
180 StartTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_SOCPERF, trace_str.c_str());
181 weakInteractionStatus_ = enable;
182 WeakInteraction();
183 SOC_PERF_LOGI("SetWeakInteractionStatus is %{public}d.", enable);
184 FinishTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_SOCPERF);
185 };
186 socperfQueue_.submit(weakInteractionFunc);
187 }
188
WeakInteraction()189 void SocPerfThreadWrap::WeakInteraction()
190 {
191 for (int i = 0; i < (int)socPerfConfig_.interAction_.size(); i++) {
192 std::shared_ptr<InterAction> interAction = socPerfConfig_.interAction_[i];
193 if (weakInteractionStatus_ && boostResCnt == 0 && interAction->status == BOOST_STATUS) {
194 interAction->status = BOOST_END_STATUS;
195 std::function<void()>&& updateLimitStatusFunc = [this, i]() {
196 socPerfConfig_.interAction_[i]->status = WEAK_INTERACTION_STATUS;
197 DoWeakInteraction(
198 socPerfConfig_.configPerfActionsInfo_[DEFAULT_CONFIG_MODE][socPerfConfig_.interAction_[i]->cmdId],
199 EVENT_ON, socPerfConfig_.interAction_[i]->actionType);
200 std::string trace_str("WeakInteraction");
201 trace_str.append(",cmdId[").append(std::to_string(socPerfConfig_.interAction_[i]->cmdId)).append("]");
202 trace_str.append(",onOff[").append(std::to_string(EVENT_ON)).append("]");
203 StartTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_SOCPERF, trace_str.c_str());
204 FinishTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_SOCPERF);
205 };
206 ffrt::task_attr taskAttr;
207 taskAttr.delay(interAction->delayTime * SCALES_OF_MILLISECONDS_TO_MICROSECONDS);
208 interAction->timerTask = socperfQueue_.submit_h(updateLimitStatusFunc, taskAttr);
209 } else if ((!weakInteractionStatus_ || boostResCnt != 0) && interAction->status == WEAK_INTERACTION_STATUS) {
210 interAction->status = BOOST_STATUS;
211 DoWeakInteraction(
212 socPerfConfig_.configPerfActionsInfo_[DEFAULT_CONFIG_MODE][interAction->cmdId],
213 EVENT_OFF, interAction->actionType);
214 std::string trace_str("WeakInteraction");
215 trace_str.append(",cmdId[").append(std::to_string(interAction->cmdId)).append("]");
216 trace_str.append(",onOff[").append(std::to_string(EVENT_OFF)).append("]");
217 StartTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_SOCPERF, trace_str.c_str());
218 FinishTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_SOCPERF);
219 } else if ((!weakInteractionStatus_ || boostResCnt != 0) && interAction->status == BOOST_END_STATUS) {
220 interAction->status = BOOST_STATUS;
221 if (interAction->timerTask != nullptr) {
222 socperfQueue_.cancel(interAction->timerTask);
223 interAction->timerTask = nullptr;
224 }
225 }
226 }
227 }
228
DoWeakInteraction(std::shared_ptr<Actions> actions,int32_t onOff,int32_t actionType)229 void SocPerfThreadWrap::DoWeakInteraction(std::shared_ptr<Actions> actions, int32_t onOff, int32_t actionType)
230 {
231 std::shared_ptr<ResActionItem> header = nullptr;
232 std::shared_ptr<ResActionItem> curItem = nullptr;
233 if (actions == nullptr) {
234 return;
235 }
236 for (auto iter = actions->actionList.begin(); iter != actions->actionList.end(); iter++) {
237 std::shared_ptr<Action> action = *iter;
238 for (int32_t i = 0; i < (int32_t)action->variable.size() - 1; i += RES_ID_AND_VALUE_PAIR) {
239 if (!socPerfConfig_.IsValidResId(action->variable[i])) {
240 continue;
241 }
242 auto resActionItem = std::make_shared<ResActionItem>(action->variable[i]);
243 resActionItem->resAction = std::make_shared<ResAction>(action->variable[i + 1], 0,
244 actionType, onOff, actions->id, MAX_INT_VALUE);
245 resActionItem->resAction->interaction = false;
246 if (curItem) {
247 curItem->next = resActionItem;
248 } else {
249 header = resActionItem;
250 }
251 curItem = resActionItem;
252 }
253 }
254 DoFreqActionPack(header);
255 }
256
SendResStatus()257 void SocPerfThreadWrap::SendResStatus()
258 {
259 std::vector<int32_t> qosId;
260 std::vector<int64_t> value;
261 std::vector<int64_t> endTime;
262 std::vector<int32_t> qosIdToRssEx;
263 std::vector<int64_t> valueToRssEx;
264 std::vector<int64_t> endTimeToRssEx;
265 for (auto iter = resStatusInfo_.begin(); iter != resStatusInfo_.end(); ++iter) {
266 int32_t resId = iter->first;
267 std::shared_ptr<ResStatus> resStatus = iter->second;
268 if (socPerfConfig_.resourceNodeInfo_.find(resId) != socPerfConfig_.resourceNodeInfo_.end() &&
269 (resStatus->previousValue != resStatus->currentValue ||
270 resStatus->previousEndTime != resStatus->currentEndTime)) {
271 if (socPerfConfig_.resourceNodeInfo_[resId]->persistMode == REPORT_TO_PERFSO) {
272 qosId.push_back(resId);
273 value.push_back(resStatus->currentValue);
274 endTime.push_back(resStatus->currentEndTime);
275 } else {
276 qosIdToRssEx.push_back(resId);
277 valueToRssEx.push_back(resStatus->currentValue);
278 endTimeToRssEx.push_back(resStatus->currentEndTime);
279 }
280 resStatus->previousValue = resStatus->currentValue;
281 resStatus->previousEndTime = resStatus->currentEndTime;
282 if (socPerfConfig_.resourceNodeInfo_[resId]->trace) {
283 CountTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_SOCPERF,
284 socPerfConfig_.resourceNodeInfo_[resId]->name.c_str(),
285 resStatus->currentValue == MAX_INT32_VALUE ? NODE_DEFAULT_VALUE : resStatus->currentValue);
286 }
287 }
288 }
289 ReportToPerfSo(qosId, value, endTime);
290 ReportToRssExe(qosIdToRssEx, valueToRssEx, endTimeToRssEx);
291
292 WeakInteraction();
293 }
294
ReportToPerfSo(std::vector<int32_t> & qosId,std::vector<int64_t> & value,std::vector<int64_t> & endTime)295 void SocPerfThreadWrap::ReportToPerfSo(std::vector<int32_t>& qosId, std::vector<int64_t>& value,
296 std::vector<int64_t>& endTime)
297 {
298 if (!socPerfConfig_.reportFunc_) {
299 return;
300 }
301 if (qosId.size() > 0) {
302 socPerfConfig_.reportFunc_(qosId, value, endTime, "");
303 std::string log("send data to perf so");
304 for (unsigned long i = 0; i < qosId.size(); i++) {
305 log.append(",[id:").append(std::to_string(qosId[i]));
306 log.append(", value:").append(std::to_string(value[i])).append("]");
307 }
308 StartTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_SOCPERF, log.c_str());
309 FinishTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_SOCPERF);
310 }
311 }
312
ReportToRssExe(std::vector<int32_t> & qosId,std::vector<int64_t> & value,std::vector<int64_t> & endTime)313 void SocPerfThreadWrap::ReportToRssExe(std::vector<int32_t>& qosId, std::vector<int64_t>& value,
314 std::vector<int64_t>& endTime)
315 {
316 if (qosId.size() > 0) {
317 nlohmann::json payload;
318 payload[QOSID_STRING] = qosId;
319 payload[VALUE_STRING] = value;
320 ResourceSchedule::ResSchedExeClient::GetInstance().SendRequestAsync(
321 ResourceSchedule::ResExeType::EWS_TYPE_SOCPERF_EXECUTOR_ASYNC_EVENT, SOCPERF_EVENT_WIRTE_NODE, payload);
322 std::string log("send data to rssexe so");
323 for (unsigned long i = 0; i < qosId.size(); i++) {
324 log.append(",[id:").append(std::to_string(qosId[i]));
325 log.append(", value:").append(std::to_string(value[i])).append("]");
326 }
327 StartTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_SOCPERF, log.c_str());
328 FinishTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_SOCPERF);
329 }
330 }
331
DoFreqActionLevel(int32_t resId,std::shared_ptr<ResAction> resAction)332 void SocPerfThreadWrap::DoFreqActionLevel(int32_t resId, std::shared_ptr<ResAction> resAction)
333 {
334 int32_t realResId = resId - RES_ID_ADDITION;
335 if (!socPerfConfig_.IsValidResId(realResId) || !resAction) {
336 return;
337 }
338 int32_t level = (int32_t)resAction->value;
339 if (!GetResValueByLevel(realResId, level, resAction->value)) {
340 return;
341 }
342 UpdateResActionList(realResId, resAction, false);
343 }
344
PostDelayTask(std::shared_ptr<ResActionItem> queueHead)345 void SocPerfThreadWrap::PostDelayTask(std::shared_ptr<ResActionItem> queueHead)
346 {
347 if (queueHead == nullptr) {
348 return;
349 }
350 std::unordered_map<int32_t, std::vector<std::shared_ptr<ResActionItem>>> resActionMap;
351 std::shared_ptr<ResActionItem> head = queueHead;
352 while (head) {
353 if (!head->resAction || head->resAction->duration == 0) {
354 head = head->next;
355 continue;
356 }
357 resActionMap[head->resAction->duration].push_back(head);
358 head = head->next;
359 }
360 for (auto item : resActionMap) {
361 ffrt::task_attr taskAttr;
362 taskAttr.delay(item.first * SCALES_OF_MILLISECONDS_TO_MICROSECONDS);
363 std::function<void()>&& postDelayTaskFunc = [this, item]() {
364 for (uint32_t i = 0; i < item.second.size(); i++) {
365 UpdateResActionList(item.second[i]->resId, item.second[i]->resAction, true);
366 }
367 SendResStatus();
368 };
369 socperfQueue_.submit(postDelayTaskFunc, taskAttr);
370 }
371 }
372
GetResValueByLevel(int32_t resId,int32_t level,int64_t & resValue)373 bool SocPerfThreadWrap::GetResValueByLevel(int32_t resId, int32_t level, int64_t& resValue)
374 {
375 if (socPerfConfig_.resourceNodeInfo_.find(resId) == socPerfConfig_.resourceNodeInfo_.end()
376 || socPerfConfig_.resourceNodeInfo_[resId]->available.empty()) {
377 SOC_PERF_LOGE("resId[%{public}d] is not valid.", resId);
378 return false;
379 }
380 if (level < 0) {
381 return false;
382 }
383
384 std::set<int64_t> available;
385 for (auto a : socPerfConfig_.resourceNodeInfo_[resId]->available) {
386 available.insert(a);
387 }
388 int32_t len = (int32_t)available.size();
389 auto iter = available.begin();
390 if (level < len) {
391 std::advance(iter, len - 1 - level);
392 }
393 resValue = *iter;
394 return true;
395 }
396
UpdateResActionList(int32_t resId,std::shared_ptr<ResAction> resAction,bool delayed)397 void SocPerfThreadWrap::UpdateResActionList(int32_t resId, std::shared_ptr<ResAction> resAction, bool delayed)
398 {
399 std::shared_ptr<ResStatus> resStatus = resStatusInfo_[resId];
400 int32_t type = resAction->type;
401
402 if (delayed) {
403 UpdateResActionListByDelayedMsg(resId, type, resAction, resStatus);
404 } else {
405 UpdateResActionListByInstantMsg(resId, type, resAction, resStatus);
406 }
407 }
408
UpdateResActionListByDelayedMsg(int32_t resId,int32_t type,std::shared_ptr<ResAction> resAction,std::shared_ptr<ResStatus> resStatus)409 void SocPerfThreadWrap::UpdateResActionListByDelayedMsg(int32_t resId, int32_t type,
410 std::shared_ptr<ResAction> resAction, std::shared_ptr<ResStatus> resStatus)
411 {
412 for (auto iter = resStatus->resActionList[type].begin();
413 iter != resStatus->resActionList[type].end(); ++iter) {
414 if (resAction == *iter) {
415 resStatus->resActionList[type].erase(iter);
416 UpdateCandidatesValue(resId, type);
417 if (resAction->interaction) {
418 boostResCnt--;
419 }
420 break;
421 }
422 }
423 }
424
HandleResAction(int32_t resId,int32_t type,std::shared_ptr<ResAction> resAction,std::shared_ptr<ResStatus> resStatus)425 void SocPerfThreadWrap::HandleResAction(int32_t resId, int32_t type,
426 std::shared_ptr<ResAction> resAction, std::shared_ptr<ResStatus> resStatus)
427 {
428 for (auto iter = resStatus->resActionList[type].begin();
429 iter != resStatus->resActionList[type].end(); ++iter) {
430 if (resAction->TotalSame(*iter)) {
431 resStatus->resActionList[type].erase(iter);
432 if (resAction->interaction) {
433 boostResCnt--;
434 }
435 break;
436 }
437 }
438 resStatus->resActionList[type].push_back(resAction);
439 UpdateCandidatesValue(resId, type);
440 if (resAction->interaction) {
441 boostResCnt++;
442 }
443 }
444
UpdateResActionListByInstantMsg(int32_t resId,int32_t type,std::shared_ptr<ResAction> resAction,std::shared_ptr<ResStatus> resStatus)445 void SocPerfThreadWrap::UpdateResActionListByInstantMsg(int32_t resId, int32_t type,
446 std::shared_ptr<ResAction> resAction, std::shared_ptr<ResStatus> resStatus)
447 {
448 switch (resAction->onOff) {
449 case EVENT_INVALID:
450 case EVENT_ON: {
451 HandleResAction(resId, type, resAction, resStatus);
452 break;
453 }
454 case EVENT_OFF: {
455 for (auto iter = resStatus->resActionList[type].begin();
456 iter != resStatus->resActionList[type].end(); ++iter) {
457 if (resAction->PartSame(*iter) && (*iter)->onOff == EVENT_ON) {
458 resStatus->resActionList[type].erase(iter);
459 UpdateCandidatesValue(resId, type);
460 boostResCnt = boostResCnt - (resAction->interaction ? 1 : 0);
461 break;
462 }
463 }
464 break;
465 }
466 default: {
467 break;
468 }
469 }
470 }
471
UpdateCandidatesValue(int32_t resId,int32_t type)472 void SocPerfThreadWrap::UpdateCandidatesValue(int32_t resId, int32_t type)
473 {
474 std::shared_ptr<ResStatus> resStatus = resStatusInfo_[resId];
475 int64_t prevValue = resStatus->candidatesValue[type];
476 int64_t prevEndTime = resStatus->candidatesEndTime[type];
477
478 if (resStatus->resActionList[type].empty()) {
479 resStatus->candidatesValue[type] = INVALID_VALUE;
480 resStatus->candidatesEndTime[type] = MAX_INT_VALUE;
481 } else {
482 InnerArbitrateCandidatesValue(type, resStatus);
483 }
484
485 if (resStatus->candidatesValue[type] != prevValue || resStatus->candidatesEndTime[type] != prevEndTime) {
486 ArbitrateCandidate(resId);
487 }
488 }
489
InnerArbitrateCandidatesValue(int32_t type,std::shared_ptr<ResStatus> resStatus)490 void SocPerfThreadWrap::InnerArbitrateCandidatesValue(int32_t type, std::shared_ptr<ResStatus> resStatus)
491 {
492 // perf first action type: ACTION_TYPE_PERF\ACTION_TYPE_PERFLVL
493 // power first action type: ACTION_TYPE_POWER\ACTION_TYPE_THERMAL
494 bool isPerfFirst = (type == ACTION_TYPE_PERF || type == ACTION_TYPE_PERFLVL);
495
496 int64_t res = isPerfFirst ? MIN_INT_VALUE : MAX_INT_VALUE;
497 int64_t endTime = MIN_INT_VALUE;
498 for (auto iter = resStatus->resActionList[type].begin();
499 iter != resStatus->resActionList[type].end(); ++iter) {
500 if (((*iter)->value > res && isPerfFirst)
501 || ((*iter)->value < res && !isPerfFirst)) {
502 res = (*iter)->value;
503 endTime = (*iter)->endTime;
504 } else if ((*iter)->value == res) {
505 endTime = Max(endTime, (*iter)->endTime);
506 }
507 }
508 resStatus->candidatesValue[type] = res;
509 resStatus->candidatesEndTime[type] = endTime;
510 }
511
ArbitrateCandidate(int32_t resId)512 void SocPerfThreadWrap::ArbitrateCandidate(int32_t resId)
513 {
514 std::shared_ptr<ResStatus> resStatus = resStatusInfo_[resId];
515 // if perf, power and thermal don't have valid value, send default value
516 if (ExistNoCandidate(resId, resStatus)) {
517 return;
518 }
519 // Arbitrate in perf, power and thermal
520 ProcessLimitCase(resId);
521 // perf request thermal level is highest priority in this freq adjuster
522 if (ArbitratePairResInPerfLvl(resId)) {
523 return;
524 }
525 // adjust resource value if it has 'max' config
526 ArbitratePairRes(resId, false);
527 }
528
ProcessLimitCase(int32_t resId)529 void SocPerfThreadWrap::ProcessLimitCase(int32_t resId)
530 {
531 std::shared_ptr<ResStatus> resStatus = resStatusInfo_[resId];
532 int64_t candidatePerfValue = resStatus->candidatesValue[ACTION_TYPE_PERF];
533 int64_t candidatePowerValue = resStatus->candidatesValue[ACTION_TYPE_POWER];
534 int64_t candidateThermalValue = resStatus->candidatesValue[ACTION_TYPE_THERMAL];
535 if (!powerLimitBoost_ && !thermalLimitBoost_) {
536 if (candidatePerfValue != INVALID_VALUE) {
537 resStatus->candidate = Max(candidatePerfValue, candidatePowerValue, candidateThermalValue);
538 } else {
539 resStatus->candidate = (candidatePowerValue == INVALID_VALUE) ? candidateThermalValue :
540 ((candidateThermalValue == INVALID_VALUE) ? candidatePowerValue :
541 Min(candidatePowerValue, candidateThermalValue));
542 }
543 } else if (!powerLimitBoost_ && thermalLimitBoost_) {
544 resStatus->candidate = (candidateThermalValue != INVALID_VALUE) ? candidateThermalValue :
545 Max(candidatePerfValue, candidatePowerValue);
546 } else if (powerLimitBoost_ && !thermalLimitBoost_) {
547 resStatus->candidate = (candidatePowerValue != INVALID_VALUE) ? candidatePowerValue :
548 Max(candidatePerfValue, candidateThermalValue);
549 } else {
550 if (candidatePowerValue == INVALID_VALUE && candidateThermalValue == INVALID_VALUE) {
551 resStatus->candidate = candidatePerfValue;
552 } else {
553 resStatus->candidate = (candidatePowerValue == INVALID_VALUE) ? candidateThermalValue :
554 ((candidateThermalValue == INVALID_VALUE) ? candidatePowerValue :
555 Min(candidatePowerValue, candidateThermalValue));
556 }
557 }
558 resStatus->currentEndTime = Min(resStatus->candidatesEndTime[ACTION_TYPE_PERF],
559 resStatus->candidatesEndTime[ACTION_TYPE_POWER], resStatus->candidatesEndTime[ACTION_TYPE_THERMAL]);
560 }
561
ArbitratePairResInPerfLvl(int32_t resId)562 bool SocPerfThreadWrap::ArbitratePairResInPerfLvl(int32_t resId)
563 {
564 std::shared_ptr<ResStatus> resStatus = resStatusInfo_[resId];
565 int32_t pairResId = INVALID_VALUE;
566 if (!socPerfConfig_.IsGovResId(resId)) {
567 pairResId = std::static_pointer_cast<ResNode>(socPerfConfig_.resourceNodeInfo_[resId])->pair;
568 }
569 // if resource self and resource's pair both not have perflvl value
570 if (resStatus->candidatesValue[ACTION_TYPE_PERFLVL] == INVALID_VALUE && (pairResId != INVALID_VALUE &&
571 resStatusInfo_[pairResId]->candidatesValue[ACTION_TYPE_PERFLVL] == INVALID_VALUE)) {
572 return false;
573 }
574 // if this resource has PerfRequestLvl value, the final arbitrate value change to PerfRequestLvl value
575 if (resStatus->candidatesValue[ACTION_TYPE_PERFLVL] != INVALID_VALUE) {
576 if (thermalLvl_ == 0 && resStatus->candidate != INVALID_VALUE) {
577 resStatus->candidate = Min(resStatus->candidate, resStatus->candidatesValue[ACTION_TYPE_PERFLVL]);
578 } else {
579 resStatus->candidate = resStatus->candidatesValue[ACTION_TYPE_PERFLVL];
580 }
581 }
582 // only limit max when PerfRequestLvl has max value
583 bool limit = false;
584 if (thermalLvl_ != 0 &&
585 !socPerfConfig_.IsGovResId(resId) &&
586 (socPerfConfig_.resourceNodeInfo_[resId]->isMaxValue ||
587 (pairResId != INVALID_VALUE && socPerfConfig_.resourceNodeInfo_[pairResId]->isMaxValue))) {
588 limit = true;
589 }
590 ArbitratePairRes(resId, limit);
591 return true;
592 }
593
ArbitratePairRes(int32_t resId,bool perfRequestLimit)594 void SocPerfThreadWrap::ArbitratePairRes(int32_t resId, bool perfRequestLimit)
595 {
596 bool limit = powerLimitBoost_ || thermalLimitBoost_ || perfRequestLimit;
597 if (socPerfConfig_.IsGovResId(resId)) {
598 UpdateCurrentValue(resId, resStatusInfo_[resId]->candidate);
599 return;
600 }
601 int32_t pairResId = std::static_pointer_cast<ResNode>(socPerfConfig_.resourceNodeInfo_[resId])->pair;
602 if (pairResId == INVALID_VALUE) {
603 UpdateCurrentValue(resId, resStatusInfo_[resId]->candidate);
604 return;
605 }
606
607 if (resStatusInfo_[pairResId]->candidate == NODE_DEFAULT_VALUE ||
608 resStatusInfo_[resId]->candidate == NODE_DEFAULT_VALUE) {
609 UpdatePairResValue(resId, resStatusInfo_[resId]->candidate, pairResId, resStatusInfo_[pairResId]->candidate);
610 return;
611 }
612
613 if (socPerfConfig_.resourceNodeInfo_[resId]->isMaxValue) {
614 if (resStatusInfo_[resId]->candidate < resStatusInfo_[pairResId]->candidate) {
615 if (limit) {
616 UpdatePairResValue(pairResId,
617 resStatusInfo_[resId]->candidate, resId, resStatusInfo_[resId]->candidate);
618 } else {
619 UpdatePairResValue(pairResId,
620 resStatusInfo_[pairResId]->candidate, resId, resStatusInfo_[pairResId]->candidate);
621 }
622 } else {
623 UpdatePairResValue(pairResId,
624 resStatusInfo_[pairResId]->candidate, resId, resStatusInfo_[resId]->candidate);
625 }
626 } else {
627 if (resStatusInfo_[resId]->candidate > resStatusInfo_[pairResId]->candidate) {
628 if (limit) {
629 UpdatePairResValue(resId,
630 resStatusInfo_[pairResId]->candidate, pairResId, resStatusInfo_[pairResId]->candidate);
631 } else {
632 UpdatePairResValue(resId,
633 resStatusInfo_[resId]->candidate, pairResId, resStatusInfo_[resId]->candidate);
634 }
635 } else {
636 UpdatePairResValue(resId,
637 resStatusInfo_[resId]->candidate, pairResId, resStatusInfo_[pairResId]->candidate);
638 }
639 }
640 }
641
UpdatePairResValue(int32_t minResId,int64_t minResValue,int32_t maxResId,int64_t maxResValue)642 void SocPerfThreadWrap::UpdatePairResValue(int32_t minResId, int64_t minResValue, int32_t maxResId,
643 int64_t maxResValue)
644 {
645 UpdateCurrentValue(minResId, minResValue);
646 UpdateCurrentValue(maxResId, maxResValue);
647 }
648
UpdateCurrentValue(int32_t resId,int64_t currValue)649 void SocPerfThreadWrap::UpdateCurrentValue(int32_t resId, int64_t currValue)
650 {
651 resStatusInfo_[resId]->currentValue = currValue;
652 }
653
ExistNoCandidate(int32_t resId,std::shared_ptr<ResStatus> resStatus)654 bool SocPerfThreadWrap::ExistNoCandidate(int32_t resId, std::shared_ptr<ResStatus> resStatus)
655 {
656 int64_t perfCandidate = resStatus->candidatesValue[ACTION_TYPE_PERF];
657 int64_t powerCandidate = resStatus->candidatesValue[ACTION_TYPE_POWER];
658 int64_t thermalCandidate = resStatus->candidatesValue[ACTION_TYPE_THERMAL];
659 int64_t perfLvlCandidate = resStatus->candidatesValue[ACTION_TYPE_PERFLVL];
660 if (perfCandidate == INVALID_VALUE && powerCandidate == INVALID_VALUE && thermalCandidate == INVALID_VALUE
661 && perfLvlCandidate == INVALID_VALUE) {
662 resStatus->candidate = NODE_DEFAULT_VALUE;
663 resStatus->currentEndTime = MAX_INT_VALUE;
664 ArbitratePairRes(resId, false);
665 return true;
666 }
667 return false;
668 }
669 } // namespace SOCPERF
670 } // namespace OHOS
671