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 "executor/memory/memory_info.h"
16
17 #include <cinttypes>
18 #include <fstream>
19 #include <numeric>
20 #include <thread>
21 #include <v1_0/imemory_tracker_interface.h>
22
23 #include "dump_common_utils.h"
24 #include "executor/memory/get_cma_info.h"
25 #include "executor/memory/get_hardware_info.h"
26 #include "executor/memory/get_kernel_info.h"
27 #include "executor/memory/get_process_info.h"
28 #include "executor/memory/get_ram_info.h"
29 #include "executor/memory/get_heap_info.h"
30 #include "executor/memory/memory_util.h"
31 #include "executor/memory/parse/meminfo_data.h"
32 #include "executor/memory/parse/parse_meminfo.h"
33 #include "executor/memory/parse/parse_smaps_rollup_info.h"
34 #include "executor/memory/parse/parse_smaps_info.h"
35 #include "hdf_base.h"
36 #include "hilog_wrapper.h"
37 #ifdef HIDUMPER_MEMMGR_ENABLE
38 #include "mem_mgr_constant.h"
39 #endif
40 #include "securec.h"
41 #include "string_ex.h"
42 #include "util/string_utils.h"
43 #include "util/file_utils.h"
44 #ifdef HIDUMPER_GRAPHIC_ENABLE
45 #include "transaction/rs_interfaces.h"
46 using namespace OHOS::Rosen;
47 #endif
48
49 using namespace std;
50 using namespace OHOS::HDI::Memorytracker::V1_0;
51
52 namespace OHOS {
53 namespace HiviewDFX {
MemoryInfo()54 MemoryInfo::MemoryInfo()
55 {
56 methodVec_.clear();
57 methodVec_.push_back(make_pair(MEMINFO_PSS,
58 bind(&MemoryInfo::SetPss, this, placeholders::_1, placeholders::_2)));
59 methodVec_.push_back(make_pair(MEMINFO_SHARED_CLEAN,
60 bind(&MemoryInfo::SetSharedClean, this, placeholders::_1, placeholders::_2)));
61 methodVec_.push_back(make_pair(MEMINFO_SHARED_DIRTY,
62 bind(&MemoryInfo::SetSharedDirty, this, placeholders::_1, placeholders::_2)));
63 methodVec_.push_back(make_pair(MEMINFO_PRIVATE_CLEAN,
64 bind(&MemoryInfo::SetPrivateClean, this, placeholders::_1, placeholders::_2)));
65 methodVec_.push_back(make_pair(MEMINFO_PRIVATE_DIRTY,
66 bind(&MemoryInfo::SetPrivateDirty, this, placeholders::_1, placeholders::_2)));
67 methodVec_.push_back(make_pair(MEMINFO_SWAP,
68 bind(&MemoryInfo::SetSwap, this, placeholders::_1, placeholders::_2)));
69 methodVec_.push_back(make_pair(MEMINFO_SWAP_PSS,
70 bind(&MemoryInfo::SetSwapPss, this, placeholders::_1, placeholders::_2)));
71 methodVec_.push_back(make_pair(MEMINFO_HEAP_SIZE,
72 bind(&MemoryInfo::SetHeapSize, this, placeholders::_1, placeholders::_2)));
73 methodVec_.push_back(make_pair(MEMINFO_HEAP_ALLOC,
74 bind(&MemoryInfo::SetHeapAlloc, this, placeholders::_1, placeholders::_2)));
75 methodVec_.push_back(make_pair(MEMINFO_HEAP_FREE,
76 bind(&MemoryInfo::SetHeapFree, this, placeholders::_1, placeholders::_2)));
77 }
78
~MemoryInfo()79 MemoryInfo::~MemoryInfo()
80 {
81 }
82
83 static uint64_t g_sumPidsMemGL = 0;
84 #ifdef HIDUMPER_GRAPHIC_ENABLE
85 std::vector<MemoryGraphic> memGraphicVec_;
86 #endif
87
insertMemoryTitle(StringMatrix result)88 void MemoryInfo::insertMemoryTitle(StringMatrix result)
89 {
90 // Pss Shared ---- this line is line1
91 // Total Clean ---- this line is line2
92 // (KB) (KB) ---- this line is line3
93 // ----- ------ ---- this line is line4
94
95 vector<string> line1;
96 vector<string> line2;
97 vector<string> line3;
98 vector<string> line4;
99
100 string space = " ";
101 StringUtils::GetInstance().SetWidth(LINE_WIDTH_, BLANK_, false, space);
102
103 string separator = "-";
104 StringUtils::GetInstance().SetWidth(LINE_WIDTH_, SEPARATOR_, false, separator);
105
106 string unit = "(" + MemoryUtil::GetInstance().KB_UNIT_ + " )";
107 StringUtils::GetInstance().SetWidth(LINE_WIDTH_, BLANK_, false, unit);
108
109 // Add spaces at the beginning of the line
110 line1.push_back(space);
111 line2.push_back(space);
112 line3.push_back(space);
113 line4.push_back(space);
114
115 for (string str : MemoryFilter::GetInstance().TITLE_HAS_PID_) {
116 vector<string> types;
117 StringUtils::GetInstance().StringSplit(str, "_", types);
118 if (types.size() == TYPE_SIZE) {
119 string title1 = types.at(0);
120 StringUtils::GetInstance().SetWidth(LINE_WIDTH_, BLANK_, false, title1);
121 line1.push_back(title1);
122
123 string title2 = types.at(1);
124 StringUtils::GetInstance().SetWidth(LINE_WIDTH_, BLANK_, false, title2);
125 line2.push_back(title2);
126 line3.push_back(unit);
127 line4.push_back(separator);
128 }
129 }
130 result->push_back(line1);
131 result->push_back(line2);
132 result->push_back(line3);
133 result->push_back(line4);
134 }
135
BuildResult(const GroupMap & infos,StringMatrix result)136 void MemoryInfo::BuildResult(const GroupMap &infos, StringMatrix result)
137 {
138 insertMemoryTitle(result);
139 for (const auto &info : infos) {
140 vector<string> tempResult;
141 vector<string> pageTag;
142 StringUtils::GetInstance().StringSplit(info.first, "#", pageTag);
143 string group;
144 if (pageTag[1] == "other") {
145 group = pageTag[0] == MemoryFilter::GetInstance().FILE_PAGE_TAG ? "FilePage other" : "AnonPage other";
146 } else {
147 group = pageTag[1];
148 }
149 StringUtils::GetInstance().SetWidth(LINE_WIDTH_, BLANK_, false, group);
150 tempResult.push_back(group);
151
152 auto &valueMap = info.second;
153 for (const auto &tag : MemoryFilter::GetInstance().VALUE_WITH_PID) {
154 auto it = valueMap.find(tag);
155 string value = "0";
156 if (it != valueMap.end()) {
157 value = to_string(it->second);
158 }
159 StringUtils::GetInstance().SetWidth(LINE_WIDTH_, BLANK_, false, value);
160 tempResult.push_back(value);
161 }
162 result->push_back(tempResult);
163 }
164 }
165
166
CalcGroup(const GroupMap & infos,StringMatrix result)167 void MemoryInfo::CalcGroup(const GroupMap &infos, StringMatrix result)
168 {
169 MemInfoData::MemInfo meminfo;
170 MemoryUtil::GetInstance().InitMemInfo(meminfo);
171 for (const auto &info : infos) {
172 auto &valueMap = info.second;
173 for (const auto &method : methodVec_) {
174 auto it = valueMap.find(method.first);
175 if (it != valueMap.end()) {
176 method.second(meminfo, it->second);
177 }
178 }
179 }
180
181 vector<string> lines;
182 vector<string> values;
183
184 MemoryUtil::GetInstance().SetMemTotalValue("Total", lines, values);
185 MemoryUtil::GetInstance().SetMemTotalValue(to_string(meminfo.pss + meminfo.swapPss), lines, values);
186 MemoryUtil::GetInstance().SetMemTotalValue(to_string(meminfo.sharedClean), lines, values);
187 MemoryUtil::GetInstance().SetMemTotalValue(to_string(meminfo.sharedDirty), lines, values);
188 MemoryUtil::GetInstance().SetMemTotalValue(to_string(meminfo.privateClean), lines, values);
189 MemoryUtil::GetInstance().SetMemTotalValue(to_string(meminfo.privateDirty), lines, values);
190 MemoryUtil::GetInstance().SetMemTotalValue(to_string(meminfo.swap), lines, values);
191 MemoryUtil::GetInstance().SetMemTotalValue(to_string(meminfo.swapPss), lines, values);
192 MemoryUtil::GetInstance().SetMemTotalValue(to_string(meminfo.heapSize), lines, values);
193 MemoryUtil::GetInstance().SetMemTotalValue(to_string(meminfo.heapAlloc), lines, values);
194 MemoryUtil::GetInstance().SetMemTotalValue(to_string(meminfo.heapFree), lines, values);
195
196 result->push_back(lines);
197 result->push_back(values);
198 }
199
GetRenderServiceGraphics(int32_t pid,MemInfoData::GraphicsMemory & graphicsMemory)200 bool MemoryInfo::GetRenderServiceGraphics(int32_t pid, MemInfoData::GraphicsMemory &graphicsMemory)
201 {
202 bool ret = false;
203 sptr<IMemoryTrackerInterface> memtrack = IMemoryTrackerInterface::Get(true);
204 if (memtrack == nullptr) {
205 DUMPER_HILOGE(MODULE_SERVICE, "memtrack service is null");
206 return ret;
207 }
208
209 for (const auto &memTrackerType : MemoryFilter::GetInstance().MEMORY_TRACKER_TYPES) {
210 std::vector<MemoryRecord> records;
211 if (memtrack->GetDevMem(pid, memTrackerType.first, records) == HDF_SUCCESS) {
212 uint64_t value = 0;
213 for (const auto &record : records) {
214 if ((static_cast<uint32_t>(record.flags) & FLAG_UNMAPPED) == FLAG_UNMAPPED) {
215 value = static_cast<uint64_t>(record.size / BYTE_PER_KB);
216 break;
217 }
218 }
219 if (memTrackerType.first == MEMORY_TRACKER_TYPE_GL) {
220 graphicsMemory.gl = value;
221 ret = true;
222 } else if (memTrackerType.first == MEMORY_TRACKER_TYPE_GRAPH) {
223 graphicsMemory.graph = value;
224 ret = true;
225 }
226 }
227 }
228 return ret;
229 }
230
IsRenderService(int32_t pid)231 bool MemoryInfo::IsRenderService(int32_t pid)
232 {
233 std::string rsName = "render_service";
234 std::string processName = GetProcName(pid);
235 const char whitespace[] = " \n\t\v\r\f";
236 processName.erase(0, processName.find_first_not_of(whitespace));
237 processName.erase(processName.find_last_not_of(whitespace) + 1U);
238 if (processName == rsName) {
239 return true;
240 }
241 return false;
242 }
243
GetMemoryInfoByPid(const int & pid,StringMatrix result)244 bool MemoryInfo::GetMemoryInfoByPid(const int &pid, StringMatrix result)
245 {
246 GroupMap groupMap;
247 unique_ptr<ParseSmapsInfo> parseSmapsInfo = make_unique<ParseSmapsInfo>();
248 if (!parseSmapsInfo->GetInfo(MemoryFilter::APPOINT_PID, pid, groupMap)) {
249 DUMPER_HILOGE(MODULE_SERVICE, "parse smaps info fail");
250 return false;
251 }
252
253 unique_ptr<GetHeapInfo> getHeapInfo = make_unique<GetHeapInfo>();
254 if (!getHeapInfo->GetInfo(MemoryFilter::APPOINT_PID, pid, groupMap)) {
255 DUMPER_HILOGE(MODULE_SERVICE, "get heap info fail");
256 return false;
257 }
258 MemInfoData::GraphicsMemory graphicsMemory;
259 MemoryUtil::GetInstance().InitGraphicsMemory(graphicsMemory);
260 if ((IsRenderService(pid))) {
261 #ifdef HIDUMPER_GRAPHIC_ENABLE
262 GetMemGraphics();
263 #endif
264 GetRenderServiceGraphics(pid, graphicsMemory);
265 graphicsMemory.gl -= g_sumPidsMemGL;
266 } else {
267 #ifdef HIDUMPER_GRAPHIC_ENABLE
268 auto& rsClient = Rosen::RSInterfaces::GetInstance();
269 unique_ptr<MemoryGraphic> memGraphic = make_unique<MemoryGraphic>(rsClient.GetMemoryGraphic(pid));
270 graphicsMemory.gl = memGraphic-> GetGpuMemorySize() / BYTE_PER_KB;
271 graphicsMemory.graph = memGraphic-> GetCpuMemorySize() / BYTE_PER_KB;
272 #endif
273 }
274
275 map<string, uint64_t> valueMap;
276 valueMap.insert(pair<string, uint64_t>("Pss", graphicsMemory.gl));
277 valueMap.insert(pair<string, uint64_t>("Private_Dirty", graphicsMemory.gl));
278 groupMap.insert(pair<string, map<string, uint64_t>>("AnonPage # GL", valueMap));
279 valueMap.clear();
280 valueMap.insert(pair<string, uint64_t>("Pss", graphicsMemory.graph));
281 valueMap.insert(pair<string, uint64_t>("Private_Dirty", graphicsMemory.graph));
282 groupMap.insert(pair<string, map<string, uint64_t>>("AnonPage # Graph", valueMap));
283
284 BuildResult(groupMap, result);
285 CalcGroup(groupMap, result);
286 return true;
287 }
288
AddKbUnit(const uint64_t & value) const289 string MemoryInfo::AddKbUnit(const uint64_t &value) const
290 {
291 return to_string(value) + MemoryUtil::GetInstance().KB_UNIT_;
292 }
293
GetSmapsInfoNoPid(const int & pid,GroupMap & result)294 bool MemoryInfo::GetSmapsInfoNoPid(const int &pid, GroupMap &result)
295 {
296 unique_ptr<ParseSmapsInfo> parseSmapsInfo = make_unique<ParseSmapsInfo>();
297 return parseSmapsInfo->GetInfo(MemoryFilter::NOT_SPECIFIED_PID, pid, result);
298 }
299
GetMeminfo(ValueMap & result)300 bool MemoryInfo::GetMeminfo(ValueMap &result)
301 {
302 unique_ptr<ParseMeminfo> parseMeminfo = make_unique<ParseMeminfo>();
303 return parseMeminfo->GetMeminfo(result);
304 }
305
GetHardWareUsage(StringMatrix result)306 bool MemoryInfo::GetHardWareUsage(StringMatrix result)
307 {
308 uint64_t value;
309 unique_ptr<GetHardwareInfo> getHardwareInfo = make_unique<GetHardwareInfo>();
310 if (getHardwareInfo->GetHardwareUsage(value)) {
311 vector<string> hardware;
312 string title = "Hardware Usage:";
313 StringUtils::GetInstance().SetWidth(RAM_WIDTH_, BLANK_, false, title);
314 hardware.push_back(title);
315 hardware.push_back(AddKbUnit(value));
316 result->push_back(hardware);
317 return true;
318 }
319 return false;
320 }
321
GetCMAUsage(StringMatrix result)322 bool MemoryInfo::GetCMAUsage(StringMatrix result)
323 {
324 uint64_t value = 0;
325 unique_ptr<GetCMAInfo> getCMAInfo = make_unique<GetCMAInfo>();
326 bool success = getCMAInfo->GetUsed(value);
327 if (success) {
328 vector<string> cma;
329 string title = "CMA Usage:";
330 StringUtils::GetInstance().SetWidth(RAM_WIDTH_, BLANK_, false, title);
331 cma.push_back(title);
332 cma.push_back(AddKbUnit(value));
333 result->push_back(cma);
334 }
335 return success;
336 }
337
GetKernelUsage(const ValueMap & infos,StringMatrix result)338 bool MemoryInfo::GetKernelUsage(const ValueMap &infos, StringMatrix result)
339 {
340 uint64_t value = 0;
341 unique_ptr<GetKernelInfo> getGetKernelInfo = make_unique<GetKernelInfo>();
342 bool success = getGetKernelInfo->GetKernel(infos, value);
343 if (success) {
344 vector<string> kernel;
345 string title = "Kernel Usage:";
346 StringUtils::GetInstance().SetWidth(RAM_WIDTH_, BLANK_, false, title);
347 kernel.push_back(title);
348 kernel.push_back(AddKbUnit(value));
349 result->push_back(kernel);
350 }
351 return success;
352 }
353
GetProcesses(const GroupMap & infos,StringMatrix result)354 void MemoryInfo::GetProcesses(const GroupMap &infos, StringMatrix result)
355 {
356 uint64_t value = 0;
357
358 unique_ptr<GetProcessInfo> getProcessInfo = make_unique<GetProcessInfo>();
359 value = getProcessInfo->GetProcess(infos);
360
361 vector<string> process;
362 string title = "Processes Usage:";
363 StringUtils::GetInstance().SetWidth(RAM_WIDTH_, BLANK_, false, title);
364 process.push_back(title);
365 process.push_back(AddKbUnit(value));
366 result->push_back(process);
367 }
368
GetPssTotal(const GroupMap & infos,StringMatrix result)369 void MemoryInfo::GetPssTotal(const GroupMap &infos, StringMatrix result)
370 {
371 vector<string> title;
372 title.push_back("Total Pss by Category:");
373 result->push_back(title);
374
375 vector<pair<string, uint64_t>> filePage;
376 vector<pair<string, uint64_t>> anonPage;
377 for (const auto &info : infos) {
378 vector<string> pageTag;
379 StringUtils::GetInstance().StringSplit(info.first, "#", pageTag);
380 string group = pageTag[1];
381 auto &valueMap = info.second;
382 uint64_t pssValue = 0;
383 for (const auto &str : MemoryFilter::GetInstance().CALC_PSS_TOTAL_) {
384 auto it = valueMap.find(str);
385 if (it != valueMap.end()) {
386 pssValue += it->second;
387 }
388 }
389
390 if (pageTag[0] == MemoryFilter::GetInstance().FILE_PAGE_TAG) {
391 filePage.push_back(make_pair(group, pssValue));
392 } else {
393 anonPage.push_back(make_pair(group, pssValue));
394 }
395 }
396 PairToStringMatrix(MemoryFilter::GetInstance().FILE_PAGE_TAG, filePage, result);
397 PairToStringMatrix(MemoryFilter::GetInstance().ANON_PAGE_TAG, anonPage, result);
398
399 vector<pair<string, uint64_t>> dmaValue;
400 dmaValue.push_back(make_pair(MemoryFilter::GetInstance().GL_OUT_LABEL, totalGL_));
401 dmaValue.push_back(make_pair(MemoryFilter::GetInstance().GRAPH_OUT_LABEL, totalGraph_));
402 PairToStringMatrix(MemoryFilter::GetInstance().DMA_TAG, dmaValue, result);
403 }
404
PairToStringMatrix(const string & titleStr,vector<pair<string,uint64_t>> & vec,StringMatrix result)405 void MemoryInfo::PairToStringMatrix(const string &titleStr, vector<pair<string, uint64_t>> &vec, StringMatrix result)
406 {
407 uint64_t totalPss = accumulate(vec.begin(), vec.end(), (uint64_t)0, [] (uint64_t a, pair<string, uint64_t> &b) {
408 return a + b.second;
409 });
410 vector<string> title;
411 title.push_back(titleStr + "(" + AddKbUnit(totalPss) + "):");
412 result->push_back(title);
413
414 std::sort(vec.begin(), vec.end(),
415 [] (pair<string, uint64_t> &left, pair<string, uint64_t> &right) {
416 return right.second < left.second;
417 });
418 for (const auto &pair : vec) {
419 vector<string> line;
420 string pssStr = AddKbUnit(pair.second);
421 StringUtils::GetInstance().SetWidth(RAM_WIDTH_, BLANK_, false, pssStr);
422 line.push_back(pssStr + " : " + pair.first);
423 result->push_back(line);
424 }
425 }
426
GetRamUsage(const GroupMap & smapsinfos,const ValueMap & meminfo,StringMatrix result)427 void MemoryInfo::GetRamUsage(const GroupMap &smapsinfos, const ValueMap &meminfo, StringMatrix result)
428 {
429 unique_ptr<GetRamInfo> getRamInfo = make_unique<GetRamInfo>();
430 GetRamInfo::Ram ram = getRamInfo->GetRam(smapsinfos, meminfo);
431
432 vector<string> total;
433 string totalTitle = "Total RAM:";
434 StringUtils::GetInstance().SetWidth(RAM_WIDTH_, BLANK_, false, totalTitle);
435 total.push_back(totalTitle);
436 total.push_back(AddKbUnit(ram.total));
437 result->push_back(total);
438
439 vector<string> free;
440 string freeTitle = "Free RAM:";
441 StringUtils::GetInstance().SetWidth(RAM_WIDTH_, BLANK_, false, freeTitle);
442 free.push_back(freeTitle);
443 free.push_back(AddKbUnit(ram.free));
444 free.push_back(" (" + to_string(ram.cachedInfo) + " cached + " + to_string(ram.freeInfo) + " free)");
445 result->push_back(free);
446
447 vector<string> used;
448 string usedTitle = "Used RAM:";
449 StringUtils::GetInstance().SetWidth(RAM_WIDTH_, BLANK_, false, usedTitle);
450 used.push_back(usedTitle);
451 used.push_back(AddKbUnit(ram.used));
452 used.push_back(" (" + to_string(ram.totalPss) + " total pss + " + to_string(ram.kernelUsed) + " kernel)");
453 result->push_back(used);
454
455 vector<string> lost;
456 string lostTitle = "Lost RAM:";
457 StringUtils::GetInstance().SetWidth(RAM_WIDTH_, BLANK_, false, lostTitle);
458 lost.push_back(lostTitle);
459 lost.push_back(AddKbUnit(ram.lost));
460 result->push_back(lost);
461 }
462
GetRamCategory(const GroupMap & smapsInfos,const ValueMap & meminfos,StringMatrix result)463 void MemoryInfo::GetRamCategory(const GroupMap &smapsInfos, const ValueMap &meminfos, StringMatrix result)
464 {
465 vector<string> title;
466 title.push_back("Total RAM by Category:");
467 result->push_back(title);
468
469 bool hardWareSuccess = GetHardWareUsage(result);
470 if (!hardWareSuccess) {
471 DUMPER_HILOGE(MODULE_SERVICE, "Get hardWare usage fail.\n");
472 }
473
474 bool cmaSuccess = GetCMAUsage(result);
475 if (!cmaSuccess) {
476 DUMPER_HILOGE(MODULE_SERVICE, "Get CMA fail.\n");
477 }
478
479 bool kernelSuccess = GetKernelUsage(meminfos, result);
480 if (!kernelSuccess) {
481 DUMPER_HILOGE(MODULE_SERVICE, "Get kernel usage fail.\n");
482 }
483
484 GetProcesses(smapsInfos, result);
485 }
486
AddBlankLine(StringMatrix result)487 void MemoryInfo::AddBlankLine(StringMatrix result)
488 {
489 vector<string> blank;
490 blank.push_back("\n");
491 result->push_back(blank);
492 }
493
GetProcName(const int & pid)494 string MemoryInfo::GetProcName(const int &pid)
495 {
496 string str = "grep \"Name\" /proc/" + to_string(pid) + "/status";
497 string procName = "unknown";
498 vector<string> cmdResult;
499 if (!MemoryUtil::GetInstance().RunCMD(str, cmdResult) || cmdResult.size() == 0) {
500 DUMPER_HILOGE(MODULE_SERVICE, "GetProcName fail! pid = %d", pid);
501 return procName;
502 }
503 vector<string> names;
504 StringUtils::GetInstance().StringSplit(cmdResult.at(0), ":", names);
505 if (names.empty()) {
506 return procName;
507 }
508 procName = cmdResult.at(0).substr(names[0].length() + 1);
509 return procName;
510 }
511
512 #ifdef HIDUMPER_MEMMGR_ENABLE
GetProcessAdjLabel(const int pid)513 string MemoryInfo::GetProcessAdjLabel(const int pid)
514 {
515 string cmd = "cat /proc/" + to_string(pid) + "/oom_score_adj";
516 vector<string> cmdResult;
517 string adjLabel = Memory::RECLAIM_PRIORITY_UNKNOWN_DESC;
518 if (!MemoryUtil::GetInstance().RunCMD(cmd, cmdResult) || cmdResult.size() == 0) {
519 DUMPER_HILOGE(MODULE_SERVICE, "GetProcessAdjLabel fail! pid = %{pubilic}d", pid);
520 return adjLabel;
521 }
522 string oom_score = cmdResult.front();
523 int value = 0;
524 bool ret = StrToInt(oom_score, value);
525 if (!ret) {
526 return adjLabel;
527 }
528 auto it = Memory::ReclaimPriorityMapping.find(value);
529 if (it != Memory::ReclaimPriorityMapping.end()) {
530 adjLabel = it->second;
531 }
532 return adjLabel;
533 }
534 #endif
535
GetPids()536 bool MemoryInfo::GetPids()
537 {
538 bool success = DumpCommonUtils::GetUserPids(pids_);
539 if (!success) {
540 DUMPER_HILOGE(MODULE_SERVICE, "GetPids error");
541 }
542 return success;
543 }
544
GetVss(const int & pid)545 uint64_t MemoryInfo::GetVss(const int &pid)
546 {
547 string path = "/proc/" + to_string(pid) + "/statm";
548 uint64_t res = 0;
549 bool ret = FileUtils::GetInstance().LoadStringFromProcCb(path, true, true, [&](const string& line) -> void {
550 if (!line.empty()) {
551 uint64_t tempValue = 0;
552 int retScanf = sscanf_s(line.c_str(), "%llu^*", &tempValue);
553 if (retScanf != -1) {
554 res = tempValue * VSS_BIT;
555 } else {
556 DUMPER_HILOGE(MODULE_SERVICE, "GetVss error! pid = %d", pid);
557 }
558 }
559 });
560 if (!ret) {
561 return 0;
562 }
563 return res;
564 }
565
GetGraphicsMemory(int32_t pid,MemInfoData::GraphicsMemory & graphicsMemory)566 bool MemoryInfo::GetGraphicsMemory(int32_t pid, MemInfoData::GraphicsMemory &graphicsMemory)
567 {
568 if (IsRenderService(pid)) {
569 GetRenderServiceGraphics(pid, graphicsMemory);
570 graphicsMemory.gl -= g_sumPidsMemGL;
571 return true;
572 }
573 #ifdef HIDUMPER_GRAPHIC_ENABLE
574 if (memGraphicVec_.empty()) {
575 return false;
576 }
577 for (auto it = memGraphicVec_.begin(); it != memGraphicVec_.end(); it++) {
578 if (pid == it->GetPid()) {
579 graphicsMemory.gl = it-> GetGpuMemorySize() / BYTE_PER_KB;
580 graphicsMemory.graph = it-> GetCpuMemorySize() / BYTE_PER_KB;
581 return true;
582 }
583 DUMPER_HILOGE(MODULE_SERVICE, "Get GL from RS fail.");
584 }
585 #endif
586 return false;
587 }
588
GetMemByProcessPid(const int & pid,MemInfoData::MemUsage & usage)589 bool MemoryInfo::GetMemByProcessPid(const int &pid, MemInfoData::MemUsage &usage)
590 {
591 bool success = false;
592 MemInfoData::MemInfo memInfo;
593 unique_ptr<ParseSmapsRollupInfo> getSmapsRollup = make_unique<ParseSmapsRollupInfo>();
594 if (getSmapsRollup->GetMemInfo(pid, memInfo)) {
595 usage.vss = GetVss(pid);
596 usage.uss = memInfo.privateClean + memInfo.privateDirty;
597 usage.rss = memInfo.rss;
598 usage.pss = memInfo.pss;
599 usage.swapPss = memInfo.swapPss;
600 usage.name = GetProcName(pid);
601 usage.pid = pid;
602 #ifdef HIDUMPER_MEMMGR_ENABLE
603 usage.adjLabel = GetProcessAdjLabel(pid);
604 #endif
605 success = true;
606 }
607
608 MemInfoData::GraphicsMemory graphicsMemory;
609 MemoryUtil::GetInstance().InitGraphicsMemory(graphicsMemory);
610 if (GetGraphicsMemory(pid, graphicsMemory)) {
611 usage.gl = graphicsMemory.gl;
612 usage.graph = graphicsMemory.graph;
613 usage.uss = usage.uss + graphicsMemory.gl + graphicsMemory.graph;
614 usage.pss = usage.pss + graphicsMemory.gl + graphicsMemory.graph;
615 usage.rss = usage.rss + graphicsMemory.gl + graphicsMemory.graph;
616 }
617 return success;
618 }
619
MemUsageToMatrix(const MemInfoData::MemUsage & memUsage,StringMatrix result)620 void MemoryInfo::MemUsageToMatrix(const MemInfoData::MemUsage &memUsage, StringMatrix result)
621 {
622 vector<string> strs;
623 string pid = to_string(memUsage.pid);
624 StringUtils::GetInstance().SetWidth(PID_WIDTH_, BLANK_, true, pid);
625 strs.push_back(pid);
626
627 string name = memUsage.name;
628 StringUtils::GetInstance().ReplaceAll(name, " ", "");
629 StringUtils::GetInstance().SetWidth(NAME_WIDTH_, BLANK_, true, name);
630 strs.push_back(name);
631
632 uint64_t pss = memUsage.pss + memUsage.swapPss;
633 string totalPss = to_string(pss) + "(" + to_string(memUsage.swapPss) + " in SwapPss) kB";
634 StringUtils::GetInstance().SetWidth(PSS_WIDTH_, BLANK_, false, totalPss);
635 strs.push_back(totalPss);
636
637 uint64_t vss = memUsage.vss;
638 string totalVss = AddKbUnit(vss);
639 StringUtils::GetInstance().SetWidth(KB_WIDTH_, BLANK_, false, totalVss);
640 strs.push_back(totalVss);
641
642 uint64_t rss = memUsage.rss;
643 string totalRss = AddKbUnit(rss);
644 StringUtils::GetInstance().SetWidth(KB_WIDTH_, BLANK_, false, totalRss);
645 strs.push_back(totalRss);
646
647 uint64_t uss = memUsage.uss;
648 string totalUss = AddKbUnit(uss);
649 StringUtils::GetInstance().SetWidth(KB_WIDTH_, BLANK_, false, totalUss);
650 strs.push_back(totalUss);
651
652 uint64_t gl = memUsage.gl;
653 string unMappedGL = AddKbUnit(gl);
654 StringUtils::GetInstance().SetWidth(KB_WIDTH_, BLANK_, false, unMappedGL);
655 strs.push_back(unMappedGL);
656
657 uint64_t graph = memUsage.graph;
658 string unMappedGraph = AddKbUnit(graph);
659 StringUtils::GetInstance().SetWidth(KB_WIDTH_, BLANK_, false, unMappedGraph);
660 strs.push_back(unMappedGraph);
661
662 result->emplace_back(strs);
663 }
664
AddMemByProcessTitle(StringMatrix result,string sortType)665 void MemoryInfo::AddMemByProcessTitle(StringMatrix result, string sortType)
666 {
667 vector<string> process;
668 string processTitle = "Total Memory Usage by " + sortType + ":";
669 process.push_back(processTitle);
670 result->push_back(process);
671
672 vector<string> title;
673 string pid = "PID";
674 StringUtils::GetInstance().SetWidth(PID_WIDTH_, BLANK_, true, pid);
675 title.push_back(pid);
676
677 string name = "Name";
678 string preBlank = " ";
679 StringUtils::GetInstance().SetWidth(NAME_WIDTH_, BLANK_, true, name);
680 title.push_back(preBlank.append(name));
681
682 string totalPss = "Total Pss(xxx in SwapPss)";
683 StringUtils::GetInstance().SetWidth(PSS_WIDTH_, BLANK_, false, totalPss);
684 title.push_back(totalPss);
685
686 string totalVss = "Total Vss";
687 StringUtils::GetInstance().SetWidth(KB_WIDTH_, BLANK_, false, totalVss);
688 title.push_back(totalVss);
689
690 string totalRss = "Total Rss";
691 StringUtils::GetInstance().SetWidth(KB_WIDTH_, BLANK_, false, totalRss);
692 title.push_back(totalRss);
693
694 string totalUss = "Total Uss";
695 StringUtils::GetInstance().SetWidth(KB_WIDTH_, BLANK_, false, totalUss);
696 title.push_back(totalUss);
697
698 string unMappedGL = MemoryFilter::GetInstance().GL_OUT_LABEL;
699 StringUtils::GetInstance().SetWidth(KB_WIDTH_, BLANK_, false, unMappedGL);
700 title.push_back(unMappedGL);
701
702 string unMappedGraph = MemoryFilter::GetInstance().GRAPH_OUT_LABEL;
703 StringUtils::GetInstance().SetWidth(KB_WIDTH_, BLANK_, false, unMappedGraph);
704 title.push_back(unMappedGraph);
705
706 result->push_back(title);
707 }
708
709 #ifdef HIDUMPER_GRAPHIC_ENABLE
GetMemGraphics()710 void MemoryInfo::GetMemGraphics()
711 {
712 memGraphicVec_.clear();
713 auto& rsClient = Rosen::RSInterfaces::GetInstance();
714 memGraphicVec_ = rsClient.GetMemoryGraphics();
715 auto sumPidsMemGL = 0;
716 for (auto it = memGraphicVec_.begin(); it != memGraphicVec_.end(); it++) {
717 sumPidsMemGL += it->GetGpuMemorySize();
718 }
719 g_sumPidsMemGL = static_cast<uint64_t>(sumPidsMemGL / BYTE_PER_KB);
720 }
721 #endif
722
GetMemoryInfoNoPid(StringMatrix result)723 DumpStatus MemoryInfo::GetMemoryInfoNoPid(StringMatrix result)
724 {
725 if (!isReady_) {
726 memUsages_.clear();
727 pids_.clear();
728 totalGL_ = 0;
729 totalGraph_ = 0;
730 AddMemByProcessTitle(result, "PID");
731 if (!GetPids()) {
732 return DUMP_FAIL;
733 }
734 #ifdef HIDUMPER_GRAPHIC_ENABLE
735 GetMemGraphics();
736 #endif
737 isReady_ = true;
738 return DUMP_MORE_DATA;
739 }
740
741 if (!dumpSmapsOnStart_) {
742 dumpSmapsOnStart_ = true;
743 fut_ = std::async(std::launch::async, [&]() {
744 GroupMap groupMap;
745 std::vector<int> pids(pids_);
746 for (auto pid : pids) {
747 GetSmapsInfoNoPid(pid, groupMap);
748 }
749 return groupMap;
750 });
751 }
752 MemInfoData::MemUsage usage;
753 MemoryUtil::GetInstance().InitMemUsage(usage);
754 if (pids_.size() > 0) {
755 if (GetMemByProcessPid(pids_.front(), usage)) {
756 memUsages_.push_back(usage);
757 adjMemResult_[usage.adjLabel].push_back(usage);
758 totalGL_ += usage.gl;
759 totalGraph_ += usage.graph;
760 MemUsageToMatrix(usage, result);
761 } else {
762 DUMPER_HILOGE(MODULE_SERVICE, "Get smaps_rollup error! pid = %{public}d\n", pids_.front());
763 }
764 pids_.erase(pids_.begin());
765 return DUMP_MORE_DATA;
766 }
767 return DealResult(result);
768 }
769
DealResult(StringMatrix result)770 DumpStatus MemoryInfo::DealResult(StringMatrix result)
771 {
772 ValueMap meminfoResult;
773 if (!GetMeminfo(meminfoResult)) {
774 DUMPER_HILOGE(MODULE_SERVICE, "Get meminfo error\n");
775 return DUMP_FAIL;
776 }
777
778 GetSortedMemoryInfoNoPid(result);
779 AddBlankLine(result);
780 #ifdef HIDUMPER_MEMMGR_ENABLE
781 GetMemoryByAdj(result);
782 #endif
783 AddBlankLine(result);
784
785 GroupMap smapsResult = fut_.get();
786
787 GetPssTotal(smapsResult, result);
788 AddBlankLine(result);
789
790 GetRamUsage(smapsResult, meminfoResult, result);
791 AddBlankLine(result);
792
793 GetRamCategory(smapsResult, meminfoResult, result);
794
795 isReady_ = false;
796 dumpSmapsOnStart_ = false;
797 memUsages_.clear();
798 smapsResult.clear();
799 return DUMP_OK;
800 }
801
GetSortedMemoryInfoNoPid(StringMatrix result)802 void MemoryInfo::GetSortedMemoryInfoNoPid(StringMatrix result)
803 {
804 AddBlankLine(result);
805 AddMemByProcessTitle(result, "Size");
806
807 std::sort(memUsages_.begin(), memUsages_.end(),
808 [] (MemInfoData::MemUsage &left, MemInfoData::MemUsage &right) {
809 if (right.pss + right.swapPss != left.pss + left.swapPss) {
810 return right.pss + right.swapPss < left.pss + left.swapPss;
811 }
812 if (right.vss != left.vss) {
813 return right.vss < left.vss;
814 }
815 if (right.rss != left.rss) {
816 return right.rss < left.rss;
817 }
818 if (right.uss != left.uss) {
819 return right.uss < left.uss;
820 }
821 return right.pid < left.pid;
822 });
823
824 for (auto &memUsage : memUsages_) {
825 MemUsageToMatrix(memUsage, result);
826 }
827 }
828
829 #ifdef HIDUMPER_MEMMGR_ENABLE
GetMemoryByAdj(StringMatrix result)830 void MemoryInfo::GetMemoryByAdj(StringMatrix result)
831 {
832 vector<string> title;
833 title.push_back("Total Pss by OOM adjustment:");
834 result->push_back(title);
835
836 vector<string> reclaimPriority_;
837 for (auto reclaim : Memory::ReclaimPriorityMapping) {
838 reclaimPriority_.push_back(reclaim.second);
839 }
840 reclaimPriority_.push_back(Memory::RECLAIM_PRIORITY_UNKNOWN_DESC);
841
842 for (const auto &adjLabel : reclaimPriority_) {
843 vector<MemInfoData::MemUsage> memUsages = adjMemResult_[adjLabel];
844 vector<string> label;
845 if (memUsages.size() == 0) {
846 label.push_back(adjLabel + ": " + AddKbUnit(0));
847 result->push_back(label);
848 continue;
849 }
850 uint64_t totalPss = accumulate(memUsages.begin(), memUsages.end(), (uint64_t)0,
851 [] (uint64_t a, MemInfoData::MemUsage &b) {
852 return a + b.pss + b.swapPss;
853 });
854 label.push_back(adjLabel + ": " + AddKbUnit(totalPss));
855 result->push_back(label);
856
857 std::sort(memUsages.begin(), memUsages.end(),
858 [] (MemInfoData::MemUsage &left, MemInfoData::MemUsage &right) {
859 return right.pss + right.swapPss < left.pss + left.swapPss;
860 });
861 for (const auto &memUsage : memUsages) {
862 vector<string> line;
863 string name = memUsage.name + "(pid=" + to_string(memUsage.pid) + "): ";
864 StringUtils::GetInstance().SetWidth(NAME_AND_PID_WIDTH, BLANK_, true, name);
865 line.push_back(name + AddKbUnit(memUsage.pss + memUsage.swapPss));
866 if (memUsage.swapPss > 0) {
867 line.push_back(" (" + to_string(memUsage.swapPss) + " kB in SwapPss)");
868 }
869 result->push_back(line);
870 }
871 }
872 }
873 #endif
874
SetPss(MemInfoData::MemInfo & meminfo,uint64_t value)875 void MemoryInfo::SetPss(MemInfoData::MemInfo &meminfo, uint64_t value)
876 {
877 meminfo.pss += value;
878 }
879
SetSharedClean(MemInfoData::MemInfo & meminfo,uint64_t value)880 void MemoryInfo::SetSharedClean(MemInfoData::MemInfo &meminfo, uint64_t value)
881 {
882 meminfo.sharedClean += value;
883 }
884
SetSharedDirty(MemInfoData::MemInfo & meminfo,uint64_t value)885 void MemoryInfo::SetSharedDirty(MemInfoData::MemInfo &meminfo, uint64_t value)
886 {
887 meminfo.sharedDirty += value;
888 }
889
SetPrivateClean(MemInfoData::MemInfo & meminfo,uint64_t value)890 void MemoryInfo::SetPrivateClean(MemInfoData::MemInfo &meminfo, uint64_t value)
891 {
892 meminfo.privateClean += value;
893 }
894
SetPrivateDirty(MemInfoData::MemInfo & meminfo,uint64_t value)895 void MemoryInfo::SetPrivateDirty(MemInfoData::MemInfo &meminfo, uint64_t value)
896 {
897 meminfo.privateDirty += value;
898 }
899
SetSwap(MemInfoData::MemInfo & meminfo,uint64_t value)900 void MemoryInfo::SetSwap(MemInfoData::MemInfo &meminfo, uint64_t value)
901 {
902 meminfo.swap += value;
903 }
904
SetSwapPss(MemInfoData::MemInfo & meminfo,uint64_t value)905 void MemoryInfo::SetSwapPss(MemInfoData::MemInfo &meminfo, uint64_t value)
906 {
907 meminfo.swapPss += value;
908 }
SetHeapSize(MemInfoData::MemInfo & meminfo,uint64_t value)909 void MemoryInfo::SetHeapSize(MemInfoData::MemInfo &meminfo, uint64_t value)
910 {
911 meminfo.heapSize += value;
912 }
913
SetHeapAlloc(MemInfoData::MemInfo & meminfo,uint64_t value)914 void MemoryInfo::SetHeapAlloc(MemInfoData::MemInfo &meminfo, uint64_t value)
915 {
916 meminfo.heapAlloc += value;
917 }
918
SetHeapFree(MemInfoData::MemInfo & meminfo,uint64_t value)919 void MemoryInfo::SetHeapFree(MemInfoData::MemInfo &meminfo, uint64_t value)
920 {
921 meminfo.heapFree += value;
922 }
923 } // namespace HiviewDFX
924 } // namespace OHOS
925