From 9dc4dbc6d775aceb8e1971e4f6e03c9aed26bbba Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 25 May 2025 18:38:07 +0200 Subject: [PATCH] Add more memory profiler categories --- Source/Engine/Content/Assets/VisualScript.cpp | 15 +++++ Source/Engine/Core/Memory/Allocation.cpp | 7 +++ Source/Engine/Graphics/GPUBuffer.cpp | 20 ++++++- .../Engine/Graphics/Textures/GPUTexture.cpp | 24 +++++++- Source/Engine/Profiler/ProfilerMemory.cpp | 55 ++++++++----------- Source/Engine/Profiler/ProfilerMemory.h | 29 +++++++++- 6 files changed, 112 insertions(+), 38 deletions(-) diff --git a/Source/Engine/Content/Assets/VisualScript.cpp b/Source/Engine/Content/Assets/VisualScript.cpp index a6d83919c..2e6ffb735 100644 --- a/Source/Engine/Content/Assets/VisualScript.cpp +++ b/Source/Engine/Content/Assets/VisualScript.cpp @@ -18,6 +18,7 @@ #include "Engine/Serialization/Serialization.h" #include "Engine/Serialization/JsonWriter.h" #include "Engine/Profiler/ProfilerCPU.h" +#include "Engine/Profiler/ProfilerMemory.h" #include "Engine/Utilities/StringConverter.h" #include "Engine/Threading/MainThreadTask.h" #include "Engine/Level/SceneObject.h" @@ -1340,6 +1341,8 @@ bool VisualScript::Save(const StringView& path) Asset::LoadResult VisualScript::load() { + PROFILE_MEM(ScriptingVisual); + // Build Visual Script typename that is based on asset id String typeName = _id.ToString(); StringUtils::ConvertUTF162ANSI(typeName.Get(), _typenameChars, 32); @@ -1532,6 +1535,7 @@ Asset::LoadResult VisualScript::load() void VisualScript::unload(bool isReloading) { + PROFILE_MEM(ScriptingVisual); #if USE_EDITOR if (isReloading) { @@ -1588,6 +1592,7 @@ AssetChunksFlag VisualScript::getChunksToPreload() const void VisualScript::CacheScriptingType() { + PROFILE_MEM(ScriptingVisual); ScopeLock lock(VisualScriptingBinaryModule::Locker); auto& binaryModule = VisualScriptingModule; @@ -1723,6 +1728,7 @@ ScriptingObject* VisualScriptingBinaryModule::VisualScriptObjectSpawn(const Scri VisualScript* visualScript = VisualScriptingModule.Scripts[params.Type.TypeIndex]; // Initialize instance data + PROFILE_MEM(ScriptingVisual); ScopeLock lock(visualScript->Locker); auto& instanceParams = visualScript->_instances[object->GetID()].Params; instanceParams.Resize(visualScript->Graph.Parameters.Count()); @@ -1747,6 +1753,8 @@ ScriptingObject* VisualScriptingBinaryModule::VisualScriptObjectSpawn(const Scri void VisualScriptingBinaryModule::OnScriptsReloading() { + PROFILE_MEM(ScriptingVisual); + // Clear any cached types from that module across all loaded Visual Scripts for (auto& script : Scripts) { @@ -1795,6 +1803,7 @@ void VisualScriptingBinaryModule::OnScriptsReloading() void VisualScriptingBinaryModule::OnEvent(ScriptingObject* object, Span parameters, ScriptingTypeHandle eventType, StringView eventName) { + PROFILE_MEM(ScriptingVisual); if (object) { // Object event @@ -1956,6 +1965,7 @@ bool VisualScriptingBinaryModule::GetFieldValue(void* field, const Variant& inst bool VisualScriptingBinaryModule::SetFieldValue(void* field, const Variant& instance, Variant& value) { + PROFILE_MEM(ScriptingVisual); const auto vsFiled = (VisualScript::Field*)field; const auto instanceObject = (ScriptingObject*)instance; if (!instanceObject) @@ -2042,6 +2052,7 @@ void VisualScriptingBinaryModule::SerializeObject(JsonWriter& stream, ScriptingO void VisualScriptingBinaryModule::DeserializeObject(ISerializable::DeserializeStream& stream, ScriptingObject* object, ISerializeModifier* modifier) { + PROFILE_MEM(ScriptingVisual); ASSERT(stream.IsObject()); Locker.Lock(); const auto asset = Scripts[object->GetTypeHandle().TypeIndex].Get(); @@ -2165,6 +2176,7 @@ const Variant& VisualScript::GetScriptInstanceParameterValue(const StringView& n void VisualScript::SetScriptInstanceParameterValue(const StringView& name, ScriptingObject* instance, const Variant& value) { + PROFILE_MEM(ScriptingVisual); CHECK(instance); for (int32 paramIndex = 0; paramIndex < Graph.Parameters.Count(); paramIndex++) { @@ -2186,6 +2198,7 @@ void VisualScript::SetScriptInstanceParameterValue(const StringView& name, Scrip void VisualScript::SetScriptInstanceParameterValue(const StringView& name, ScriptingObject* instance, Variant&& value) { + PROFILE_MEM(ScriptingVisual); CHECK(instance); for (int32 paramIndex = 0; paramIndex < Graph.Parameters.Count(); paramIndex++) { @@ -2383,6 +2396,7 @@ VisualScriptingBinaryModule* VisualScripting::GetBinaryModule() Variant VisualScripting::Invoke(VisualScript::Method* method, ScriptingObject* instance, Span parameters) { + PROFILE_MEM(ScriptingVisual); CHECK_RETURN(method && method->Script->IsLoaded(), Variant::Zero); PROFILE_CPU_SRC_LOC(method->ProfilerData); @@ -2423,6 +2437,7 @@ bool VisualScripting::Evaluate(VisualScript* script, ScriptingObject* instance, const auto box = node->GetBox(boxId); if (!box) return false; + PROFILE_MEM(ScriptingVisual); // Add to the calling stack ScopeContext scope; diff --git a/Source/Engine/Core/Memory/Allocation.cpp b/Source/Engine/Core/Memory/Allocation.cpp index 59b3a8a7e..b2e74b8b6 100644 --- a/Source/Engine/Core/Memory/Allocation.cpp +++ b/Source/Engine/Core/Memory/Allocation.cpp @@ -2,6 +2,7 @@ #include "ArenaAllocation.h" #include "../Math/Math.h" +#include "Engine/Profiler/ProfilerMemory.h" void ArenaAllocator::Free() { @@ -9,6 +10,9 @@ void ArenaAllocator::Free() Page* page = _first; while (page) { +#if COMPILE_WITH_PROFILER + ProfilerMemory::OnGroupUpdate(ProfilerMemory::Groups::MallocArena, -page->Size, -1); +#endif Allocator::Free(page->Memory); Page* next = page->Next; Allocator::Free(page); @@ -30,6 +34,9 @@ void* ArenaAllocator::Allocate(uint64 size, uint64 alignment) if (!page) { uint64 pageSize = Math::Max(_pageSize, size); +#if COMPILE_WITH_PROFILER + ProfilerMemory::OnGroupUpdate(ProfilerMemory::Groups::MallocArena, pageSize, 1); +#endif page = (Page*)Allocator::Allocate(sizeof(Page)); page->Memory = Allocator::Allocate(pageSize); page->Next = _first; diff --git a/Source/Engine/Graphics/GPUBuffer.cpp b/Source/Engine/Graphics/GPUBuffer.cpp index db7845227..f8372572e 100644 --- a/Source/Engine/Graphics/GPUBuffer.cpp +++ b/Source/Engine/Graphics/GPUBuffer.cpp @@ -244,7 +244,15 @@ bool GPUBuffer::Init(const GPUBufferDescription& desc) LOG(Warning, "Cannot initialize buffer. Description: {0}", desc.ToString()); return true; } - PROFILE_MEM_INC(GraphicsBuffers, GetMemoryUsage()); + +#if COMPILE_WITH_PROFILER + auto group = ProfilerMemory::Groups::GraphicsBuffers; + if (EnumHasAnyFlags(_desc.Flags, GPUBufferFlags::VertexBuffer)) + group = ProfilerMemory::Groups::GraphicsVertexBuffers; + else if (EnumHasAnyFlags(_desc.Flags, GPUBufferFlags::IndexBuffer)) + group = ProfilerMemory::Groups::GraphicsIndexBuffers; + ProfilerMemory::IncrementGroup(group, _memoryUsage); +#endif return false; } @@ -480,7 +488,15 @@ GPUResourceType GPUBuffer::GetResourceType() const void GPUBuffer::OnReleaseGPU() { - PROFILE_MEM_DEC(GraphicsBuffers, GetMemoryUsage()); +#if COMPILE_WITH_PROFILER + auto group = ProfilerMemory::Groups::GraphicsBuffers; + if (EnumHasAnyFlags(_desc.Flags, GPUBufferFlags::VertexBuffer)) + group = ProfilerMemory::Groups::GraphicsVertexBuffers; + else if (EnumHasAnyFlags(_desc.Flags, GPUBufferFlags::IndexBuffer)) + group = ProfilerMemory::Groups::GraphicsIndexBuffers; + ProfilerMemory::IncrementGroup(group, _memoryUsage); +#endif + _desc.Clear(); _isLocked = false; } diff --git a/Source/Engine/Graphics/Textures/GPUTexture.cpp b/Source/Engine/Graphics/Textures/GPUTexture.cpp index 6d138a40c..245fb1e01 100644 --- a/Source/Engine/Graphics/Textures/GPUTexture.cpp +++ b/Source/Engine/Graphics/Textures/GPUTexture.cpp @@ -503,7 +503,17 @@ bool GPUTexture::Init(const GPUTextureDescription& desc) LOG(Warning, "Cannot initialize texture. Description: {0}", desc.ToString()); return true; } - PROFILE_MEM_INC(GraphicsTextures, GetMemoryUsage()); + +#if COMPILE_WITH_PROFILER + auto group = ProfilerMemory::Groups::GraphicsTextures; + if (_desc.IsRenderTarget()) + group = ProfilerMemory::Groups::GraphicsRenderTargets; + else if (_desc.IsCubeMap()) + group = ProfilerMemory::Groups::GraphicsCubeMaps; + else if (_desc.IsVolume()) + group = ProfilerMemory::Groups::GraphicsVolumeTextures; + ProfilerMemory::IncrementGroup(group, _memoryUsage); +#endif // Render targets and depth buffers doesn't support normal textures streaming and are considered to be always resident if (IsRegularTexture() == false) @@ -593,7 +603,17 @@ GPUResourceType GPUTexture::GetResourceType() const void GPUTexture::OnReleaseGPU() { - PROFILE_MEM_DEC(GraphicsTextures, GetMemoryUsage()); +#if COMPILE_WITH_PROFILER + auto group = ProfilerMemory::Groups::GraphicsTextures; + if (_desc.IsRenderTarget()) + group = ProfilerMemory::Groups::GraphicsRenderTargets; + else if (_desc.IsCubeMap()) + group = ProfilerMemory::Groups::GraphicsCubeMaps; + else if (_desc.IsVolume()) + group = ProfilerMemory::Groups::GraphicsVolumeTextures; + ProfilerMemory::DecrementGroup(group, _memoryUsage); +#endif + _desc.Clear(); _residentMipLevels = 0; } diff --git a/Source/Engine/Profiler/ProfilerMemory.cpp b/Source/Engine/Profiler/ProfilerMemory.cpp index adb244f26..f05ac5f64 100644 --- a/Source/Engine/Profiler/ProfilerMemory.cpp +++ b/Source/Engine/Profiler/ProfilerMemory.cpp @@ -25,14 +25,14 @@ struct GroupNameBuffer Char Buffer[30]; template - void Set(const T* str) + void Set(const T* str, bool autoFormat = false) { int32 max = StringUtils::Length(str), dst = 0; char prev = 0; for (int32 i = 0; i < max && dst < ARRAY_COUNT(Buffer) - 2; i++) { char cur = str[i]; - if (StringUtils::IsUpper(cur) && StringUtils::IsLower(prev)) + if (autoFormat && StringUtils::IsUpper(cur) && StringUtils::IsLower(prev)) Buffer[dst++] = '/'; Buffer[dst++] = cur; prev = cur; @@ -52,10 +52,6 @@ struct GroupStackData { if (Count < ARRAY_COUNT(Stack)) Count++; - else - { - int a= 10; - } Stack[Count - 1] = (uint8)group; } @@ -112,8 +108,15 @@ namespace for (int32 i = 0; i < GROUPS_COUNT; i++) { const char* name = ScriptingEnum::GetName((ProfilerMemory::Groups)i); - GroupNames[i].Set(name); + GroupNames[i].Set(name, true); } +#define RENAME_GROUP(group, name) GroupNames[(int32)ProfilerMemory::Groups::group].Set(name) + RENAME_GROUP(GraphicsRenderTargets, "Graphics/RenderTargets"); + RENAME_GROUP(GraphicsCubeMaps, "Graphics/CubeMaps"); + RENAME_GROUP(GraphicsVolumeTextures, "Graphics/VolumeTextures"); + RENAME_GROUP(GraphicsVertexBuffers, "Graphics/VertexBuffers"); + RENAME_GROUP(GraphicsIndexBuffers, "Graphics/IndexBuffers"); +#undef RENAME_GROUP // Init constant memory PROFILE_MEM_INC(ProgramSize, Platform::GetMemoryStats().ProgramSizeMemory); @@ -162,31 +165,6 @@ namespace output.AppendLine(); } -#if 0 - // Print count of memory allocs count per group - for (int32 i = 0; i < GROUPS_COUNT; i++) - { - GroupInfo& group = groups[i]; - group.Group = (ProfilerMemory::Groups)i; - group.Size = 0; - } - PointersLocker.Lock(); - for (auto& e : Pointers) - groups[e.Value.Group].Size++; - PointersLocker.Unlock(); - Sorting::QuickSort(groups, GROUPS_COUNT); - output.Append(TEXT("Memory allocations count summary:")).AppendLine(); - for (int32 i = 0; i < maxCount; i++) - { - const GroupInfo& group = groups[i]; - if (group.Size == 0) - break; - const Char* name = GroupName[(int32)group.Group].Buffer; - output.AppendFormat(TEXT("{:>30}: {:>11}"), name, group.Size); - output.AppendLine(); - } -#endif - // Warn that data might be missing due to inactive profiler if (!ProfilerMemory::Enabled) output.AppendLine(TEXT("Detailed memory profiling is disabled. Run with command line: -mem")); @@ -243,8 +221,14 @@ void InitProfilerMemory(const Char* cmdLine) // Init hierarchy #define INIT_PARENT(parent, child) GroupParents[(int32)ProfilerMemory::Groups::child] = (uint8)ProfilerMemory::Groups::parent + INIT_PARENT(Malloc, MallocArena); INIT_PARENT(Graphics, GraphicsTextures); + INIT_PARENT(Graphics, GraphicsRenderTargets); + INIT_PARENT(Graphics, GraphicsCubeMaps); + INIT_PARENT(Graphics, GraphicsVolumeTextures); INIT_PARENT(Graphics, GraphicsBuffers); + INIT_PARENT(Graphics, GraphicsVertexBuffers); + INIT_PARENT(Graphics, GraphicsIndexBuffers); INIT_PARENT(Graphics, GraphicsMeshes); INIT_PARENT(Graphics, GraphicsShaders); INIT_PARENT(Graphics, GraphicsMaterials); @@ -414,4 +398,11 @@ void ProfilerMemory::OnMemoryFree(void* ptr) stack.SkipRecursion = false; } +void ProfilerMemory::OnGroupUpdate(Groups group, int64 sizeDelta, int64 countDetla) +{ + Platform::InterlockedAdd(&GroupMemory[(int32)group], sizeDelta); + Platform::InterlockedAdd(&GroupMemoryCount[(int32)group], countDetla); + UPDATE_PEEK(group); +} + #endif diff --git a/Source/Engine/Profiler/ProfilerMemory.h b/Source/Engine/Profiler/ProfilerMemory.h index 206814560..a9dedadad 100644 --- a/Source/Engine/Profiler/ProfilerMemory.h +++ b/Source/Engine/Profiler/ProfilerMemory.h @@ -30,19 +30,32 @@ public: TotalUntracked, // Initial memory used by program upon startup (eg. executable size, static variables). ProgramSize, - // Total memory allocated via malloc. - Malloc, // General purpose engine memory. Engine, // Profiling tool memory overhead. Profiler, + // Total memory allocated via dynamic memory allocations. + Malloc, + // Total memory allocated via arena allocators (all pages). + MallocArena, + // Total graphics memory usage. Graphics, // Total textures memory usage. GraphicsTextures, + // Total render targets memory usage (textures used as target image for rendering). + GraphicsRenderTargets, + // Total cubemap textures memory usage (each cubemap is 6 textures). + GraphicsCubeMaps, + // Total volume textures memory usage (3D textures). + GraphicsVolumeTextures, // Total buffers memory usage. GraphicsBuffers, + // Total vertex buffers memory usage. + GraphicsVertexBuffers, + // Total index buffers memory usage. + GraphicsIndexBuffers, // Total meshes memory usage (vertex and idnex buffers allocated by models). GraphicsMeshes, // Totoal shaders memory usage (shaders bytecode, PSOs data). @@ -95,6 +108,8 @@ public: // Total scripting memory allocated by game. Scripting, + // Total Visual scripting memory allocated by game (visual script graphs, data and runtime allocations). + ScriptingVisual, // Total User Interface components memory. UI, @@ -144,6 +159,15 @@ public: // Custom plugin-specific memory tracking. CustomPlugin9, + // Custom platform-specific memory tracking. + CustomPlatform0, + // Custom platform-specific memory tracking. + CustomPlatform1, + // Custom platform-specific memory tracking. + CustomPlatform2, + // Custom platform-specific memory tracking. + CustomPlatform3, + // Total editor-specific memory. Editor, @@ -219,6 +243,7 @@ public: static void OnMemoryAlloc(void* ptr, uint64 size); static void OnMemoryFree(void* ptr); + static void OnGroupUpdate(Groups group, int64 sizeDelta, int64 countDetla); public: ///