1 /*
2 * Copyright (c) 2022-2023 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 "memory/rs_memory_track.h"
16
17 #include "platform/common/rs_log.h"
18 namespace OHOS {
19 namespace Rosen {
20 namespace {
21 constexpr uint32_t MEM_MAX_SIZE = 2;
22 constexpr uint32_t MEM_SIZE_STRING_LEN = 10;
23 constexpr uint32_t MEM_ADDR_STRING_LEN = 16;
24 constexpr uint32_t MEM_TYPE_STRING_LEN = 16;
25 constexpr uint32_t MEM_PID_STRING_LEN = 8;
26 constexpr uint32_t MEM_WID_STRING_LEN = 20;
27 constexpr uint32_t MEM_SURNODE_STRING_LEN = 40;
28 constexpr uint32_t MEM_FRAME_STRING_LEN = 35;
29 constexpr uint32_t MEM_NODEID_STRING_LEN = 20;
30 }
31
MemoryNodeOfPid(size_t size,NodeId id)32 MemoryNodeOfPid::MemoryNodeOfPid(size_t size, NodeId id) : nodeSize_(size), nodeId_(id) {}
33
GetMemSize()34 size_t MemoryNodeOfPid::GetMemSize()
35 {
36 return nodeSize_;
37 }
38
operator ==(const MemoryNodeOfPid & other)39 bool MemoryNodeOfPid::operator==(const MemoryNodeOfPid& other)
40 {
41 return nodeId_ == other.nodeId_;
42 }
43
Instance()44 MemoryTrack& MemoryTrack::Instance()
45 {
46 static MemoryTrack instance;
47 return instance;
48 }
49
AddNodeRecord(const NodeId id,const MemoryInfo & info)50 void MemoryTrack::AddNodeRecord(const NodeId id, const MemoryInfo& info)
51 {
52 std::lock_guard<std::mutex> lock(mutex_);
53 memNodeMap_.emplace(id, info);
54 MemoryNodeOfPid nodeInfoOfPid(info.size, id);
55 memNodeOfPidMap_[info.pid].push_back(nodeInfoOfPid);
56 }
57
RemoveNodeFromMap(const NodeId id,pid_t & pid,size_t & size)58 bool MemoryTrack::RemoveNodeFromMap(const NodeId id, pid_t& pid, size_t& size)
59 {
60 auto itr = memNodeMap_.find(id);
61 if (itr == memNodeMap_.end()) {
62 RS_LOGD("MemoryTrack::RemoveNodeFromMap no this nodeId = %{public}" PRIu64, id);
63 return false;
64 }
65 pid = memNodeMap_[id].pid;
66 size = memNodeMap_[id].size;
67 memNodeMap_.erase(itr);
68 return true;
69 }
70
RemoveNodeOfPidFromMap(const pid_t pid,const size_t size,const NodeId id)71 void MemoryTrack::RemoveNodeOfPidFromMap(const pid_t pid, const size_t size, const NodeId id)
72 {
73 if (memNodeOfPidMap_.find(pid) == memNodeOfPidMap_.end()) {
74 RS_LOGW("MemoryTrack::RemoveNodeOfPidFromMap no this nodeId = %{public}" PRIu64, id);
75 return;
76 }
77 MemoryNodeOfPid nodeInfoOfPid = {size, id};
78 auto itr = std::find(memNodeOfPidMap_[pid].begin(), memNodeOfPidMap_[pid].end(), nodeInfoOfPid);
79 if (itr != memNodeOfPidMap_[pid].end()) {
80 memNodeOfPidMap_[pid].erase(itr);
81 }
82 }
83
RemoveNodeRecord(const NodeId id)84 void MemoryTrack::RemoveNodeRecord(const NodeId id)
85 {
86 std::lock_guard<std::mutex> lock(mutex_);
87 pid_t pid = 0;
88 size_t size = 0;
89 bool isSuccess = RemoveNodeFromMap(id, pid, size);
90 if (!isSuccess) {
91 return;
92 }
93 RemoveNodeOfPidFromMap(pid, size, id);
94 }
95
CountRSMemory(const pid_t pid)96 MemoryGraphic MemoryTrack::CountRSMemory(const pid_t pid)
97 {
98 std::lock_guard<std::mutex> lock(mutex_);
99 MemoryGraphic memoryGraphic;
100 auto itr = memNodeOfPidMap_.find(pid);
101 if (itr == memNodeOfPidMap_.end()) {
102 return memoryGraphic;
103 }
104 auto nodeInfoOfPid = memNodeOfPidMap_[pid];
105 if (nodeInfoOfPid.empty()) {
106 memNodeOfPidMap_.erase(pid);
107 } else {
108 int totalMemSize = 0;
109 std::for_each(nodeInfoOfPid.begin(), nodeInfoOfPid.end(), [&totalMemSize](MemoryNodeOfPid& info) {
110 totalMemSize += info.GetMemSize();
111 });
112
113 for (auto it = memPicRecord_.begin(); it != memPicRecord_.end(); it++) {
114 pid_t picPid = it->second.pid;
115 if (pid == picPid) {
116 totalMemSize += static_cast<int>(it->second.size);
117 }
118 }
119 memoryGraphic.SetPid(pid);
120 memoryGraphic.SetCpuMemorySize(totalMemSize);
121 }
122 return memoryGraphic;
123 }
124
GetAppMemorySizeInMB()125 float MemoryTrack::GetAppMemorySizeInMB()
126 {
127 float total = 0.f;
128 for (auto& [_, memInfo] : memPicRecord_) {
129 total += static_cast<float>(memInfo.size);
130 }
131 return total / BYTE_CONVERT / BYTE_CONVERT / 2; // app mem account for 50%
132 }
133
DumpMemoryStatistics(DfxString & log,std::function<std::tuple<uint64_t,std::string,RectI> (uint64_t)> func)134 void MemoryTrack::DumpMemoryStatistics(DfxString& log,
135 std::function<std::tuple<uint64_t, std::string, RectI> (uint64_t)> func)
136 {
137 std::lock_guard<std::mutex> lock(mutex_);
138 DumpMemoryPicStatistics(log, func);
139 DumpMemoryNodeStatistics(log);
140 }
141
DumpMemoryNodeStatistics(DfxString & log)142 void MemoryTrack::DumpMemoryNodeStatistics(DfxString& log)
143 {
144 log.AppendFormat("\nRSRenderNode:\n");
145
146 int totalSize = 0;
147 int count = 0;
148 //calculate by byte
149 for (auto& [nodeId, info] : memNodeMap_) {
150 //total of all
151 totalSize += static_cast<int>(info.size);
152 count++;
153 }
154 log.AppendFormat("Total Node Size = %d KB (%d entries)\n", totalSize / BYTE_CONVERT, count);
155 }
156
UpdatePictureInfo(const void * addr,NodeId nodeId,pid_t pid)157 void MemoryTrack::UpdatePictureInfo(const void* addr, NodeId nodeId, pid_t pid)
158 {
159 std::lock_guard<std::mutex> lock(mutex_);
160 auto itr = memPicRecord_.find(addr);
161 if (itr != memPicRecord_.end()) {
162 itr->second.pid = pid;
163 itr->second.nid = nodeId;
164 }
165 }
166
MemoryType2String(MEMORY_TYPE type)167 const char* MemoryTrack::MemoryType2String(MEMORY_TYPE type)
168 {
169 switch (type) {
170 case MEM_PIXELMAP : {
171 return "pixelmap";
172 }
173 case MEM_SKIMAGE : {
174 return "skimage";
175 }
176 default : {
177 return "";
178 }
179 }
180 }
181
Data2String(std::string data,uint32_t tagetNumber)182 static std::string Data2String(std::string data, uint32_t tagetNumber)
183 {
184 if (data.length() < tagetNumber) {
185 return std::string(tagetNumber - data.length(), ' ') + data;
186 } else {
187 return data;
188 }
189 }
190
GenerateDumpTitle()191 std::string MemoryTrack::GenerateDumpTitle()
192 {
193 std::string size_title = Data2String("Size", MEM_SIZE_STRING_LEN);
194 std::string type_title = Data2String("Type", MEM_TYPE_STRING_LEN);
195 std::string pid_title = Data2String("Pid", MEM_PID_STRING_LEN);
196 std::string wid_title = Data2String("Wid", MEM_WID_STRING_LEN);
197 std::string surfaceNode_title = Data2String("SurfaceName", MEM_SURNODE_STRING_LEN);
198 std::string frame_title = Data2String("Frame", MEM_FRAME_STRING_LEN);
199 std::string nid_title = Data2String("NodeId", MEM_NODEID_STRING_LEN);
200 std::string addr_tile = Data2String("Addr", MEM_ADDR_STRING_LEN);
201 return size_title + "\t" + type_title + "\t" + pid_title + "\t" + wid_title + "\t" +
202 surfaceNode_title + "\t" + frame_title + nid_title + "\t" + addr_tile;
203 }
204
GenerateDetail(MemoryInfo info,uint64_t wId,std::string & wName,RectI & nFrame)205 std::string MemoryTrack::GenerateDetail(MemoryInfo info, uint64_t wId, std::string& wName, RectI& nFrame)
206 {
207 std::string size_str = Data2String(std::to_string(info.size), MEM_SIZE_STRING_LEN);
208 std::string type_str = Data2String(MemoryType2String(info.type), MEM_TYPE_STRING_LEN);
209 std::string pid_str = Data2String(std::to_string(ExtractPid(info.nid)), MEM_PID_STRING_LEN);
210 std::string wid_str = Data2String(std::to_string(wId), MEM_WID_STRING_LEN);
211 std::string wname_str = Data2String(wName, MEM_SURNODE_STRING_LEN);
212 std::string frame_str = Data2String(nFrame.ToString(), MEM_FRAME_STRING_LEN);
213 std::string nid_str = Data2String(std::to_string(info.nid), MEM_NODEID_STRING_LEN);
214 return size_str + "\t"+ type_str + "\t" + pid_str + "\t" + wid_str + "\t" +
215 wname_str + "\t" + frame_str + nid_str;
216 }
217
DumpMemoryPicStatistics(DfxString & log,std::function<std::tuple<uint64_t,std::string,RectI> (uint64_t)> func)218 void MemoryTrack::DumpMemoryPicStatistics(DfxString& log,
219 std::function<std::tuple<uint64_t, std::string, RectI> (uint64_t)> func)
220 {
221 log.AppendFormat("RSImageCache:\n");
222 log.AppendFormat("%s:\n", GenerateDumpTitle().c_str());
223
224 int arrTotal[MEM_MAX_SIZE] = {0};
225 int arrCount[MEM_MAX_SIZE] = {0};
226 int totalSize = 0;
227 int count = 0;
228 //calculate by byte
229 for (auto& [addr, info] : memPicRecord_) {
230 int size = static_cast<int>(info.size / BYTE_CONVERT); // k
231 //total of type
232 arrTotal[info.type] += size;
233 arrCount[info.type]++;
234
235 //total of all
236 totalSize += size;
237 count++;
238 auto [windowId, windowName, nodeFrameRect] = func(info.nid);
239 log.AppendFormat("%s \t %p\n", GenerateDetail(info, windowId, windowName, nodeFrameRect).c_str(), addr);
240 }
241
242 for (uint32_t i = MEM_PIXELMAP; i < MEM_MAX_SIZE; i++) {
243 MEMORY_TYPE type = static_cast<MEMORY_TYPE>(i);
244 log.AppendFormat(" %s:Size = %d KB (%d entries)\n", MemoryType2String(type), arrTotal[i], arrCount[i]);
245 }
246 log.AppendFormat("Total Size = %d KB (%d entries)\n", totalSize, count);
247 }
248
AddPictureRecord(const void * addr,MemoryInfo info)249 void MemoryTrack::AddPictureRecord(const void* addr, MemoryInfo info)
250 {
251 std::lock_guard<std::mutex> lock(mutex_);
252 memPicRecord_.emplace(addr, info);
253 }
254
RemovePictureRecord(const void * addr)255 void MemoryTrack::RemovePictureRecord(const void* addr)
256 {
257 std::lock_guard<std::mutex> lock(mutex_);
258 memPicRecord_.erase(addr);
259 }
260
261 }
262 }