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