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