Add memory profiling events to the main areas of the engine

This commit is contained in:
Wojtek Figat
2025-05-22 04:47:01 +02:00
parent 32bc73610f
commit c639a3103c
101 changed files with 502 additions and 17 deletions

View File

@@ -526,6 +526,7 @@ ContentLoadTask* Asset::createLoadingTask()
void Asset::startLoading()
{
PROFILE_MEM(ContentAssets);
ASSERT(!IsLoaded());
ASSERT(Platform::AtomicRead(&_loadingTask) == 0);
auto loadingTask = createLoadingTask();

View File

@@ -9,6 +9,7 @@
#include "Engine/Animations/Animations.h"
#include "Engine/Animations/SceneAnimations/SceneAnimation.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Profiler/ProfilerMemory.h"
#include "Engine/Threading/Threading.h"
#include "Engine/Serialization/MemoryReadStream.h"
#if USE_EDITOR
@@ -598,6 +599,7 @@ void Animation::OnScriptingDispose()
Asset::LoadResult Animation::load()
{
PROFILE_MEM(AnimationsData);
ConcurrentSystemLocker::WriteScope systemScope(Animations::SystemLocker);
// Get stream with animations data

View File

@@ -9,6 +9,7 @@
#include "Engine/Core/Types/DataContainer.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Serialization/MemoryWriteStream.h"
#include "Engine/Profiler/ProfilerMemory.h"
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Animations/Animations.h"
#include "Engine/Threading/Threading.h"
@@ -25,6 +26,7 @@ AnimationGraph::AnimationGraph(const SpawnParams& params, const AssetInfo* info)
Asset::LoadResult AnimationGraph::load()
{
PROFILE_MEM(AnimationsData);
ConcurrentSystemLocker::WriteScope systemScope(Animations::SystemLocker);
// Get stream with graph data
@@ -83,6 +85,7 @@ bool AnimationGraph::InitAsAnimation(SkinnedModel* baseModel, Animation* anim, b
Log::ArgumentNullException();
return true;
}
PROFILE_MEM(AnimationsData);
ConcurrentSystemLocker::WriteScope systemScope(Animations::SystemLocker);
// Create Graph data

View File

@@ -8,6 +8,7 @@
#include "Engine/Serialization/MemoryWriteStream.h"
#endif
#include "Engine/Animations/Animations.h"
#include "Engine/Profiler/ProfilerMemory.h"
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Threading/Threading.h"
@@ -20,6 +21,7 @@ AnimationGraphFunction::AnimationGraphFunction(const SpawnParams& params, const
Asset::LoadResult AnimationGraphFunction::load()
{
PROFILE_MEM(AnimationsData);
ConcurrentSystemLocker::WriteScope systemScope(Animations::SystemLocker);
// Get graph data from chunk

View File

@@ -165,9 +165,13 @@ Asset::LoadResult Material::load()
MaterialGenerator generator;
generator.Error.Bind(&OnGeneratorError);
if (_shaderHeader.Material.GraphVersion != MATERIAL_GRAPH_VERSION)
{
LOG(Info, "Converting material \'{0}\', from version {1} to {2}...", name, _shaderHeader.Material.GraphVersion, MATERIAL_GRAPH_VERSION);
}
else
{
LOG(Info, "Updating material \'{0}\'...", name);
}
// Load or create material surface
MaterialLayer* layer;

View File

@@ -18,6 +18,7 @@
#include "Engine/Graphics/Models/MeshDeformation.h"
#include "Engine/Graphics/Textures/GPUTexture.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Profiler/ProfilerMemory.h"
#include "Engine/Renderer/DrawCall.h"
#include "Engine/Threading/Threading.h"
#include "Engine/Tools/ModelTool/ModelTool.h"
@@ -304,6 +305,7 @@ bool Model::Init(const Span<int32>& meshesCountPerLod)
Log::ArgumentOutOfRangeException();
return true;
}
PROFILE_MEM(GraphicsMeshes);
// Dispose previous data and disable streaming (will start data uploading tasks manually)
StopStreaming();
@@ -343,6 +345,7 @@ bool Model::Init(const Span<int32>& meshesCountPerLod)
bool Model::LoadHeader(ReadStream& stream, byte& headerVersion)
{
PROFILE_MEM(GraphicsMeshes);
if (ModelBase::LoadHeader(stream, headerVersion))
return true;
@@ -509,6 +512,7 @@ bool Model::Save(bool withMeshDataFromGpu, Function<FlaxChunk*(int32)>& getChunk
void Model::SetupMaterialSlots(int32 slotsCount)
{
PROFILE_MEM(GraphicsMeshes);
ModelBase::SetupMaterialSlots(slotsCount);
// Adjust meshes indices for slots
@@ -584,6 +588,8 @@ int32 Model::GetAllocatedResidency() const
Asset::LoadResult Model::load()
{
PROFILE_MEM(GraphicsMeshes);
// Get header chunk
auto chunk0 = GetChunk(0);
if (chunk0 == nullptr || chunk0->IsMissing())

View File

@@ -5,6 +5,7 @@
#include "Engine/Core/Math/Transform.h"
#include "Engine/Content/WeakAssetReference.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Profiler/ProfilerMemory.h"
#include "Engine/Graphics/Config.h"
#include "Engine/Graphics/Models/MeshBase.h"
#include "Engine/Graphics/Models/MeshDeformation.h"
@@ -51,6 +52,7 @@ public:
AssetReference<ModelBase> model = _model.Get();
if (model == nullptr)
return true;
PROFILE_MEM(GraphicsMeshes);
// Get data
BytesContainer data;
@@ -334,6 +336,8 @@ bool ModelBase::LoadHeader(ReadStream& stream, byte& headerVersion)
bool ModelBase::LoadMesh(MemoryReadStream& stream, byte meshVersion, MeshBase* mesh, MeshData* dataIfReadOnly)
{
PROFILE_MEM(GraphicsMeshes);
// Load descriptor
static_assert(MODEL_MESH_VERSION == 2, "Update code");
uint32 vertices, triangles;

View File

@@ -18,6 +18,7 @@
#include "Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h"
#include "Engine/Debug/Exceptions/ArgumentOutOfRangeException.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Profiler/ProfilerMemory.h"
#include "Engine/Renderer/DrawCall.h"
#if USE_EDITOR
#include "Engine/Graphics/Models/ModelData.h"
@@ -458,6 +459,7 @@ bool SkinnedModel::Init(const Span<int32>& meshesCountPerLod)
Log::ArgumentOutOfRangeException();
return true;
}
PROFILE_MEM(GraphicsMeshes);
// Dispose previous data and disable streaming (will start data uploading tasks manually)
StopStreaming();
@@ -501,6 +503,7 @@ void BlendShape::LoadHeader(ReadStream& stream, byte headerVersion)
void BlendShape::Load(ReadStream& stream, byte meshVersion)
{
PROFILE_MEM(GraphicsMeshes);
UseNormals = stream.ReadBool();
stream.ReadUint32(&MinVertexIndex);
stream.ReadUint32(&MaxVertexIndex);
@@ -531,6 +534,7 @@ void BlendShape::Save(WriteStream& stream) const
bool SkinnedModel::LoadMesh(MemoryReadStream& stream, byte meshVersion, MeshBase* mesh, MeshData* dataIfReadOnly)
{
PROFILE_MEM(GraphicsMeshes);
if (ModelBase::LoadMesh(stream, meshVersion, mesh, dataIfReadOnly))
return true;
static_assert(MODEL_MESH_VERSION == 2, "Update code");
@@ -560,6 +564,7 @@ bool SkinnedModel::LoadMesh(MemoryReadStream& stream, byte meshVersion, MeshBase
bool SkinnedModel::LoadHeader(ReadStream& stream, byte& headerVersion)
{
PROFILE_MEM(GraphicsMeshes);
if (ModelBase::LoadHeader(stream, headerVersion))
return true;
static_assert(MODEL_HEADER_VERSION == 2, "Update code");
@@ -861,6 +866,7 @@ uint64 SkinnedModel::GetMemoryUsage() const
void SkinnedModel::SetupMaterialSlots(int32 slotsCount)
{
PROFILE_MEM(GraphicsMeshes);
ModelBase::SetupMaterialSlots(slotsCount);
// Adjust meshes indices for slots
@@ -954,6 +960,7 @@ Asset::LoadResult SkinnedModel::load()
if (chunk0 == nullptr || chunk0->IsMissing())
return LoadResult::MissingDataChunk;
MemoryReadStream headerStream(chunk0->Get(), chunk0->Size());
PROFILE_MEM(GraphicsMeshes);
// Load asset data (anything but mesh contents that use streaming)
byte headerVersion;

View File

@@ -1900,9 +1900,13 @@ bool VisualScriptingBinaryModule::InvokeMethod(void* method, const Variant& inst
if (!instanceObject || instanceObject->GetTypeHandle() != vsMethod->Script->GetScriptingType())
{
if (!instanceObject)
{
LOG(Error, "Failed to call method '{0}.{1}' (args count: {2}) without object instance", String(vsMethod->Script->GetScriptTypeName()), String(vsMethod->Name), vsMethod->ParamNames.Count());
}
else
{
LOG(Error, "Failed to call method '{0}.{1}' (args count: {2}) with invalid object instance of type '{3}'", String(vsMethod->Script->GetScriptTypeName()), String(vsMethod->Name), vsMethod->ParamNames.Count(), String(instanceObject->GetType().Fullname));
}
return true;
}
}

View File

@@ -10,6 +10,7 @@
#include "Engine/Serialization/JsonTools.h"
#include "Engine/Debug/Exceptions/JsonParseException.h"
#include "Engine/Threading/ThreadPoolTask.h"
#include "Engine/Profiler/ProfilerMemory.h"
#if USE_EDITOR
#include "Engine/Platform/FileSystem.h"
#include "Engine/Threading/Threading.h"
@@ -527,6 +528,7 @@ protected:
auto storage = ref->Storage;
auto factory = (BinaryAssetFactoryBase*)Content::GetAssetFactory(ref->GetTypeName());
ASSERT(factory);
PROFILE_MEM(ContentAssets);
// Here we should open storage and extract AssetInitData
// This would also allow to convert/upgrade data

View File

@@ -28,6 +28,7 @@
#include "Engine/Engine/Globals.h"
#include "Engine/Level/Types.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Profiler/ProfilerMemory.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/Scripting.h"
#if USE_EDITOR
@@ -117,6 +118,8 @@ ContentService ContentServiceInstance;
bool ContentService::Init()
{
PROFILE_MEM(Content);
// Load assets registry
Cache.Init();
@@ -159,6 +162,7 @@ void ContentService::Update()
void ContentService::LateUpdate()
{
PROFILE_CPU();
PROFILE_MEM(Content);
// Check if need to perform an update of unloading assets
const TimeSpan timeNow = Time::Update.UnscaledTime;
@@ -324,6 +328,7 @@ String LoadingThread::ToString() const
int32 LoadingThread::Run()
{
PROFILE_MEM(Content);
#if USE_EDITOR && PLATFORM_WINDOWS
// Initialize COM
// TODO: maybe add sth to Thread::Create to indicate that thread will use COM stuff
@@ -416,6 +421,7 @@ bool Content::GetAssetInfo(const Guid& id, AssetInfo& info)
if (Cache.FindAsset(id, info))
return true;
PROFILE_CPU();
PROFILE_MEM(Content);
// Locking injects some stalls but we need to make it safe (only one thread can pass though it at once)
ScopeLock lock(WorkspaceDiscoveryLocker);
@@ -465,6 +471,7 @@ bool Content::GetAssetInfo(const StringView& path, AssetInfo& info)
if (!FileSystem::FileExists(path))
return false;
PROFILE_CPU();
PROFILE_MEM(Content);
const auto extension = FileSystem::GetExtension(path).ToLower();
@@ -593,6 +600,7 @@ Asset* Content::LoadAsyncInternal(const StringView& internalPath, const MClass*
Asset* Content::LoadAsyncInternal(const StringView& internalPath, const ScriptingTypeHandle& type)
{
PROFILE_MEM(Content);
#if USE_EDITOR
const String path = Globals::EngineContentFolder / internalPath + ASSET_FILES_EXTENSION_WITH_DOT;
if (!FileSystem::FileExists(path))
@@ -635,6 +643,8 @@ Asset* Content::LoadAsync(const StringView& path, const MClass* type)
Asset* Content::LoadAsync(const StringView& path, const ScriptingTypeHandle& type)
{
PROFILE_MEM(Content);
// Ensure path is in a valid format
String pathNorm(path);
ContentStorageManager::FormatPath(pathNorm);
@@ -687,7 +697,6 @@ Asset* Content::GetAsset(const StringView& outputPath)
{
if (outputPath.IsEmpty())
return nullptr;
ScopeLock lock(AssetsLocker);
for (auto i = Assets.Begin(); i.IsNotEnd(); ++i)
{
@@ -1023,6 +1032,7 @@ Asset* Content::CreateVirtualAsset(const MClass* type)
Asset* Content::CreateVirtualAsset(const ScriptingTypeHandle& type)
{
PROFILE_CPU();
PROFILE_MEM(Content);
auto& assetType = type.GetType();
// Init mock asset info
@@ -1045,7 +1055,9 @@ Asset* Content::CreateVirtualAsset(const ScriptingTypeHandle& type)
}
// Create asset object
PROFILE_MEM_BEGIN(ContentAssets);
auto asset = factory->NewVirtual(info);
PROFILE_MEM_END();
if (asset == nullptr)
{
LOG(Error, "Cannot create virtual asset object.");
@@ -1054,7 +1066,9 @@ Asset* Content::CreateVirtualAsset(const ScriptingTypeHandle& type)
asset->RegisterObject();
// Call initializer function
PROFILE_MEM_BEGIN(ContentAssets);
asset->InitAsVirtual();
PROFILE_MEM_END();
// Register asset
AssetsLocker.Lock();
@@ -1209,6 +1223,7 @@ Asset* Content::LoadAsync(const Guid& id, const ScriptingTypeHandle& type)
{
if (!id.IsValid())
return nullptr;
PROFILE_MEM(Content);
// Check if asset has been already loaded
Asset* result = nullptr;
@@ -1277,7 +1292,9 @@ Asset* Content::LoadAsync(const Guid& id, const ScriptingTypeHandle& type)
}
// Create asset object
PROFILE_MEM_BEGIN(ContentAssets);
result = factory->New(assetInfo);
PROFILE_MEM_END();
if (result == nullptr)
{
LOG(Error, "Cannot create asset object. Info: {0}", assetInfo.ToString());

View File

@@ -20,6 +20,7 @@
#include "Engine/Core/Cache.h"
#include "Engine/Debug/Exceptions/JsonParseException.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Profiler/ProfilerMemory.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MField.h"
@@ -39,6 +40,7 @@ String JsonAssetBase::GetData() const
if (Data == nullptr)
return String::Empty;
PROFILE_CPU_NAMED("JsonAsset.GetData");
PROFILE_MEM(ContentAssets);
rapidjson_flax::StringBuffer buffer;
OnGetData(buffer);
return String((const char*)buffer.GetString(), (int32)buffer.GetSize());
@@ -49,6 +51,7 @@ void JsonAssetBase::SetData(const StringView& value)
if (!IsLoaded())
return;
PROFILE_CPU_NAMED("JsonAsset.SetData");
PROFILE_MEM(ContentAssets);
const StringAnsi dataJson(value);
ScopeLock lock(Locker);
const StringView dataTypeName = DataTypeName;
@@ -60,6 +63,7 @@ void JsonAssetBase::SetData(const StringView& value)
bool JsonAssetBase::Init(const StringView& dataTypeName, const StringAnsiView& dataJson)
{
PROFILE_MEM(ContentAssets);
unload(true);
DataTypeName = dataTypeName;
DataEngineBuild = FLAXENGINE_VERSION_BUILD;
@@ -239,6 +243,7 @@ Asset::LoadResult JsonAssetBase::loadAsset()
{
if (IsVirtual() || _isVirtualDocument)
return LoadResult::Ok;
PROFILE_MEM(ContentAssets);
// Load data (raw json file in editor, cooked asset in build game)
#if USE_EDITOR
@@ -453,6 +458,7 @@ bool JsonAsset::CreateInstance()
ScopeLock lock(Locker);
if (Instance)
return false;
PROFILE_MEM(ContentAssets);
// Try to scripting type for this data
const StringAsANSI<> dataTypeNameAnsi(DataTypeName.Get(), DataTypeName.Length());

View File

@@ -8,6 +8,7 @@
#include "Engine/Content/WeakAssetReference.h"
#include "Engine/Core/Log.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Profiler/ProfilerMemory.h"
/// <summary>
/// Asset loading task object.
@@ -44,6 +45,7 @@ protected:
Result run() override
{
PROFILE_CPU();
PROFILE_MEM(ContentAssets);
// Keep valid ref to the asset
AssetReference<::Asset> ref = Asset.Get();

View File

@@ -182,10 +182,5 @@ public:
/// Clones this chunk data (doesn't copy location in file).
/// </summary>
/// <returns>The cloned chunk.</returns>
FlaxChunk* Clone() const
{
auto chunk = New<FlaxChunk>();
chunk->Data.Copy(Data);
return chunk;
}
FlaxChunk* Clone() const;
};

View File

@@ -8,6 +8,7 @@
#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Platform/File.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Profiler/ProfilerMemory.h"
#include "Engine/Serialization/FileWriteStream.h"
#include "Engine/Content/Asset.h"
#include "Engine/Content/Content.h"
@@ -63,6 +64,14 @@ void FlaxChunk::RegisterUsage()
LastAccessTime = Platform::GetTimeSeconds();
}
FlaxChunk* FlaxChunk::Clone() const
{
PROFILE_MEM(ContentFiles);
auto chunk = New<FlaxChunk>();
chunk->Data.Copy(Data);
return chunk;
}
const int32 FlaxStorage::MagicCode = 1180124739;
FlaxStorage::LockData FlaxStorage::LockData::Invalid(nullptr);
@@ -281,19 +290,12 @@ uint32 FlaxStorage::GetMemoryUsage() const
bool FlaxStorage::Load()
{
// Check if was already loaded
if (IsLoaded())
{
return false;
}
// Prevent loading by more than one thread
PROFILE_MEM(ContentFiles);
ScopeLock lock(_loadLocker);
if (IsLoaded())
{
// Other thread loaded it
return false;
}
ASSERT(GetEntriesCount() == 0);
// Open file
@@ -693,6 +695,7 @@ bool FlaxStorage::LoadAssetHeader(const Guid& id, AssetInitData& data)
bool FlaxStorage::LoadAssetChunk(FlaxChunk* chunk)
{
PROFILE_MEM(ContentFiles);
ASSERT(IsLoaded());
ASSERT(chunk != nullptr && _chunks.Contains(chunk));
@@ -866,6 +869,7 @@ FlaxChunk* FlaxStorage::AllocateChunk()
{
if (AllowDataModifications())
{
PROFILE_MEM(ContentFiles);
auto chunk = New<FlaxChunk>();
_chunks.Add(chunk);
return chunk;
@@ -1125,6 +1129,7 @@ bool FlaxStorage::Save(const AssetInitData& data, bool silentMode)
bool FlaxStorage::LoadAssetHeader(const Entry& e, AssetInitData& data)
{
PROFILE_MEM(ContentFiles);
ASSERT(IsLoaded());
auto lock = Lock();
@@ -1396,6 +1401,8 @@ FileReadStream* FlaxStorage::OpenFile()
auto& stream = _file.Get();
if (stream == nullptr)
{
PROFILE_MEM(ContentFiles);
// Open file
auto file = File::Open(_path, FileMode::OpenExisting, FileAccess::Read, FileShare::Read);
if (file == nullptr)