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