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> ¶msInfo,
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