1 /*
2  * Copyright (c) 2023-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 "cpu_calculator.h"
16 
17 #include <cinttypes>
18 
19 #include "file_util.h"
20 #include "hiview_logger.h"
21 #include "string_util.h"
22 
23 namespace OHOS {
24 namespace HiviewDFX {
25 namespace UCollectUtil {
26 DEFINE_LOG_TAG("UCollectUtil-CpuCalculator");
27 namespace {
CalcSysCpuTotalTime(const CpuTimeInfo & cpuTimeInfo)28 uint32_t CalcSysCpuTotalTime(const CpuTimeInfo& cpuTimeInfo)
29 {
30     return cpuTimeInfo.userTime + cpuTimeInfo.niceTime + cpuTimeInfo.systemTime + cpuTimeInfo.idleTime
31         + cpuTimeInfo.ioWaitTime + cpuTimeInfo.irqTime + cpuTimeInfo.softIrqTime;
32 }
33 
CalcSysCpuUsage(uint32_t deltaTime,uint32_t currTime,uint32_t lastTime)34 double CalcSysCpuUsage(uint32_t deltaTime, uint32_t currTime, uint32_t lastTime)
35 {
36     return currTime <= lastTime ?  0 : (((currTime - lastTime) * 1.0) / deltaTime);
37 }
38 }
39 
CpuCalculator()40 CpuCalculator::CpuCalculator()
41 {
42     InitNumOfCpuCores();
43     InitCpuDmipses();
44     InitMaxCpuLoadUnit();
45 }
46 
InitNumOfCpuCores()47 void CpuCalculator::InitNumOfCpuCores()
48 {
49     numOfCpuCores_ = CpuUtil::GetNumOfCpuCores();
50 }
51 
InitCpuDmipses()52 void CpuCalculator::InitCpuDmipses()
53 {
54     for (uint32_t i = 0; i < numOfCpuCores_; i++) {
55         std::string cpuCapacityFilePath = SYS_CPU_DIR_PREFIX + std::to_string(i) + "/cpu_capacity";
56         std::string cpuCapacityFileContent = FileUtil::GetFirstLine(cpuCapacityFilePath);
57         if (cpuCapacityFileContent.empty()) {
58             HIVIEW_LOGE("failed to get cpu capacity content from file=%{public}s", cpuCapacityFileContent.c_str());
59             return;
60         }
61         uint32_t dmipse = StringUtil::StringToUl(cpuCapacityFileContent);
62         cpuDmipses_.emplace_back(dmipse);
63         HIVIEW_LOGD("get cpu=%{public}u capacity value=%{public}u", i, dmipse);
64     }
65 }
66 
InitMaxCpuLoadUnit()67 void CpuCalculator::InitMaxCpuLoadUnit()
68 {
69     maxCpuLoadUnit_ = IsSMTEnabled() ? GetMaxStCpuLoadWithSMT() : GetMaxStCpuLoad();
70     HIVIEW_LOGD("init max cpu load unit=%{public}" PRIu64, maxCpuLoadUnit_);
71 }
72 
IsSMTEnabled()73 bool CpuCalculator::IsSMTEnabled()
74 {
75     constexpr uint32_t numOfCpuCoresWithSMT = 12;
76     return numOfCpuCores_ == numOfCpuCoresWithSMT;
77 }
78 
GetMaxStCpuLoad()79 uint64_t CpuCalculator::GetMaxStCpuLoad()
80 {
81     uint64_t maxStCpuLoadSum = 0;
82     for (uint32_t cpuCoreIndex = 0; cpuCoreIndex < numOfCpuCores_; cpuCoreIndex++) {
83         if (cpuCoreIndex >= cpuDmipses_.size()) {
84             HIVIEW_LOGW("failed to get max st load from cpu=%{public}u", cpuCoreIndex);
85             continue;
86         }
87         maxStCpuLoadSum += cpuDmipses_[cpuCoreIndex];
88     }
89     return maxStCpuLoadSum;
90 }
91 
GetMaxStCpuLoadWithSMT()92 uint64_t CpuCalculator::GetMaxStCpuLoadWithSMT()
93 {
94     uint64_t maxStCpuLoadSum = 0;
95     for (uint32_t cpuCoreIndex = 0; cpuCoreIndex < numOfCpuCores_; cpuCoreIndex++) {
96         if (cpuCoreIndex >= cpuDmipses_.size()) {
97             HIVIEW_LOGW("failed to get max st load with smt from cpu=%{public}u", cpuCoreIndex);
98             continue;
99         }
100         uint32_t tmpDmipse = cpuDmipses_[cpuCoreIndex];
101         constexpr uint32_t maxIndexOfSmallCore = 3; // small cores do not support smt
102         if (cpuCoreIndex > maxIndexOfSmallCore) {
103             constexpr uint32_t capDiscount = 65;
104             tmpDmipse = tmpDmipse * capDiscount / 100; // 100: %
105         }
106         maxStCpuLoadSum += tmpDmipse;
107     }
108     return maxStCpuLoadSum;
109 }
110 
CalculateCpuLoad(uint64_t currCpuLoad,uint64_t lastCpuLoad,uint64_t statPeriod)111 double CpuCalculator::CalculateCpuLoad(uint64_t currCpuLoad, uint64_t lastCpuLoad, uint64_t statPeriod)
112 {
113     if (lastCpuLoad > currCpuLoad || statPeriod == 0) {
114         HIVIEW_LOGW("invalid params, currCpuLoad=%{public}" PRIu64 ", lastCpuLoad=%{public}" PRIu64
115             ", statPeriod=%{public}" PRIu64, currCpuLoad, lastCpuLoad, statPeriod);
116         return 0;
117     }
118     if (maxCpuLoadUnit_ == 0) {
119         HIVIEW_LOGW("invalid num of max cpu load unit");
120         return 0;
121     }
122     uint64_t maxCpuLoadOfSystemInStatPeriod = statPeriod * maxCpuLoadUnit_;
123     uint64_t cpuLoadInStatPeriod = currCpuLoad - lastCpuLoad;
124     return ((cpuLoadInStatPeriod * 1.0) / maxCpuLoadOfSystemInStatPeriod);
125 }
126 
CalculateCpuUsage(uint64_t currCpuUsage,uint64_t lastCpuUsage,uint64_t statPeriod)127 double CpuCalculator::CalculateCpuUsage(uint64_t currCpuUsage, uint64_t lastCpuUsage, uint64_t statPeriod)
128 {
129     if (lastCpuUsage > currCpuUsage || statPeriod == 0) {
130         HIVIEW_LOGW("invalid params, currCpuUsage=%{public}" PRIu64 ", lastCpuUsage=%{public}" PRIu64
131             ", statPeriod=%{public}" PRIu64, currCpuUsage, lastCpuUsage, statPeriod);
132         return 0;
133     }
134     if (numOfCpuCores_ == 0) {
135         HIVIEW_LOGW("invalid num of cpu cores");
136         return 0;
137     }
138     uint64_t cpuUsageInStatPeriod = currCpuUsage - lastCpuUsage;
139     uint64_t totalCpuUsageOfSystemInStatPeriod = statPeriod * numOfCpuCores_;
140     return ((cpuUsageInStatPeriod * 1.0) / totalCpuUsageOfSystemInStatPeriod);
141 }
142 
CalculateSysCpuUsageInfo(const CpuTimeInfo & currCpuTimeInfo,const CpuTimeInfo & lastCpuTimeInfo)143 CpuUsageInfo CpuCalculator::CalculateSysCpuUsageInfo(const CpuTimeInfo& currCpuTimeInfo,
144     const CpuTimeInfo& lastCpuTimeInfo)
145 {
146     CpuUsageInfo calcInfo;
147     calcInfo.cpuId = currCpuTimeInfo.cpuId;
148     uint32_t currTotalTime = CalcSysCpuTotalTime(currCpuTimeInfo);
149     uint32_t lastTotalTime = CalcSysCpuTotalTime(lastCpuTimeInfo);
150     if (currTotalTime <= lastTotalTime) {
151         return calcInfo;
152     }
153 
154     uint32_t deltaTime = currTotalTime - lastTotalTime;
155     calcInfo.userUsage = CalcSysCpuUsage(deltaTime, currCpuTimeInfo.userTime, lastCpuTimeInfo.userTime);
156     calcInfo.niceUsage = CalcSysCpuUsage(deltaTime, currCpuTimeInfo.niceTime, lastCpuTimeInfo.niceTime);
157     calcInfo.systemUsage = CalcSysCpuUsage(deltaTime, currCpuTimeInfo.systemTime, lastCpuTimeInfo.systemTime);
158     calcInfo.idleUsage = CalcSysCpuUsage(deltaTime, currCpuTimeInfo.idleTime, lastCpuTimeInfo.idleTime);
159     calcInfo.ioWaitUsage = CalcSysCpuUsage(deltaTime, currCpuTimeInfo.ioWaitTime, lastCpuTimeInfo.ioWaitTime);
160     calcInfo.irqUsage = CalcSysCpuUsage(deltaTime, currCpuTimeInfo.irqTime, lastCpuTimeInfo.irqTime);
161     calcInfo.softIrqUsage = CalcSysCpuUsage(deltaTime, currCpuTimeInfo.softIrqTime, lastCpuTimeInfo.softIrqTime);
162     return calcInfo;
163 }
164 
GetCpuDmipses()165 std::vector<uint32_t> CpuCalculator::GetCpuDmipses()
166 {
167     return cpuDmipses_;
168 }
169 } // UCollectUtil
170 } // HiViewDFX
171 } // OHOS
172