• 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 <unistd.h>
16 #include "executor/cpu_dumper.h"
17 #include "file_ex.h"
18 #include "datetime_ex.h"
19 #include "dump_utils.h"
20 #include "securec.h"
21 #include "util/string_utils.h"
22 namespace OHOS {
23 namespace HiviewDFX {
24 const std::string CPUDumper::LOAD_AVG_FILE_PATH = "/proc/loadavg";
25 const size_t CPUDumper::LOAD_AVG_INFO_COUNT = 3;
26 const int CPUDumper::TM_START_YEAR = 1900;
27 const int CPUDumper::DEC_SYSTEM_VALUE = 10;
28 const int CPUDumper::PROC_CPU_LENGTH = 256;
29 const long unsigned CPUDumper::HUNDRED_PERCENT_VALUE = 100;
30 
CPUDumper()31 CPUDumper::CPUDumper()
32 {
33 }
34 
~CPUDumper()35 CPUDumper::~CPUDumper()
36 {
37 }
38 
PreExecute(const std::shared_ptr<DumperParameter> & parameter,StringMatrix dumpDatas)39 DumpStatus CPUDumper::PreExecute(const std::shared_ptr<DumperParameter> &parameter, StringMatrix dumpDatas)
40 {
41     DUMPER_HILOGD(MODULE_COMMON, "debug|CPUDumper PreExecute");
42     dumpCPUDatas_ = dumpDatas;
43     isDumpCpuUsage_ = (parameter->GetOpts()).isDumpCpuUsage_;
44     cpuUsagePid_ = (parameter->GetOpts()).cpuUsagePid_;
45     if (cpuUsagePid_ != -1) {
46         curSpecProc_ = std::make_shared<ProcInfo>();
47         oldSpecProc_ = std::make_shared<ProcInfo>();
48     }
49     curCPUInfo_ = std::make_shared<CPUInfo>();
50     oldCPUInfo_ = std::make_shared<CPUInfo>();
51     return DumpStatus::DUMP_OK;
52 }
53 
Execute()54 DumpStatus CPUDumper::Execute()
55 {
56     DUMPER_HILOGD(MODULE_COMMON, "debug|CPUDumper Execute");
57     DumpStatus ret = DumpStatus::DUMP_FAIL;
58     if (isDumpCpuUsage_) {
59         ret = DumpCpuUsageData();
60     } else {
61         return DumpStatus::DUMP_FAIL;
62     }
63     return ret;
64 }
65 
AfterExecute()66 DumpStatus CPUDumper::AfterExecute()
67 {
68     curCPUInfo_.reset();
69     oldCPUInfo_.reset();
70     curProcs_.clear();
71     oldProcs_.clear();
72     if (cpuUsagePid_ != -1) {
73         curSpecProc_.reset();
74         oldSpecProc_.reset();
75     }
76     return DumpStatus::DUMP_OK;
77 }
78 
DumpCpuUsageData()79 DumpStatus CPUDumper::DumpCpuUsageData()
80 {
81     GetDateAndTime(startTime_);
82     if (!DumpCpuInfoUtil::GetInstance().GetCurCPUInfo(curCPUInfo_)) {
83         DUMPER_HILOGE(MODULE_COMMON, "Get current cpu info failed!.");
84         return DumpStatus::DUMP_FAIL;
85     }
86     if (!DumpCpuInfoUtil::GetInstance().GetOldCPUInfo(oldCPUInfo_)) {
87         DUMPER_HILOGE(MODULE_COMMON, "Get old cpu info failed!.");
88         return DumpStatus::DUMP_FAIL;
89     }
90 
91     if (cpuUsagePid_ != -1) {
92         if (!GetProcCPUInfo()) {
93             return DumpStatus::DUMP_FAIL;
94         }
95     } else {
96         if (!DumpCpuInfoUtil::GetInstance().GetCurProcInfo(curProcs_)) {
97             DUMPER_HILOGE(MODULE_COMMON, "Get current process info failed!.");
98             return DumpStatus::DUMP_FAIL;
99         }
100         if (!DumpCpuInfoUtil::GetInstance().GetOldProcInfo(oldProcs_)) {
101             DUMPER_HILOGE(MODULE_COMMON, "Get old process info failed!.");
102             return DumpStatus::DUMP_FAIL;
103         }
104     }
105     std::string avgInfo;
106     DumpStatus ret = ReadLoadAvgInfo(LOAD_AVG_FILE_PATH, avgInfo);
107     if (ret != DumpStatus::DUMP_OK) {
108         DUMPER_HILOGD(MODULE_COMMON, "Get LoadAvgInfo failed!");
109         return DumpStatus::DUMP_FAIL;
110     }
111     AddStrLineToDumpInfo(avgInfo);
112 
113     GetDateAndTime(endTime_);
114     std::string dumpTimeStr;
115     CreateDumpTimeString(startTime_, endTime_, dumpTimeStr);
116     AddStrLineToDumpInfo(dumpTimeStr);
117 
118     std::string cpuStatStr;
119     CreateCPUStatString(cpuStatStr);
120     AddStrLineToDumpInfo(cpuStatStr);
121 
122     DumpProcInfo();
123     DumpCpuInfoUtil::GetInstance().UpdateCpuInfo();
124     return DumpStatus::DUMP_OK;
125 }
126 
GetProcCPUInfo()127 bool CPUDumper::GetProcCPUInfo()
128 {
129     bool ret = false;
130     if (!DumpCpuInfoUtil::GetInstance().GetOldSpecProcInfo(cpuUsagePid_, oldSpecProc_)) {
131         DumpCpuInfoUtil::GetInstance().UpdateCpuInfo();
132         if (!DumpCpuInfoUtil::GetInstance().GetOldSpecProcInfo(cpuUsagePid_, oldSpecProc_)) {
133             DUMPER_HILOGE(MODULE_COMMON, "Get old process %{public}d info failed!.", cpuUsagePid_);
134             return ret;
135         }
136 
137         GetInitOldCPUInfo(oldCPUInfo_, curCPUInfo_);
138         usleep(DELAY_VALUE);
139         if (!DumpCpuInfoUtil::GetInstance().GetCurCPUInfo(curCPUInfo_)) {
140             DUMPER_HILOGE(MODULE_COMMON, "Get current cpu info failed!.");
141             return ret;
142         }
143     }
144 
145     if (!DumpCpuInfoUtil::GetInstance().GetCurSpecProcInfo(cpuUsagePid_, curSpecProc_)) {
146         DUMPER_HILOGE(MODULE_COMMON, "Get current process %{public}d info failed!.", cpuUsagePid_);
147         return ret;
148     }
149     ret = true;
150     return ret;
151 }
152 
GetInitOldCPUInfo(std::shared_ptr<CPUInfo> tar,const std::shared_ptr<CPUInfo> source)153 void CPUDumper::GetInitOldCPUInfo(std::shared_ptr<CPUInfo> tar, const std::shared_ptr<CPUInfo> source)
154 {
155     if ((tar == nullptr) || (source == nullptr)) {
156         return;
157     }
158 
159     tar->uTime = source->uTime;
160     tar->nTime = source->nTime;
161     tar->sTime = source->sTime;
162     tar->iTime = source->iTime;
163     tar->iowTime = source->iowTime;
164     tar->irqTime = source->irqTime;
165     tar->sirqTime = source->sirqTime;
166 }
167 
ReadLoadAvgInfo(const std::string & filePath,std::string & info)168 DumpStatus CPUDumper::ReadLoadAvgInfo(const std::string &filePath, std::string &info)
169 {
170     if (!FileExists(filePath)) {
171         return DumpStatus::DUMP_FAIL;
172     }
173 
174     std::string rawData;
175     if (!LoadStringFromFile(filePath, rawData)) {
176         return DumpStatus::DUMP_FAIL;
177     }
178     DUMPER_HILOGD(MODULE_COMMON, "debug|rawData is %{public}s", rawData.c_str());
179     std::vector<std::string> vec;
180     SplitStr(rawData, DumpUtils::SPACE, vec);
181     info = "Load average:";
182     for (size_t i = 0; i < LOAD_AVG_INFO_COUNT; i++) {
183         info.append(" ");
184         info.append(vec[i]);
185         if (i == LOAD_AVG_INFO_COUNT - 1) {
186             info.append(";");
187         } else {
188             info.append(" /");
189         }
190     }
191     info.append(" the cpu load average in 1 min, 5 min and 15 min");
192     DUMPER_HILOGD(MODULE_COMMON, "debug|info is %{public}s", info.c_str());
193     return DumpStatus::DUMP_OK;
194 }
195 
GetDateAndTime(std::string & dateTime)196 bool CPUDumper::GetDateAndTime(std::string &dateTime)
197 {
198     struct tm timeData = {0};
199     if (!GetSystemCurrentTime(&timeData)) {
200         return false;
201     }
202 
203     dateTime = " ";
204     dateTime.append(std::to_string(TM_START_YEAR + timeData.tm_year));
205     dateTime.append("-");
206     if (1 + timeData.tm_mon < DEC_SYSTEM_VALUE) {
207         dateTime.append(std::to_string(0));
208     }
209     dateTime.append(std::to_string(1 + timeData.tm_mon));
210     dateTime.append("-");
211     if (timeData.tm_mday < DEC_SYSTEM_VALUE) {
212         dateTime.append(std::to_string(0));
213     }
214     dateTime.append(std::to_string(timeData.tm_mday));
215     dateTime.append(" ");
216     if (timeData.tm_hour < DEC_SYSTEM_VALUE) {
217         dateTime.append(std::to_string(0));
218     }
219     dateTime.append(std::to_string(timeData.tm_hour));
220     dateTime.append(":");
221     if (timeData.tm_min < DEC_SYSTEM_VALUE) {
222         dateTime.append(std::to_string(0));
223     }
224     dateTime.append(std::to_string(timeData.tm_min));
225     dateTime.append(":");
226     if (timeData.tm_sec < DEC_SYSTEM_VALUE) {
227         dateTime.append(std::to_string(0));
228     }
229     dateTime.append(std::to_string(timeData.tm_sec));
230     return true;
231 }
232 
CreateDumpTimeString(const std::string & startTime,const std::string & endTime,std::string & timeStr)233 void CPUDumper::CreateDumpTimeString(const std::string &startTime, const std::string &endTime, std::string &timeStr)
234 {
235     timeStr = "CPU usage from";
236     timeStr.append(startTime);
237     timeStr.append(" to");
238     timeStr.append(endTime);
239 }
240 
AddStrLineToDumpInfo(const std::string & strLine)241 void CPUDumper::AddStrLineToDumpInfo(const std::string &strLine)
242 {
243     std::vector<std::string> vec;
244     vec.push_back(strLine);
245     dumpCPUDatas_->push_back(vec);
246 }
247 
CreateCPUStatString(std::string & str)248 void CPUDumper::CreateCPUStatString(std::string &str)
249 {
250     long unsigned totalDeltaTime = (curCPUInfo_->uTime + curCPUInfo_->nTime + curCPUInfo_->sTime + curCPUInfo_->iTime
251                                     + curCPUInfo_->iowTime + curCPUInfo_->irqTime + curCPUInfo_->sirqTime)
252                                    - (oldCPUInfo_->uTime + oldCPUInfo_->nTime + oldCPUInfo_->sTime + oldCPUInfo_->iTime
253                                       + oldCPUInfo_->iowTime + oldCPUInfo_->irqTime + oldCPUInfo_->sirqTime);
254     if (cpuUsagePid_ != -1) {
255         curSpecProc_->userSpaceUsage =
256             (curSpecProc_->uTime - oldSpecProc_->uTime) * HUNDRED_PERCENT_VALUE / totalDeltaTime;
257         curSpecProc_->sysSpaceUsage =
258             (curSpecProc_->sTime - oldSpecProc_->sTime) * HUNDRED_PERCENT_VALUE / totalDeltaTime;
259         curSpecProc_->totalUsage = curSpecProc_->userSpaceUsage + curSpecProc_->sysSpaceUsage;
260     } else {
261         for (size_t i = 0; i < curProcs_.size(); i++) {
262             if (curProcs_[i] == nullptr) {
263                 continue;
264             }
265             std::shared_ptr<ProcInfo> oldProc = GetOldProc(curProcs_[i]->pid);
266             if (oldProc) {
267                 curProcs_[i]->userSpaceUsage =
268                     (curProcs_[i]->uTime - oldProc->uTime) * HUNDRED_PERCENT_VALUE / totalDeltaTime;
269                 curProcs_[i]->sysSpaceUsage =
270                     (curProcs_[i]->sTime - oldProc->sTime) * HUNDRED_PERCENT_VALUE / totalDeltaTime;
271                 curProcs_[i]->totalUsage = curProcs_[i]->userSpaceUsage + curProcs_[i]->sysSpaceUsage;
272             } else {
273                 curProcs_[i]->userSpaceUsage = 0;
274                 curProcs_[i]->sysSpaceUsage = 0;
275                 curProcs_[i]->totalUsage = 0;
276             }
277         }
278     }
279 
280     long unsigned userSpaceUsage =
281         ((curCPUInfo_->uTime + curCPUInfo_->nTime) - (oldCPUInfo_->uTime + oldCPUInfo_->nTime)) * HUNDRED_PERCENT_VALUE
282         / totalDeltaTime;
283     long unsigned sysSpaceUsage = (curCPUInfo_->sTime - oldCPUInfo_->sTime) * HUNDRED_PERCENT_VALUE / totalDeltaTime;
284     long unsigned iowUsage = (curCPUInfo_->iowTime - oldCPUInfo_->iowTime) * HUNDRED_PERCENT_VALUE / totalDeltaTime;
285     long unsigned irqUsage =
286         ((curCPUInfo_->irqTime + curCPUInfo_->sirqTime) - (oldCPUInfo_->irqTime + oldCPUInfo_->sirqTime))
287         * HUNDRED_PERCENT_VALUE / totalDeltaTime;
288     long unsigned idleUsage = (curCPUInfo_->iTime - oldCPUInfo_->iTime) * HUNDRED_PERCENT_VALUE / totalDeltaTime;
289     long unsigned totalUsage = userSpaceUsage + sysSpaceUsage;
290 
291     str = "Total: ";
292     str.append(std::to_string(totalUsage)).append("%; ");
293     str.append("User Space: ").append(std::to_string(userSpaceUsage)).append("%; ");
294     str.append("Kernel Space: ").append(std::to_string(sysSpaceUsage)).append("%; ");
295     str.append("iowait: ").append(std::to_string(iowUsage)).append("%; ");
296     str.append("irq: ").append(std::to_string(irqUsage)).append("%; ");
297     str.append("idle: ").append(std::to_string(idleUsage)).append("%");
298 }
299 
GetOldProc(const std::string & pid)300 std::shared_ptr<ProcInfo> CPUDumper::GetOldProc(const std::string &pid)
301 {
302     for (size_t i = 0; i < oldProcs_.size(); i++) {
303         if (StringUtils::GetInstance().IsSameStr(oldProcs_[i]->pid, pid)) {
304             return oldProcs_[i];
305         }
306     }
307     return nullptr;
308 }
309 
DumpProcInfo()310 void CPUDumper::DumpProcInfo()
311 {
312     std::vector<std::shared_ptr<ProcInfo>> sortedInfos;
313     sortedInfos.assign(curProcs_.begin(), curProcs_.end());
314     std::sort(sortedInfos.begin(), sortedInfos.end(), SortProcInfo);
315 
316     AddStrLineToDumpInfo("Details of Processes:");
317     AddStrLineToDumpInfo("    PID   Total Usage	   User Space    Kernel Space    Page Fault Minor"
318                          "    Page Fault Major    Name");
319     if (cpuUsagePid_ != -1) {
320         char format[PROC_CPU_LENGTH] = {0};
321         int ret = sprintf_s(format, PROC_CPU_LENGTH,
322                             "    %-5s    %3lu%%             %3lu%%"
323                             "           %3lu%%            %8s            %8s        %-15s",
324                             (curSpecProc_->pid).c_str(), curSpecProc_->totalUsage,
325                             curSpecProc_->userSpaceUsage, curSpecProc_->sysSpaceUsage,
326                             (curSpecProc_->minflt).c_str(), (curSpecProc_->majflt).c_str(),
327                             (curSpecProc_->comm).c_str());
328         AddStrLineToDumpInfo(std::string(format));
329         if (ret < 0) {
330             DUMPER_HILOGE(MODULE_COMMON, "Dump process %{public}d cpu info failed!.", cpuUsagePid_);
331         }
332         return;
333     }
334     for (size_t i = 0; i < sortedInfos.size(); i++) {
335         char format[PROC_CPU_LENGTH] = {0};
336         int ret = sprintf_s(format, PROC_CPU_LENGTH,
337                             "    %-5s    %3lu%%             %3lu%%"
338                             "           %3lu%%            %8s            %8s        %-15s",
339                             (sortedInfos[i]->pid).c_str(), sortedInfos[i]->totalUsage,
340                             sortedInfos[i]->userSpaceUsage, sortedInfos[i]->sysSpaceUsage,
341                             (sortedInfos[i]->minflt).c_str(), (sortedInfos[i]->majflt).c_str(),
342                             (sortedInfos[i]->comm).c_str());
343         if (ret < 0) {
344             continue;
345         }
346         AddStrLineToDumpInfo(std::string(format));
347     }
348 }
349 
SortProcInfo(std::shared_ptr<ProcInfo> & left,std::shared_ptr<ProcInfo> & right)350 bool CPUDumper::SortProcInfo(std::shared_ptr<ProcInfo> &left, std::shared_ptr<ProcInfo> &right)
351 {
352     if (right->totalUsage != left->totalUsage) {
353         return right->totalUsage < left->totalUsage;
354     }
355     if (right->userSpaceUsage != left->userSpaceUsage) {
356         return right->userSpaceUsage < left->userSpaceUsage;
357     }
358     if (right->sysSpaceUsage != left->sysSpaceUsage) {
359         return right->sysSpaceUsage < left->sysSpaceUsage;
360     }
361     if (right->pid.length() != left->pid.length()) {
362         return right->pid.length() < left->pid.length();
363     }
364     return (right->pid.compare(left->pid) < 0);
365 }
366 } // namespace HiviewDFX
367 } // namespace OHOS
368