• 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 
16 #include "executor/memory/parse/parse_smaps_info.h"
17 #include <fstream>
18 #include "executor/memory/memory_util.h"
19 #include "hilog_wrapper.h"
20 #include "util/string_utils.h"
21 #include "util/file_utils.h"
22 
23 using namespace std;
24 namespace OHOS {
25 namespace HiviewDFX {
ParseSmapsInfo()26 ParseSmapsInfo::ParseSmapsInfo()
27 {
28 }
29 
~ParseSmapsInfo()30 ParseSmapsInfo::~ParseSmapsInfo()
31 {
32 }
33 
GetHasPidValue(const string & str,string & type,uint64_t & value)34 bool ParseSmapsInfo::GetHasPidValue(const string &str, string &type, uint64_t &value)
35 {
36     bool success = false;
37     if (StringUtils::GetInstance().IsBegin(str, "R")) {
38         success = MemoryUtil::GetInstance().GetTypeAndValue(str, type, value);
39         if (success) {
40             if (type == "Rss") {
41                 return true;
42             }
43         }
44         return false;
45     } else if (StringUtils::GetInstance().IsBegin(str, "P")) {
46         success = MemoryUtil::GetInstance().GetTypeAndValue(str, type, value);
47         if (success) {
48             if (type == "Pss" || type == "Private_Clean" || type == "Private_Dirty") {
49                 return true;
50             }
51         }
52         return false;
53     } else if (StringUtils::GetInstance().IsBegin(str, "S")) {
54         success = MemoryUtil::GetInstance().GetTypeAndValue(str, type, value);
55         if (success) {
56             if (type == "Shared_Clean" || type == "Shared_Dirty" || type == "Swap" || type == "SwapPss" ||
57                 type == "Size") {
58                 return true;
59             }
60         }
61         return false;
62     }
63     return false;
64 }
65 
GetNoPidValue(const string & str,string & type,uint64_t & value)66 bool ParseSmapsInfo::GetNoPidValue(const string &str, string &type, uint64_t &value)
67 {
68     if (StringUtils::GetInstance().IsBegin(str, "Pss") || StringUtils::GetInstance().IsBegin(str, "SwapPss")) {
69         return MemoryUtil::GetInstance().GetTypeAndValue(str, type, value);
70     }
71     return false;
72 }
73 
GetValue(const MemoryFilter::MemoryType & memType,const string & str,string & type,uint64_t & value)74 bool ParseSmapsInfo::GetValue(const MemoryFilter::MemoryType &memType, const string &str, string &type, uint64_t &value)
75 {
76     if (memType == MemoryFilter::MemoryType::APPOINT_PID) {
77         return GetHasPidValue(str, type, value);
78     } else {
79         return GetNoPidValue(str, type, value);
80     }
81 }
82 
83 /**
84  * @description: Parse smaps file
85  * @param {MemoryType} &memType-APPOINT_PID-Specify the PID,NOT_SPECIFIED_PID-No PID is specified
86  * @param {int} &pid-Pid
87  * @param {GroupMap} &result-The result of parsing
88  * @return bool-true:parse success,false-parse fail
89  */
GetInfo(const MemoryFilter::MemoryType & memType,const int & pid,GroupMap & nativeMap,GroupMap & result)90 bool ParseSmapsInfo::GetInfo(const MemoryFilter::MemoryType &memType, const int &pid,
91                              GroupMap &nativeMap, GroupMap &result)
92 {
93     DUMPER_HILOGD(MODULE_SERVICE, "ParseSmapsInfo: GetInfo pid:(%{public}d) begin.\n", pid);
94     string path = "/proc/" + to_string(pid) + "/smaps";
95     bool ret = FileUtils::GetInstance().LoadStringFromProcCb(path, false, true, [&](const string& line) -> void {
96         string name;
97         uint64_t iNode = 0;
98         if (StringUtils::GetInstance().IsEnd(line, "B")) {
99             string type;
100             uint64_t value = 0;
101             if (GetValue(memType, line, type, value)) {
102                 MemoryUtil::GetInstance().CalcGroup(memGroup_, type, value, result);
103                 MemoryUtil::GetInstance().CalcGroup(nativeMemGroup_, type, value, nativeMap);
104             }
105         } else if (MemoryUtil::GetInstance().IsNameLine(line, name, iNode)) {
106             MemoryFilter::GetInstance().ParseMemoryGroup(name, memGroup_, iNode);
107             MemoryFilter::GetInstance().ParseNativeHeapMemoryGroup(name, nativeMemGroup_, iNode);
108         }
109     });
110     DUMPER_HILOGD(MODULE_SERVICE, "ParseSmapsInfo: GetInfo pid:(%{public}d) end,success!\n", pid);
111     return ret;
112 }
113 
SetMemoryData(MemoryData & memoryData,const MemoryItem & memoryItem,const std::string & memoryClassStr)114 void ParseSmapsInfo::SetMemoryData(MemoryData &memoryData, const MemoryItem &memoryItem,
115     const std::string& memoryClassStr)
116 {
117     memoryData.name = memoryItem.name == "" ? "[anon]" : memoryItem.name;
118     memoryData.memoryClass = memoryClassStr;
119     memoryData.counts = 1;
120     memoryData.size = memoryItem.size;
121     memoryData.rss = memoryItem.rss;
122     memoryData.pss = memoryItem.pss;
123     memoryData.swapPss = memoryItem.swapPss;
124     memoryData.swap = memoryItem.swap;
125     memoryData.sharedDirty = memoryItem.sharedDirty;
126     memoryData.privateDirty = memoryItem.privateDirty;
127     memoryData.sharedClean = memoryItem.sharedClean;
128     memoryData.privateClean = memoryItem.privateClean;
129     memoryData.iNode = memoryItem.iNode;
130 }
131 
UpdateCountSameNameMemMap(const std::vector<MemoryItem> & memoryItems,const std::string & memoryClassStr,std::map<std::string,MemoryData> & countSameNameMemMap)132 void ParseSmapsInfo::UpdateCountSameNameMemMap(const std::vector<MemoryItem>& memoryItems,
133     const std::string& memoryClassStr, std::map<std::string, MemoryData>& countSameNameMemMap)
134 {
135     for (const auto& memoryItem : memoryItems) {
136         if (countSameNameMemMap.find(memoryItem.name) == countSameNameMemMap.end()) {
137             MemoryData memoryData;
138             SetMemoryData(memoryData, memoryItem, memoryClassStr);
139             countSameNameMemMap[memoryItem.name] = memoryData;
140         } else {
141             MemoryData& data = countSameNameMemMap[memoryItem.name];
142             data.size += memoryItem.size;
143             data.rss += memoryItem.rss;
144             data.pss += memoryItem.pss;
145             data.swapPss += memoryItem.swapPss;
146             data.swap += memoryItem.swap;
147             data.sharedDirty += memoryItem.sharedDirty;
148             data.privateDirty += memoryItem.privateDirty;
149             data.sharedClean += memoryItem.sharedClean;
150             data.privateClean += memoryItem.privateClean;
151             data.counts++;
152         }
153     }
154 }
155 
UpdateShowAddressMemInfoVec(const std::vector<MemoryItem> & memoryItems,const std::string & memoryClassStr,std::vector<MemoryData> & showAddressMemInfoVec)156 void ParseSmapsInfo::UpdateShowAddressMemInfoVec(const std::vector<MemoryItem>& memoryItems,
157     const std::string& memoryClassStr, std::vector<MemoryData>& showAddressMemInfoVec)
158 {
159     for (const auto& memoryItem : memoryItems) {
160         MemoryData memoryData;
161         memoryData.permission = memoryItem.permission;
162         memoryData.startAddr = memoryItem.startAddr;
163         memoryData.endAddr = memoryItem.endAddr;
164         SetMemoryData(memoryData, memoryItem, memoryClassStr);
165         showAddressMemInfoVec.push_back(memoryData);
166     }
167 }
168 
GetSmapsData(const int & pid,bool isShowSmapsAddress,std::map<std::string,MemoryData> & countSameNameMemMap,std::vector<MemoryData> & showAddressMemInfoVec)169 bool ParseSmapsInfo::GetSmapsData(const int &pid, bool isShowSmapsAddress,
170     std::map<std::string, MemoryData>& countSameNameMemMap, std::vector<MemoryData>& showAddressMemInfoVec)
171 {
172     DUMPER_HILOGI(MODULE_SERVICE, "collect memory begin, pid:%{public}d", pid);
173     std::shared_ptr<UCollectUtil::MemoryCollector> collector = UCollectUtil::MemoryCollector::Create();
174     auto collectRet = collector->CollectProcessMemoryDetail(pid, GraphicMemOption::NONE);
175     if (collectRet.retCode != UCollect::UcError::SUCCESS) {
176         DUMPER_HILOGE(MODULE_SERVICE, "collect process memory error, ret:%{public}d", collectRet.retCode);
177         return false;
178     }
179     DUMPER_HILOGI(MODULE_SERVICE, "collect memory end, pid:%{public}d", pid);
180     vector<MemoryDetail> memoryDetails = collectRet.data.details;
181     for (const auto& memoryDetail : memoryDetails) {
182         MemoryClass memoryClass = memoryDetail.memoryClass;
183         if (static_cast<int>(memoryClass) < 0 ||
184             static_cast<size_t>(memoryClass) > MEMORY_CLASS_VEC.size()) {
185             DUMPER_HILOGE(MODULE_SERVICE, "memoryClass:%{public}d is not exist", memoryClass);
186             continue;
187         }
188         string memoryClassStr = MEMORY_CLASS_VEC[static_cast<int>(memoryClass)];
189         if (memoryClassStr == "graph") {
190             continue;
191         }
192         vector<MemoryItem> memoryItems = memoryDetail.items;
193         if (isShowSmapsAddress) {
194             UpdateShowAddressMemInfoVec(memoryItems, memoryClassStr, showAddressMemInfoVec);
195         } else {
196             UpdateCountSameNameMemMap(memoryItems, memoryClassStr, countSameNameMemMap);
197         }
198     }
199     return true;
200 }
201 } // namespace HiviewDFX
202 } // namespace OHOS
203