1 /*
2 * Copyright (c) 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
16 #include "memory/rs_memory_manager.h"
17
18 #include <malloc.h>
19 #include "include/core/SkGraphics.h"
20 #include "rs_trace.h"
21
22 #include "memory/rs_dfx_string.h"
23 #include "skia_adapter/rs_skia_memory_tracer.h"
24 #include "skia_adapter/skia_graphics.h"
25 #include "memory/rs_memory_graphic.h"
26 #include "include/gpu/GrDirectContext.h"
27 #include "src/gpu/GrDirectContextPriv.h"
28
29 #include "common/rs_obj_abs_geometry.h"
30 #include "memory/rs_tag_tracker.h"
31 #ifdef NEW_RENDER_CONTEXT
32 #include "render_context/memory_handler.h"
33 #endif
34 #include "pipeline/rs_main_thread.h"
35 #include "pipeline/rs_surface_render_node.h"
36 #include "platform/common/rs_log.h"
37 #include "pipeline/parallel_render/rs_sub_thread_manager.h"
38
39 #ifdef USE_ROSEN_DRAWING
40 #include "image/gpu_context.h"
41 #endif
42
43 #ifdef RS_ENABLE_VK
44 #include "pipeline/rs_vk_image_manager.h"
45 #include "platform/ohos/backend/rs_vulkan_context.h"
46 #endif
47
48 namespace OHOS::Rosen {
49 namespace {
50 constexpr uint32_t MEMUNIT_RATE = 1024;
51 constexpr const char* MEM_RS_TYPE = "renderservice";
52 constexpr const char* MEM_CPU_TYPE = "cpu";
53 constexpr const char* MEM_GPU_TYPE = "gpu";
54 constexpr const char* MEM_JEMALLOC_TYPE = "jemalloc";
55 }
56
57 #ifndef USE_ROSEN_DRAWING
DumpMemoryUsage(DfxString & log,const GrDirectContext * grContext,std::string & type)58 void MemoryManager::DumpMemoryUsage(DfxString& log, const GrDirectContext* grContext, std::string& type)
59 {
60 if (type.empty() || type == MEM_RS_TYPE) {
61 DumpRenderServiceMemory(log);
62 }
63 if (type.empty() || type == MEM_CPU_TYPE) {
64 DumpDrawingCpuMemory(log);
65 }
66 if (type.empty() || type == MEM_GPU_TYPE) {
67 DumpDrawingGpuMemory(log, grContext);
68 }
69 if (type.empty() || type == MEM_JEMALLOC_TYPE) {
70 std::string out;
71 DumpMallocStat(out);
72 log.AppendFormat("%s\n... detail dump at hilog\n", out.c_str());
73 }
74 }
75 #else
DumpMemoryUsage(DfxString & log,const Drawing::GPUContext * gpuContext,std::string & type)76 void MemoryManager::DumpMemoryUsage(DfxString& log, const Drawing::GPUContext* gpuContext, std::string& type)
77 {
78 if (type.empty() || type == MEM_RS_TYPE) {
79 DumpRenderServiceMemory(log);
80 }
81 if (type.empty() || type == MEM_CPU_TYPE) {
82 DumpDrawingCpuMemory(log);
83 }
84 if (type.empty() || type == MEM_GPU_TYPE) {
85 DumpDrawingGpuMemory(log, gpuContext);
86 }
87 if (type.empty() || type == MEM_JEMALLOC_TYPE) {
88 std::string out;
89 DumpMallocStat(out);
90 log.AppendFormat("%s\n... detail dump at hilog\n", out.c_str());
91 }
92 }
93 #endif // USE_ROSEN_DRAWING
94
95 #ifndef USE_ROSEN_DRAWING
ReleaseAllGpuResource(GrDirectContext * grContext,GrGpuResourceTag & tag)96 void MemoryManager::ReleaseAllGpuResource(GrDirectContext* grContext, GrGpuResourceTag& tag)
97 {
98 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
99 if (!grContext) {
100 RS_LOGE("ReleaseGpuResByTag fail, grContext is nullptr");
101 return;
102 }
103 RS_TRACE_NAME_FMT("ReleaseAllGpuResource [Pid:%d Tid:%d Nid:%d Funcid:%d]",
104 tag.fPid, tag.fTid, tag.fWid, tag.fFid);
105 grContext->releaseByTag(tag);
106 #endif
107 }
108 #else
ReleaseAllGpuResource(Drawing::GPUContext * gpuContext,Drawing::GPUResourceTag & tag)109 void MemoryManager::ReleaseAllGpuResource(Drawing::GPUContext* gpuContext, Drawing::GPUResourceTag& tag)
110 {
111 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
112 if (!gpuContext) {
113 RS_LOGE("ReleaseGpuResByTag fail, gpuContext is nullptr");
114 return;
115 }
116 RS_TRACE_NAME_FMT("ReleaseAllGpuResource [Pid:%d Tid:%d Nid:%d Funcid:%d]",
117 tag.fPid, tag.fTid, tag.fWid, tag.fFid);
118 gpuContext->ReleaseByTag(tag);
119 #endif
120 }
121 #endif
122
123 #ifndef USE_ROSEN_DRAWING
ReleaseAllGpuResource(GrDirectContext * grContext,pid_t pid)124 void MemoryManager::ReleaseAllGpuResource(GrDirectContext* grContext, pid_t pid)
125 {
126 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
127 GrGpuResourceTag tag(pid, 0, 0, 0);
128 ReleaseAllGpuResource(grContext, tag);
129 #endif
130 }
131 #else
ReleaseAllGpuResource(Drawing::GPUContext * gpuContext,pid_t pid)132 void MemoryManager::ReleaseAllGpuResource(Drawing::GPUContext* gpuContext, pid_t pid)
133 {
134 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
135 Drawing::GPUResourceTag tag(pid, 0, 0, 0);
136 ReleaseAllGpuResource(gpuContext, tag);
137 #endif
138 }
139 #endif
140
141 #ifndef USE_ROSEN_DRAWING
ReleaseUnlockGpuResource(GrDirectContext * grContext,GrGpuResourceTag & tag)142 void MemoryManager::ReleaseUnlockGpuResource(GrDirectContext* grContext, GrGpuResourceTag& tag)
143 {
144 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
145 if (!grContext) {
146 RS_LOGE("ReleaseGpuResByTag fail, grContext is nullptr");
147 return;
148 }
149 RS_TRACE_NAME_FMT("ReleaseUnlockGpuResource [Pid:%d Tid:%d Nid:%d Funcid:%d]",
150 tag.fPid, tag.fTid, tag.fWid, tag.fFid);
151 grContext->purgeUnlockedResourcesByTag(false, tag);
152 #endif
153 }
154 #else
ReleaseUnlockGpuResource(Drawing::GPUContext * gpuContext,Drawing::GPUResourceTag & tag)155 void MemoryManager::ReleaseUnlockGpuResource(Drawing::GPUContext* gpuContext, Drawing::GPUResourceTag& tag)
156 {
157 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
158 if (!gpuContext) {
159 RS_LOGE("ReleaseGpuResByTag fail, gpuContext is nullptr");
160 return;
161 }
162 RS_TRACE_NAME_FMT("ReleaseUnlockGpuResource [Pid:%d Tid:%d Nid:%d Funcid:%d]",
163 tag.fPid, tag.fTid, tag.fWid, tag.fFid);
164 gpuContext->PurgeUnlockedResourcesByTag(false, tag);
165 #endif
166 }
167 #endif
168
169 #ifndef USE_ROSEN_DRAWING
ReleaseUnlockGpuResource(GrDirectContext * grContext,NodeId surfaceNodeId)170 void MemoryManager::ReleaseUnlockGpuResource(GrDirectContext* grContext, NodeId surfaceNodeId)
171 {
172 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
173 GrGpuResourceTag tag(ExtractPid(surfaceNodeId), 0, 0, 0);
174 ReleaseUnlockGpuResource(grContext, tag); // clear gpu resource by pid
175 #endif
176 }
177 #else
ReleaseUnlockGpuResource(Drawing::GPUContext * grContext,NodeId surfaceNodeId)178 void MemoryManager::ReleaseUnlockGpuResource(Drawing::GPUContext* grContext, NodeId surfaceNodeId)
179 {
180 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
181 Drawing::GPUResourceTag tag(ExtractPid(surfaceNodeId), 0, 0, 0);
182 ReleaseUnlockGpuResource(grContext, tag);
183 #endif
184 }
185 #endif
186
187 #ifndef USE_ROSEN_DRAWING
ReleaseUnlockGpuResource(GrDirectContext * grContext,pid_t pid)188 void MemoryManager::ReleaseUnlockGpuResource(GrDirectContext* grContext, pid_t pid)
189 {
190 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
191 GrGpuResourceTag tag(pid, 0, 0, 0);
192 ReleaseUnlockGpuResource(grContext, tag); // clear gpu resource by pid
193 #endif
194 }
195 #else
ReleaseUnlockGpuResource(Drawing::GPUContext * grContext,pid_t pid)196 void MemoryManager::ReleaseUnlockGpuResource(Drawing::GPUContext* grContext, pid_t pid)
197 {
198 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
199 Drawing::GPUResourceTag tag(pid, 0, 0, 0);
200 ReleaseUnlockGpuResource(grContext, tag); // clear gpu resource by pid
201 #endif
202 }
203 #endif
204
205 #ifndef USE_ROSEN_DRAWING
ReleaseUnlockGpuResource(GrDirectContext * grContext,bool scratchResourcesOnly)206 void MemoryManager::ReleaseUnlockGpuResource(GrDirectContext* grContext, bool scratchResourcesOnly)
207 {
208 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
209 if (!grContext) {
210 RS_LOGE("ReleaseGpuResByTag fail, grContext is nullptr");
211 return;
212 }
213 RS_TRACE_NAME_FMT("ReleaseUnlockGpuResource scratchResourcesOnly:%d", scratchResourcesOnly);
214 grContext->purgeUnlockedResources(scratchResourcesOnly);
215 #endif
216 }
217 #else
ReleaseUnlockGpuResource(Drawing::GPUContext * gpuContext,bool scratchResourcesOnly)218 void MemoryManager::ReleaseUnlockGpuResource(Drawing::GPUContext* gpuContext, bool scratchResourcesOnly)
219 {
220 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
221 if (!gpuContext) {
222 RS_LOGE("ReleaseGpuResByTag fail, gpuContext is nullptr");
223 return;
224 }
225 RS_TRACE_NAME_FMT("ReleaseUnlockGpuResource scratchResourcesOnly:%d", scratchResourcesOnly);
226 gpuContext->PurgeUnlockedResources(scratchResourcesOnly);
227 #endif
228 }
229 #endif
230
231 #ifndef USE_ROSEN_DRAWING
ReleaseUnlockAndSafeCacheGpuResource(GrDirectContext * grContext)232 void MemoryManager::ReleaseUnlockAndSafeCacheGpuResource(GrDirectContext* grContext)
233 {
234 #if defined (RS_ENABLE_GL) || defined(RS_ENABLE_VK)
235 if (!grContext) {
236 RS_LOGE("ReleaseUnlockAndSafeCacheGpuResource fail, grContext is nullptr");
237 return;
238 }
239 RS_TRACE_NAME_FMT("ReleaseUnlockAndSafeCacheGpuResource");
240 grContext->purgeUnlockAndSafeCacheGpuResources();
241 #endif
242 }
243 #else
ReleaseUnlockAndSafeCacheGpuResource(Drawing::GPUContext * gpuContext)244 void MemoryManager::ReleaseUnlockAndSafeCacheGpuResource(Drawing::GPUContext* gpuContext)
245 {
246 #if defined (RS_ENABLE_GL) || defined(RS_ENABLE_VK)
247 if (!gpuContext) {
248 RS_LOGE("ReleaseUnlockAndSafeCacheGpuResource fail, gpuContext is nullptr");
249 return;
250 }
251 RS_TRACE_NAME_FMT("ReleaseUnlockAndSafeCacheGpuResource");
252 gpuContext->PurgeUnlockAndSafeCacheGpuResources();
253 #endif
254 }
255 #endif
256
257 #ifndef USE_ROSEN_DRAWING
GetAppGpuMemoryInMB(GrDirectContext * grContext)258 float MemoryManager::GetAppGpuMemoryInMB(GrDirectContext* grContext)
259 {
260 if (!grContext) {
261 return 0.f;
262 }
263 #if defined (RS_ENABLE_GL) || defined (RS_ENABLE_VK)
264 SkiaMemoryTracer trace("category", true);
265 grContext->dumpMemoryStatistics(&trace);
266 auto total = trace.GetGpuMemorySizeInMB();
267 float rsMemSize = 0.f;
268 for (uint32_t tagtype = RSTagTracker::TAG_SAVELAYER_DRAW_NODE; tagtype <= RSTagTracker::TAG_CAPTURE; tagtype++) {
269 GrGpuResourceTag resourceTag(0, 0, 0, tagtype);
270 SkiaMemoryTracer gpuTrace("category", true);
271 grContext->dumpMemoryStatisticsByTag(&gpuTrace, resourceTag);
272 rsMemSize += gpuTrace.GetGpuMemorySizeInMB();
273 }
274 return total - rsMemSize;
275 #else
276 return 0.f;
277 #endif
278 }
279 #else
GetAppGpuMemoryInMB(Drawing::GPUContext * gpuContext)280 float MemoryManager::GetAppGpuMemoryInMB(Drawing::GPUContext* gpuContext)
281 {
282 if (!gpuContext) {
283 return 0.f;
284 }
285 #if defined (RS_ENABLE_GL) || defined(RS_ENABLE_VK)
286 Drawing::TraceMemoryDump trace("category", true);
287 gpuContext->DumpMemoryStatistics(&trace);
288 auto total = trace.GetGpuMemorySizeInMB();
289 float rsMemSize = 0.f;
290 for (uint32_t tagtype = RSTagTracker::TAG_SAVELAYER_DRAW_NODE; tagtype <= RSTagTracker::TAG_CAPTURE; tagtype++) {
291 Drawing::GPUResourceTag resourceTag(0, 0, 0, tagtype);
292 Drawing::TraceMemoryDump gpuTrace("category", true);
293 gpuContext->DumpMemoryStatisticsByTag(&gpuTrace, resourceTag);
294 rsMemSize += gpuTrace.GetGpuMemorySizeInMB();
295 }
296 return total - rsMemSize;
297 #else
298 return 0.f;
299 #endif
300 }
301 #endif
302
303 #ifndef USE_ROSEN_DRAWING
DumpPidMemory(DfxString & log,int pid,const GrDirectContext * grContext)304 void MemoryManager::DumpPidMemory(DfxString& log, int pid, const GrDirectContext* grContext)
305 {
306 //MemoryTrack::Instance().DumpMemoryStatistics(log, pid);
307 MemoryGraphic mem = CountPidMemory(pid, grContext);
308 log.AppendFormat("GPU Mem(MB):%f\n", mem.GetGpuMemorySize() / (MEMUNIT_RATE * MEMUNIT_RATE));
309 log.AppendFormat("CPU Mem(MB):%f\n", mem.GetCpuMemorySize() / (MEMUNIT_RATE * MEMUNIT_RATE));
310 log.AppendFormat("Total Mem(MB):%f\n", mem.GetTotalMemorySize() / (MEMUNIT_RATE * MEMUNIT_RATE));
311 }
312 #else
DumpPidMemory(DfxString & log,int pid,const Drawing::GPUContext * gpuContext)313 void MemoryManager::DumpPidMemory(DfxString& log, int pid, const Drawing::GPUContext* gpuContext)
314 {
315 MemoryGraphic mem = CountPidMemory(pid, gpuContext);
316 log.AppendFormat("GPU Mem(MB):%f\n", mem.GetGpuMemorySize() / (MEMUNIT_RATE * MEMUNIT_RATE));
317 log.AppendFormat("CPU Mem(KB):%f\n", mem.GetCpuMemorySize() / (MEMUNIT_RATE * MEMUNIT_RATE));
318 log.AppendFormat("Total Mem(MB):%f\n", mem.GetTotalMemorySize() / (MEMUNIT_RATE * MEMUNIT_RATE));
319 }
320 #endif
321
322 #ifndef USE_ROSEN_DRAWING
CountSubMemory(int pid,const GrDirectContext * grContext)323 MemoryGraphic MemoryManager::CountSubMemory(int pid, const GrDirectContext* grContext)
324 {
325 MemoryGraphic memoryGraphic;
326 auto subThreadManager = RSSubThreadManager::Instance();
327 std::vector<MemoryGraphic> subMems = subThreadManager->CountSubMem(pid);
328 for (const auto& mem : subMems) {
329 memoryGraphic += mem;
330 }
331 return memoryGraphic;
332 }
333 #else
CountSubMemory(int pid,const Drawing::GPUContext * gpuContext)334 MemoryGraphic MemoryManager::CountSubMemory(int pid, const Drawing::GPUContext* gpuContext)
335 {
336 MemoryGraphic memoryGraphic;
337 auto subThreadManager = RSSubThreadManager::Instance();
338 std::vector<MemoryGraphic> subMems = subThreadManager->CountSubMem(pid);
339 for (const auto& mem : subMems) {
340 memoryGraphic += mem;
341 }
342 return memoryGraphic;
343 }
344 #endif
345
346 #ifndef USE_ROSEN_DRAWING
CountPidMemory(int pid,const GrDirectContext * grContext)347 MemoryGraphic MemoryManager::CountPidMemory(int pid, const GrDirectContext* grContext)
348 {
349 MemoryGraphic totalMemGraphic;
350
351 // Count mem of RS
352 totalMemGraphic.SetPid(pid);
353
354 #if defined (RS_ENABLE_GL) || defined (RS_ENABLE_VK)
355 // Count mem of Skia GPU
356 if (grContext) {
357 SkiaMemoryTracer gpuTracer("category", true);
358 GrGpuResourceTag tag(pid, 0, 0, 0);
359 grContext->dumpMemoryStatisticsByTag(&gpuTracer, tag);
360 float gpuMem = gpuTracer.GetGLMemorySize();
361 totalMemGraphic.IncreaseGpuMemory(gpuMem);
362 }
363 #endif
364
365 return totalMemGraphic;
366 }
367 #else
CountPidMemory(int pid,const Drawing::GPUContext * gpuContext)368 MemoryGraphic MemoryManager::CountPidMemory(int pid, const Drawing::GPUContext* gpuContext)
369 {
370 MemoryGraphic totalMemGraphic;
371
372 // Count mem of RS
373 totalMemGraphic.SetPid(pid);
374
375 #if defined (RS_ENABLE_GL) || defined(RS_ENABLE_VK)
376 // Count mem of Skia GPU
377 if (gpuContext) {
378 Drawing::TraceMemoryDump gpuTracer("category", true);
379 Drawing::GPUResourceTag tag(pid, 0, 0, 0);
380 gpuContext->DumpMemoryStatisticsByTag(&gpuTracer, tag);
381 float gpuMem = gpuTracer.GetGLMemorySize();
382 totalMemGraphic.IncreaseGpuMemory(gpuMem);
383 }
384 #endif
385
386 return totalMemGraphic;
387 }
388 #endif
389
390 #ifndef USE_ROSEN_DRAWING
CountMemory(std::vector<pid_t> pids,const GrDirectContext * grContext,std::vector<MemoryGraphic> & mems)391 void MemoryManager::CountMemory(std::vector<pid_t> pids, const GrDirectContext* grContext,
392 std::vector<MemoryGraphic>& mems)
393 {
394 auto countMem = [&grContext, &mems] (pid_t pid) {
395 mems.emplace_back(CountPidMemory(pid, grContext));
396 };
397 // Count mem of Skia GPU
398 std::for_each(pids.begin(), pids.end(), countMem);
399 }
400 #else
CountMemory(std::vector<pid_t> pids,const Drawing::GPUContext * gpuContext,std::vector<MemoryGraphic> & mems)401 void MemoryManager::CountMemory(
402 std::vector<pid_t> pids, const Drawing::GPUContext* gpuContext, std::vector<MemoryGraphic>& mems)
403 {
404 auto countMem = [&gpuContext, &mems] (pid_t pid) {
405 mems.emplace_back(CountPidMemory(pid, gpuContext));
406 };
407 // Count mem of Skia GPU
408 std::for_each(pids.begin(), pids.end(), countMem);
409 }
410 #endif
411
FindGeoById(uint64_t nodeId)412 static std::tuple<uint64_t, std::string, RectI> FindGeoById(uint64_t nodeId)
413 {
414 const auto& nodeMap = RSMainThread::Instance()->GetContext().GetNodeMap();
415 auto node = nodeMap.GetRenderNode<RSRenderNode>(nodeId);
416 uint64_t windowId = nodeId;
417 std::string windowName = "NONE";
418 RectI nodeFrameRect;
419 if (!node) {
420 return { windowId, windowName, nodeFrameRect };
421 }
422 nodeFrameRect =
423 (node->GetRenderProperties().GetBoundsGeometry())->GetAbsRect();
424 // Obtain the window according to childId
425 auto parent = node->GetParent().lock();
426 while (parent) {
427 if (parent->IsInstanceOf<RSSurfaceRenderNode>()) {
428 const auto& surfaceNode = RSBaseRenderNode::ReinterpretCast<RSSurfaceRenderNode>(parent);
429 windowName = surfaceNode->GetName();
430 windowId = surfaceNode->GetId();
431 break;
432 }
433 parent = parent->GetParent().lock();
434 }
435 return { windowId, windowName, nodeFrameRect };
436 }
437
DumpRenderServiceMemory(DfxString & log)438 void MemoryManager::DumpRenderServiceMemory(DfxString& log)
439 {
440 log.AppendFormat("\n----------\nRenderService caches:\n");
441 MemoryTrack::Instance().DumpMemoryStatistics(log, FindGeoById);
442 }
443
DumpDrawingCpuMemory(DfxString & log)444 void MemoryManager::DumpDrawingCpuMemory(DfxString& log)
445 {
446 #ifndef USE_ROSEN_DRAWING
447 // CPU
448 log.AppendFormat("\n----------\nSkia CPU caches:\n");
449 log.AppendFormat("Font Cache (CPU):\n");
450 log.AppendFormat(" Size: %.2f kB \n", SkGraphics::GetFontCacheUsed() / MEMUNIT_RATE);
451 log.AppendFormat(" Glyph Count: %d \n", SkGraphics::GetFontCacheCountUsed());
452
453 std::vector<ResourcePair> cpuResourceMap = {
454 { "skia/sk_resource_cache/bitmap_", "Bitmaps" },
455 { "skia/sk_resource_cache/rrect-blur_", "Masks" },
456 { "skia/sk_resource_cache/rects-blur_", "Masks" },
457 { "skia/sk_resource_cache/tessellated", "Shadows" },
458 { "skia/sk_resource_cache/yuv-planes_", "YUVPlanes" },
459 { "skia/sk_resource_cache/budget_glyph_count", "Bitmaps" },
460 };
461 SkiaMemoryTracer cpuTracer(cpuResourceMap, true);
462 SkGraphics::DumpMemoryStatistics(&cpuTracer);
463 log.AppendFormat("CPU Cachesxx:\n");
464 cpuTracer.LogOutput(log);
465 log.AppendFormat("Total CPU memory usage:\n");
466 cpuTracer.LogTotals(log);
467
468 // cache limit
469 size_t cacheLimit = SkGraphics::GetResourceCacheTotalByteLimit();
470 size_t fontCacheLimit = SkGraphics::GetFontCacheLimit();
471 log.AppendFormat("\ncpu cache limit = %zu ( fontcache = %zu ):\n", cacheLimit, fontCacheLimit);
472 #else
473 // CPU
474 log.AppendFormat("\n----------\nSkia CPU caches:\n");
475 log.AppendFormat("Font Cache (CPU):\n");
476 log.AppendFormat(" Size: %.2f kB \n", Drawing::SkiaGraphics::GetFontCacheUsed() / MEMUNIT_RATE);
477 log.AppendFormat(" Glyph Count: %d \n", Drawing::SkiaGraphics::GetFontCacheCountUsed());
478
479 std::vector<ResourcePair> cpuResourceMap = {
480 { "skia/sk_resource_cache/bitmap_", "Bitmaps" },
481 { "skia/sk_resource_cache/rrect-blur_", "Masks" },
482 { "skia/sk_resource_cache/rects-blur_", "Masks" },
483 { "skia/sk_resource_cache/tessellated", "Shadows" },
484 { "skia/sk_resource_cache/yuv-planes_", "YUVPlanes" },
485 { "skia/sk_resource_cache/budget_glyph_count", "Bitmaps" },
486 };
487 SkiaMemoryTracer cpuTracer(cpuResourceMap, true);
488 Drawing::SkiaGraphics::DumpMemoryStatistics(&cpuTracer);
489 log.AppendFormat("CPU Cachesxx:\n");
490 cpuTracer.LogOutput(log);
491 log.AppendFormat("Total CPU memory usage:\n");
492 cpuTracer.LogTotals(log);
493
494 // cache limit
495 size_t cacheLimit = Drawing::SkiaGraphics::GetResourceCacheTotalByteLimit();
496 size_t fontCacheLimit = Drawing::SkiaGraphics::GetFontCacheLimit();
497 log.AppendFormat("\ncpu cache limit = %zu ( fontcache = %zu ):\n", cacheLimit, fontCacheLimit);
498 #endif
499 }
500
501 #ifndef USE_ROSEN_DRAWING
DumpGpuCache(DfxString & log,const GrDirectContext * grContext,GrGpuResourceTag * tag,std::string & name)502 void MemoryManager::DumpGpuCache(
503 DfxString& log, const GrDirectContext* grContext, GrGpuResourceTag* tag, std::string& name)
504 {
505 if (!grContext) {
506 log.AppendFormat("grContext is nullptr.\n");
507 return;
508 }
509 /////////////////////////////GPU/////////////////////////
510 #if defined (RS_ENABLE_GL) || defined (RS_ENABLE_VK)
511 log.AppendFormat("\n---------------\nSkia GPU Caches:%s\n", name.c_str());
512 SkiaMemoryTracer gpuTracer("category", true);
513 if (tag) {
514 grContext->dumpMemoryStatisticsByTag(&gpuTracer, *tag);
515 } else {
516 grContext->dumpMemoryStatistics(&gpuTracer);
517 }
518 gpuTracer.LogOutput(log);
519 log.AppendFormat("Total GPU memory usage:\n");
520 gpuTracer.LogTotals(log);
521 #endif
522 }
523 #else
DumpGpuCache(DfxString & log,const Drawing::GPUContext * gpuContext,Drawing::GPUResourceTag * tag,std::string & name)524 void MemoryManager::DumpGpuCache(
525 DfxString& log, const Drawing::GPUContext* gpuContext, Drawing::GPUResourceTag* tag, std::string& name)
526 {
527 if (!gpuContext) {
528 log.AppendFormat("gpuContext is nullptr.\n");
529 return;
530 }
531 /* GPU */
532 #if defined (RS_ENABLE_GL) || defined(RS_ENABLE_VK)
533 log.AppendFormat("\n---------------\nSkia GPU Caches:%s\n", name.c_str());
534 Drawing::TraceMemoryDump gpuTracer("category", true);
535 if (tag) {
536 gpuContext->DumpMemoryStatisticsByTag(&gpuTracer, *tag);
537 } else {
538 gpuContext->DumpMemoryStatistics(&gpuTracer);
539 }
540 gpuTracer.LogOutput(log);
541 log.AppendFormat("Total GPU memory usage:\n");
542 gpuTracer.LogTotals(log);
543 #endif
544 }
545 #endif
546
547 #ifndef USE_ROSEN_DRAWING
DumpAllGpuInfo(DfxString & log,const GrDirectContext * grContext)548 void MemoryManager::DumpAllGpuInfo(DfxString& log, const GrDirectContext* grContext)
549 {
550 if (!grContext) {
551 log.AppendFormat("No valid gpu cache instance.\n");
552 return;
553 }
554 #if defined (RS_ENABLE_GL) || defined (RS_ENABLE_VK)
555 const auto& nodeMap = RSMainThread::Instance()->GetContext().GetNodeMap();
556 nodeMap.TraverseSurfaceNodes([&log, &grContext](const std::shared_ptr<RSSurfaceRenderNode> node) {
557 GrGpuResourceTag tag(ExtractPid(node->GetId()), 0, node->GetId(), 0);
558 std::string name = node->GetName() + " " + std::to_string(node->GetId());
559 DumpGpuCache(log, grContext, &tag, name);
560 });
561 #endif
562 }
563 #else
DumpAllGpuInfo(DfxString & log,const Drawing::GPUContext * gpuContext)564 void MemoryManager::DumpAllGpuInfo(DfxString& log, const Drawing::GPUContext* gpuContext)
565 {
566 if (!gpuContext) {
567 log.AppendFormat("No valid gpu cache instance.\n");
568 return;
569 }
570 #if defined (RS_ENABLE_GL) || defined(RS_ENABLE_VK)
571 const auto& nodeMap = RSMainThread::Instance()->GetContext().GetNodeMap();
572 nodeMap.TraverseSurfaceNodes([&log, &gpuContext](const std::shared_ptr<RSSurfaceRenderNode> node) {
573 Drawing::GPUResourceTag tag(ExtractPid(node->GetId()), 0, node->GetId(), 0);
574 std::string name = node->GetName() + " " + std::to_string(node->GetId());
575 DumpGpuCache(log, gpuContext, &tag, name);
576 });
577 #endif
578 }
579 #endif
580
581 #ifndef USE_ROSEN_DRAWING
DumpDrawingGpuMemory(DfxString & log,const GrDirectContext * grContext)582 void MemoryManager::DumpDrawingGpuMemory(DfxString& log, const GrDirectContext* grContext)
583 {
584 if (!grContext) {
585 log.AppendFormat("No valid gpu cache instance.\n");
586 return;
587 }
588 /////////////////////////////GPU/////////////////////////
589 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
590 std::string gpuInfo;
591 // total
592 DumpGpuCache(log, grContext, nullptr, gpuInfo);
593 // Get memory of window by tag
594 DumpAllGpuInfo(log, grContext);
595 for (uint32_t tagtype = RSTagTracker::TAG_SAVELAYER_DRAW_NODE; tagtype <= RSTagTracker::TAG_CAPTURE; tagtype++) {
596 GrGpuResourceTag tag(0, 0, 0, tagtype);
597 std::string tagType = RSTagTracker::TagType2String(static_cast<RSTagTracker::TAGTYPE>(tagtype));
598 DumpGpuCache(log, grContext, &tag, tagType);
599 }
600 // cache limit
601 size_t cacheLimit = 0;
602 size_t cacheUsed = 0;
603 grContext->getResourceCacheLimits(nullptr, &cacheLimit);
604 grContext->getResourceCacheUsage(nullptr, &cacheUsed);
605 log.AppendFormat("\ngpu limit = %zu ( used = %zu ):\n", cacheLimit, cacheUsed);
606
607 //////////////////////////ShaderCache///////////////////
608 log.AppendFormat("\n---------------\nShader Caches:\n");
609 #ifdef NEW_RENDER_CONTEXT
610 log.AppendFormat(MemoryHandler::QuerryShader().c_str());
611 #else
612 std::shared_ptr<RenderContext> rendercontext = std::make_shared<RenderContext>();
613 log.AppendFormat(rendercontext->GetShaderCacheSize().c_str());
614 #endif
615 // gpu stat
616 log.AppendFormat("\n---------------\ndumpGpuStats:\n");
617 SkString stat;
618 grContext->priv().dumpGpuStats(&stat);
619
620 log.AppendFormat("%s\n", stat.c_str());
621 #endif
622 }
623 #else
DumpDrawingGpuMemory(DfxString & log,const Drawing::GPUContext * gpuContext)624 void MemoryManager::DumpDrawingGpuMemory(DfxString& log, const Drawing::GPUContext* gpuContext)
625 {
626 if (!gpuContext) {
627 log.AppendFormat("No valid gpu cache instance.\n");
628 return;
629 }
630 /* GPU */
631 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
632 std::string gpuInfo;
633 // total
634 DumpGpuCache(log, gpuContext, nullptr, gpuInfo);
635 // Get memory of window by tag
636 DumpAllGpuInfo(log, gpuContext);
637 for (uint32_t tagtype = RSTagTracker::TAG_SAVELAYER_DRAW_NODE; tagtype <= RSTagTracker::TAG_CAPTURE; tagtype++) {
638 Drawing::GPUResourceTag tag(0, 0, 0, tagtype);
639 std::string tagType = RSTagTracker::TagType2String(static_cast<RSTagTracker::TAGTYPE>(tagtype));
640 DumpGpuCache(log, gpuContext, &tag, tagType);
641 }
642 // cache limit
643 size_t cacheLimit = 0;
644 size_t cacheUsed = 0;
645 gpuContext->GetResourceCacheLimits(nullptr, &cacheLimit);
646 gpuContext->GetResourceCacheUsage(nullptr, &cacheUsed);
647 log.AppendFormat("\ngpu limit = %zu ( used = %zu ):\n", cacheLimit, cacheUsed);
648
649 /* ShaderCache */
650 log.AppendFormat("\n---------------\nShader Caches:\n");
651 #ifdef NEW_RENDER_CONTEXT
652 log.AppendFormat(MemoryHandler::QuerryShader().c_str());
653 #else
654 std::shared_ptr<RenderContext> rendercontext = std::make_shared<RenderContext>();
655 log.AppendFormat(rendercontext->GetShaderCacheSize().c_str());
656 #endif
657 // gpu stat
658 log.AppendFormat("\n---------------\ndumpGpuStats:\n");
659 std::string stat;
660 gpuContext->DumpGpuStats(stat);
661
662 log.AppendFormat("%s\n", stat.c_str());
663 #endif
664 }
665 #endif // USE_ROSEN_DRAWING
666
DumpMallocStat(std::string & log)667 void MemoryManager::DumpMallocStat(std::string& log)
668 {
669 malloc_stats_print(
670 [](void* fp, const char* str) {
671 if (!fp) {
672 RS_LOGE("DumpMallocStat fp is nullptr");
673 return;
674 }
675 std::string* sp = static_cast<std::string*>(fp);
676 if (str) {
677 // cause log only support 2096 len. we need to only output critical log
678 // and only put total log in RSLOG
679 // get allocated string
680 if (strncmp(str, "Allocated", strlen("Allocated")) == 0) {
681 sp->append(str);
682 }
683 RS_LOGW("[mallocstat]:%{public}s", str);
684 }
685 },
686 &log, nullptr);
687 }
688 } // namespace OHOS::Rosen