Add more memory profiling coverage

This commit is contained in:
Wojtek Figat
2025-06-06 14:38:22 +02:00
parent 9d8e75caa3
commit cd637e8a7a
14 changed files with 57 additions and 3 deletions

View File

@@ -1425,6 +1425,7 @@ bool FlaxStorage::CloseFileHandles()
return false; return false;
} }
PROFILE_CPU(); PROFILE_CPU();
PROFILE_MEM(ContentFiles);
// Note: this is usually called by the content manager when this file is not used or on exit // Note: this is usually called by the content manager when this file is not used or on exit
// In those situations all the async tasks using this storage should be cancelled externally // In those situations all the async tasks using this storage should be cancelled externally

View File

@@ -12,6 +12,9 @@
#include "Engine/Threading/Threading.h" #include "Engine/Threading/Threading.h"
#include "Engine/Core/Collections/HashSet.h" #include "Engine/Core/Collections/HashSet.h"
#endif #endif
#if COMPILE_WITH_PROFILER
#include "Engine/Profiler/ProfilerMemory.h"
#endif
/// <summary> /// <summary>
/// The function object that supports binding static, member and lambda functions. /// The function object that supports binding static, member and lambda functions.
@@ -457,6 +460,7 @@ public:
/// <param name="f">The function to bind.</param> /// <param name="f">The function to bind.</param>
void Bind(const FunctionType& f) void Bind(const FunctionType& f)
{ {
PROFILE_MEM(EngineDelegate);
#if DELEGATE_USE_ATOMIC #if DELEGATE_USE_ATOMIC
const intptr size = Platform::AtomicRead(&_size); const intptr size = Platform::AtomicRead(&_size);
FunctionType* bindings = (FunctionType*)Platform::AtomicRead(&_ptr); FunctionType* bindings = (FunctionType*)Platform::AtomicRead(&_ptr);

View File

@@ -628,6 +628,7 @@ GPUTask* GPUTexture::UploadMipMapAsync(const BytesContainer& data, int32 mipInde
GPUTask* GPUTexture::UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, int32 rowPitch, int32 slicePitch, bool copyData) GPUTask* GPUTexture::UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, int32 rowPitch, int32 slicePitch, bool copyData)
{ {
PROFILE_CPU(); PROFILE_CPU();
PROFILE_MEM(GraphicsTextures);
ASSERT(IsAllocated()); ASSERT(IsAllocated());
ASSERT(mipIndex < MipLevels() && data.IsValid()); ASSERT(mipIndex < MipLevels() && data.IsValid());
ASSERT(data.Length() >= slicePitch); ASSERT(data.Length() >= slicePitch);
@@ -720,6 +721,7 @@ bool GPUTexture::DownloadData(TextureData& result)
MISSING_CODE("support volume texture data downloading."); MISSING_CODE("support volume texture data downloading.");
} }
PROFILE_CPU(); PROFILE_CPU();
PROFILE_MEM(GraphicsTextures);
// Use faster path for staging resources // Use faster path for staging resources
if (IsStaging()) // TODO: what about chips with unified memory? if rendering is not active then we can access GPU memory from CPU directly (eg. mobile, integrated GPUs and some consoles) if (IsStaging()) // TODO: what about chips with unified memory? if rendering is not active then we can access GPU memory from CPU directly (eg. mobile, integrated GPUs and some consoles)
@@ -806,6 +808,7 @@ Task* GPUTexture::DownloadDataAsync(TextureData& result)
MISSING_CODE("support volume texture data downloading."); MISSING_CODE("support volume texture data downloading.");
} }
PROFILE_CPU(); PROFILE_CPU();
PROFILE_MEM(GraphicsTextures);
// Use faster path for staging resources // Use faster path for staging resources
if (IsStaging()) if (IsStaging())

View File

@@ -169,6 +169,7 @@ void Mouse::OnMouseMoved(const Float2& newPosition)
void Mouse::OnMouseDown(const Float2& position, const MouseButton button, Window* target) void Mouse::OnMouseDown(const Float2& position, const MouseButton button, Window* target)
{ {
PROFILE_MEM(Input);
Event& e = _queue.AddOne(); Event& e = _queue.AddOne();
e.Type = EventType::MouseDown; e.Type = EventType::MouseDown;
e.Target = target; e.Target = target;
@@ -187,6 +188,7 @@ bool Mouse::IsAnyButtonDown() const
void Mouse::OnMouseUp(const Float2& position, const MouseButton button, Window* target) void Mouse::OnMouseUp(const Float2& position, const MouseButton button, Window* target)
{ {
PROFILE_MEM(Input);
Event& e = _queue.AddOne(); Event& e = _queue.AddOne();
e.Type = EventType::MouseUp; e.Type = EventType::MouseUp;
e.Target = target; e.Target = target;
@@ -196,6 +198,7 @@ void Mouse::OnMouseUp(const Float2& position, const MouseButton button, Window*
void Mouse::OnMouseDoubleClick(const Float2& position, const MouseButton button, Window* target) void Mouse::OnMouseDoubleClick(const Float2& position, const MouseButton button, Window* target)
{ {
PROFILE_MEM(Input);
Event& e = _queue.AddOne(); Event& e = _queue.AddOne();
e.Type = EventType::MouseDoubleClick; e.Type = EventType::MouseDoubleClick;
e.Target = target; e.Target = target;
@@ -205,6 +208,7 @@ void Mouse::OnMouseDoubleClick(const Float2& position, const MouseButton button,
void Mouse::OnMouseMove(const Float2& position, Window* target) void Mouse::OnMouseMove(const Float2& position, Window* target)
{ {
PROFILE_MEM(Input);
Event& e = _queue.AddOne(); Event& e = _queue.AddOne();
e.Type = EventType::MouseMove; e.Type = EventType::MouseMove;
e.Target = target; e.Target = target;
@@ -213,6 +217,7 @@ void Mouse::OnMouseMove(const Float2& position, Window* target)
void Mouse::OnMouseLeave(Window* target) void Mouse::OnMouseLeave(Window* target)
{ {
PROFILE_MEM(Input);
Event& e = _queue.AddOne(); Event& e = _queue.AddOne();
e.Type = EventType::MouseLeave; e.Type = EventType::MouseLeave;
e.Target = target; e.Target = target;
@@ -220,6 +225,7 @@ void Mouse::OnMouseLeave(Window* target)
void Mouse::OnMouseWheel(const Float2& position, float delta, Window* target) void Mouse::OnMouseWheel(const Float2& position, float delta, Window* target)
{ {
PROFILE_MEM(Input);
Event& e = _queue.AddOne(); Event& e = _queue.AddOne();
e.Type = EventType::MouseWheel; e.Type = EventType::MouseWheel;
e.Target = target; e.Target = target;
@@ -316,6 +322,7 @@ void Keyboard::OnCharInput(Char c, Window* target)
if (c < 32) if (c < 32)
return; return;
PROFILE_MEM(Input);
Event& e = _queue.AddOne(); Event& e = _queue.AddOne();
e.Type = EventType::Char; e.Type = EventType::Char;
e.Target = target; e.Target = target;
@@ -326,6 +333,7 @@ void Keyboard::OnKeyUp(KeyboardKeys key, Window* target)
{ {
if (key >= KeyboardKeys::MAX) if (key >= KeyboardKeys::MAX)
return; return;
PROFILE_MEM(Input);
Event& e = _queue.AddOne(); Event& e = _queue.AddOne();
e.Type = EventType::KeyUp; e.Type = EventType::KeyUp;
e.Target = target; e.Target = target;
@@ -336,6 +344,7 @@ void Keyboard::OnKeyDown(KeyboardKeys key, Window* target)
{ {
if (key >= KeyboardKeys::MAX) if (key >= KeyboardKeys::MAX)
return; return;
PROFILE_MEM(Input);
Event& e = _queue.AddOne(); Event& e = _queue.AddOne();
e.Type = EventType::KeyDown; e.Type = EventType::KeyDown;
e.Target = target; e.Target = target;

View File

@@ -3,6 +3,7 @@
#if COMPILE_WITH_PROFILER #if COMPILE_WITH_PROFILER
#include "ProfilerCPU.h" #include "ProfilerCPU.h"
#include "ProfilerMemory.h"
#include "Engine/Engine/Globals.h" #include "Engine/Engine/Globals.h"
#include "Engine/Threading/ThreadRegistry.h" #include "Engine/Threading/ThreadRegistry.h"
@@ -157,6 +158,7 @@ int32 ProfilerCPU::BeginEvent()
auto thread = Thread::Current; auto thread = Thread::Current;
if (thread == nullptr) if (thread == nullptr)
{ {
PROFILE_MEM(Profiler);
const auto id = Platform::GetCurrentThreadID(); const auto id = Platform::GetCurrentThreadID();
const auto t = ThreadRegistry::GetThread(id); const auto t = ThreadRegistry::GetThread(id);
if (t) if (t)

View File

@@ -3,6 +3,7 @@
#if COMPILE_WITH_PROFILER #if COMPILE_WITH_PROFILER
#include "ProfilerGPU.h" #include "ProfilerGPU.h"
#include "ProfilerMemory.h"
#include "Engine/Core/Log.h" #include "Engine/Core/Log.h"
#include "Engine/Engine/Engine.h" #include "Engine/Engine/Engine.h"
#include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/GPUDevice.h"
@@ -45,6 +46,7 @@ void ProfilerGPU::EventBuffer::TryResolve()
} }
// Collect queries results and free them // Collect queries results and free them
PROFILE_MEM(Profiler);
for (int32 i = 0; i < _data.Count(); i++) for (int32 i = 0; i < _data.Count(); i++)
{ {
auto& e = _data[i]; auto& e = _data[i];
@@ -58,6 +60,7 @@ void ProfilerGPU::EventBuffer::TryResolve()
int32 ProfilerGPU::EventBuffer::Add(const Event& e) int32 ProfilerGPU::EventBuffer::Add(const Event& e)
{ {
PROFILE_MEM(Profiler);
const int32 index = _data.Count(); const int32 index = _data.Count();
_data.Add(e); _data.Add(e);
return index; return index;
@@ -88,6 +91,7 @@ GPUTimerQuery* ProfilerGPU::GetTimerQuery()
} }
else else
{ {
PROFILE_MEM(Profiler);
result = GPUDevice::Instance->CreateTimerQuery(); result = GPUDevice::Instance->CreateTimerQuery();
_timerQueriesPool.Add(result); _timerQueriesPool.Add(result);
} }

View File

@@ -234,6 +234,8 @@ void InitProfilerMemory(const Char* cmdLine, int32 stage)
// Init hierarchy // Init hierarchy
#define INIT_PARENT(parent, child) GroupParents[(int32)ProfilerMemory::Groups::child] = (uint8)ProfilerMemory::Groups::parent #define INIT_PARENT(parent, child) GroupParents[(int32)ProfilerMemory::Groups::child] = (uint8)ProfilerMemory::Groups::parent
INIT_PARENT(Engine, EngineThreading);
INIT_PARENT(Engine, EngineDelegate);
INIT_PARENT(Malloc, MallocArena); INIT_PARENT(Malloc, MallocArena);
INIT_PARENT(Graphics, GraphicsTextures); INIT_PARENT(Graphics, GraphicsTextures);
INIT_PARENT(Graphics, GraphicsRenderTargets); INIT_PARENT(Graphics, GraphicsRenderTargets);

View File

@@ -30,8 +30,6 @@ public:
TotalUntracked, TotalUntracked,
// Initial memory used by program upon startup (eg. executable size, static variables). // Initial memory used by program upon startup (eg. executable size, static variables).
ProgramSize, ProgramSize,
// General purpose engine memory.
Engine,
// Profiling tool memory overhead. // Profiling tool memory overhead.
Profiler, Profiler,
@@ -40,6 +38,13 @@ public:
// Total memory allocated via arena allocators (all pages). // Total memory allocated via arena allocators (all pages).
MallocArena, MallocArena,
// General purpose engine memory.
Engine,
// Memory used by the threads (and relevant systems such as Job System).
EngineThreading,
// Memory used by Delegate (engine events system to store all references).
EngineDelegate,
// Total graphics memory usage. // Total graphics memory usage.
Graphics, Graphics,
// Total textures memory usage. // Total textures memory usage.

View File

@@ -3,6 +3,7 @@
#pragma once #pragma once
#include "Engine/Core/Memory/Memory.h" #include "Engine/Core/Memory/Memory.h"
#include "Engine/Profiler/ProfilerMemory.h"
#define MOODYCAMEL_EXCEPTIONS_ENABLED 0 #define MOODYCAMEL_EXCEPTIONS_ENABLED 0
#include <ThirdParty/concurrentqueue.h> #include <ThirdParty/concurrentqueue.h>
@@ -17,6 +18,7 @@ struct ConcurrentQueueSettings : public moodycamel::ConcurrentQueueDefaultTraits
// Use default engine memory allocator // Use default engine memory allocator
static inline void* malloc(size_t size) static inline void* malloc(size_t size)
{ {
PROFILE_MEM(EngineThreading);
return Allocator::Allocate((uint64)size); return Allocator::Allocate((uint64)size);
} }

View File

@@ -12,6 +12,7 @@
#include "Engine/Core/Collections/RingBuffer.h" #include "Engine/Core/Collections/RingBuffer.h"
#include "Engine/Engine/EngineService.h" #include "Engine/Engine/EngineService.h"
#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Profiler/ProfilerMemory.h"
#if USE_CSHARP #if USE_CSHARP
#include "Engine/Scripting/ManagedCLR/MCore.h" #include "Engine/Scripting/ManagedCLR/MCore.h"
#endif #endif
@@ -118,17 +119,22 @@ void* JobSystemAllocation::Allocate(uintptr size)
} }
} }
if (!result) if (!result)
{
PROFILE_MEM(EngineThreading);
result = Platform::Allocate(size, 16); result = Platform::Allocate(size, 16);
}
return result; return result;
} }
void JobSystemAllocation::Free(void* ptr, uintptr size) void JobSystemAllocation::Free(void* ptr, uintptr size)
{ {
PROFILE_MEM(EngineThreading);
MemPool.Add({ ptr, size }); MemPool.Add({ ptr, size });
} }
bool JobSystemService::Init() bool JobSystemService::Init()
{ {
PROFILE_MEM(EngineThreading);
ThreadsCount = Math::Min<int32>(Platform::GetCPUInfo().LogicalProcessorCount, ARRAY_COUNT(Threads)); ThreadsCount = Math::Min<int32>(Platform::GetCPUInfo().LogicalProcessorCount, ARRAY_COUNT(Threads));
for (int32 i = 0; i < ThreadsCount; i++) for (int32 i = 0; i < ThreadsCount; i++)
{ {

View File

@@ -14,6 +14,7 @@
#include "Engine/Platform/ConditionVariable.h" #include "Engine/Platform/ConditionVariable.h"
#include "Engine/Platform/CPUInfo.h" #include "Engine/Platform/CPUInfo.h"
#include "Engine/Platform/Thread.h" #include "Engine/Platform/Thread.h"
#include "Engine/Profiler/ProfilerMemory.h"
FLAXENGINE_API bool IsInMainThread() FLAXENGINE_API bool IsInMainThread()
{ {
@@ -36,6 +37,7 @@ String ThreadPoolTask::ToString() const
void ThreadPoolTask::Enqueue() void ThreadPoolTask::Enqueue()
{ {
PROFILE_MEM(EngineThreading);
ThreadPoolImpl::Jobs.Add(this); ThreadPoolImpl::Jobs.Add(this);
ThreadPoolImpl::JobsSignal.NotifyOne(); ThreadPoolImpl::JobsSignal.NotifyOne();
} }
@@ -58,6 +60,8 @@ ThreadPoolService ThreadPoolServiceInstance;
bool ThreadPoolService::Init() bool ThreadPoolService::Init()
{ {
PROFILE_MEM(EngineThreading);
// Spawn threads // Spawn threads
const int32 numThreads = Math::Clamp<int32>(Platform::GetCPUInfo().ProcessorCoreCount - 1, 2, PLATFORM_THREADS_LIMIT / 2); const int32 numThreads = Math::Clamp<int32>(Platform::GetCPUInfo().ProcessorCoreCount - 1, 2, PLATFORM_THREADS_LIMIT / 2);
LOG(Info, "Spawning {0} Thread Pool workers", numThreads); LOG(Info, "Spawning {0} Thread Pool workers", numThreads);

View File

@@ -3,10 +3,11 @@
#include "ThreadRegistry.h" #include "ThreadRegistry.h"
#include "Engine/Core/Collections/Dictionary.h" #include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Platform/CriticalSection.h" #include "Engine/Platform/CriticalSection.h"
#include "Engine/Profiler/ProfilerMemory.h"
namespace ThreadRegistryImpl namespace ThreadRegistryImpl
{ {
Dictionary<uint64, Thread*> Registry(64); Dictionary<uint64, Thread*> Registry;
CriticalSection Locker; CriticalSection Locker;
} }
@@ -46,6 +47,7 @@ void ThreadRegistry::KillEmAll()
void ThreadRegistry::Add(Thread* thread) void ThreadRegistry::Add(Thread* thread)
{ {
PROFILE_MEM(EngineThreading);
ASSERT(thread && thread->GetID() != 0); ASSERT(thread && thread->GetID() != 0);
Locker.Lock(); Locker.Lock();
ASSERT(!Registry.ContainsKey(thread->GetID()) && !Registry.ContainsValue(thread)); ASSERT(!Registry.ContainsKey(thread->GetID()) && !Registry.ContainsValue(thread));

View File

@@ -14,6 +14,7 @@
#include "Engine/Graphics/PixelFormatSampler.h" #include "Engine/Graphics/PixelFormatSampler.h"
#include "Engine/Graphics/Textures/TextureData.h" #include "Engine/Graphics/Textures/TextureData.h"
#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Profiler/ProfilerMemory.h"
#if USE_EDITOR #if USE_EDITOR
#include "Engine/Core/Collections/Dictionary.h" #include "Engine/Core/Collections/Dictionary.h"
@@ -210,6 +211,7 @@ bool TextureTool::HasAlpha(const StringView& path)
bool TextureTool::ImportTexture(const StringView& path, TextureData& textureData) bool TextureTool::ImportTexture(const StringView& path, TextureData& textureData)
{ {
PROFILE_CPU(); PROFILE_CPU();
PROFILE_MEM(GraphicsTextures);
LOG(Info, "Importing texture from \'{0}\'", path); LOG(Info, "Importing texture from \'{0}\'", path);
const auto startTime = DateTime::NowUTC(); const auto startTime = DateTime::NowUTC();
@@ -247,6 +249,7 @@ bool TextureTool::ImportTexture(const StringView& path, TextureData& textureData
bool TextureTool::ImportTexture(const StringView& path, TextureData& textureData, Options options, String& errorMsg) bool TextureTool::ImportTexture(const StringView& path, TextureData& textureData, Options options, String& errorMsg)
{ {
PROFILE_CPU(); PROFILE_CPU();
PROFILE_MEM(GraphicsTextures);
LOG(Info, "Importing texture from \'{0}\'. Options: {1}", path, options.ToString()); LOG(Info, "Importing texture from \'{0}\'. Options: {1}", path, options.ToString());
const auto startTime = DateTime::NowUTC(); const auto startTime = DateTime::NowUTC();
@@ -296,6 +299,7 @@ bool TextureTool::ImportTexture(const StringView& path, TextureData& textureData
bool TextureTool::ExportTexture(const StringView& path, const TextureData& textureData) bool TextureTool::ExportTexture(const StringView& path, const TextureData& textureData)
{ {
PROFILE_CPU(); PROFILE_CPU();
PROFILE_MEM(GraphicsTextures);
LOG(Info, "Exporting texture to \'{0}\'.", path); LOG(Info, "Exporting texture to \'{0}\'.", path);
const auto startTime = DateTime::NowUTC(); const auto startTime = DateTime::NowUTC();
ImageType type; ImageType type;
@@ -346,6 +350,7 @@ bool TextureTool::Convert(TextureData& dst, const TextureData& src, const PixelF
return true; return true;
} }
PROFILE_CPU(); PROFILE_CPU();
PROFILE_MEM(GraphicsTextures);
#if COMPILE_WITH_DIRECTXTEX #if COMPILE_WITH_DIRECTXTEX
return ConvertDirectXTex(dst, src, dstFormat); return ConvertDirectXTex(dst, src, dstFormat);
@@ -375,6 +380,7 @@ bool TextureTool::Resize(TextureData& dst, const TextureData& src, int32 dstWidt
return true; return true;
} }
PROFILE_CPU(); PROFILE_CPU();
PROFILE_MEM(GraphicsTextures);
#if COMPILE_WITH_DIRECTXTEX #if COMPILE_WITH_DIRECTXTEX
return ResizeDirectXTex(dst, src, dstWidth, dstHeight); return ResizeDirectXTex(dst, src, dstWidth, dstHeight);
#elif COMPILE_WITH_STB #elif COMPILE_WITH_STB
@@ -488,6 +494,7 @@ bool TextureTool::GetImageType(const StringView& path, ImageType& type)
bool TextureTool::Transform(TextureData& texture, const Function<void(Color&)>& transformation) bool TextureTool::Transform(TextureData& texture, const Function<void(Color&)>& transformation)
{ {
PROFILE_CPU(); PROFILE_CPU();
PROFILE_MEM(GraphicsTextures);
auto sampler = PixelFormatSampler::Get(texture.Format); auto sampler = PixelFormatSampler::Get(texture.Format);
if (!sampler) if (!sampler)
return true; return true;

View File

@@ -82,6 +82,7 @@ bool CaptureScreenshot::Run()
LOG(Warning, "Missing target render task."); LOG(Warning, "Missing target render task.");
return true; return true;
} }
PROFILE_MEM(Graphics);
// TODO: how about a case two or more screenshots at the same second? update counter and check files // TODO: how about a case two or more screenshots at the same second? update counter and check files
@@ -147,6 +148,7 @@ void Screenshot::Capture(GPUTexture* target, const StringView& path)
LOG(Warning, "Cannot take screenshot. Graphics device is not ready."); LOG(Warning, "Cannot take screenshot. Graphics device is not ready.");
return; return;
} }
PROFILE_MEM(Graphics);
// Faster path for staging textures that contents are ready to access on a CPU // Faster path for staging textures that contents are ready to access on a CPU
if (target->IsStaging()) if (target->IsStaging())
@@ -211,6 +213,7 @@ void Screenshot::Capture(SceneRenderTask* target, const StringView& path)
LOG(Warning, "Cannot take screenshot. Graphics device is not ready."); LOG(Warning, "Cannot take screenshot. Graphics device is not ready.");
return; return;
} }
PROFILE_MEM(Graphics);
// Create tasks // Create tasks
auto saveTask = New<CaptureScreenshot>(target, path); auto saveTask = New<CaptureScreenshot>(target, path);