• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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