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_TYPE_STRING_LEN = 16;
25 constexpr uint32_t PIXELMAP_INFO_STRING_LEN = 32;
26 constexpr uint32_t MEM_PID_STRING_LEN = 8;
27 constexpr uint32_t MEM_WID_STRING_LEN = 20;
28 constexpr uint32_t MEM_UID_STRING_LEN = 8;
29 constexpr uint32_t MEM_SURNODE_STRING_LEN = 40;
30 constexpr uint32_t MEM_FRAME_STRING_LEN = 35;
31 constexpr uint32_t MEM_NODEID_STRING_LEN = 20;
32 }
33 
MemoryNodeOfPid(size_t size,NodeId id)34 MemoryNodeOfPid::MemoryNodeOfPid(size_t size, NodeId id) : nodeSize_(size), nodeId_(id) {}
35 
GetMemSize()36 size_t MemoryNodeOfPid::GetMemSize()
37 {
38     return nodeSize_;
39 }
40 
operator ==(const MemoryNodeOfPid & other)41 bool MemoryNodeOfPid::operator==(const MemoryNodeOfPid& other)
42 {
43     return nodeId_ == other.nodeId_;
44 }
45 
Instance()46 MemoryTrack& MemoryTrack::Instance()
47 {
48     static MemoryTrack instance;
49     return instance;
50 }
51 
AddNodeRecord(const NodeId id,const MemoryInfo & info)52 void MemoryTrack::AddNodeRecord(const NodeId id, const MemoryInfo& info)
53 {
54     std::lock_guard<std::mutex> lock(mutex_);
55     memNodeMap_.emplace(id, info);
56     MemoryNodeOfPid nodeInfoOfPid(info.size, id);
57     memNodeOfPidMap_[info.pid].push_back(nodeInfoOfPid);
58 }
59 
RemoveNodeFromMap(const NodeId id,pid_t & pid,size_t & size)60 bool MemoryTrack::RemoveNodeFromMap(const NodeId id, pid_t& pid, size_t& size)
61 {
62     auto itr = memNodeMap_.find(id);
63     if (itr == memNodeMap_.end()) {
64         RS_LOGD("MemoryTrack::RemoveNodeFromMap no this nodeId = %{public}" PRIu64, id);
65         return false;
66     }
67     pid = memNodeMap_[id].pid;
68     size = memNodeMap_[id].size;
69     memNodeMap_.erase(itr);
70     return true;
71 }
72 
RemoveNodeOfPidFromMap(const pid_t pid,const size_t size,const NodeId id)73 void MemoryTrack::RemoveNodeOfPidFromMap(const pid_t pid, const size_t size, const NodeId id)
74 {
75     if (memNodeOfPidMap_.find(pid) == memNodeOfPidMap_.end()) {
76         RS_LOGW("MemoryTrack::RemoveNodeOfPidFromMap no this nodeId = %{public}" PRIu64, id);
77         return;
78     }
79     MemoryNodeOfPid nodeInfoOfPid = {size, id};
80     auto itr = std::find(memNodeOfPidMap_[pid].begin(), memNodeOfPidMap_[pid].end(), nodeInfoOfPid);
81     if (itr != memNodeOfPidMap_[pid].end()) {
82         memNodeOfPidMap_[pid].erase(itr);
83     }
84 }
85 
RemoveNodeRecord(const NodeId id)86 void MemoryTrack::RemoveNodeRecord(const NodeId id)
87 {
88     std::lock_guard<std::mutex> lock(mutex_);
89     pid_t pid = 0;
90     size_t size = 0;
91     bool isSuccess = RemoveNodeFromMap(id, pid, size);
92     if (!isSuccess) {
93         return;
94     }
95     RemoveNodeOfPidFromMap(pid, size, id);
96 }
97 
CountRSMemory(const pid_t pid)98 MemoryGraphic MemoryTrack::CountRSMemory(const pid_t pid)
99 {
100     std::lock_guard<std::mutex> lock(mutex_);
101     MemoryGraphic memoryGraphic;
102     auto itr = memNodeOfPidMap_.find(pid);
103     if (itr == memNodeOfPidMap_.end()) {
104         return memoryGraphic;
105     }
106     auto nodeInfoOfPid = memNodeOfPidMap_[pid];
107     if (nodeInfoOfPid.empty()) {
108         memNodeOfPidMap_.erase(pid);
109     } else {
110         int totalMemSize = 0;
111         std::for_each(nodeInfoOfPid.begin(), nodeInfoOfPid.end(), [&totalMemSize](MemoryNodeOfPid& info) {
112             totalMemSize += info.GetMemSize();
113         });
114 
115         for (auto it = memPicRecord_.begin(); it != memPicRecord_.end(); it++) {
116             pid_t picPid = it->second.pid;
117             if (pid == picPid) {
118                 totalMemSize += static_cast<int>(it->second.size);
119             }
120         }
121         memoryGraphic.SetPid(pid);
122         memoryGraphic.SetCpuMemorySize(totalMemSize);
123     }
124     return memoryGraphic;
125 }
126 
GetAppMemorySizeInMB()127 float MemoryTrack::GetAppMemorySizeInMB()
128 {
129     float total = 0.f;
130     std::lock_guard<std::mutex> lock(mutex_);
131     for (auto& [_, memInfo] : memPicRecord_) {
132         total += static_cast<float>(memInfo.size);
133     }
134     return total / BYTE_CONVERT / BYTE_CONVERT / 2; // app mem account for 50%
135 }
136 
DumpMemoryStatistics(DfxString & log,std::function<std::tuple<uint64_t,std::string,RectI> (uint64_t)> func)137 void MemoryTrack::DumpMemoryStatistics(DfxString& log,
138     std::function<std::tuple<uint64_t, std::string, RectI> (uint64_t)> func)
139 {
140     std::lock_guard<std::mutex> lock(mutex_);
141     DumpMemoryPicStatistics(log, func);
142     DumpMemoryNodeStatistics(log);
143 }
144 
DumpMemoryNodeStatistics(DfxString & log)145 void MemoryTrack::DumpMemoryNodeStatistics(DfxString& log)
146 {
147     log.AppendFormat("\nRSRenderNode:\n");
148 
149     int totalSize = 0;
150     int count = 0;
151     //calculate by byte
152     for (auto& [nodeId, info] : memNodeMap_) {
153         //total of all
154         totalSize += static_cast<int>(info.size);
155         count++;
156     }
157     log.AppendFormat("Total Node Size = %d KB (%d entries)\n", totalSize / BYTE_CONVERT, count);
158 }
159 
UpdatePictureInfo(const void * addr,NodeId nodeId,pid_t pid)160 void MemoryTrack::UpdatePictureInfo(const void* addr, NodeId nodeId, pid_t pid)
161 {
162     std::lock_guard<std::mutex> lock(mutex_);
163     auto itr = memPicRecord_.find(addr);
164     if (itr != memPicRecord_.end()) {
165         itr->second.pid = pid;
166         itr->second.nid = nodeId;
167     }
168 }
169 
MemoryType2String(MEMORY_TYPE type)170 const char* MemoryTrack::MemoryType2String(MEMORY_TYPE type)
171 {
172     switch (type) {
173         case MEM_PIXELMAP : {
174             return "pixelmap";
175         }
176         case MEM_SKIMAGE : {
177             return "skimage";
178         }
179         default : {
180             return "";
181         }
182     }
183 }
184 
PixelMapInfo2String(MemoryInfo info)185 const std::string MemoryTrack::PixelMapInfo2String(MemoryInfo info)
186 {
187     std::string alloc_type_str = AllocatorType2String(info.allocType);
188     std::string use_cnt_str = "-1";
189     std::string is_un_map_str = "-1";
190     std::string un_map_cnt_str = "-1";
191 
192 #ifdef ROSEN_OHOS
193     if (RSSystemProperties::GetDumpUIPixelmapEnabled()) {
194         auto pixelMap = info.pixelMap.lock();
195         if (pixelMap) {
196             use_cnt_str = std::to_string(pixelMap->GetUseCount());
197             is_un_map_str = std::to_string(pixelMap->IsUnMap());
198             un_map_cnt_str = std::to_string(pixelMap->GetUnMapCount());
199         }
200     }
201 #endif
202     return alloc_type_str + "," + use_cnt_str + "," + is_un_map_str + "," + un_map_cnt_str;
203 }
204 
AllocatorType2String(OHOS::Media::AllocatorType type)205 const std::string MemoryTrack::AllocatorType2String(OHOS::Media::AllocatorType type)
206 {
207     switch (type) {
208         case OHOS::Media::AllocatorType::DEFAULT:
209             return "DEFAULT";
210         case OHOS::Media::AllocatorType::HEAP_ALLOC:
211             return "HEAP";
212         case OHOS::Media::AllocatorType::SHARE_MEM_ALLOC:
213             return "SHARE_MEM";
214         case OHOS::Media::AllocatorType::CUSTOM_ALLOC:
215             return "CUSTOM";
216         case OHOS::Media::AllocatorType::DMA_ALLOC:
217             return "DMA";
218         default :
219             return "UNKNOW";
220     }
221     return "UNKNOW";
222 }
223 
Data2String(std::string data,uint32_t tagetNumber)224 static std::string Data2String(std::string data, uint32_t tagetNumber)
225 {
226     if (data.length() < tagetNumber) {
227         return std::string(tagetNumber - data.length(), ' ') + data;
228     } else {
229         return data;
230     }
231 }
232 
GenerateDumpTitle()233 std::string MemoryTrack::GenerateDumpTitle()
234 {
235     std::string size_title = Data2String("Size", MEM_SIZE_STRING_LEN);
236     std::string type_title = Data2String("Type", MEM_TYPE_STRING_LEN);
237     std::string pixelmap_info_title = Data2String("Type,UseCnt,IsUnMap,UnMapCnt", PIXELMAP_INFO_STRING_LEN);
238     std::string pid_title = Data2String("Pid", MEM_PID_STRING_LEN);
239     std::string wid_title = Data2String("Wid", MEM_WID_STRING_LEN);
240     std::string uid_title = Data2String("Uid", MEM_UID_STRING_LEN);
241     std::string surfaceNode_title = Data2String("SurfaceName", MEM_SURNODE_STRING_LEN);
242     std::string frame_title = Data2String("Frame", MEM_FRAME_STRING_LEN);
243     std::string nid_title = Data2String("NodeId", MEM_NODEID_STRING_LEN);
244     return size_title + "\t" + type_title + "\t" + pixelmap_info_title + "\t" + pid_title + "\t" + wid_title + "\t" +
245         uid_title + "\t" + surfaceNode_title + "\t" + frame_title + nid_title;
246 }
247 
GenerateDetail(MemoryInfo info,uint64_t wId,std::string & wName,RectI & nFrame)248 std::string MemoryTrack::GenerateDetail(MemoryInfo info, uint64_t wId, std::string& wName, RectI& nFrame)
249 {
250     std::string size_str = Data2String(std::to_string(info.size), MEM_SIZE_STRING_LEN);
251     std::string type_str = Data2String(MemoryType2String(info.type), MEM_TYPE_STRING_LEN);
252     std::string pixelmap_info_str = Data2String(PixelMapInfo2String(info), PIXELMAP_INFO_STRING_LEN);
253     std::string pid_str = Data2String(std::to_string(ExtractPid(info.nid)), MEM_PID_STRING_LEN);
254     std::string wid_str = Data2String(std::to_string(wId), MEM_WID_STRING_LEN);
255     std::string uid_str = Data2String(std::to_string(info.uid), MEM_UID_STRING_LEN);
256     std::string wname_str = Data2String(wName, MEM_SURNODE_STRING_LEN);
257     std::string frame_str = Data2String(nFrame.ToString(), MEM_FRAME_STRING_LEN);
258     std::string nid_str = Data2String(std::to_string(info.nid), MEM_NODEID_STRING_LEN);
259     return size_str + "\t" + type_str + "\t" + pixelmap_info_str + "\t" + pid_str + "\t" + wid_str + "\t" +
260         uid_str + "\t" + wname_str + "\t" + frame_str + nid_str;
261 }
262 
DumpMemoryPicStatistics(DfxString & log,std::function<std::tuple<uint64_t,std::string,RectI> (uint64_t)> func)263 void MemoryTrack::DumpMemoryPicStatistics(DfxString& log,
264     std::function<std::tuple<uint64_t, std::string, RectI> (uint64_t)> func)
265 {
266     log.AppendFormat("RSImageCache:\n");
267     log.AppendFormat("%s:\n", GenerateDumpTitle().c_str());
268 
269     int arrTotal[MEM_MAX_SIZE] = {0};
270     int arrCount[MEM_MAX_SIZE] = {0};
271     int arrWithoutDMATotal[MEM_MAX_SIZE] = {0};
272     int arrWithoutDMACount[MEM_MAX_SIZE] = {0};
273     int totalSize = 0;
274     int count = 0;
275     int totalWithoutDMASize = 0;
276     int countWithoutDMA = 0;
277 #ifdef ROSEN_OHOS
278     int totalUnMapSize = 0;
279     int totalUnMapCount = 0;
280 #endif
281     //calculate by byte
282     for (auto& [addr, info] : memPicRecord_) {
283         int size = static_cast<int>(info.size / BYTE_CONVERT); // k
284         //total of type
285         arrTotal[info.type] += size;
286         arrCount[info.type]++;
287 
288         //total of all
289         totalSize += size;
290         count++;
291 
292         if (info.allocType != OHOS::Media::AllocatorType::DMA_ALLOC) {
293             arrWithoutDMATotal[info.type] += size;
294             arrWithoutDMACount[info.type]++;
295             totalWithoutDMASize += size;
296             countWithoutDMA++;
297 #ifdef ROSEN_OHOS
298             if (RSSystemProperties::GetDumpUIPixelmapEnabled()) {
299                 auto pixelMap = info.pixelMap.lock();
300                 if (pixelMap && pixelMap->IsUnMap()) {
301                     totalUnMapSize += size;
302                     totalUnMapCount++;
303                 }
304             }
305 #endif
306         }
307 
308         auto [windowId, windowName, nodeFrameRect] = func(info.nid);
309         log.AppendFormat("%s\n", GenerateDetail(info, windowId, windowName, nodeFrameRect).c_str());
310     }
311 
312     for (uint32_t i = MEM_PIXELMAP; i < MEM_MAX_SIZE; i++) {
313         MEMORY_TYPE type = static_cast<MEMORY_TYPE>(i);
314         log.AppendFormat("  %s:Size = %d KB (%d entries)\n", MemoryType2String(type), arrTotal[i], arrCount[i]);
315         log.AppendFormat("  %s Without DMA:Size = %d KB (%d entries)\n",
316             MemoryType2String(type), arrWithoutDMATotal[i], arrWithoutDMACount[i]);
317     }
318     log.AppendFormat("Total Size = %d KB (%d entries)\n", totalSize, count);
319     log.AppendFormat("Total Without DMA Size = %d KB (%d entries)\n", totalWithoutDMASize, countWithoutDMA);
320 #ifdef ROSEN_OHOS
321     log.AppendFormat("Total UnMap Size = %d KB (%d entries)\n", totalUnMapSize, totalUnMapCount);
322 #endif
323 }
324 
AddPictureRecord(const void * addr,MemoryInfo info)325 void MemoryTrack::AddPictureRecord(const void* addr, MemoryInfo info)
326 {
327     std::lock_guard<std::mutex> lock(mutex_);
328     memPicRecord_.emplace(addr, info);
329 }
330 
RemovePictureRecord(const void * addr)331 void MemoryTrack::RemovePictureRecord(const void* addr)
332 {
333     std::lock_guard<std::mutex> lock(mutex_);
334     memPicRecord_.erase(addr);
335 }
336 
337 }
338 }