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