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