• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "include/RAM.h"
16 #include <sstream>
17 #include <fstream>
18 #include <climits>
19 #include <cstdio>
20 #include <algorithm>
21 #include <iostream>
22 #include <thread>
23 #include <string>
24 #include <regex>
25 #include "include/sp_utils.h"
26 #include "memory_collector.h"
27 #include "collect_result.h"
28 #include "include/startup_delay.h"
29 #include "include/sp_log.h"
30 #include "include/common.h"
31 
32 using namespace OHOS::HiviewDFX;
33 using namespace OHOS::HiviewDFX::UCollectUtil;
34 using namespace OHOS::HiviewDFX::UCollect;
35 
36 namespace OHOS {
37 namespace SmartPerf {
38 bool g_flagFirst = false;
39 std::map<std::string, std::string> procRamInfoLast {
40         {"pss", "NA"},
41         {"gpuPss", "NA"},
42         {"graphicPss", "NA"},
43         {"arktsHeapPss", "NA"},
44         {"nativeHeapPss", "NA"},
45         {"stackPss", "NA"},
46         {"sharedClean", "NA"},
47         {"sharedDirty", "NA"},
48         {"privateClean", "NA"},
49         {"privateDirty", "NA"},
50         {"swap", "NA"},
51         {"swapPss", "NA"},
52         {"heapSize", "NA"},
53         {"heapAlloc", "NA"},
54         {"heapFree", "NA"},
55         {"childCarktsHeapPss", "NA"},
56         {"childGpuPss", "NA"},
57         {"childGraphicPss", "NA"},
58         {"childHeapAlloc", "NA" },
59         {"childHeapFree", "NA"},
60         {"childHeapSize", "NA"},
61         {"childNativeHeapPss", "NA"},
62         {"childPrivateClean", "NA"},
63         {"childPrivateDirty", "NA"},
64         {"childPss", "NA"},
65         {"childSharedClean", "NA"},
66         {"childSharedDirty", "NA"},
67         {"childStackPss", "NA"},
68         {"childSwap", "NA"},
69         {"childSwapPss", "NA"}
70 };
ItemData()71 std::map<std::string, std::string> RAM::ItemData()
72 {
73     std::map<std::string, std::string> result;
74     std::map<std::string, std::string> sysRamInfo = RAM::GetSysRamInfo();
75     for (const auto& item : sysRamInfo) {
76         result.insert(item);
77     }
78     if (!processId.empty()) {
79         std::map<std::string, std::string> procRamInfomation;
80         if (g_flagFirst) {
81             RAM::TriggerGetPss();
82         } else {
83             procRamInfoLast = RAM::GetRamInfo();
84             g_flagFirst = true;
85         }
86         if (!procRamInfoLast.empty()) {
87             procRamInfomation = procRamInfoLast;
88             for (const auto& item : procRamInfomation) {
89                 result.insert(item);
90             }
91         } else {
92             procRamInfomation = ProcMemNaInfo();
93             for (const auto& item : procRamInfomation) {
94                 result.insert(item);
95             }
96         }
97     } else if (!packageName.empty() && processId.empty()) {
98         std::map<std::string, std::string> procMemInfo = RAM::ProcMemNaInfo();
99         for (const auto& item : procMemInfo) {
100             result.insert(item);
101         }
102     }
103     return result;
104 }
105 
ThreadGetPss() const106 void RAM::ThreadGetPss() const
107 {
108     std::map<std::string, std::string> procRamInfo = RAM::GetRamInfo();
109     procRamInfoLast = procRamInfo;
110 }
111 
TriggerGetPss() const112 void RAM::TriggerGetPss() const
113 {
114     auto tStart = std::thread([this]() {
115         this->ThreadGetPss();
116     });
117     tStart.detach();
118 }
119 
SetFirstFlag()120 void RAM::SetFirstFlag()
121 {
122     g_flagFirst = false;
123 }
124 
SetHapFirstFlag()125 void RAM::SetHapFirstFlag()
126 {
127     g_flagFirst = true;
128 }
129 
ProcMemNaInfo() const130 std::map<std::string, std::string> RAM::ProcMemNaInfo() const
131 {
132     std::map<std::string, std::string> procMemInfo;
133     procMemInfo["arktsHeapPss"] = "NA";
134     procMemInfo["gpuPss"] = "NA";
135     procMemInfo["graphicPss"] = "NA";
136     procMemInfo["heapAlloc"] = "NA";
137     procMemInfo["heapFree"] = "NA";
138     procMemInfo["heapSize"] = "NA";
139     procMemInfo["nativeHeapPss"] = "NA";
140     procMemInfo["privateClean"] = "NA";
141     procMemInfo["privateDirty"] = "NA";
142     procMemInfo["pss"] = "NA";
143     procMemInfo["sharedClean"] = "NA";
144     procMemInfo["sharedDirty"] = "NA";
145     procMemInfo["stackPss"] = "NA";
146     procMemInfo["swap"] = "NA";
147     procMemInfo["swapPss"] = "NA";
148     return procMemInfo;
149 }
150 
ChildProcMemNaInfo() const151 std::map<std::string, std::string> RAM::ChildProcMemNaInfo() const
152 {
153     std::map<std::string, std::string> procMemInfo;
154     procMemInfo["childCarktsHeapPss"] = "NA";
155     procMemInfo["childGpuPss"] = "NA";
156     procMemInfo["childGraphicPss"] = "NA";
157     procMemInfo["childHeapAlloc"] = "NA";
158     procMemInfo["childHeapFree"] = "NA";
159     procMemInfo["childHeapSize"] = "NA";
160     procMemInfo["childNativeHeapPss"] = "NA";
161     procMemInfo["childPrivateClean"] = "NA";
162     procMemInfo["childPrivateDirty"] = "NA";
163     procMemInfo["childPss"] = "NA";
164     procMemInfo["childSharedClean"] = "NA";
165     procMemInfo["childSharedDirty"] = "NA";
166     procMemInfo["childStackPss"] = "NA";
167     procMemInfo["childSwap"] = "NA";
168     procMemInfo["childSwapPss"] = "NA";
169     return procMemInfo;
170 }
171 
GetSysRamInfo() const172 std::map<std::string, std::string> RAM::GetSysRamInfo() const
173 {
174     std::map<std::string, std::string> sysRamInfo;
175     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
176     if (collector == nullptr) {
177         LOGE("RAM::GetSysRamInfo collector is nullptr!");
178         return sysRamInfo;
179     }
180     CollectResult<SysMemory> result = collector->CollectSysMemory();
181     sysRamInfo["memTotal"] = std::to_string(result.data.memTotal);
182     sysRamInfo["memFree"] = std::to_string(result.data.memFree);
183     sysRamInfo["memAvailable"] = std::to_string(result.data.memAvailable);
184     //整机内存信息
185     LOGD("sysRamInfo map size(%u)", sysRamInfo.size());
186     return sysRamInfo;
187 }
188 
SetPackageName(const std::string & pName)189 void RAM::SetPackageName(const std::string &pName)
190 {
191     packageName = pName;
192 }
193 
SetProcessId(const std::string & pid)194 void RAM::SetProcessId(const std::string &pid)
195 {
196     processId.clear();
197     SPUtils::StrSplit(pid, " ", processId);
198     LOGD("RAM SetProcessId (%s)", pid.c_str());
199 }
200 
CollectRam(std::string ramPid,size_t index) const201 std::map<std::string, std::string> RAM::CollectRam(std::string ramPid, size_t index) const
202 {
203     std::map<std::string, std::string> procRamInfo;
204     std::map<std::string, std::string> emptyprocRamInfo;
205     std::string pssValue = "";
206     if (!std::all_of(ramPid.begin(), ramPid.end(), ::isdigit)) {
207         LOGE("RAM::CollectRam invalid ramPid");
208         return emptyprocRamInfo;
209     }
210     const std::string cmd = HIDUMPER_CMD_MAP.at(HidumperCmd::DUMPER_MEM) + ramPid;
211     if (cmd.empty()) {
212         LOGE("RAM::GetRamInfo cmd is null");
213         return emptyprocRamInfo;
214     }
215     FILE *fd = popen(cmd.c_str(), "r");
216     if (fd == nullptr) {
217         LOGD("RAM::fd is empty");
218         emptyprocRamInfo = ProcMemNaInfo();
219         for (auto item : emptyprocRamInfo) {
220             item.second = "0";
221         }
222         return emptyprocRamInfo;
223     }
224     std::vector<std::string> paramsInfo;
225     procRamInfo = GetPssRamInfo(fd, paramsInfo, ramPid, index);
226     if (procRamInfo.empty()) {
227         pclose(fd);
228         return emptyprocRamInfo;
229     }
230     for (const auto &value : paramsInfo) {
231         if (procRamInfo[value].empty()) {
232             procRamInfo[value] = "0";
233         }
234     }
235     if (pclose(fd) == -1) {
236         LOGE("Error: Failed to close file");
237         return emptyprocRamInfo;
238     }
239     return procRamInfo;
240 }
241 
SetRamValue(std::promise<std::map<std::string,std::string>> p,std::string ramPid,size_t index) const242 void RAM::SetRamValue(std::promise<std::map<std::string, std::string>> p,
243     std::string ramPid, size_t index) const
244 {
245     p.set_value(CollectRam(ramPid, index));
246 }
247 
AsyncCollectRam(std::string ramPid,size_t index) const248 std::future<std::map<std::string, std::string>> RAM::AsyncCollectRam(std::string ramPid, size_t index) const
249 {
250     std::promise<std::map<std::string, std::string>> p;
251     std::future<std::map<std::string, std::string>> futureResult = p.get_future();
252     std::thread(&RAM::SetRamValue, this, std::move(p), ramPid, index).detach();
253     return futureResult;
254 }
255 
CheckFutureRam(std::future<std::map<std::string,std::string>> & fdsResult,std::map<std::string,std::string> & dataMap,std::string pid,size_t index) const256 void RAM::CheckFutureRam(std::future<std::map<std::string, std::string>> &fdsResult,
257                          std::map<std::string, std::string> &dataMap, std::string pid, size_t index) const
258 {
259     if (fdsResult.valid()) {
260         std::map<std::string, std::string> result = fdsResult.get();
261         if (index == 0) {
262             dataMap.insert(result.begin(), result.end());
263         } else {
264             for (auto &item : result) {
265                 dataMap[item.first].append(item.second);
266             }
267         }
268     }
269 }
270 
GetRamInfo() const271 std::map<std::string, std::string> RAM::GetRamInfo() const
272 {
273     std::map<std::string, std::string> dataMap;
274     std::vector<std::future<std::map<std::string, std::string>>>
275         fdsResult;
276     std::vector<std::string> processIds = processId;
277     for (size_t i = 0; i < processIds.size(); i++) {
278         fdsResult.emplace_back(AsyncCollectRam(processIds[i], i));
279     }
280     for (size_t i = 0; i < processIds.size(); i++) {
281         CheckFutureRam(fdsResult[i], dataMap, processIds[i], i);
282     }
283     if (processIds.size() == 1) {
284         std::map<std::string, std::string> procMemInfo = RAM::ChildProcMemNaInfo();
285         for (auto it = procMemInfo.begin(); it != procMemInfo.end(); ++it) {
286             dataMap.insert(*it);
287         }
288     }
289     return dataMap;
290 }
291 
GetPssRamInfo(FILE * fd,std::vector<std::string> paramsInfo,const std::string pid,size_t index) const292 std::map<std::string, std::string> RAM::GetPssRamInfo(FILE *fd, std::vector<std::string> paramsInfo,
293     const std::string pid, size_t index) const
294 {
295     std::map<std::string, std::string> pssRamInfo = ParsePssValues(fd, paramsInfo, pid, index);
296     std::map<std::string, std::string> sumRamInfo = SaveSumRamInfo(paramsInfo, pid, index);
297     pssRamInfo.insert(sumRamInfo.cbegin(), sumRamInfo.cend());
298     if (paramsInfo.empty()) {
299         for (auto &pss : pssRamInfo) {
300             pss.second = pid + ":" + "0" + "|";
301         }
302         return pssRamInfo;
303     }
304     return pssRamInfo;
305 }
306 
ParsePssValues(FILE * fd,std::vector<std::string> & paramsInfo,std::string pid,size_t index) const307 std::map<std::string, std::string> RAM::ParsePssValues(FILE *fd, std::vector<std::string> &paramsInfo,
308     std::string pid, size_t index) const
309 {
310     std::map<std::string, std::string> pssRamInfo;
311     struct PssValues pss;
312     char buf[1024] = {'\0'};
313     while ((fgets(buf, sizeof(buf), fd)) != nullptr) {
314         std::string line(buf);
315         LOGD("ParsePssValues::line = %s", line.c_str());
316         if (line[0] == '-') {
317             continue;
318         }
319         std::vector<std::string> params;
320         SPUtils::StrSplit(line, " ", params);
321         if (params.size() > RAM_SECOND && params[0].find("GL") != std::string::npos) {
322             pss.gpuPssValue = params[1];
323         }
324         if (params.size() > RAM_SECOND && params[0].find("Graph") != std::string::npos) {
325             pss.graphicPssValue = params[1];
326         }
327         if (params.size() > RAM_FOURTH && params[0].find("ark") != std::string::npos) {
328             pss.arktsHeapPssValue = params[RAM_THIRD];
329         }
330         if (params.size() > RAM_THIRD && params[0].find("native") != std::string::npos &&
331             params[1].find("heap") != std::string::npos) {
332             pss.nativeHeapPssValue = params[RAM_SECOND];
333         }
334         if (params.size() > RAM_SECOND && params[0].find("stack") != std::string::npos) {
335             pss.stackPssValue = params[1];
336         }
337         if (!pss.gpuPssValue.empty() && params.size() > 0 && params[0].find("Total") != std::string::npos) {
338             paramsInfo = params;
339         }
340         if (paramsInfo.size() > 0) {
341             break;
342         }
343     }
344 
345     FillPssRamInfo(index, pid, pss, pssRamInfo);
346     // 应用程序的内存占用信息
347     LOGD("pssRamInfo map size(%u)", pssRamInfo.size());
348     return pssRamInfo;
349 }
350 
FillPssRamInfo(size_t index,std::string pid,const PssValues & pss,std::map<std::string,std::string> & pssRamInfo) const351 void RAM::FillPssRamInfo(size_t index, std::string pid,
352     const PssValues &pss, std::map<std::string, std::string> &pssRamInfo) const
353 {
354     if (index == 0) {
355         pssRamInfo["gpuPss"] = pss.gpuPssValue;
356         pssRamInfo["graphicPss"] = pss.graphicPssValue;
357         pssRamInfo["arktsHeapPss"] = pss.arktsHeapPssValue;
358         pssRamInfo["nativeHeapPss"] = pss.nativeHeapPssValue;
359         pssRamInfo["stackPss"] = pss.stackPssValue;
360     } else {
361         pid.append(":");
362         pssRamInfo["childGpuPss"].append(pid).append(pss.gpuPssValue).append("|");
363         pssRamInfo["childGraphicPss"].append(pid).append(pss.graphicPssValue).append("|");
364         pssRamInfo["childArktsHeapPss"].append(pid).append(pss.arktsHeapPssValue).append("|");
365         pssRamInfo["childNativeHeapPss"].append(pid).append(pss.nativeHeapPssValue).append("|");
366         pssRamInfo["childStackPss"].append(pid).append(pss.stackPssValue).append("|");
367     }
368 }
369 
SaveSumRamInfo(std::vector<std::string> paramsInfo,std::string pid,size_t index) const370 std::map<std::string, std::string> RAM::SaveSumRamInfo(std::vector<std::string> paramsInfo,
371     std::string pid, size_t index) const
372 {
373     std::map<std::string, std::string> sumRamInfo;
374     if (paramsInfo.empty()) {
375         if (index == 0) {
376             sumRamInfo = ProcMemNaInfo();
377         } else {
378             sumRamInfo = ChildProcMemNaInfo();
379         }
380         for (auto &sumRam : sumRamInfo) {
381             sumRam.second = "0";
382         }
383         return sumRamInfo;
384     }
385     std::vector<std::string> sumRamKeys = {"pss", "sharedClean", "sharedDirty", "privateClean",
386         "privateDirty", "swap", "swapPss", "heapSize", "heapAlloc", "heapFree"};
387     std::vector<std::string> childSumRamKeys = {"childPss", "childSharedClean", "childSharedDirty", "childPrivateClean",
388         "childPrivateDirty", "childSwap", "childSwapPss", "childHeapSize", "childHeapAlloc", "childHeapFree"};
389     if (index == 0) {
390         for (size_t i = 0; i < paramsInfo.size() - 1 && i < sumRamKeys.size(); i++) {
391             if (i == RAM_NINTH) {
392                 sumRamInfo["heapFree"] =
393                     paramsInfo[RAM_TENTH].erase(static_cast<int>(paramsInfo[RAM_TENTH].size()) - 1);
394                 break;
395             }
396             sumRamInfo[sumRamKeys[i]] = paramsInfo[i + 1];
397         }
398     } else {
399         for (size_t i = 0; i < paramsInfo.size() - 1 && i < childSumRamKeys.size(); i++) {
400             if (i == RAM_NINTH) {
401                 sumRamInfo["childHeapFree"] = pid + ":" +
402                     paramsInfo[RAM_TENTH].erase(static_cast<int>(paramsInfo[RAM_TENTH].size()) - 1).append("|");
403                 break;
404             }
405             sumRamInfo[childSumRamKeys[i]] = pid + ":" + paramsInfo[i + 1].append("|");
406         }
407     }
408 
409     //应用程序的内存消耗信息
410     LOGD("sumRamInfo map size(%u)", sumRamInfo.size());
411     return sumRamInfo;
412 }
413 }
414 }
415