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 #include "platform/common/rs_system_properties.h"
19 namespace OHOS {
20 namespace Rosen {
21 namespace {
22 constexpr uint32_t MEM_MAX_SIZE = 2;
23 constexpr uint32_t MEM_SIZE_STRING_LEN = 10;
24 constexpr uint32_t MEM_ADDR_STRING_LEN = 16;
25 constexpr uint32_t MEM_TYPE_STRING_LEN = 16;
26 constexpr uint32_t PIXELMAP_INFO_STRING_LEN = 36;
27 constexpr uint32_t MEM_PID_STRING_LEN = 8;
28 constexpr uint32_t MEM_WID_STRING_LEN = 20;
29 constexpr uint32_t MEM_UID_STRING_LEN = 8;
30 constexpr uint32_t MEM_SURNODE_STRING_LEN = 40;
31 constexpr uint32_t MEM_FRAME_STRING_LEN = 35;
32 constexpr uint32_t MEM_NODEID_STRING_LEN = 20;
33 }
34
MemoryNodeOfPid(size_t size,NodeId id)35 MemoryNodeOfPid::MemoryNodeOfPid(size_t size, NodeId id) : nodeSize_(size), nodeId_(id) {}
36
GetMemSize()37 size_t MemoryNodeOfPid::GetMemSize()
38 {
39 return nodeSize_;
40 }
41
SetMemSize(size_t size)42 void MemoryNodeOfPid::SetMemSize(size_t size)
43 {
44 nodeSize_ = size;
45 }
46
operator ==(const MemoryNodeOfPid & other)47 bool MemoryNodeOfPid::operator==(const MemoryNodeOfPid& other)
48 {
49 return nodeId_ == other.nodeId_;
50 }
51
Instance()52 MemoryTrack& MemoryTrack::Instance()
53 {
54 static MemoryTrack instance;
55 return instance;
56 }
57
AddNodeRecord(const NodeId id,const MemoryInfo & info)58 void MemoryTrack::AddNodeRecord(const NodeId id, const MemoryInfo& info)
59 {
60 std::lock_guard<std::mutex> lock(mutex_);
61 MemoryNodeOfPid nodeInfoOfPid(info.size, id);
62 auto itr = memNodeMap_.find(id);
63 if (itr == memNodeMap_.end()) {
64 memNodeMap_.emplace(id, info);
65 memNodeOfPidMap_[info.pid].push_back(nodeInfoOfPid);
66 return;
67 } else if (info.size > itr->second.size) {
68 nodeInfoOfPid.SetMemSize(itr->second.size);
69 itr->second.size = info.size;
70 } else {
71 return;
72 }
73
74 if (memNodeOfPidMap_.find(info.pid) != memNodeOfPidMap_.end()) {
75 auto pidMemItr = std::find(memNodeOfPidMap_[info.pid].begin(),
76 memNodeOfPidMap_[info.pid].end(), nodeInfoOfPid);
77 if (pidMemItr != memNodeOfPidMap_[info.pid].end()) {
78 pidMemItr->SetMemSize(info.size);
79 } else {
80 nodeInfoOfPid.SetMemSize(info.size);
81 memNodeOfPidMap_[info.pid].push_back(nodeInfoOfPid);
82 }
83 } else {
84 nodeInfoOfPid.SetMemSize(info.size);
85 memNodeOfPidMap_[info.pid].push_back(nodeInfoOfPid);
86 }
87 }
88
RemoveNodeFromMap(const NodeId id,pid_t & pid,size_t & size)89 bool MemoryTrack::RemoveNodeFromMap(const NodeId id, pid_t& pid, size_t& size)
90 {
91 auto itr = memNodeMap_.find(id);
92 if (itr == memNodeMap_.end()) {
93 RS_LOGD("MemoryTrack::RemoveNodeFromMap no this nodeId = %{public}" PRIu64, id);
94 return false;
95 }
96 pid = memNodeMap_[id].pid;
97 size = memNodeMap_[id].size;
98 memNodeMap_.erase(itr);
99 return true;
100 }
101
RemoveNodeOfPidFromMap(const pid_t pid,const size_t size,const NodeId id)102 void MemoryTrack::RemoveNodeOfPidFromMap(const pid_t pid, const size_t size, const NodeId id)
103 {
104 if (memNodeOfPidMap_.find(pid) == memNodeOfPidMap_.end()) {
105 RS_LOGW("MemoryTrack::RemoveNodeOfPidFromMap no this nodeId = %{public}" PRIu64, id);
106 return;
107 }
108 MemoryNodeOfPid nodeInfoOfPid = {size, id};
109 auto itr = std::find(memNodeOfPidMap_[pid].begin(), memNodeOfPidMap_[pid].end(), nodeInfoOfPid);
110 if (itr != memNodeOfPidMap_[pid].end()) {
111 memNodeOfPidMap_[pid].erase(itr);
112 }
113 }
114
RemoveNodeRecord(const NodeId id)115 void MemoryTrack::RemoveNodeRecord(const NodeId id)
116 {
117 std::lock_guard<std::mutex> lock(mutex_);
118 pid_t pid = 0;
119 size_t size = 0;
120 bool isSuccess = RemoveNodeFromMap(id, pid, size);
121 if (!isSuccess) {
122 return;
123 }
124 RemoveNodeOfPidFromMap(pid, size, id);
125 }
126
CountRSMemory(const pid_t pid)127 MemoryGraphic MemoryTrack::CountRSMemory(const pid_t pid)
128 {
129 std::lock_guard<std::mutex> lock(mutex_);
130 MemoryGraphic memoryGraphic;
131 auto itr = memNodeOfPidMap_.find(pid);
132 if (itr == memNodeOfPidMap_.end()) {
133 return memoryGraphic;
134 }
135 auto nodeInfoOfPid = memNodeOfPidMap_[pid];
136 if (nodeInfoOfPid.empty()) {
137 memNodeOfPidMap_.erase(pid);
138 } else {
139 uint64_t totalMemSize = 0;
140 std::for_each(nodeInfoOfPid.begin(), nodeInfoOfPid.end(), [&totalMemSize](MemoryNodeOfPid& info) {
141 totalMemSize += static_cast<uint64_t>(info.GetMemSize());
142 });
143
144 for (auto it = memPicRecord_.begin(); it != memPicRecord_.end(); it++) {
145 pid_t picPid = it->second.pid;
146 if (pid == picPid) {
147 totalMemSize += static_cast<int>(it->second.size);
148 }
149 }
150 memoryGraphic.SetPid(pid);
151 memoryGraphic.SetCpuMemorySize(totalMemSize);
152 }
153 return memoryGraphic;
154 }
155
GetAppMemorySizeInMB()156 float MemoryTrack::GetAppMemorySizeInMB()
157 {
158 float total = 0.f;
159 std::lock_guard<std::mutex> lock(mutex_);
160 for (auto& [_, memInfo] : memPicRecord_) {
161 total += static_cast<float>(memInfo.size);
162 }
163 return total / BYTE_CONVERT / BYTE_CONVERT / 2; // app mem account for 50%
164 }
165
DumpMemoryStatistics(DfxString & log,std::function<std::tuple<uint64_t,std::string,RectI,bool> (uint64_t)> func)166 void MemoryTrack::DumpMemoryStatistics(DfxString& log,
167 std::function<std::tuple<uint64_t, std::string, RectI, bool> (uint64_t)> func)
168 {
169 std::vector<MemoryInfo> memPicRecord;
170 {
171 std::lock_guard<std::mutex> lock(mutex_);
172 for (auto& [addr, info] : memPicRecord_) {
173 memPicRecord.push_back(info);
174 }
175 }
176 // dump without mutex to avoid dead lock
177 // because it may free pixelmap after fetch shard_ptr(use_count = 1) from pixelmap's weak_ptr
178 DumpMemoryPicStatistics(log, func, memPicRecord);
179 {
180 std::lock_guard<std::mutex> lock(mutex_);
181 DumpMemoryNodeStatistics(log);
182 }
183 }
184
DumpMemoryNodeStatistics(DfxString & log)185 void MemoryTrack::DumpMemoryNodeStatistics(DfxString& log)
186 {
187 log.AppendFormat("\nRSRenderNode:\n");
188
189 uint64_t totalSize = 0;
190 int count = 0;
191 //calculate by byte
192 for (auto& [nodeId, info] : memNodeMap_) {
193 //total of all
194 totalSize += static_cast<uint64_t>(info.size);
195 count++;
196 }
197 log.AppendFormat("Total Node Size = %d KB (%d entries)\n", totalSize / BYTE_CONVERT, count);
198 }
199
UpdatePictureInfo(const void * addr,NodeId nodeId,pid_t pid)200 void MemoryTrack::UpdatePictureInfo(const void* addr, NodeId nodeId, pid_t pid)
201 {
202 std::lock_guard<std::mutex> lock(mutex_);
203 auto itr = memPicRecord_.find(addr);
204 if (itr != memPicRecord_.end()) {
205 itr->second.pid = pid;
206 itr->second.nid = nodeId;
207 }
208 }
209
MemoryType2String(MEMORY_TYPE type)210 const char* MemoryTrack::MemoryType2String(MEMORY_TYPE type)
211 {
212 switch (type) {
213 case MEM_PIXELMAP : {
214 return "pixelmap";
215 }
216 case MEM_SKIMAGE : {
217 return "skimage";
218 }
219 default : {
220 return "";
221 }
222 }
223 }
224
PixelMapInfo2String(MemoryInfo info)225 const std::string MemoryTrack::PixelMapInfo2String(MemoryInfo info)
226 {
227 std::string alloc_type_str = AllocatorType2String(info.allocType);
228 std::string pixelformat_str = "UNDEFINED";
229 #ifdef ROSEN_OHOS
230 pixelformat_str = PixelFormat2String(info.pixelMapFormat);
231 #endif
232 return alloc_type_str + "," + pixelformat_str;
233 }
234
235 #ifdef ROSEN_OHOS
PixelFormat2String(OHOS::Media::PixelFormat type)236 const std::string MemoryTrack::PixelFormat2String(OHOS::Media::PixelFormat type)
237 {
238 // sync with foundation/multimedia/image_framework/interfaces/innerkits/include/image_type.h
239 switch (type) {
240 case OHOS::Media::PixelFormat::ARGB_8888:
241 return "ARGB_8888";
242 case OHOS::Media::PixelFormat::RGB_565:
243 return "RGB_565";
244 case OHOS::Media::PixelFormat::RGBA_8888:
245 return "RGBA_8888";
246 case OHOS::Media::PixelFormat::BGRA_8888:
247 return "BGRA_8888";
248 case OHOS::Media::PixelFormat::RGB_888:
249 return "RGB_888";
250 case OHOS::Media::PixelFormat::ALPHA_8:
251 return "ALPHA_8";
252 case OHOS::Media::PixelFormat::RGBA_F16:
253 return "RGBA_F16";
254 case OHOS::Media::PixelFormat::NV21:
255 return "NV21";
256 case OHOS::Media::PixelFormat::NV12:
257 return "NV12";
258 case OHOS::Media::PixelFormat::RGBA_1010102:
259 return "RGBA_1010102";
260 case OHOS::Media::PixelFormat::YCBCR_P010:
261 return "YCBCR_P010";
262 case OHOS::Media::PixelFormat::YCRCB_P010:
263 return "YCRCB_P010";
264 case OHOS::Media::PixelFormat::RGBA_U16:
265 return "RGBA_U16";
266 case OHOS::Media::PixelFormat::YUV_400:
267 return "YUV_400";
268 case OHOS::Media::PixelFormat::CMYK:
269 return "CMYK";
270 case OHOS::Media::PixelFormat::ASTC_4x4:
271 return "ASTC_4x4";
272 case OHOS::Media::PixelFormat::ASTC_6x6:
273 return "ASTC_6x6";
274 case OHOS::Media::PixelFormat::ASTC_8x8:
275 return "ASTC_8x8";
276 default :
277 return std::to_string(static_cast<int32_t>(type));
278 }
279 return "UNKNOW";
280 }
281 #endif
282
AllocatorType2String(OHOS::Media::AllocatorType type)283 const std::string MemoryTrack::AllocatorType2String(OHOS::Media::AllocatorType type)
284 {
285 switch (type) {
286 case OHOS::Media::AllocatorType::DEFAULT:
287 return "DEFAULT";
288 case OHOS::Media::AllocatorType::HEAP_ALLOC:
289 return "HEAP";
290 case OHOS::Media::AllocatorType::SHARE_MEM_ALLOC:
291 return "SHARE_MEM";
292 case OHOS::Media::AllocatorType::CUSTOM_ALLOC:
293 return "CUSTOM";
294 case OHOS::Media::AllocatorType::DMA_ALLOC:
295 return "DMA";
296 default :
297 return "UNKNOW";
298 }
299 return "UNKNOW";
300 }
301
Data2String(std::string data,uint32_t tagetNumber)302 static std::string Data2String(std::string data, uint32_t tagetNumber)
303 {
304 if (data.length() < tagetNumber) {
305 return std::string(tagetNumber - data.length(), ' ') + data;
306 } else {
307 return data;
308 }
309 }
310
GenerateDumpTitle()311 std::string MemoryTrack::GenerateDumpTitle()
312 {
313 std::string size_title = Data2String("Size", MEM_SIZE_STRING_LEN);
314 std::string type_title = Data2String("Type", MEM_TYPE_STRING_LEN);
315 std::string pixelmap_info_title = Data2String("Type,UseCnt,IsUnMap,UnMapCnt,Format", PIXELMAP_INFO_STRING_LEN);
316 std::string pid_title = Data2String("Pid", MEM_PID_STRING_LEN);
317 std::string wid_title = Data2String("Wid", MEM_WID_STRING_LEN);
318 std::string uid_title = Data2String("Uid", MEM_UID_STRING_LEN);
319 std::string surfaceNode_title = Data2String("SurfaceName", MEM_SURNODE_STRING_LEN);
320 std::string frame_title = Data2String("Frame", MEM_FRAME_STRING_LEN);
321 std::string nid_title = Data2String("NodeId", MEM_NODEID_STRING_LEN);
322 std::string addr_tile = Data2String("Addr", MEM_ADDR_STRING_LEN);
323 return size_title + "\t" + type_title + "\t" + pixelmap_info_title + "\t" + pid_title + "\t" + wid_title + "\t" +
324 uid_title + "\t" + surfaceNode_title + "\t" + frame_title + nid_title + "\t" + addr_tile;
325 }
326
GenerateDetail(MemoryInfo info,uint64_t wId,std::string & wName,RectI & nFrame)327 std::string MemoryTrack::GenerateDetail(MemoryInfo info, uint64_t wId, std::string& wName, RectI& nFrame)
328 {
329 std::string size_str = Data2String(std::to_string(info.size), MEM_SIZE_STRING_LEN);
330 std::string type_str = Data2String(MemoryType2String(info.type), MEM_TYPE_STRING_LEN);
331 std::string pixelmap_info_str = Data2String(PixelMapInfo2String(info), PIXELMAP_INFO_STRING_LEN);
332 std::string pid_str = Data2String(std::to_string(ExtractPid(info.nid)), MEM_PID_STRING_LEN);
333 std::string wid_str = Data2String(std::to_string(wId), MEM_WID_STRING_LEN);
334 std::string uid_str = Data2String(std::to_string(info.uid), MEM_UID_STRING_LEN);
335 std::string wname_str = Data2String(wName, MEM_SURNODE_STRING_LEN);
336 std::string frame_str = Data2String(nFrame.ToString(), MEM_FRAME_STRING_LEN);
337 std::string nid_str = Data2String(std::to_string(info.nid), MEM_NODEID_STRING_LEN);
338 return size_str + "\t" + type_str + "\t" + pixelmap_info_str + "\t" + pid_str + "\t" + wid_str + "\t" +
339 uid_str + "\t" + wname_str + "\t" + frame_str + nid_str;
340 }
341
DumpMemoryPicStatistics(DfxString & log,std::function<std::tuple<uint64_t,std::string,RectI,bool> (uint64_t)> func,const std::vector<MemoryInfo> & memPicRecord)342 void MemoryTrack::DumpMemoryPicStatistics(DfxString& log,
343 std::function<std::tuple<uint64_t, std::string, RectI, bool> (uint64_t)> func,
344 const std::vector<MemoryInfo>& memPicRecord)
345 {
346 log.AppendFormat("RSImageCache:\n");
347 log.AppendFormat("%s:\n", GenerateDumpTitle().c_str());
348
349 int arrTotal[MEM_MAX_SIZE] = {0};
350 int arrCount[MEM_MAX_SIZE] = {0};
351 int arrWithoutDMATotal[MEM_MAX_SIZE] = {0};
352 int arrWithoutDMACount[MEM_MAX_SIZE] = {0};
353 uint64_t totalSize = 0;
354 int count = 0;
355 int totalWithoutDMASize = 0;
356 int countWithoutDMA = 0;
357 int totalNullNodeSize = 0;
358 int countNullNodes = 0;
359 int nullWithoutDMASize = 0;
360 int nullWithoutDMA = 0;
361 //calculate by byte
362 for (auto& info : memPicRecord) {
363 int size = static_cast<uint64_t>(info.size / BYTE_CONVERT); // k
364 //total of type
365 arrTotal[info.type] += size;
366 arrCount[info.type]++;
367
368 //total of all
369 totalSize += size;
370 count++;
371
372 if (info.allocType != OHOS::Media::AllocatorType::DMA_ALLOC) {
373 arrWithoutDMATotal[info.type] += size;
374 arrWithoutDMACount[info.type]++;
375 totalWithoutDMASize += size;
376 countWithoutDMA++;
377 }
378
379 auto [windowId, windowName, nodeFrameRect, isNodeNull] = func(info.nid);
380 log.AppendFormat("%s", GenerateDetail(info, windowId, windowName, nodeFrameRect).c_str());
381 if (info.type == MEMORY_TYPE::MEM_PIXELMAP) {
382 log.AppendFormat(" %d\n", isNodeNull ? 1 : 0);
383 if (isNodeNull) {
384 totalNullNodeSize += size;
385 countNullNodes++;
386 if (info.allocType != OHOS::Media::AllocatorType::DMA_ALLOC) {
387 nullWithoutDMASize += size;
388 nullWithoutDMA++;
389 }
390 }
391 }
392 }
393
394 for (uint32_t i = MEM_PIXELMAP; i < MEM_MAX_SIZE; i++) {
395 MEMORY_TYPE type = static_cast<MEMORY_TYPE>(i);
396 log.AppendFormat(" %s:Size = %d KB (%d entries)\n", MemoryType2String(type), arrTotal[i], arrCount[i]);
397 log.AppendFormat(" %s Without DMA:Size = %d KB (%d entries)\n",
398 MemoryType2String(type), arrWithoutDMATotal[i], arrWithoutDMACount[i]);
399 }
400 log.AppendFormat("Total Size = %d KB (%d entries)\n", totalSize, count);
401 log.AppendFormat("Total Without DMA Size = %d KB (%d entries)\n", totalWithoutDMASize, countWithoutDMA);
402 log.AppendFormat("MEM_PIXELMAP Null Nodes: Size = %d KB (%d entries)\n", totalNullNodeSize, countNullNodes);
403 log.AppendFormat("Null Nodes Without DMA: Size = %d KB (%d entries)\n", nullWithoutDMASize, nullWithoutDMA);
404 }
405
AddPictureRecord(const void * addr,MemoryInfo info)406 void MemoryTrack::AddPictureRecord(const void* addr, MemoryInfo info)
407 {
408 std::lock_guard<std::mutex> lock(mutex_);
409 memPicRecord_.emplace(addr, info);
410 }
411
RemovePictureRecord(const void * addr)412 void MemoryTrack::RemovePictureRecord(const void* addr)
413 {
414 std::lock_guard<std::mutex> lock(mutex_);
415 memPicRecord_.erase(addr);
416 }
417
418 #ifdef RS_MEMORY_INFO_MANAGER
SetGlobalRootNodeStatusChangeFlag(bool flag)419 void MemoryTrack::SetGlobalRootNodeStatusChangeFlag(bool flag)
420 {
421 globalRootNodeStatusChangeFlag.store(flag);
422 }
423
GetGlobalRootNodeStatusChangeFlag()424 bool MemoryTrack::GetGlobalRootNodeStatusChangeFlag()
425 {
426 return globalRootNodeStatusChangeFlag.load();
427 }
428
GetNodeOnTreeStatus(const void * address)429 NODE_ON_TREE_STATUS MemoryTrack::GetNodeOnTreeStatus(const void* address)
430 {
431 std::lock_guard<std::mutex> lock(mutex_);
432
433 auto picRecordIt = memPicRecord_.find(address);
434 if (picRecordIt == memPicRecord_.end()) {
435 return NODE_ON_TREE_STATUS::STATUS_INVALID;
436 }
437
438 NodeId nodeId = picRecordIt->second.nid;
439 auto nodeInfoIt = memNodeMap_.find(nodeId);
440 if (nodeInfoIt == memNodeMap_.end()) {
441 return NODE_ON_TREE_STATUS::STATUS_INVALID;
442 }
443
444 const auto& nodeInfo = nodeInfoIt->second;
445 if (nodeInfo.isOnTree && !nodeInfo.rootNodeStatusChangeFlag) {
446 return NODE_ON_TREE_STATUS::STATUS_ON_TREE;
447 } else if (nodeInfo.isOnTree) {
448 return NODE_ON_TREE_STATUS::STATUS_ON_TREE_IN_ROOT;
449 } else if (!nodeInfo.isOnTree && !nodeInfo.rootNodeStatusChangeFlag) {
450 return NODE_ON_TREE_STATUS::STATUS_OFF_TREE;
451 } else {
452 return NODE_ON_TREE_STATUS::STATUS_OFF_TREE_IN_ROOT;
453 }
454 }
455
SetNodeOnTreeStatus(NodeId nodeId,bool rootNodeStatusChangeFlag,bool isOnTree)456 void MemoryTrack::SetNodeOnTreeStatus(NodeId nodeId, bool rootNodeStatusChangeFlag, bool isOnTree)
457 {
458 std::lock_guard<std::mutex> lock(mutex_);
459
460 auto itr = memNodeMap_.find(nodeId);
461 if (itr == memNodeMap_.end()) {
462 return;
463 }
464 itr->second.rootNodeStatusChangeFlag = rootNodeStatusChangeFlag;
465 itr->second.isOnTree = isOnTree;
466 }
467 #endif
468 }
469 }