1 /*
2 * Copyright (C) 2023 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_util.h"
16
17 #include "file_util.h"
18 #include "hiview_logger.h"
19 #include "string_util.h"
20
21 namespace OHOS {
22 namespace HiviewDFX {
23 namespace UCollectUtil {
24 DEFINE_LOG_TAG("UCollectUtil-CpuUtil");
25 namespace {
GetIntegerFromFile(const std::string & path)26 uint32_t GetIntegerFromFile(const std::string& path)
27 {
28 std::string content = FileUtil::GetFirstLine(path);
29 if (content.empty()) {
30 HIVIEW_LOGW("failed to get content from file=%{public}s", path.c_str());
31 return 0;
32 }
33 return StringUtil::StringToUl(content);
34 }
35
GetCpuUsageInfoFromString(const std::string & cpuInfoStr,CpuTimeInfo & cpuInfo)36 bool GetCpuUsageInfoFromString(const std::string& cpuInfoStr, CpuTimeInfo& cpuInfo)
37 {
38 std::vector<std::string> splitStrs;
39 StringUtil::SplitStr(cpuInfoStr, " ", splitStrs);
40 constexpr size_t cpuInfoSize = 11; // cpu user nice ...
41 if (splitStrs.size() != cpuInfoSize) {
42 return false;
43 }
44 size_t parseIndex = 0;
45 if (splitStrs[parseIndex].find("cpu") != 0) {
46 return false;
47 }
48 cpuInfo.cpuId = splitStrs[parseIndex++];
49 cpuInfo.userTime = StringUtil::StringToUl(splitStrs[parseIndex++]);
50 cpuInfo.niceTime = StringUtil::StringToUl(splitStrs[parseIndex++]);
51 cpuInfo.systemTime = StringUtil::StringToUl(splitStrs[parseIndex++]);
52 cpuInfo.idleTime = StringUtil::StringToUl(splitStrs[parseIndex++]);
53 cpuInfo.ioWaitTime = StringUtil::StringToUl(splitStrs[parseIndex++]);
54 cpuInfo.irqTime = StringUtil::StringToUl(splitStrs[parseIndex++]);
55 cpuInfo.softIrqTime = StringUtil::StringToUl(splitStrs[parseIndex++]);
56 return true;
57 }
58 }
59
GetNumOfCpuCores()60 uint32_t CpuUtil::GetNumOfCpuCores()
61 {
62 uint32_t numOfCpuCores = 0;
63 const std::string cpuCoresFilePath = "/sys/devices/system/cpu/possible";
64 std::string cpuCoresFileFirstLine = FileUtil::GetFirstLine(cpuCoresFilePath);
65 if (cpuCoresFileFirstLine.empty()) {
66 HIVIEW_LOGW("failed to get cpu cores content from file=%{public}s", cpuCoresFilePath.c_str());
67 } else if (cpuCoresFileFirstLine.length() == 1) { // 1: '0'
68 constexpr uint32_t singleCpuCores = 1;
69 numOfCpuCores = singleCpuCores;
70 } else if (cpuCoresFileFirstLine.length() >= 3) { // 3: '0-7' '0-11'
71 constexpr uint32_t maxCoreIndex = 2; // 2: next char of '0-'
72 numOfCpuCores = StringUtil::StringToUl(cpuCoresFileFirstLine.substr(maxCoreIndex)) + 1; // 1 for real num
73 } else {
74 HIVIEW_LOGW("invalid cpu cores content=%{public}s", cpuCoresFileFirstLine.c_str());
75 }
76 return numOfCpuCores;
77 }
78
GetSysCpuLoad(SysCpuLoad & sysCpuLoad)79 UCollect::UcError CpuUtil::GetSysCpuLoad(SysCpuLoad& sysCpuLoad)
80 {
81 const std::string procLoadAvgPath = "/proc/loadavg";
82 std::string loadContent = FileUtil::GetFirstLine(procLoadAvgPath);
83 if (loadContent.empty()) {
84 HIVIEW_LOGW("failed to read %{public}s", procLoadAvgPath.c_str());
85 return UCollect::READ_FAILED;
86 }
87 std::vector<std::string> loadStrs;
88 StringUtil::SplitStr(loadContent, " ", loadStrs);
89 constexpr size_t loadStrSize = 5; // lavg_1 lavg_5 lavg_15 nr_running/nr_threads last_pid
90 if (loadStrs.size() != loadStrSize) {
91 HIVIEW_LOGW("failed to parse content=%{public}s", loadContent.c_str());
92 return UCollect::READ_FAILED;
93 }
94 sysCpuLoad.avgLoad1 = StringUtil::StringToDouble(loadStrs[0]); // 0: lavg_1
95 sysCpuLoad.avgLoad5 = StringUtil::StringToDouble(loadStrs[1]); // 1: lavg_5
96 sysCpuLoad.avgLoad15 = StringUtil::StringToDouble(loadStrs[2]); // 2: lavg_15
97 return UCollect::SUCCESS;
98 }
99
GetCpuTimeInfos(std::vector<CpuTimeInfo> & cpuInfos)100 UCollect::UcError CpuUtil::GetCpuTimeInfos(std::vector<CpuTimeInfo>& cpuInfos)
101 {
102 const std::string procStatPath = "/proc/stat";
103 std::vector<std::string> lines;
104 if (!FileUtil::LoadLinesFromFile(procStatPath, lines) || lines.empty()) {
105 HIVIEW_LOGW("failed to read %{public}s", procStatPath.c_str());
106 return UCollect::READ_FAILED;
107 }
108 for (const auto& line : lines) {
109 CpuTimeInfo cpuInfo;
110 if (!GetCpuUsageInfoFromString(line, cpuInfo)) {
111 break; // if the current line fails, all cpu info has been read.
112 }
113 cpuInfos.emplace_back(cpuInfo);
114 }
115 HIVIEW_LOGD("get cpu usage info, size=%{public}zu", cpuInfos.size());
116 return UCollect::SUCCESS;
117 }
118
GetCpuFrequency(std::vector<CpuFreq> & cpuFreqs)119 UCollect::UcError CpuUtil::GetCpuFrequency(std::vector<CpuFreq>& cpuFreqs)
120 {
121 uint32_t numOfCpuCores = GetNumOfCpuCores();
122 if (numOfCpuCores == 0) {
123 return UCollect::READ_FAILED;
124 }
125 for (uint32_t i = 0; i < numOfCpuCores; ++i) {
126 std::string cpuCurFreqPath = SYS_CPU_DIR_PREFIX + std::to_string(i) + "/cpufreq/scaling_cur_freq";
127 std::string cpuMinFreqPath = SYS_CPU_DIR_PREFIX + std::to_string(i) + "/cpufreq/scaling_min_freq";
128 std::string cpuMaxFreqPath = SYS_CPU_DIR_PREFIX + std::to_string(i) + "/cpufreq/scaling_max_freq";
129 CpuFreq cpuFreq = {
130 .cpuId = i,
131 .curFreq = GetIntegerFromFile(cpuCurFreqPath),
132 .minFreq = GetIntegerFromFile(cpuMinFreqPath),
133 .maxFreq = GetIntegerFromFile(cpuMaxFreqPath),
134 };
135 cpuFreqs.emplace_back(cpuFreq);
136 HIVIEW_LOGD("cpu%{public}u: curFreq=%{public}u, minFreq=%{public}u, maxFreq=%{public}u",
137 i, cpuFreq.cpuId, cpuFreq.minFreq, cpuFreq.maxFreq);
138 }
139 return UCollect::SUCCESS;
140 }
141 } // UCollectUtil
142 } // namespace HiviewDFX
143 } // namespace OHOS
144