• 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 <climits>
18 #include <cstdio>
19 #include <algorithm>
20 #include <iostream>
21 #include <thread>
22 #include <string>
23 #include <regex>
24 #include "include/sp_utils.h"
25 #include "memory_collector.h"
26 #include "collect_result.h"
27 #include "include/startup_delay.h"
28 #include "include/sp_log.h"
29 #include "include/common.h"
30 
31 using namespace OHOS::HiviewDFX;
32 using namespace OHOS::HiviewDFX::UCollectUtil;
33 using namespace OHOS::HiviewDFX::UCollect;
34 
35 namespace OHOS {
36 namespace SmartPerf {
37 const int COLLECT_INTERVAL = 6;
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     static int collectCount = 0;
74     if ((collectCount++ % COLLECT_INTERVAL) != 0) {
75         return result;
76     }
77     result = RAM::GetSysRamInfo();
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         } else {
89             procRamInfomation = ProcMemNaInfo();
90         }
91         result.merge(procRamInfomation);
92     } else if (!packageName.empty() && processId.empty()) {
93         result.merge(RAM::ProcMemNaInfo());
94     }
95     LOGI("RAM:ItemData map size(%u)", result.size());
96     return result;
97 }
98 
ThreadGetPss() const99 void RAM::ThreadGetPss() const
100 {
101     procRamInfoLast = RAM::GetRamInfo();
102 }
103 
TriggerGetPss() const104 void RAM::TriggerGetPss() const
105 {
106     std::thread([this]() {
107         this->ThreadGetPss();
108     }).detach();
109 }
110 
SetFirstFlag()111 void RAM::SetFirstFlag()
112 {
113     g_flagFirst = false;
114 }
115 
SetHapFirstFlag()116 void RAM::SetHapFirstFlag()
117 {
118     g_flagFirst = true;
119 }
120 
ProcMemNaInfo() const121 std::map<std::string, std::string> RAM::ProcMemNaInfo() const
122 {
123     std::map<std::string, std::string> procMemInfo;
124     procMemInfo["arktsHeapPss"] = "NA";
125     procMemInfo["gpuPss"] = "NA";
126     procMemInfo["graphicPss"] = "NA";
127     procMemInfo["heapAlloc"] = "NA";
128     procMemInfo["heapFree"] = "NA";
129     procMemInfo["heapSize"] = "NA";
130     procMemInfo["nativeHeapPss"] = "NA";
131     procMemInfo["privateClean"] = "NA";
132     procMemInfo["privateDirty"] = "NA";
133     procMemInfo["pss"] = "NA";
134     procMemInfo["sharedClean"] = "NA";
135     procMemInfo["sharedDirty"] = "NA";
136     procMemInfo["stackPss"] = "NA";
137     procMemInfo["swap"] = "NA";
138     procMemInfo["swapPss"] = "NA";
139     return procMemInfo;
140 }
141 
ChildProcMemNaInfo() const142 std::map<std::string, std::string> RAM::ChildProcMemNaInfo() const
143 {
144     std::map<std::string, std::string> procMemInfo;
145     procMemInfo["childCarktsHeapPss"] = "NA";
146     procMemInfo["childGpuPss"] = "NA";
147     procMemInfo["childGraphicPss"] = "NA";
148     procMemInfo["childHeapAlloc"] = "NA";
149     procMemInfo["childHeapFree"] = "NA";
150     procMemInfo["childHeapSize"] = "NA";
151     procMemInfo["childNativeHeapPss"] = "NA";
152     procMemInfo["childPrivateClean"] = "NA";
153     procMemInfo["childPrivateDirty"] = "NA";
154     procMemInfo["childPss"] = "NA";
155     procMemInfo["childSharedClean"] = "NA";
156     procMemInfo["childSharedDirty"] = "NA";
157     procMemInfo["childStackPss"] = "NA";
158     procMemInfo["childSwap"] = "NA";
159     procMemInfo["childSwapPss"] = "NA";
160     return procMemInfo;
161 }
162 
GetSysRamInfo() const163 std::map<std::string, std::string> RAM::GetSysRamInfo() const
164 {
165     std::map<std::string, std::string> sysRamInfo;
166     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
167     if (collector == nullptr) {
168         LOGE("RAM::GetSysRamInfo collector is nullptr!");
169         return sysRamInfo;
170     }
171     CollectResult<SysMemory> result = collector->CollectSysMemory();
172     sysRamInfo["memTotal"] = std::to_string(result.data.memTotal);
173     sysRamInfo["memFree"] = std::to_string(result.data.memFree);
174     sysRamInfo["memAvailable"] = std::to_string(result.data.memAvailable);
175     //整机内存信息
176     LOGD("sysRamInfo map size(%u)", sysRamInfo.size());
177     return sysRamInfo;
178 }
179 
SetPackageName(const std::string & pName)180 void RAM::SetPackageName(const std::string &pName)
181 {
182     packageName = pName;
183 }
184 
SetProcessId(const std::string & pid)185 void RAM::SetProcessId(const std::string &pid)
186 {
187     processId.clear();
188     SPUtils::StrSplit(pid, " ", processId);
189     LOGD("RAM SetProcessId (%s)", pid.c_str());
190 }
191 
CollectRam(const std::string & ramPid,size_t index) const192 std::map<std::string, std::string> RAM::CollectRam(const std::string& ramPid, size_t index) const
193 {
194     std::map<std::string, std::string> emptyprocRamInfo;
195 
196     if (!std::all_of(ramPid.begin(), ramPid.end(), ::isdigit)) {
197         LOGE("RAM::CollectRam invalid ramPid");
198         return emptyprocRamInfo;
199     }
200     const std::string cmd = HIDUMPER_CMD_MAP.at(HidumperCmd::DUMPER_MEM) + ramPid;
201     if (cmd.empty()) {
202         LOGE("RAM::GetRamInfo cmd is null");
203         return emptyprocRamInfo;
204     }
205     FILE *fd = popen(cmd.c_str(), "r");
206     if (fd == nullptr) {
207         LOGD("RAM::fd is empty");
208         emptyprocRamInfo = ProcMemNaInfo();
209         for (auto& item : emptyprocRamInfo) {
210             item.second = "0";
211         }
212         return emptyprocRamInfo;
213     }
214 
215     std::map<std::string, std::string> procRamInfo = GetPssRamInfo(fd, ramPid, index);
216     if (procRamInfo.empty()) {
217         pclose(fd);
218         return emptyprocRamInfo;
219     }
220 
221     if (pclose(fd) == -1) {
222         LOGE("Error: Failed to close file");
223         return emptyprocRamInfo;
224     }
225     return procRamInfo;
226 }
227 
SetRamValue(std::promise<std::map<std::string,std::string>> p,std::string ramPid,size_t index) const228 void RAM::SetRamValue(std::promise<std::map<std::string, std::string>> p,
229     std::string ramPid, size_t index) const
230 {
231     p.set_value(CollectRam(ramPid, index));
232 }
233 
AsyncCollectRam(const std::string & ramPid,size_t index) const234 std::future<std::map<std::string, std::string>> RAM::AsyncCollectRam(const std::string& ramPid, size_t index) const
235 {
236     std::promise<std::map<std::string, std::string>> p;
237     std::future<std::map<std::string, std::string>> futureResult = p.get_future();
238     std::thread(&RAM::SetRamValue, this, std::move(p), ramPid, index).detach();
239     return futureResult;
240 }
241 
CheckFutureRam(std::future<std::map<std::string,std::string>> & fdsResult,std::map<std::string,std::string> & dataMap,const std::string & pid,size_t index) const242 void RAM::CheckFutureRam(std::future<std::map<std::string, std::string>> &fdsResult,
243                          std::map<std::string, std::string> &dataMap, const std::string& pid, size_t index) const
244 {
245     if (fdsResult.valid()) {
246         std::map<std::string, std::string> result = fdsResult.get();
247         if (index == 0) {
248             dataMap.insert(result.begin(), result.end());
249         } else {
250             for (auto &item : result) {
251                 dataMap[item.first].append(item.second);
252             }
253         }
254     }
255 }
256 
GetRamInfo() const257 std::map<std::string, std::string> RAM::GetRamInfo() const
258 {
259     std::map<std::string, std::string> dataMap;
260     std::vector<std::future<std::map<std::string, std::string>>>
261         fdsResult;
262     std::vector<std::string> processIds = processId;
263     for (size_t i = 0; i < processIds.size(); i++) {
264         fdsResult.emplace_back(AsyncCollectRam(processIds[i], i));
265     }
266     for (size_t i = 0; i < processIds.size(); i++) {
267         CheckFutureRam(fdsResult[i], dataMap, processIds[i], i);
268     }
269     if (processIds.size() == 1) {
270         std::map<std::string, std::string> procMemInfo = RAM::ChildProcMemNaInfo();
271         for (const auto& item : procMemInfo) {
272             dataMap.insert(item);
273         }
274     }
275     return dataMap;
276 }
277 
GetPssRamInfo(FILE * fd,const std::string & pid,size_t index) const278 std::map<std::string, std::string> RAM::GetPssRamInfo(FILE *fd, const std::string& pid, size_t index) const
279 {
280     std::vector<std::string> paramsInfo;
281     std::map<std::string, std::string> pssRamInfo = ParsePssValues(fd, paramsInfo, pid, index);
282     std::map<std::string, std::string> sumRamInfo = SaveSumRamInfo(paramsInfo, pid, index);
283     pssRamInfo.insert(std::make_move_iterator(sumRamInfo.begin()), std::make_move_iterator(sumRamInfo.end()));
284     if (paramsInfo.empty()) {
285         for (auto &pss : pssRamInfo) {
286             pss.second = pid + ":" + "0" + "|";
287         }
288         return pssRamInfo;
289     }
290     return pssRamInfo;
291 }
292 
ParsePssValues(FILE * fd,std::vector<std::string> & paramsInfo,std::string pid,size_t index) const293 std::map<std::string, std::string> RAM::ParsePssValues(FILE *fd, std::vector<std::string> &paramsInfo,
294     std::string pid, size_t index) const
295 {
296     std::map<std::string, std::string> pssRamInfo;
297     struct PssValues pss;
298     char buf[1024] = {'\0'};
299     while ((fgets(buf, sizeof(buf), fd)) != nullptr) {
300         std::string line(buf);
301         if (line[0] == '-') {
302             continue;
303         }
304         std::vector<std::string> params;
305         SPUtils::StrSplit(line, " ", params);
306         if (params.size() > RAM_SECOND && params[0].find("GL") != std::string::npos) {
307             pss.gpuPssValue = params[1];
308         }
309         if (params.size() > RAM_SECOND && params[0].find("Graph") != std::string::npos) {
310             pss.graphicPssValue = params[1];
311         }
312         if (params.size() > RAM_FOURTH && params[0].find("ark") != std::string::npos) {
313             pss.arktsHeapPssValue = params[RAM_THIRD];
314         }
315         if (params.size() > RAM_THIRD && params[0].find("native") != std::string::npos &&
316             params[1].find("heap") != std::string::npos) {
317             pss.nativeHeapPssValue = params[RAM_SECOND];
318         }
319         if (params.size() > RAM_SECOND && params[0].find("stack") != std::string::npos) {
320             pss.stackPssValue = params[1];
321         }
322         if (!pss.gpuPssValue.empty() && params.size() > 0 && params[0].find("Total") != std::string::npos) {
323             paramsInfo = params;
324         }
325         if (paramsInfo.size() > 0) {
326             break;
327         }
328     }
329 
330     FillPssRamInfo(index, pid, pss, pssRamInfo);
331     // 应用程序的内存占用信息
332     LOGD("pssRamInfo map size(%u)", pssRamInfo.size());
333     return pssRamInfo;
334 }
335 
FillPssRamInfo(size_t index,std::string pid,const PssValues & pss,std::map<std::string,std::string> & pssRamInfo) const336 void RAM::FillPssRamInfo(size_t index, std::string pid,
337     const PssValues &pss, std::map<std::string, std::string> &pssRamInfo) const
338 {
339     if (index == 0) {
340         pssRamInfo["gpuPss"] = pss.gpuPssValue;
341         pssRamInfo["graphicPss"] = pss.graphicPssValue;
342         pssRamInfo["arktsHeapPss"] = pss.arktsHeapPssValue;
343         pssRamInfo["nativeHeapPss"] = pss.nativeHeapPssValue;
344         pssRamInfo["stackPss"] = pss.stackPssValue;
345     } else {
346         pid.append(":");
347         pssRamInfo["childGpuPss"].append(pid).append(pss.gpuPssValue).append("|");
348         pssRamInfo["childGraphicPss"].append(pid).append(pss.graphicPssValue).append("|");
349         pssRamInfo["childArktsHeapPss"].append(pid).append(pss.arktsHeapPssValue).append("|");
350         pssRamInfo["childNativeHeapPss"].append(pid).append(pss.nativeHeapPssValue).append("|");
351         pssRamInfo["childStackPss"].append(pid).append(pss.stackPssValue).append("|");
352     }
353 }
354 
SaveSumRamInfo(std::vector<std::string> & paramsInfo,const std::string & pid,size_t index) const355 std::map<std::string, std::string> RAM::SaveSumRamInfo(std::vector<std::string>& paramsInfo,
356     const std::string& pid, size_t index) const
357 {
358     std::map<std::string, std::string> sumRamInfo;
359     if (paramsInfo.empty()) {
360         if (index == 0) {
361             sumRamInfo = ProcMemNaInfo();
362         } else {
363             sumRamInfo = ChildProcMemNaInfo();
364         }
365         for (auto &sumRam : sumRamInfo) {
366             sumRam.second = "0";
367         }
368         return sumRamInfo;
369     }
370     std::vector<std::string> sumRamKeys = {"pss", "sharedClean", "sharedDirty", "privateClean",
371         "privateDirty", "swap", "swapPss", "heapSize", "heapAlloc", "heapFree"};
372     std::vector<std::string> childSumRamKeys = {"childPss", "childSharedClean", "childSharedDirty", "childPrivateClean",
373         "childPrivateDirty", "childSwap", "childSwapPss", "childHeapSize", "childHeapAlloc", "childHeapFree"};
374     if (index == 0) {
375         for (size_t i = 0; i < paramsInfo.size() - 1 && i < sumRamKeys.size(); i++) {
376             if (i == RAM_NINTH) {
377                 sumRamInfo["heapFree"] =
378                     paramsInfo[RAM_TENTH].erase(static_cast<int>(paramsInfo[RAM_TENTH].size()) - 1);
379                 break;
380             }
381             sumRamInfo[sumRamKeys[i]] = paramsInfo[i + 1];
382         }
383     } else {
384         for (size_t i = 0; i < paramsInfo.size() - 1 && i < childSumRamKeys.size(); i++) {
385             if (i == RAM_NINTH) {
386                 sumRamInfo["childHeapFree"] = pid + ":" +
387                     paramsInfo[RAM_TENTH].erase(static_cast<int>(paramsInfo[RAM_TENTH].size()) - 1).append("|");
388                 break;
389             }
390             sumRamInfo[childSumRamKeys[i]] = pid + ":" + paramsInfo[i + 1].append("|");
391         }
392     }
393 
394     //应用程序的内存消耗信息
395     LOGD("sumRamInfo map size(%u)", sumRamInfo.size());
396     return sumRamInfo;
397 }
398 }
399 }
400