可可西

UE4 LLM工具

LLM(Low Level Memory Tracker) 是从 4.18 开始引入的新的内存统计工具,比memreport 统计数据更加详细精确,但又不会像 MallocProfiler 那样有很大的本身开销

通过LLM,可以知道游戏消耗的内存分别来自引擎的哪些模块,让开发者可以对内存占用高的模块进行有针对性优化。

Debug、Development包才会启用ENABLE_LOW_LEVEL_MEM_TRACKER宏,统计逻辑才会编译进可执行二进制中,才能使用LLM相关的功能

Shipping包是没有LLM功能,对于Test包可以#define ALLOW_LOW_LEVEL_MEM_TRACKER_IN_TEST 1来将LLM代码编译进包

相关逻辑在UnrealEngine\Engine\Source\Runtime\Core\Public\HAL\LowLevelMemTracker.hUnrealEngine\Engine\Source\Runtime\Core\Private\HAL\LowLevelMemTracker.cpp文件中

 

LLM通过插入各种tag来将所有待统计的内存划归到某个tag下。实现原理是:插入的tag会形成一个tag的栈,将FMalloc分配的内存统计到当前栈顶的tag下(离FMalloc分配最近的一个tag)。

LLM在最底层hook了FMalloc的每一个统计,如果没有任何tag在当前栈中,那么所有内存计入在untagged这个tag下。LLM通过TLS机制来实现tag多线程安全读写,避免了不必要的锁机制,提升效率。

如果我们在代码中插入一个基于scoped的tag,就可以把这个scope下的独占内存(Exclusive)计入这个tag下。通过LLM我们不会遗漏任何FMalloc分配的内存。

此外程序刚初始化,加载libUE4.so时,LLM会记录一个内存,被它估计为可执行程序本身的内存,记在ProgramSize这个tag中。

 

在RHI中对gpu资源的创建也会被LLM记录 ,在额外的texture,buffer等标签下,它们不是FMalloc内存的一部分,是对GPU的内存占用的估算。

 

LLM目前有两个Tracker(跟踪器):Default Tracker(默认跟踪器)Platform Tracker(平台跟踪器)。它们都有自己的独立分配映射和标记堆栈。

Default Tracker(ELLMTracker::Default)的级别较高,记录引擎中FMemoryMalloc函数进行的分配。为 stat LLM和 stat LLMFULL控制台命令提供统计信息。

Platform Tracker(ELLMTracker::Platform)的级别较低,记录从OS进行的所有分配。例如,它会跟踪FMemoryMalloc函数进行的内部分配。因此,Default Tracker是Platform Tracker统计信息的子集。

 

运行开关

在编译时打开 LLM 后,要想在运行时使用 LLM 的功能,还要加上启动命令行 -LLM -LLMCSV

-LLM:运行时打开LLM统计    或者通过定义#define LLM_AUTO_ENABLE 1默认打开   注:开了之后会导致fps下降23.7%,对性能影响很大

-LLMCSV:将内存统计信息输出到CSV 文件中,CSV 文件保存在 Saved\Profiling\LLM 目录下  注:设置控制台变量LLM.LLMWriteInterval xx,修改写csv文件的频率为xx秒,默认5秒写一行

会得到两个 csv 文件,一个是 LLM_ 前缀,另一个是 LLMPlatform_前缀,这两个文件分别由两个 Tracker 生成,这两个文件的关注点不同

① LLM 主要关注FMalloc内存的消费者,主要就是引擎内各个部分的内存开销

② LLMPlatform 只关注系统内存的消费者,主要有几大类: ProgramSize, FMalloc, LLMOverhead

注:开启了csv写入,每写入一行也会打印log

。。。
 [2023.05.19-15.48.16:537][   792]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 10
 [2023.05.19-15.48.16:539][   792]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 10
 [2023.05.19-15.48.21:542][   877]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 11
 [2023.05.19-15.48.21:545][   877]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 11
 [2023.05.19-15.48.26:562][  1092]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 12
 [2023.05.19-15.48.26:565][  1092]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 12
 [2023.05.19-15.48.31:578][  1332]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 13
 [2023.05.19-15.48.31:580][  1332]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 13
 [2023.05.19-15.48.36:578][  1582]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 14
 [2023.05.19-15.48.36:581][  1582]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 14
 [2023.05.19-15.48.41:586][  1830]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 15
 [2023.05.19-15.48.41:589][  1830]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 15
 [2023.05.19-15.48.46:595][  2079]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 16
 [2023.05.19-15.48.46:599][  2079]LogHAL: Display: |LowLevelMemTracker.cpp:2596|Wrote LLM csv line 16
。。。

 

-LLMTAGSETS=Assets:显示每个资源分配的统计,不只是有大类别的数据。   注:需打开LLM_ALLOW_ASSETS_TAGS

-LLMTAGSETS=AssetClasses:按UObject类别进行分类统计

注:写CSV时,如果开启了-LLMTAGSETS 命令行,CSV 文件可能会错乱。

       因为写 CSV 文件时预留了第一行标题栏内容的缓冲区,当每个资源或资源类很多,会导致标题栏内容溢出,覆盖了后面的数据区域,所以这里需要自己按需求修改一下

       具体的控制台命令为:LLM.LLMHeaderMaxSize 500000

运行时开关 LLM 的处理见 FLowLevelMemTracker::ProcessCommandLine 函数

 

在UE4CommandLine.txt文件中添加命令行参数:

../../../MyGame/MyGame.uproject -LLM -LLMCSV

 

Android需要将该文件push到手机的UE4Game/MyGame/UE4CommandLine.txt

iOS需要将ue4commandline.txt注:需要全小写)放在如下目录中:

 

从csv生成html图表

PerfreportTool.exe -csv F:\UAGame\Saved\Profiling\LLM\LLM_Pid23989_2021.03.30-14.14.55.csv -o c:\LLMOutput -reporttype LLM -topng. -graphxml LLMReportGraphs.xml -reportxml LLMReportTypes.xml -nostripevents

PerfreportTool.exe -csv F:\UAGame\Saved\Profiling\LLM\LLMPlatform_Pid23989_2021.03.30-14.14.55.csv -o c:\LLMOutput -reporttype LLM -topng. -graphxml LLMReportGraphs.xml -reportxml LLMReportTypes.xml -nostripevents

生成的html文件如下:

 

统计项说明

Android

LLM_Pid23989_2021.03.30-14.14.55内容如下:

Untagged,RenderingThread,Audio/AudioMisc,EngineInit,Stats,LoadMapMisc,Audio/AudioMixer,GC,Audio,AsyncLoading,UObject,FileSystem,Materials,Shaders,TextureMetaData,InitUObject,UI,EnginePreInit,Textures,Meshes,SceneRender,RenderTargets,RHIMisc,Meshes/StaticMesh,FName,MaterialInstance,PSO,Particles,Localization,ConfigSystem,TaskGraphMiscTasks,Physics/PhysXAllocator,Physics,AssetRegistry,CsvProfiler,Audio/AudioMixerPlugins,Physics/PhysX,NavigationRecast,EngineMisc,ProgramSize,GenericPlatformMallocCrash,FMallocUnused,TrackedTotal,Total,Untracked,StreamingManager,Lua,Meshes/Landscape,Animation,Meshes/SkeletalMesh,Niagara,MediaStreaming,Meshes/InstancedMesh,Physics/PhysXLandscape,Audio/AudioSynthesis, 
。。。 。。。
35.32,6.21,0.02,0.90,21.65,5.05,9.52,0.62,9.55,3.08,105.19,13.72,0.54,19.11,0.65,12.84,42.70,18.71,67.28,31.85,34.72,40.85,0.80,8.79,7.12,0.31,0.15,0.78,36.59,2.80,0.00,6.32,6.71,0.13,0.00,0.00,0.39,0.71,3.78,157.18,3.61,55.31,789.20,830.58,41.44,0.44,28.88,0.03,13.38,12.33,0.00,0.00,0.13,0.00,0.00,
35.32,6.21,0.02,0.90,21.52,5.05,9.52,0.62,9.55,3.08,105.22,13.72,0.54,19.11,0.65,12.84,42.71,18.71,67.28,31.78,34.25,40.85,0.80,8.79,7.12,0.31,0.15,0.78,36.59,2.80,0.00,6.33,6.71,0.13,0.00,0.00,0.39,0.71,3.78,157.18,3.61,56.45,789.74,842.68,52.88,0.44,28.91,0.03,13.38,12.27,0.00,0.00,0.13,0.00,0.00,
35.32,6.21,0.02,0.90,21.65,5.05,9.52,0.62,9.55,3.08,105.22,13.72,0.54,19.11,0.65,12.84,42.74,18.71,67.28,31.89,34.99,40.85,0.80,8.79,7.12,0.31,0.15,0.78,36.59,2.80,0.00,6.34,6.73,0.13,0.00,0.00,0.39,0.71,3.79,157.18,3.61,55.68,790.05,828.77,38.50,0.44,28.94,0.03,13.38,12.37,0.00,0.00,0.13,0.00,0.00,
35.32,6.21,0.02,0.90,21.59,5.05,9.52,0.62,9.55,3.08,105.25,13.72,0.54,19.11,0.65,12.84,42.72,18.71,67.28,31.86,35.13,40.85,0.80,8.79,7.12,0.31,0.15,0.78,36.59,2.80,0.00,6.32,6.71,0.13,0.00,0.00,0.39,0.71,3.81,157.18,3.61,55.56,790.05,841.99,52.15,0.44,28.96,0.03,13.44,12.34,0.00,0.00,0.13,0.00,0.00,
35.32,6.21,0.02,0.90,21.40,5.05,9.52,0.65,9.55,3.08,105.18,13.72,0.54,19.11,0.65,12.84,42.72,18.71,67.28,31.32,35.28,40.85,0.80,8.79,7.12,0.31,0.15,0.78,36.59,2.80,0.00,6.34,6.73,0.13,0.00,0.00,0.39,0.71,3.77,157.18,3.61,54.50,788.20,838.28,50.08,0.44,28.99,0.03,13.26,11.80,0.00,0.00,0.13,0.00,0.00,
35.32,6.21,0.02,0.90,21.84,5.05,9.52,0.65,9.55,3.08,105.18,13.72,0.54,19.11,0.65,12.84,42.74,18.71,67.28,31.59,35.64,40.85,0.80,8.79,7.12,0.31,0.15,0.78,36.59,2.80,0.00,6.34,6.73,0.13,0.00,0.00,0.39,0.71,3.77,157.18,3.61,55.04,789.89,837.26,46.91,0.44,29.02,0.03,13.26,12.07,0.00,0.00,0.13,0.00,0.00,
35.32,6.21,0.02,0.90,22.03,5.05,9.52,0.65,9.55,3.08,105.17,13.72,0.54,19.11,0.65,12.84,42.75,18.71,67.28,31.52,35.90,40.85,0.80,8.79,7.12,0.31,0.15,0.78,36.59,2.80,0.00,6.34,6.73,0.13,0.00,0.00,0.39,0.71,3.74,157.18,3.61,54.95,790.17,831.60,40.49,0.44,29.05,0.03,13.26,11.96,0.00,0.00,0.13,0.00,0.00,
35.32,6.21,0.02,0.90,21.46,5.05,9.52,0.65,9.55,3.08,105.19,13.72,0.54,19.11,0.65,12.84,42.73,18.71,67.28,31.74,35.36,40.85,0.80,8.79,7.12,0.31,0.15,0.78,36.59,2.80,0.00,6.34,6.73,0.13,0.00,0.00,0.39,0.71,3.75,157.18,3.61,55.90,790.32,843.07,53.02,0.44,29.07,0.03,13.31,12.22,0.00,0.00,0.13,0.00,0.00,
35.32,6.21,0.02,0.90,21.46,5.05,9.52,0.65,9.55,3.08,105.22,13.72,0.54,19.11,0.65,12.84,42.74,18.71,67.28,31.82,35.44,40.85,0.80,8.79,7.12,0.31,0.15,0.78,36.59,2.80,0.00,6.34,6.73,0.13,0.00,0.00,0.39,0.71,3.77,157.18,3.61,56.08,790.86,843.15,52.41,0.44,29.23,0.03,13.32,12.30,0.00,0.00,0.13,0.00,0.00,
35.32,6.21,0.02,0.90,21.78,5.05,9.52,0.65,9.55,3.08,105.23,13.72,0.54,19.11,0.65,12.84,42.75,18.71,67.28,31.71,36.19,40.85,0.80,8.79,7.12,0.31,0.15,0.78,36.59,2.80,0.00,6.33,6.72,0.13,0.00,0.00,0.39,0.71,3.77,157.18,3.61,55.50,791.27,842.89,51.62,0.44,29.26,0.03,13.32,12.18,0.00,0.00,0.13,0.00,0.00,

Total(830.58) = TrackedTotal(789.2) + Untracked(41.44

TrackedTotal(789.2) = Untagged(35.32) + RenderingThread(6.21) + EngineInit(0.9) + Stats(21.65) + LoadMapMisc(5.05) + GC(0.62) + Audio(9.55) + AsyncLoading(3.08) + UObject(105.19) + FileSystem(13.72)+ Materials(0.54

             + Shaders(19.11) + TextureMetaData(0.65) + InitUObject(12.84) + UI(42.7) + EnginePreInit(18.71) + Textures(67.28) + Meshes(31.85) + SceneRender(34.72) + RenderTargets(40.85) + RHIMisc(0.8) + FName(7.12

            + MaterialInstance(0.31) + PSO(0.15) + Particles(0.78) + Localization(36.59) + ConfigSystem(2.8) + TaskGraphMiscTasks(0)+ Physics(6.71) + AssetRegistry(0.13) + CsvProfiler(0) + NavigationRecast(0.71

            + EngineMisc(3.78) + ProgramSize(157.18) + GenericPlatformMallocCrash(3.61) + FMallocUnused(55.31) + StreamingManager(0.44) + Lua(28.88) + Animation(13.38) + Niagara(0) + MediaStreaming(0

Meshes(31.85)  >  Meshes/StaticMesh(8.79) + Meshes/Landscape(0.03) + Meshes/InstancedMesh(0.13) + Meshes/SkeletalMesh(12.33

Physics(6.71) = Physics/PhysXAllocator(6.32) + Physics/PhysX(0.39) + Physics/PhysXLandscape(0

Audio(9.55) = Audio/AudioMisc(0.02) + Audio/AudioMixer(9.52) + Audio/AudioMixerPlugins(0) + Audio/AudioSynthesis(0

注1:Audio内存占用,可在DefaultEngine.ini中关闭掉

[Audio]
UseAudioMixer=False

注2:带上-NoAudioMixer命令行参数

 

LLMPlatform_Pid23989_2021.03.30-14.14.55.csv内容如下:

Untagged,FMalloc,Graphics,ProgramSize,GenericPlatformMallocCrash,TrackedTotal,Total,Untracked,LLMOverhead,OSAvailable,
。。。 。。。
0.00,511.05,115.27,157.18,3.61,918.22,961.69,43.47,131.11,3389.45,
0.00,511.61,115.27,157.18,3.61,907.32,962.20,54.88,119.64,3388.55,
0.00,511.86,115.28,157.18,3.61,920.53,961.36,40.84,132.58,3387.90,
0.00,511.86,115.27,157.18,3.61,907.62,961.63,54.02,119.69,3386.14,
0.00,510.05,115.27,157.18,3.61,905.81,957.96,52.16,119.69,3389.23,
0.00,511.74,115.27,157.18,3.61,907.49,956.95,49.46,119.69,3387.49,
0.00,511.99,115.31,157.18,3.61,919.30,962.82,43.52,131.22,3385.75,
0.00,512.18,115.27,157.18,3.61,907.96,962.80,54.84,119.72,3388.29,
0.00,512.68,115.27,157.18,3.61,908.46,962.87,54.41,119.72,3386.87,
0.00,513.11,115.27,157.18,3.61,908.93,962.64,53.72,119.75,3386.62,

Total(961.69) = TrackedTotal(918.22) + Untracked(43.47

TrackedTotal(918.22) = Untagged(0.00) + FMalloc(511.05) + Graphics(115.27) + ProgramSize(157.18) + GenericPlatformMallocCrash(3.61) + LLMOverhead(131.11

 

IOS

LLM_Pid0_2021.09.27-19.41.13.csv内容如下:

Untagged,Stats,EngineInit,RenderingThread,AsyncLoading,UObject,FileSystem,Materials,Shaders,TextureMetaData,FName,InitUObject,Wwise,EnginePreInit,UI,Textures,Metal Textures,Metal Buffers,SceneRender,RenderTargets,RHIMisc,Meshes/StaticMesh,PSO,MaterialInstance,LoadMapMisc,Particles,GC,Meshes,Localization,ConfigSystem,TaskGraphMiscTasks,Physics/PhysXAllocator,AssetRegistry,CsvProfiler,Physics/PhysX,NavigationRecast,EngineMisc,Physics,ProgramSize,FMallocUnused,TrackedTotal,Total,Untracked,StreamingManager,Meshes/Landscape,Lua,Animation,UI/Font,Meshes/InstancedMesh,Meshes/SkeletalMesh,Audio/AudioSoundWaves,Niagara,MediaStreaming,GCloud,Networking,Textures/MergeTexture,Physics/PhysXLandscape,   
。。。 。。。
9.39,12.94,1.13,1.22,4.16,93.28,17.82,0.28,20.41,0.53,11.50,13.35,8.13,2.47,34.46,0.56,0.10,0.12,2.62,0.01,0.65,1.23,14.10,0.29,0.97,2.05,7.74,13.00,12.56,3.55,0.00,25.29,0.89,0.00,0.46,0.07,10.36,25.76,29.87,-42.96,363.24,847.58,484.39,0.28,0.00,47.04,2.11,0.89,0.05,11.73,0.00,0.03,0.00,0.05,0.30,0.00,0.01,
9.39,13.13,1.13,1.22,4.16,93.28,17.82,0.28,20.41,0.53,11.50,13.35,8.13,2.47,34.46,0.56,0.10,0.12,2.62,0.01,0.65,1.24,14.10,0.29,0.97,2.05,7.74,13.01,12.56,3.55,0.00,25.29,0.89,0.00,0.46,0.07,10.36,25.76,29.87,-42.98,363.42,847.71,484.25,0.28,0.00,47.06,2.11,0.89,0.05,11.73,0.00,0.03,0.00,0.05,0.30,0.00,0.01,
9.39,12.88,1.13,1.22,4.16,93.28,17.82,0.28,20.41,0.53,11.50,13.35,8.13,2.47,34.47,0.56,0.10,0.12,2.59,0.01,0.65,1.20,14.10,0.29,0.97,2.05,7.74,12.95,12.56,3.55,0.00,25.29,0.89,0.00,0.46,0.07,10.36,25.75,29.87,-42.92,363.15,847.51,484.38,0.28,0.00,47.08,2.11,0.89,0.05,11.71,0.00,0.03,0.00,0.05,0.30,0.00,0.01,
9.39,13.00,1.13,1.22,4.16,93.28,17.82,0.28,20.41,0.53,11.50,13.35,8.13,2.47,34.47,0.56,0.10,0.12,2.66,0.01,0.65,1.20,14.10,0.29,0.97,2.05,7.74,12.97,12.56,3.55,0.00,25.29,0.89,0.00,0.46,0.07,10.36,25.75,29.87,-43.02,363.27,847.60,484.24,0.28,0.00,47.10,2.11,0.89,0.05,11.72,0.00,0.03,0.00,0.05,0.30,0.00,0.01,
9.39,12.88,1.13,1.22,4.16,93.28,17.82,0.28,20.41,0.53,11.50,13.35,8.13,2.47,34.47,0.56,0.10,0.12,2.62,0.01,0.65,1.24,14.10,0.29,0.97,2.05,7.74,13.01,12.56,3.55,0.00,25.29,0.89,0.00,0.46,0.07,10.36,25.76,29.87,-43.05,363.18,847.52,484.31,0.28,0.00,47.12,2.11,0.89,0.05,11.74,0.00,0.03,0.00,0.05,0.30,0.00,0.01,
9.39,13.10,1.13,1.22,4.17,99.00,17.82,0.28,20.41,0.54,11.50,13.76,8.19,2.48,44.66,0.57,0.10,0.12,2.61,0.01,0.65,1.27,14.10,0.29,0.97,2.05,7.74,13.03,14.75,3.55,0.00,25.29,0.89,0.00,0.46,0.07,10.42,25.75,29.87,-53.73,373.40,858.88,485.47,0.28,0.00,49.14,2.11,0.89,0.05,11.72,0.00,0.03,0.00,0.05,0.30,0.00,0.01,
9.39,13.04,1.13,1.22,4.17,99.02,17.82,0.28,20.41,0.54,11.50,13.76,8.16,2.48,44.67,0.57,0.10,0.12,2.65,0.01,0.65,1.20,14.10,0.29,0.97,2.05,7.74,12.96,14.75,3.55,0.00,25.29,0.89,0.00,0.46,0.07,10.46,25.75,29.87,-53.91,373.50,861.30,487.85,0.28,0.00,49.49,2.11,0.89,0.05,11.72,0.00,0.03,0.00,0.05,0.30,0.00,0.01,
9.39,12.79,1.13,1.22,4.17,99.10,17.82,0.28,20.41,0.54,11.50,13.76,8.13,2.48,44.87,0.57,0.10,0.12,2.65,0.01,0.65,1.27,14.10,0.29,0.97,2.05,7.74,13.04,14.79,3.55,0.00,25.29,0.89,0.00,0.46,0.07,10.50,25.76,29.87,-55.87,373.64,861.69,488.01,0.28,0.00,51.43,2.11,0.89,0.05,11.72,0.00,0.03,0.00,0.05,0.30,0.00,0.01,
9.39,12.98,1.13,1.22,4.17,99.10,17.82,0.28,20.41,0.54,11.50,13.76,8.14,2.48,44.86,0.57,0.10,0.12,2.65,0.01,0.65,1.25,14.10,0.29,0.97,2.05,7.74,13.01,14.79,3.55,0.00,25.29,0.89,0.00,0.46,0.07,10.50,25.76,29.87,-55.93,373.84,861.91,488.08,0.28,0.00,51.52,2.11,0.89,0.05,11.72,0.00,0.03,0.00,0.05,0.30,0.00,0.01,

Total(847.58) = TrackedTotal(363.24) + Untracked(484.39

TrackedTotal(363.24) = Untagged(9.39) + Stats(12.94) + EngineInit(1.13) + RenderingThread(1.22) + AsyncLoading(4.16) + UObject(93.28) + FileSystem(17.82) + Materials(0.28) + Shaders(20.41) + TextureMetaData(0.53

        + FName(11.5)+ InitUObject(13.35) + Wwise(8.13) + EnginePreInit(2.47) + UI(34.46) + Textures(0.56) + Metal Textures(0.1) + Metal Buffers(0.12) + SceneRender(2.62) + RenderTargets(0.01) + RHIMisc(0.65) + PSO(14.1

          + MaterialInstance(0.29)+ LoadMapMisc(0.97)+ Particles(2.05)+ GC(7.74)+ Meshes(13)+ Localization(12.56)+ ConfigSystem(3.55)+ TaskGraphMiscTasks(0)+ AssetRegistry(0.89)+ CsvProfiler(0)+ NavigationRecast(0.07

          + EngineMisc(10.36) + Physics(25.76) + ProgramSize(29.87) + FMallocUnused(-42.96) + StreamingManager(0.28) + Lua(47.04) + Animation(2.11) +  Niagara(0.03) +  MediaStreaming(0) + GCloud(0.05) + Networking(0.3

Meshes(13) = Meshes/StaticMesh(1.23) + Meshes/Landscape(0) + Meshes/InstancedMesh(0.05) + Meshes/SkeletalMesh(11.73

Physics(25.76) = Physics/PhysXAllocator(25.29) + Physics/PhysX(0.46)  + Physics/PhysXLandscape(0.01

 

LLMPlatform_Pid0_2021.09.27-19.41.13.csv内容如下:

Virtual Memory,Untagged,FMalloc,Metal Textures,Metal Buffers,Metal Render Targets,ProgramSize,TrackedTotal,Total,Untracked,LLMOverhead,OSAvailable,MMIO,  
。。。 。。。
400460.56,1.05,333.55,87.24,17.30,156.70,29.87,800.97,1010.75,209.78,163.04,1088.45,12.22,
400451.62,1.05,333.30,87.24,17.30,156.70,29.87,800.72,1010.55,209.83,163.04,1088.65,12.22,
400450.56,1.05,333.42,87.24,17.30,156.70,29.87,800.84,1010.64,209.80,163.04,1088.56,12.22,
400450.50,1.05,333.30,87.24,17.34,156.70,29.87,800.76,1010.56,209.80,163.04,1088.64,12.22,
400456.47,1.05,343.53,87.82,17.25,156.70,29.87,811.49,1021.92,210.43,163.04,1077.28,12.22,
400458.53,1.05,343.62,87.82,17.34,156.70,29.87,808.43,1021.09,212.67,159.79,1078.11,12.22,
400460.06,1.05,343.77,87.82,17.34,156.70,29.87,808.57,1021.48,212.92,159.79,1077.72,12.22,
400453.75,1.05,343.97,87.82,17.34,156.70,29.87,808.77,1021.70,212.93,159.79,1077.50,12.22,
400454.81,1.05,343.78,87.82,17.30,156.70,29.87,808.54,1021.56,213.03,159.79,1077.64,12.22,
400459.12,1.05,343.66,87.82,17.30,156.70,29.87,808.46,1021.39,212.93,159.81,1077.81,12.22,
400459.06,1.05,344.19,87.82,17.30,156.70,29.87,808.96,1021.91,212.95,159.81,1077.29,12.22,

Total(1010.75) = TrackedTotal(800.97) + Untracked(209.78

TrackedTotal(800.97) = Untagged(1.05)  + FMalloc(333.55) + Metal Textures(87.24) + Metal Buffers(17.3) + Metal Render Targets(156.7) + ProgramSize(29.87) + LLMOverhead(163.04) + MMIO(12.22

 

以第1条采集的值为例(单位MB),说明各统计项含义:

Untagged // 未分类的内存,即分配内存时候不在 LLM_SCOPE 宏范围内
ELLMTag::Untagged(Default Tracker): 35.32
ELLMTag::Untagged(Platform Tracker): 0

LLMOverhead // LLM本身消耗的内存
(Default Tracker): 无
ELLMTag::PlatformOverhead(Platform Tracker): 119.64

TrackedTotal // 通过调用 LLM OnLowLevelAlloc/OnLowLevelFree 统计到的所有内存   即:LLM跟踪到的所有内存
ELLMTag::TrackedTotal(Default Tracker):789.74
ELLMTag::PlatformTrackedTotal(Platform Tracker):907.32
注:统计到的内存值ELLMTag::PlatformTrackedTotal比ELLMTag::TrackedTotal要大

Total // 总内存

ELLMTag::PlatformTotal(Platform Tracker):962.2
从操作系统获得的实际内存,不从llm获得。在Android上为RSS,Resident Set Size 实际使用物理内存(包含共享库占用的内存)

在iOS上为Resident(Wired),物理内存,即常驻内存,含干净页(代码、文件)和dirty页。

 

ELLMTag::Total(Default Tracker):842.68
PlatformTotal - LLMOverhead。即为上面的内存减去 LLM 本身消耗的内存,这个内存值可以认为是在不打开 LLM 功能下的进程内存值

Untracked // 未知的内存分配,即 LLM 无法追踪的内存,比如第三方库里的内存分配
ELLMTag::PlatformUntracked(Platform Tracker): 54.88  // PlatformTotal - PlatformTrackedTotal
ELLMTag::Untracked(Default Tracker):52.88  // Total - TrackedTotal

FMalloc // 通过FMemory内存分配器分配的内存,也就是一般意义上引擎分配的内存,比如各种UObject,纹理,动画等占用的内存
(Default Tracker): 无
ELLMTag::FMalloc(Platform Tracker): 511.61

FMallocUnused  // ELLMTag::FMalloc内存分配器的内存 - 通过FMemory得到的内存。即内存分配器中未使用的内存
ELLMTag::FMallocUnused(Default Tracker): 56.45
(Platform Tracker): 无
注:LLM追踪的内存有2种ELLMAllocType::FMalloc和ELLMAllocType::System

ProgramSize // 程序刚起来时占用的内存(具体时机是初始化某个static FName变量,在进入main函数之前),用来弥补LLM初始化之前没有跟踪到的部分
ELLMTag::ProgramSize(Default Tracker):157.18
ELLMTag::ProgramSizePlatform(Platform Tracker):157.18

Graphics  // 显存
(Default Tracker): 无
ELLMTag::GraphicsPlatform(Platform Tracker): 115.27

GenericPlatformMallocCrash // 预分配的 crash 相关的内存,当 crash 发生时用来替换GMalloc
ELLMTag::GenericPlatformMallocCrash(Default Tracker):3.61
ELLMTag::GenericPlatformMallocCrashPlatform(Platform Tracker):3.61

OSAvailable // 系统当前可用的物理内存
(Default Tracker): 无
ELLMTag::PlatformOSAvailable(Platform Tracker): 3388.55

OOMBackupPool  // Out of memory 备用内存池
ELLMTag::BackupOOMMemoryPool(Default Tracker):未统计
ELLMTag::BackupOOMMemoryPoolPlatform(Platform Tracker): 未统计

Default Tracker详细的统计项
ELLMTag::EngineMisc 3.78 // 在以下函数执行过程中分配的内存
AActor::ProcessEvent
UPackageMapClient::SerializeNewActor
FEngineLoop::Tick

ELLMTag::TaskGraphTasksMisc 0 // FTaskThreadAnyThread::ProcessTasks 函数执行过程中分配的内存

Audio  9.52 // 音频相关的内存,包括音频资源,音频线程中分配的内存,具体还包含以下子类别
ELLMTag::AudioMisc   0.02
ELLMTag::AudioSoundWaves
ELLMTag::AudioMixer   9.52
ELLMTag::AudioPrecache
ELLMTag::AudioDecompress
ELLMTag::AudioRealtimePrecache
ELLMTag::AudioFullDecompress
ELLMTag::AudioVoiceChat

ELLMTag::FName 7.12 // FName占用的内存
ELLMTag::Networking // 网络相关的内存,包含网络包处理,连接对象内存等

ELLMTag::Meshes 31.85 // Mesh 的顶点缓存,顶点索引缓存占用的内存,还有以下子类别    注:包括VertexBuffer相关在cpu这边的内存+估算的gpu内存
ELLMTag::StaticMesh 8.79 // StaticMesh 相关的内存,包含 StaticMesh 资源,StaticMeshComponent
ELLMTag::SkeletalMesh 12.33 // SkeletalMeshComponent, SkinnedMeshComponent, SkeletalMesh内存
ELLMTag::InstancedMesh 0.13 // InstancedStaticMeshComponent, HierarchicalInstancedStaticMeshComponent内存

ELLMTag::Landscape // LandscapeComponent, LandscapeProxy, LandscapeComponentSceneProxy内存
ELLMTag::Stats 21.65 // stat 统计相关的内存占用
ELLMTag::Shaders 19.11 // 各种类型 Shander 的内存占用
ELLMTag::PSO 0.15 // Pipeline State Object 缓存的内存占用
ELLMTag::Textures 67.28 // 纹理相关的内存占用   注:包括texture相关在cpu这边的内存+估算的gpu内存
ELLMTag::TextureMetaData 0.65 // UTexture2D::Serialize 函数执行过程中分配的内存
ELLMTag::RenderTargets 40.85 // RT 相关的内存,包含在 Viewport 中渲染使用的内存
ELLMTag::SceneRender 34.72 // 场景渲染相关的内存占用,包含 Slate RHI Render 的窗口渲染
ELLMTag::RHIMisc 0.8 // 其它渲染相关的内存占用,如各种渲染状态,RHI Thread 运行过程中的内存
ELLMTag::AsyncLoading 3.08 // 异步资源加载过程中的内存占用,包含 AsyncLoadingThread, Event Driven Loader
ELLMTag::UObject 105.19 // UObject 占用的内存,包含 UClass 等
ELLMTag::Animation 13.38 // 动画相关的内存,包含 AnimInstance, AnimSequence, AnimationAsset, AnimBlueprint, MorphTarget
ELLMTag::Materials 0.54 // 材质相关的内存,包含 MaterialInterface, MaterialFunction
ELLMTag::Particles 0.78 // 特效相关的内存,包含 ParticleSystemComponent

ELLMTag::GC 0.62 // GC 过程中的内存,分别为以下两个函数
CollectGarbageInternal
PerformReachabilityAnalysis

ELLMTag::UI 42.7 // Slate 相关的内存,包含字体,TextureAtlas  注:TextureAltas为slate内部的altas,不是TEXTGROUP为UI的贴图
ELLMTag::PhysX // PhysX 物理相关的内存
ELLMTag::EnginePreInitMemory 18.71 // FEngineLoop::PreInit 函数执行过程中的内存
ELLMTag::EngineInitMemory 0.9 // FEngineLoop::Init 函数执行过程中的内存
ELLMTag::RenderingThreadMemory 6.21 // 渲染线程(RenderingThreadMain)执行过程中的内存

ELLMTag::LoadMapMisc 5.05   // 地图加载过程中的内存,分别为以下两个函数
UEngine::LoadMap
UWorld::UpdateLevelStreaming

ELLMTag::StreamingManager 0.44 // StreamableManager 相关的内存,主要是资源 streaming 函数执行过程中的内存

ELLMTag::FileSystem 13.72 // 文件系统相关的内存,主要是文件读取时的缓冲区,比如Pak 文件
ELLMTag::Localization 36.59 // 本地化相关的内存
ELLMTag::AssetRegistry 0.13 // AssetRegistryModule 内存
ELLMTag::ConfigSystem 2.8 // 配置文件相关的内存
ELLMTag::InitUObject 12.84 // InitUObject函数执行过程中的内存
ELLMTag::MaterialInstance 0.31 // MaterialInstance, MaterialInstanceDynamic包括材质参数内存占用
ELLMTag::Lua 28.88 // Lua 内存

Windows下特有统计项

ELLMTag::WorkingSetSize  // 进程物理内存,可用这个值替代上面的PlatformTotal
ELLMTag::PagefileUsed  // 进程虚拟内存

ThreadStack  // Windows 线程栈内存
ELLMTag::ThreadStack(Platform Tracker)
ELLMTag::ThreadStackPlatform(Default Tracker)

IOS下特有统计项

Metal Buffers

ELLMTagMetal::Buffers(Platform Tracker)  17.30

ELLMTagMetal::Buffers(Default Tracker)  0.12

Metal Textures

ELLMTagMetal::Textures(Platform Tracker)87.24

ELLMTagMetal::Textures(Default Tracker)0.1

Metal RenderTargets

ELLMTagMetal::RenderTargets(Platform Tracker)156.70

MMIO

ELLMTag::PlatformMMIO(Platform Tracker,mmap / munmap文件映射)12.22

 

llm stat控制台命令

stat llm   // 显示 Default Tracker 分组的简要内存统计信息

 

stat llmfull  // 显示 Default Tracker 分组的所有内存统计信息

注1:默认一个Group最多显示的行数为25,可通过执行控制台变量stats.MaxPerGroup xx来指定新的最大行数为xx

注2:为了能查看显示不下的内容,自定义开发了stat scroll控制台命令

stat scroll 1 // 向下滚动1行
stat scroll -1 // 向上滚动1行
stat scroll 999 // 滚动到底部
stat scroll -999 // 滚动到顶部
stat scroll restore //恢复初始

 

 Stat LLMPlatform   // 显示 Platform Tracker 分组的内存统计信息

 

Stat LLMOverhead  // 显示 LLM 本身使用的内存信息

 

新增统计项标签

可以通过以下方式新增一个ELLMTag::ANR的统计项标签

/*** UnrealEngine\Engine\Source\Runtime\Core\Public\HAL\LowLevelMemTracker.h ***/
#define LLM_ENUM_GENERIC_TAGS(macro) \
    //   枚举名                                  用于显示的名称                   显示在stat llmfull命令的输出结果中                            显示在stat llm命令的输出结果中                  父llm类别
    macro(Untagged,                                "Untagged",                        NAME_None,                                                    NAME_None,                                        -1)\ //0
    macro(Paused,                                "Paused",                        NAME_None,                                                    NAME_None,                                        -1)\ //1
    macro(Total,                                "Total",                        GET_STATFNAME(STAT_TotalLLM),                                GET_STATFNAME(STAT_TrackedTotalSummaryLLM),        -1)\ //2
    macro(Untracked,                            "Untracked",                    GET_STATFNAME(STAT_UntrackedLLM),                            GET_STATFNAME(STAT_TrackedTotalSummaryLLM),        -1)\ //3
    macro(PlatformTotal,                        "Total",                        GET_STATFNAME(STAT_PlatformTotalLLM),                        NAME_None,                                        -1)\ //4
    macro(TrackedTotal,                            "TrackedTotal",                    GET_STATFNAME(STAT_TrackedTotalLLM),                        GET_STATFNAME(STAT_TrackedTotalSummaryLLM),        -1)\ //5
    macro(UntaggedTotal,                        "Untagged",                        GET_STATFNAME(STAT_UntaggedTotalLLM),                        NAME_None,                                        -1)\ //6
    macro(WorkingSetSize,                        "WorkingSetSize",                GET_STATFNAME(STAT_WorkingSetSizeLLM),                        GET_STATFNAME(STAT_TrackedTotalSummaryLLM),        -1)\ //7
    macro(PagefileUsed,                            "PagefileUsed",                    GET_STATFNAME(STAT_PagefileUsedLLM),                        GET_STATFNAME(STAT_TrackedTotalSummaryLLM),        -1)\ //8
    macro(PlatformTrackedTotal,                    "TrackedTotal",                    GET_STATFNAME(STAT_PlatformTrackedTotalLLM),                NAME_None,                                        -1)\ //9
    macro(PlatformUntaggedTotal,                "Untagged",                        GET_STATFNAME(STAT_PlatformUntaggedTotalLLM),                NAME_None,                                        -1)\ //10
    macro(PlatformUntracked,                    "Untracked",                    GET_STATFNAME(STAT_PlatformUntrackedLLM),                    NAME_None,                                        -1)\ //11
    macro(PlatformOverhead,                        "LLMOverhead",                    GET_STATFNAME(STAT_PlatformOverheadLLM),                    NAME_None,                                        -1)\ //12
    macro(PlatformOSAvailable,                    "OSAvailable",                    GET_STATFNAME(STAT_PlatformOSAvailableLLM),                    NAME_None,                                        -1)\ //13
    macro(FMalloc,                                "FMalloc",                        GET_STATFNAME(STAT_FMallocLLM),                                NAME_None,                                        -1)\ //14
    macro(FMallocUnused,                        "FMallocUnused",                GET_STATFNAME(STAT_FMallocUnusedLLM),                        GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //15
    macro(ThreadStack,                            "ThreadStack",                    GET_STATFNAME(STAT_ThreadStackLLM),                            GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //16
    macro(ThreadStackPlatform,                    "ThreadStack",                    GET_STATFNAME(STAT_ThreadStackPlatformLLM),                    NAME_None,                                        -1)\ //17
    macro(ProgramSizePlatform,                    "ProgramSize",                    GET_STATFNAME(STAT_ProgramSizePlatformLLM),                    NAME_None,                                        -1)\ //18
    macro(ProgramSize,                            "ProgramSize",                    GET_STATFNAME(STAT_ProgramSizeLLM),                            GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //19
    macro(BackupOOMMemoryPoolPlatform,            "OOMBackupPool",                GET_STATFNAME(STAT_OOMBackupPoolPlatformLLM),                NAME_None,                                        -1)\ //20
    macro(BackupOOMMemoryPool,                    "OOMBackupPool",                GET_STATFNAME(STAT_OOMBackupPoolLLM),                        GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //21
    macro(GenericPlatformMallocCrash,            "GenericPlatformMallocCrash",    GET_STATFNAME(STAT_GenericPlatformMallocCrashLLM),            GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //22
    macro(GenericPlatformMallocCrashPlatform,    "GenericPlatformMallocCrash",    GET_STATFNAME(STAT_GenericPlatformMallocCrashPlatformLLM),    GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //23
    macro(EngineMisc,                            "EngineMisc",                    GET_STATFNAME(STAT_EngineMiscLLM),                            GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //24
    macro(TaskGraphTasksMisc,                    "TaskGraphMiscTasks",            GET_STATFNAME(STAT_TaskGraphTasksMiscLLM),                    GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //25
    macro(Audio,                                "Audio",                        GET_STATFNAME(STAT_AudioLLM),                                GET_STATFNAME(STAT_AudioSummaryLLM),            -1)\ //26
    macro(AudioMisc,                            "AudioMisc",                    GET_STATFNAME(STAT_AudioMiscLLM),                            GET_STATFNAME(STAT_AudioSummaryLLM),            ELLMTag::Audio)\ //27
    macro(AudioSoundWaves,                        "AudioSoundWaves",                GET_STATFNAME(STAT_AudioSoundWavesLLM),                        GET_STATFNAME(STAT_AudioSummaryLLM),            ELLMTag::Audio)\ //28
    macro(AudioMixer,                            "AudioMixer",                    GET_STATFNAME(STAT_AudioMixerLLM),                            GET_STATFNAME(STAT_AudioSummaryLLM),            ELLMTag::Audio)\ //29
    macro(AudioMixerPlugins,                    "AudioMixerPlugins",            GET_STATFNAME(STAT_AudioMixerPluginsLLM),                    GET_STATFNAME(STAT_AudioSummaryLLM),            ELLMTag::Audio)\ //30
    macro(AudioPrecache,                        "AudioPrecache",                GET_STATFNAME(STAT_AudioPrecacheLLM),                        GET_STATFNAME(STAT_AudioSummaryLLM),            ELLMTag::Audio)\ //31
    macro(AudioDecompress,                        "AudioDecompress",                GET_STATFNAME(STAT_AudioDecompressLLM),                        GET_STATFNAME(STAT_AudioSummaryLLM),            ELLMTag::Audio)\ //32
    macro(AudioRealtimePrecache,                "AudioRealtimePrecache",        GET_STATFNAME(STAT_AudioRealtimePrecacheLLM),                GET_STATFNAME(STAT_AudioSummaryLLM),            ELLMTag::Audio)\ //33
    macro(AudioFullDecompress,                    "AudioFullDecompress",            GET_STATFNAME(STAT_AudioFullDecompressLLM),                    GET_STATFNAME(STAT_AudioSummaryLLM),            ELLMTag::Audio)\ //34
    macro(AudioVoiceChat,                        "AudioVoiceChat",                GET_STATFNAME(STAT_AudioVoiceChatLLM),                        GET_STATFNAME(STAT_AudioSummaryLLM),            ELLMTag::Audio)\ //35
    macro(AudioStreamCache,                        "AudioStreamCache",                GET_STATFNAME(STAT_AudioStreamCacheLLM),                    GET_STATFNAME(STAT_AudioSummaryLLM),            ELLMTag::Audio)\ //36
    macro(AudioStreamCacheCompressedData,        "AudioStreamCacheCompressedData",GET_STATFNAME(STAT_AudioStreamCacheCompressedDataLLM),        GET_STATFNAME(STAT_AudioSummaryLLM),            ELLMTag::Audio)\ //37
    macro(AudioSynthesis,                        "AudioSynthesis",                GET_STATFNAME(STAT_AudioSynthesisLLM),                        GET_STATFNAME(STAT_AudioSummaryLLM),            ELLMTag::Audio)\ //38
    macro(FName,                                "FName",                        GET_STATFNAME(STAT_FNameLLM),                                GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //39
    macro(Networking,                            "Networking",                    GET_STATFNAME(STAT_NetworkingLLM),                            GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //40
    macro(Meshes,                                "Meshes",                        GET_STATFNAME(STAT_MeshesLLM),                                GET_STATFNAME(STAT_MeshesSummaryLLM),            -1)\ //41
    macro(Stats,                                "Stats",                        GET_STATFNAME(STAT_StatsLLM),                                GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //42
    macro(Shaders,                                "Shaders",                        GET_STATFNAME(STAT_ShadersLLM),                                GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //43
    macro(PSO,                                    "PSO",                            GET_STATFNAME(STAT_PSOLLM),                                    GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //44
    macro(Textures,                                "Textures",                        GET_STATFNAME(STAT_TexturesLLM),                            GET_STATFNAME(STAT_TexturesSummaryLLM),            -1)\ //45 
    macro(TextureMetaData,                        "TextureMetaData",                GET_STATFNAME(STAT_TextureMetaDataLLM),                        GET_STATFNAME(STAT_TexturesSummaryLLM),            -1)\ //46
    macro(VirtualTextureSystem,                    "VirtualTextureSystem",            GET_STATFNAME(STAT_VirtualTextureSystemLLM),                GET_STATFNAME(STAT_TexturesSummaryLLM),            -1)\ //47
    macro(RenderTargets,                        "RenderTargets",                GET_STATFNAME(STAT_RenderTargetsLLM),                        GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //48
    macro(SceneRender,                            "SceneRender",                    GET_STATFNAME(STAT_SceneRenderLLM),                            GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //49
    macro(RHIMisc,                                "RHIMisc",                        GET_STATFNAME(STAT_RHIMiscLLM),                                GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //50
    macro(AsyncLoading,                            "AsyncLoading",                    GET_STATFNAME(STAT_AsyncLoadingLLM),                        GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //51
    macro(UObject,                                "UObject",                        GET_STATFNAME(STAT_UObjectLLM),                                GET_STATFNAME(STAT_UObjectSummaryLLM),            -1)\ //52
    macro(Animation,                            "Animation",                    GET_STATFNAME(STAT_AnimationLLM),                            GET_STATFNAME(STAT_AnimationSummaryLLM),        -1)\ //53
    macro(StaticMesh,                            "StaticMesh",                    GET_STATFNAME(STAT_StaticMeshLLM),                            GET_STATFNAME(STAT_StaticMeshSummaryLLM),        ELLMTag::Meshes)\ //54
    macro(Materials,                            "Materials",                    GET_STATFNAME(STAT_MaterialsLLM),                            GET_STATFNAME(STAT_MaterialsSummaryLLM),        -1)\ //55
    macro(Particles,                            "Particles",                    GET_STATFNAME(STAT_ParticlesLLM),                            GET_STATFNAME(STAT_ParticlesSummaryLLM),        -1)\ //56
    macro(Niagara,                                "Niagara",                        GET_STATFNAME(STAT_NiagaraLLM),                                GET_STATFNAME(STAT_NiagaraSummaryLLM),            -1)\ //57
    macro(GPUSort,                                "GPUSort",                        GET_STATFNAME(STAT_GPUSortLLM),                                GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //58
    macro(GC,                                    "GC",                            GET_STATFNAME(STAT_GCLLM),                                    GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //59
    macro(UI,                                    "UI",                            GET_STATFNAME(STAT_UILLM),                                    GET_STATFNAME(STAT_UISummaryLLM),                -1)\ //60
    macro(NavigationRecast,                        "NavigationRecast",                GET_STATFNAME(STAT_NavigationRecastLLM),                    GET_STATFNAME(STAT_NavigationSummaryLLM),        -1)\ //61
    macro(Physics,                                "Physics",                        GET_STATFNAME(STAT_PhysicsLLM),                                GET_STATFNAME(STAT_PhysicsSummaryLLM),            -1)\ //62
    macro(PhysX,                                "PhysX",                        GET_STATFNAME(STAT_PhysXLLM),                                GET_STATFNAME(STAT_PhysXSummaryLLM),            ELLMTag::Physics)\ //63
    macro(PhysXGeometry,                        "PhysXGeometry",                GET_STATFNAME(STAT_PhysXGeometryLLM),                        GET_STATFNAME(STAT_PhysXSummaryLLM),            ELLMTag::Physics)\ //64
    macro(PhysXTrimesh,                            "PhysXTrimesh",                    GET_STATFNAME(STAT_PhysXTrimeshLLM),                        GET_STATFNAME(STAT_PhysXSummaryLLM),            ELLMTag::Physics)\ //65
    macro(PhysXConvex,                            "PhysXConvex",                    GET_STATFNAME(STAT_PhysXConvexLLM),                            GET_STATFNAME(STAT_PhysXSummaryLLM),            ELLMTag::Physics)\ //66
    macro(PhysXAllocator,                        "PhysXAllocator",                GET_STATFNAME(STAT_PhysXAllocatorLLM),                        GET_STATFNAME(STAT_PhysXSummaryLLM),            ELLMTag::Physics)\ //67
    macro(PhysXLandscape,                        "PhysXLandscape",                GET_STATFNAME(STAT_PhysXLandscapeLLM),                        GET_STATFNAME(STAT_PhysXSummaryLLM),            ELLMTag::Physics)\ //68
    macro(Chaos,                                "Chaos",                        GET_STATFNAME(STAT_ChaosLLM),                                GET_STATFNAME(STAT_ChaosSummaryLLM),            ELLMTag::Physics)\ //69
    macro(ChaosGeometry,                        "ChaosGeometry",                GET_STATFNAME(STAT_ChaosGeometryLLM),                        GET_STATFNAME(STAT_ChaosSummaryLLM),            ELLMTag::Physics)\ //70
    macro(ChaosAcceleration,                    "ChaosAcceleration",            GET_STATFNAME(STAT_ChaosAccelerationLLM),                    GET_STATFNAME(STAT_ChaosSummaryLLM),            ELLMTag::Physics)\ //71
    macro(ChaosParticles,                        "ChaosParticles",                GET_STATFNAME(STAT_ChaosParticlesLLM),                        GET_STATFNAME(STAT_ChaosSummaryLLM),            ELLMTag::Physics)\ //72
    macro(ChaosLandscape,                        "ChaosLandscape",                GET_STATFNAME(STAT_ChaosLandscapeLLM),                        GET_STATFNAME(STAT_ChaosSummaryLLM),            ELLMTag::Physics)\ //73
    macro(ChaosTrimesh,                            "ChaosTrimesh",                    GET_STATFNAME(STAT_ChaosTrimeshLLM),                        GET_STATFNAME(STAT_ChaosSummaryLLM),            ELLMTag::Physics)\ //74
    macro(ChaosConvex,                            "ChaosConvex",                    GET_STATFNAME(STAT_ChaosConvexLLM),                            GET_STATFNAME(STAT_ChaosSummaryLLM),            ELLMTag::Physics)\ //75
    macro(EnginePreInitMemory,                    "EnginePreInit",                GET_STATFNAME(STAT_EnginePreInitLLM),                        GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //76
    macro(EngineInitMemory,                        "EngineInit",                    GET_STATFNAME(STAT_EngineInitLLM),                            GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //77
    macro(RenderingThreadMemory,                "RenderingThread",                GET_STATFNAME(STAT_RenderingThreadLLM),                        GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //78
    macro(LoadMapMisc,                            "LoadMapMisc",                    GET_STATFNAME(STAT_LoadMapMiscLLM),                            GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //79
    macro(StreamingManager,                        "StreamingManager",                GET_STATFNAME(STAT_StreamingManagerLLM),                    GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //80
    macro(GraphicsPlatform,                        "Graphics",                        GET_STATFNAME(STAT_GraphicsPlatformLLM),                    NAME_None,                                        -1)\ //81
    macro(FileSystem,                            "FileSystem",                    GET_STATFNAME(STAT_FileSystemLLM),                            GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //82
    macro(Localization,                            "Localization",                    GET_STATFNAME(STAT_LocalizationLLM),                        GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //83
    macro(AssetRegistry,                        "AssetRegistry",                GET_STATFNAME(STAT_AssetRegistryLLM),                        GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //84
    macro(ConfigSystem,                            "ConfigSystem",                    GET_STATFNAME(STAT_ConfigSystemLLM),                        GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //85
    macro(InitUObject,                            "InitUObject",                    GET_STATFNAME(STAT_InitUObjectLLM),                            GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //86
    macro(VideoRecording,                        "VideoRecording",                GET_STATFNAME(STAT_VideoRecordingLLM),                        GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //87
    macro(Replays,                                "Replays",                        GET_STATFNAME(STAT_ReplaysLLM),                                GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //88
    macro(MaterialInstance,                        "MaterialInstance",                GET_STATFNAME(STAT_MaterialInstanceLLM),                    GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ //89
    macro(SkeletalMesh,                            "SkeletalMesh",                    GET_STATFNAME(STAT_SkeletalMeshLLM),                        GET_STATFNAME(STAT_EngineSummaryLLM),            ELLMTag::Meshes)\ //90
    macro(InstancedMesh,                        "InstancedMesh",                GET_STATFNAME(STAT_InstancedMeshLLM),                        GET_STATFNAME(STAT_EngineSummaryLLM),            ELLMTag::Meshes)\ //91
    macro(Landscape,                            "Landscape",                    GET_STATFNAME(STAT_LandscapeLLM),                            GET_STATFNAME(STAT_EngineSummaryLLM),            ELLMTag::Meshes)\ //92
    macro(CsvProfiler,                            "CsvProfiler",                    GET_STATFNAME(STAT_CsvProfilerLLM),                            GET_STATFNAME(STAT_EngineSummaryLLM),            -1)\ // 93
    macro(MediaStreaming,                        "MediaStreaming",                GET_STATFNAME(STAT_MediaStreamingLLM),                        GET_STATFNAME(STAT_MediaStreamingSummaryLLM),    -1)\ // 94
    macro(ElectraPlayer,                        "ElectraPlayer",                GET_STATFNAME(STAT_ElectraPlayerLLM),                        GET_STATFNAME(STAT_MediaStreamingSummaryLLM),    ELLMTag::MediaStreaming)\ // 95
    macro(WMFPlayer,                            "WMFPlayer",                    GET_STATFNAME(STAT_WMFPlayerLLM),                            GET_STATFNAME(STAT_MediaStreamingSummaryLLM),    ELLMTag::MediaStreaming)\ // 96
    macro(PlatformMMIO,                            "MMIO",                            GET_STATFNAME(STAT_PlatformMMIOLLM),                        NAME_None,                                        -1)\ // 97
    macro(PlatformVM,                            "Virtual Memory",                GET_STATFNAME(STAT_PlatformVMLLM),                            NAME_None,                                        -1)\ // 98
    macro(Lua,                                    "Lua",                            GET_STATFNAME(STAT_LuaLLM),                                    GET_STATFNAME(STAT_LuaSummaryLLM),                -1)\  // 99
    macro(Font,                                    "Font",                            GET_STATFNAME(STAT_FontLLM),                                NAME_None,                                        ELLMTag::UI)\ // 100
    macro(Wwise,                                "Wwise",                        GET_STATFNAME(STAT_WwiseLLM),                                NAME_None,                                        -1)\ // 101
    macro(GCloud,                                "GCloud",                        GET_STATFNAME(STAT_GCloudLLM),                                NAME_None,                                        -1)\ // 102
    macro(MergeTexture,                            "MergeTexture",                    GET_STATFNAME(STAT_MergeTextureLLM),                        GET_STATFNAME(STAT_TexturesSummaryLLM),            ELLMTag::Textures)\ // 103
    macro(SlateGenerateByClass,                    "SlateGenerateByClass",            GET_STATFNAME(STAT_SlateGenerateByClassLLM),                NAME_None,                                        ELLMTag::UI)\ // 104
    /* 自定义一个llm分类标签 */
    macro(ANR,                                    "Application Not Respond",        GET_STATFNAME(STAT_ANRLLM),                                    GET_STATFNAME(STAT_ANRSummaryLLM),                -1)\ // 105
    macro(MemoryTestType,                         "MemoryTestType",                 NAME_None,                                                     NAME_None,                                       -1)\

    macro(MemoryTestSubType,                      "MemoryTestSubType",              NAME_None,                                                     NAME_None,                                ELLMTag::MemoryTestType)\

/*** UnrealEngine\Engine\Source\Runtime\Core\Private\HAL\LowLevelMemTracker.cpp ***/

DECLARE_LLM_MEMORY_STAT(TEXT("ANR"), STAT_ANRLLM, STATGROUP_LLMFULL); // ANR显示在stat llmfull的统计中  注:这个STAT分类定义不是必须的

DECLARE_LLM_MEMORY_STAT(TEXT("ANR"), STAT_ANRSummaryLLM, STATGROUP_LLM);  // ANR显示在stat llm的统计中   注:这个STAT分类定义不是必须的


/*** 统计 LLMPlatform_Pid100956_2022.03.28-17.52.11.csv ***/
{
    LLM_PLATFORM_SCOPE(ELLMTag::ANR);

    // Do Something
}

/*** LLM_Pid100956_2022.03.28-17.52.11.csv ***/
{
    LLM_SCOPE(ELLMTag::ANR);

    // Do Something
}

 

嵌套统计

LLM_SCOPE(ELLMTag::ANR);  // 统计ANR作用域范围内的独占内存(Exclusive):2MB + 5 MB = 7MB
int8* p1 = new int8[2*1024*1024]; // 2MB

{
    LLM_SCOPE(ELLMTag::MemoryTestType); // 统计MemoryTestType作用域范围内的独占内存(Exclusive):3MB
    int8* p2 = new int8[3*1024*1024]; // 3MB
}

int8* p3 = new int8[5 * 1024 * 1024]; // 5MB

 

子分类统计:上面的示例代码中,MemoryTestSubTypeMemoryTestType的子分类,当执行LLM_SCOPE(ELLMTag::MemoryTestSubType)统计时,ELLMTag::MemoryTestType会自动进行统计累加。

 

如果要将ANR的统计写入csv文件,需要在开始写csv文件之前,触发LLM_SCOPE(ELLMTag::ANR)一次,且在其作用域内触发堆内存分配。

/*** LLM_Pid100956_2022.03.28-17.52.11.csv ***/
{
    LLM_SCOPE(ELLMTag::ANR);

    TUniquePtr<int32> up1(new int32(5)); // 内部会触发堆内存分配
    
    // Do Something
}

 

LLM_SCOPE(InheritedLLMTag)

使用当前ActiveTag来统计。在AsyncWork.h、TaskGraphInterfaces.h中有使用到该动态Tag。

以TaskGraphInterfaces为例,具体实现方式是在构造Task任务时,获取当前ActiveTag来动态设置InheritedLLMTag的值

FBaseGraphTask(int32 InNumberOfPrerequistitesOutstanding)
    : ThreadToExecuteOn(ENamedThreads::AnyThread)
    , NumberOfPrerequistitesOutstanding(InNumberOfPrerequistitesOutstanding + 1) // + 1 is not a prerequisite, it is a lock to prevent it from executing while it is getting prerequisites, one it is safe to execute, call PrerequisitesComplete
{
    checkThreadGraph(LifeStage.Increment() == int32(LS_Contructed));
    LLM(InheritedLLMTag = FLowLevelMemTracker::bIsDisabled ? ELLMTag::Untagged : (ELLMTag)FLowLevelMemTracker::Get().GetActiveTag(ELLMTracker::Default));
}

设置后,就可以在相应逻辑中使用该Tag进行内存统计

 

放置LLM_SCOPE的函数如果发生了内联,统计分类将放到调用处的函数中

UnrealEngine\Engine\Source\Runtime\Core\Public\Async\TaskGraphInterfaces.h文件中的FBaseGraphTask.Execute函数

FORCEINLINE void Execute(TArray<FBaseGraphTask*>& NewTasks, ENamedThreads::Type CurrentThread)
{
    LLM_SCOPE(InheritedLLMTag);
    checkThreadGraph(LifeStage.Increment() == int32(LS_Executing));
    ExecuteTask(NewTasks, CurrentThread);
}

 

导致在非Debug包下,在堆栈中看不到这个函数名:

0x000000748C7CB524 libUE4.so(0x0000000014747524)!FLLMScope::FLLMScope(ELLMTag, ELLMTagSet, ELLMTracker)  []
0x000000748C6EBECC libUE4.so(0x0000000014667ECC)!FNamedTaskThread::ProcessTasksNamedThread(int, bool)  []  // FBaseGraphTask.Execute函数被inline到了FNamedTaskThread::ProcessTasksNamedThread函数中了
0x000000748C6E8DFC libUE4.so(0x0000000014664DFC)!FNamedTaskThread::ProcessTasksUntilQuit(int)  []
0x000000748DF66740 libUE4.so(0x0000000015EE2740)!FRHIThread::Run()  []
0x000000748C81D65C libUE4.so(0x000000001479965C)!FRunnableThreadPThread::Run()  []
0x000000748C6E2940 libUE4.so(0x000000001465E940)!FRunnableThreadPThread::_ThreadProc(void*)  []
0x000000759D609868 libc.so(0x00000000000EB868)![Unknown]()  []
0x000000759D5A9A88 libc.so(0x000000000008BA88)![Unknown]()  []

在Debug包中,则能看到FBaseGraphTask.Execute函数的栈帧:

 

引擎写csv文件的时机

 

打印某类tag的内存分配Stack

如下:在FLLMTracker::TrackAllocation函数中,打印DefaultTriacker所有Untaged标签的线程栈到log文件

static bool GIsStackDumping = false; // 防止在Dump的过程中,分配内存被TrackAllocation,造成死循环
void FLLMTracker::TrackAllocation(const void* Ptr, uint64 Size, ELLMTag DefaultTag, ELLMTracker Tracker, ELLMAllocType AllocType, bool bTrackInMemPro)
{
    if (IsPaused(AllocType))
    {
        return;
    }

    // track the total quickly
    FPlatformAtomics::InterlockedAdd(&TrackedMemoryOverFrames, (int64)Size);
    
    FLLMThreadState* State = GetOrCreateState();
    
    // track on the thread state, and get the tag
    State->TrackAllocation(Ptr, Size, DefaultTag, Tracker, AllocType, bTrackInMemPro);

    // tracking a nullptr with a Size is allowed, but we don't need to remember it, since we can't free it ever
    if (Ptr != nullptr)
    {
        // remember the size and tag info
        int64 Tag = State->GetTopTag();
        if (Tag == (int64)ELLMTag::Untagged)
        {
            Tag = (int64)DefaultTag;
        }
        
        // 打印DefaultTriacker所有Untaged标签的线程栈到log文件
        if (Tag == (int64)ELLMTag::Untagged && Tracker == ELLMTracker::Default)
        {
#if PLATFORM_ANDROID
            static bool bDumpStack = (access("/storage/emulated/0/UE4Game/dumpstack.txt", 0) == 0);
#elif PLATFORM_IOS
            NSString* DocumentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
            NSString* FlagFilePath = [DocumentsPath stringByAppendingPathComponent : @"/dumpstack.txt"];
            static bool bDumpStack = (access([FlagFilePath UTF8String], 0) == 0);
#else
            static bool bDumpStack = false;
#endif
            if (bDumpStack && !GIsStackDumping)
            {
                GIsStackDumping = true;
                UE_LOG(LogTemp, Display, TEXT("Track Size: %lld"), Size);        
                FDebug::DumpStackTraceToLog(ELogVerbosity::Display);
                GIsStackDumping = false;
            }
        }

        FLLMTracker::FLowLevelAllocInfo AllocInfo;
        #if LLM_USE_ALLOC_INFO_STRUCT
        AllocInfo.Tag = Tag;
            #if LLM_ALLOW_ASSETS_TAGS
        AllocInfo.AssetTag = State->GetTopAssetTag();
            #endif
        #else
        LLMCheck(Tag >= 0 && Tag < (int64)LLM_TAG_COUNT);
        AllocInfo = (ELLMTag)Tag;
        #endif

        LLMCheck(Size <= 0xffffffffu);
        GetAllocationMap().Add(Ptr, (uint32)Size, AllocInfo);
    }
}

 

参考

UE4 Low Level Memory Tracker 使用(知乎)

UE4 Low Level Memory Tracker 使用

 

posted on 2021-06-16 22:07  可可西  阅读(5657)  评论(0编辑  收藏  举报

导航