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