• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "util/dump_cpu_info_util.h"
16 #include <dirent.h>
17 #include <unistd.h>
18 #include <chrono>
19 #include <mutex>
20 #include "string_ex.h"
21 #include "hilog_wrapper.h"
22 #include "datetime_ex.h"
23 #include "util/file_utils.h"
24 
25 namespace OHOS {
26 namespace HiviewDFX {
27 const std::string DumpCpuInfoUtil::PROC_STAT_PATH = "/proc/stat";
28 const std::string DumpCpuInfoUtil::SPACE = " ";
29 const int DumpCpuInfoUtil::TM_START_YEAR = 1900;
30 const int DumpCpuInfoUtil::DEC_SYSTEM_VALUE = 10;
31 
DumpCpuInfoUtil()32 DumpCpuInfoUtil::DumpCpuInfoUtil()
33 {
34     DUMPER_HILOGD(MODULE_COMMON, "create debug|");
35     curCPUInfo_ = std::make_shared<CPUInfo>();
36     oldCPUInfo_ = std::make_shared<CPUInfo>();
37 }
38 
~DumpCpuInfoUtil()39 DumpCpuInfoUtil::~DumpCpuInfoUtil()
40 {
41     DUMPER_HILOGD(MODULE_COMMON, "release debug|");
42     curCPUInfo_.reset();
43     oldCPUInfo_.reset();
44     curProcs_.clear();
45     oldProcs_.clear();
46 }
47 
UpdateCpuInfo()48 void DumpCpuInfoUtil::UpdateCpuInfo()
49 {
50     DUMPER_HILOGI(MODULE_COMMON, "UpdateCpuInfo debug|enter");
51     static std::mutex mutexUpdateCpu;
52     std::unique_lock<std::mutex> lock(mutexUpdateCpu);
53     CopyCpuInfo(oldCPUInfo_, curCPUInfo_);
54     GetCurCPUInfo(curCPUInfo_);
55     oldProcs_.assign(curProcs_.begin(), curProcs_.end());
56     GetCurProcInfo(curProcs_);
57     GetDateAndTime(startTime_);
58     DUMPER_HILOGI(MODULE_COMMON, "UpdateCpuInfo debug|exit");
59 }
60 
GetCurCPUInfo(std::shared_ptr<CPUInfo> & cpuInfo)61 bool DumpCpuInfoUtil::GetCurCPUInfo(std::shared_ptr<CPUInfo> &cpuInfo)
62 {
63     if (cpuInfo == nullptr) {
64         return false;
65     }
66     std::string statRawData;
67     auto& fileInstance = FileUtils::GetInstance();
68     bool ret = fileInstance.LoadStringFromProcCb(PROC_STAT_PATH, false, false, [&](const std::string& line) -> void {
69         statRawData += line;
70     });
71     if (!ret) {
72         return false;
73     }
74     size_t pos = statRawData.find_first_of("\n");
75     if (pos == std::string::npos) {
76         return false;
77     }
78 
79     statRawData = statRawData.substr(0, pos);
80     std::vector<std::string> cpuStates;
81     SplitStr(statRawData, SPACE, cpuStates);
82     if (cpuStates.size() <= static_cast<size_t>(CPU_STAT_SIRQ_TIME_INDEX)) {
83         return false;
84     }
85 
86     SetCPUInfo(cpuInfo->uTime, cpuStates[CPU_STAT_USER_TIME_INDEX]);
87     SetCPUInfo(cpuInfo->nTime, cpuStates[CPU_STAT_NICE_TIME_INDEX]);
88     SetCPUInfo(cpuInfo->sTime, cpuStates[CPU_STAT_SYS_TIME_INDEX]);
89     SetCPUInfo(cpuInfo->iTime, cpuStates[CPU_STAT_IDLE_TIME_INDEX]);
90     SetCPUInfo(cpuInfo->iowTime, cpuStates[CPU_STAT_IOW_TIME_INDEX]);
91     SetCPUInfo(cpuInfo->irqTime, cpuStates[CPU_STAT_IRQ_TIME_INDEX]);
92     SetCPUInfo(cpuInfo->sirqTime, cpuStates[CPU_STAT_SIRQ_TIME_INDEX]);
93     return true;
94 }
95 
SetCPUInfo(long unsigned & info,const std::string & strInfo)96 void DumpCpuInfoUtil::SetCPUInfo(long unsigned &info, const std::string &strInfo)
97 {
98     if (IsNumericStr(strInfo)) {
99         const int base = CONSTANT_NUM_10;
100         info = strtoul(strInfo.c_str(), nullptr, base);
101     } else {
102         info = 0;
103     }
104 }
105 
GetCurProcInfo(std::vector<std::shared_ptr<ProcInfo>> & procInfos)106 bool DumpCpuInfoUtil::GetCurProcInfo(std::vector<std::shared_ptr<ProcInfo>> &procInfos)
107 {
108     std::vector<std::string> procFiles;
109     GetProcessDirFiles("/proc", "stat", procFiles);
110     if (procFiles.size() < 1) {
111         return false;
112     }
113     // Set procInfos size 0
114     procInfos.clear();
115     auto& fileInstance = FileUtils::GetInstance();
116     for (size_t i = 0; i < procFiles.size(); i++) {
117         std::string rawData;
118         bool ret = fileInstance.LoadStringFromProcCb(procFiles[i], false, false, [&](const std::string& line) -> void {
119             rawData += line;
120         });
121         if (!ret) {
122             continue;
123         }
124 
125         // Get comm name, (xxx) in stat file.
126         std::vector<std::string> comms;
127         GetSubStrBetween(rawData, "(", ")", comms);
128         if (comms.empty()) {
129             continue;
130         }
131 
132         /**
133          * @brief (xxx xxx xx) contain ' ' will effect function SplitStr,
134          * there will be wrong string for infos, so replace '()' instead of (xxx xxx xx)
135          */
136         rawData = ReplaceStr(rawData, comms[0], "()");
137         std::vector<std::string> procInfosStr;
138         SplitStr(rawData, SPACE, procInfosStr);
139         if (procInfosStr.size() <= static_cast<size_t>(PROC_INFO_SYS_TIME_INDEX)) {
140             continue;
141         }
142 
143         std::shared_ptr<ProcInfo> ptrProcInfo = std::make_shared<ProcInfo>();
144         ptrProcInfo->comm = comms[0];
145         ptrProcInfo->pid = procInfosStr[0];
146         SetCPUInfo(ptrProcInfo->uTime, procInfosStr[PROC_INFO_USER_TIME_INDEX]);
147         SetCPUInfo(ptrProcInfo->sTime, procInfosStr[PROC_INFO_SYS_TIME_INDEX]);
148         ptrProcInfo->minflt = procInfosStr[PROC_INFO_MINOR_FAULT_INDEX];
149         ptrProcInfo->majflt = procInfosStr[PROC_INFO_MAJOR_FAULT_INDEX];
150         procInfos.push_back(ptrProcInfo);
151     }
152     return true;
153 }
154 
GetProcessDirFiles(const std::string & path,const std::string & file,std::vector<std::string> & files)155 void DumpCpuInfoUtil::GetProcessDirFiles(const std::string &path, const std::string &file,
156     std::vector<std::string> &files)
157 {
158     DIR *dir = opendir(path.c_str());
159     if (dir == nullptr) {
160         return;
161     }
162 
163     while (true) {
164         struct dirent *pidDir = readdir(dir);
165         if (pidDir == nullptr) {
166             break;
167         }
168 
169         if (!IsNumericStr(std::string(pidDir->d_name))) {
170             continue;
171         }
172 
173         std::string filePath(path + "/" + std::string(pidDir->d_name) + "/" + file);
174         files.push_back(std::move(filePath));
175     }
176     closedir(dir);
177 }
178 
GetCurSpecProcInfo(int pid,std::shared_ptr<ProcInfo> & specProc)179 bool DumpCpuInfoUtil::GetCurSpecProcInfo(int pid, std::shared_ptr<ProcInfo> &specProc)
180 {
181     if (specProc == nullptr) {
182         return false;
183     }
184 
185     std::string path = "/proc/" + std::to_string(pid) + "/stat";
186     std::string rawData;
187     bool ret = FileUtils::GetInstance().LoadStringFromProcCb(path, false, false, [&](const std::string& line) -> void {
188         rawData += line;
189     });
190     if (!ret) {
191         return false;
192     }
193 
194     // Get comm name, (xxx) in stat file.
195     std::vector<std::string> comms;
196     GetSubStrBetween(rawData, "(", ")", comms);
197     if (comms.empty()) {
198         return false;
199     }
200 
201     /**
202      * @brief (xxx xxx xx) contain ' ' will effect function SplitStr,
203      * there will be wrong string for infos, so replace '()' instead of (xxx xxx xx)
204      */
205     rawData = ReplaceStr(rawData, comms[0], "()");
206     std::vector<std::string> procInfosStr;
207     SplitStr(rawData, SPACE, procInfosStr);
208     if (procInfosStr.size() <= static_cast<size_t>(PROC_INFO_SYS_TIME_INDEX)) {
209         return false;
210     }
211 
212     specProc->comm = comms[0];
213     specProc->pid = procInfosStr[0];
214     SetCPUInfo(specProc->uTime, procInfosStr[PROC_INFO_USER_TIME_INDEX]);
215     SetCPUInfo(specProc->sTime, procInfosStr[PROC_INFO_SYS_TIME_INDEX]);
216     specProc->minflt = procInfosStr[PROC_INFO_MINOR_FAULT_INDEX];
217     specProc->majflt = procInfosStr[PROC_INFO_MAJOR_FAULT_INDEX];
218     return true;
219 }
220 
GetOldCPUInfo(std::shared_ptr<CPUInfo> & cpuInfo)221 bool DumpCpuInfoUtil::GetOldCPUInfo(std::shared_ptr<CPUInfo> &cpuInfo)
222 {
223     if (!CheckFrequentDumpping()) {
224         CopyCpuInfo(cpuInfo, curCPUInfo_);
225     } else {
226         CopyCpuInfo(cpuInfo, oldCPUInfo_);
227     }
228     return true;
229 }
230 
GetOldProcInfo(std::vector<std::shared_ptr<ProcInfo>> & procInfos)231 bool DumpCpuInfoUtil::GetOldProcInfo(std::vector<std::shared_ptr<ProcInfo>> &procInfos)
232 {
233     if (!CheckFrequentDumpping()) {
234         procInfos.assign(curProcs_.begin(), curProcs_.end());
235     } else {
236         procInfos.assign(oldProcs_.begin(), oldProcs_.end());
237     }
238     return true;
239 }
240 
GetOldSpecProcInfo(int pid,std::shared_ptr<ProcInfo> & specProc)241 bool DumpCpuInfoUtil::GetOldSpecProcInfo(int pid, std::shared_ptr<ProcInfo> &specProc)
242 {
243     if (!CheckFrequentDumpping()) {
244         for (size_t i = 0; i < curProcs_.size(); i++) {
245             if (curProcs_[i] == nullptr) {
246                 continue;
247             }
248             if (!IsNumericStr(curProcs_[i]->pid)) {
249                 return false;
250             }
251             int specPid = 0;
252             if (!StrToInt(curProcs_[i]->pid, specPid)) {
253                 return false;
254             }
255             if (pid == specPid) {
256                 CopyProcInfo(specProc, curProcs_[i]);
257                 return true;
258             }
259         }
260     } else {
261         for (size_t i = 0; i < oldProcs_.size(); i++) {
262             if (oldProcs_[i] == nullptr) {
263                 continue;
264             }
265             if (!IsNumericStr(oldProcs_[i]->pid)) {
266                 return false;
267             }
268             int specPid = 0;
269             if (!StrToInt(oldProcs_[i]->pid, specPid)) {
270                 return false;
271             }
272             if (pid == specPid) {
273                 CopyProcInfo(specProc, oldProcs_[i]);
274                 return true;
275             }
276         }
277     }
278     return false;
279 }
280 
CopyCpuInfo(std::shared_ptr<CPUInfo> & tar,const std::shared_ptr<CPUInfo> & source)281 void DumpCpuInfoUtil::CopyCpuInfo(std::shared_ptr<CPUInfo> &tar, const std::shared_ptr<CPUInfo> &source)
282 {
283     if ((tar == nullptr) || (source == nullptr)) {
284         return;
285     }
286 
287     tar->uTime = source->uTime;
288     tar->nTime = source->nTime;
289     tar->sTime = source->sTime;
290     tar->iTime = source->iTime;
291     tar->iowTime = source->iowTime;
292     tar->irqTime = source->irqTime;
293     tar->sirqTime = source->sirqTime;
294 }
295 
CopyProcInfo(std::shared_ptr<ProcInfo> & tar,const std::shared_ptr<ProcInfo> & source)296 void DumpCpuInfoUtil::CopyProcInfo(std::shared_ptr<ProcInfo> &tar, const std::shared_ptr<ProcInfo> &source)
297 {
298     if ((tar == nullptr) || (source == nullptr)) {
299         return;
300     }
301 
302     tar->pid = source->pid;
303     tar->comm = source->comm;
304     tar->uTime = source->uTime;
305     tar->sTime = source->sTime;
306     tar->minflt = source->minflt;
307     tar->majflt = source->majflt;
308 }
309 
CheckFrequentDumpping()310 bool DumpCpuInfoUtil::CheckFrequentDumpping()
311 {
312     time_t curTime;
313     struct tm ptrCurtime = {0};
314     (void)time(&curTime);
315     gmtime_r(&curTime, &ptrCurtime);
316     int interval = ptrCurtime.tm_sec - dumpTimeSec_;
317     if (interval > 0 && interval < DUMP_TIME_INTERVAL) {
318         return true;
319     }
320     dumpTimeSec_ = ptrCurtime.tm_sec;
321     return false;
322 }
323 
IsNeedRefreshCpu()324 bool DumpCpuInfoUtil::IsNeedRefreshCpu()
325 {
326     std::chrono::milliseconds ms = std::chrono::duration_cast< std::chrono::milliseconds >(
327         std::chrono::system_clock::now().time_since_epoch());
328     if (lastCpuTimeMs_ > 0 && (ms.count() - lastCpuTimeMs_) < CUP_REFRESH_MIN_TIME) {
329         return true;
330     }
331     lastCpuTimeMs_ = ms.count();
332     return false;
333 }
334 
GetCpuUsage(const int pid)335 float DumpCpuInfoUtil::GetCpuUsage(const int pid)
336 {
337     std::shared_ptr<CPUInfo> oldCPUInfo = std::make_shared<CPUInfo>();
338     if (!GetCurCPUInfo(oldCPUInfo)) {
339         return false;
340     }
341     std::shared_ptr<ProcInfo> oldSpecProc = std::make_shared<ProcInfo>();
342     if (!GetCurSpecProcInfo(pid, oldSpecProc)) {
343         return false;
344     }
345 
346     sleep(1);
347 
348     std::shared_ptr<CPUInfo> curCPUInfo = std::make_shared<CPUInfo>();
349     if (!GetCurCPUInfo(curCPUInfo)) {
350         return false;
351     }
352     std::shared_ptr<ProcInfo> curSpecProc = std::make_shared<ProcInfo>();
353     if (!GetCurSpecProcInfo(pid, curSpecProc)) {
354         return false;
355     }
356 
357     long unsigned totalDeltaTime = (curCPUInfo->uTime + curCPUInfo->nTime + curCPUInfo->sTime + curCPUInfo->iTime
358                                     + curCPUInfo->iowTime + curCPUInfo->irqTime + curCPUInfo->sirqTime)
359                                    - (oldCPUInfo->uTime + oldCPUInfo->nTime + oldCPUInfo->sTime + oldCPUInfo->iTime
360                                       + oldCPUInfo->iowTime + oldCPUInfo->irqTime + oldCPUInfo->sirqTime);
361 
362     if (totalDeltaTime != 0) {
363         float cpuUsage = static_cast<float>((curSpecProc->uTime - oldSpecProc->uTime)
364                + (curSpecProc->sTime - oldSpecProc->sTime)) / static_cast<float>(totalDeltaTime);
365         return cpuUsage;
366     } else {
367         return 0;
368     }
369 }
370 
GetUpdateCpuStartTime(std::string & dateTime)371 void DumpCpuInfoUtil::GetUpdateCpuStartTime(std::string& dateTime)
372 {
373     dateTime = startTime_;
374 }
375 
GetDateAndTime(std::string & dateTime)376 bool DumpCpuInfoUtil::GetDateAndTime(std::string &dateTime)
377 {
378     struct tm timeData = {0};
379     if (!GetSystemCurrentTime(&timeData)) {
380         return false;
381     }
382 
383     dateTime = " ";
384     dateTime.append(std::to_string(TM_START_YEAR + timeData.tm_year));
385     dateTime.append("-");
386     if (1 + timeData.tm_mon < DEC_SYSTEM_VALUE) {
387         dateTime.append(std::to_string(0));
388     }
389     dateTime.append(std::to_string(1 + timeData.tm_mon));
390     dateTime.append("-");
391     if (timeData.tm_mday < DEC_SYSTEM_VALUE) {
392         dateTime.append(std::to_string(0));
393     }
394     dateTime.append(std::to_string(timeData.tm_mday));
395     dateTime.append(" ");
396     if (timeData.tm_hour < DEC_SYSTEM_VALUE) {
397         dateTime.append(std::to_string(0));
398     }
399     dateTime.append(std::to_string(timeData.tm_hour));
400     dateTime.append(":");
401     if (timeData.tm_min < DEC_SYSTEM_VALUE) {
402         dateTime.append(std::to_string(0));
403     }
404     dateTime.append(std::to_string(timeData.tm_min));
405     dateTime.append(":");
406     if (timeData.tm_sec < DEC_SYSTEM_VALUE) {
407         dateTime.append(std::to_string(0));
408     }
409     dateTime.append(std::to_string(timeData.tm_sec));
410     return true;
411 }
412 
413 } // namespace HiviewDFX
414 } // namespace OHOS
415