Add Tracy profiler support
This commit is contained in:
@@ -357,7 +357,15 @@ bool Asset::onLoad(LoadAssetTask* task)
|
||||
Locker.Lock();
|
||||
|
||||
// Load asset
|
||||
const LoadResult result = loadAsset();
|
||||
LoadResult result;
|
||||
{
|
||||
#if TRACY_ENABLE
|
||||
ZoneScoped;
|
||||
const StringView name(GetPath());
|
||||
ZoneName(*name, name.Length());
|
||||
#endif
|
||||
result = loadAsset();
|
||||
}
|
||||
const bool isLoaded = result == LoadResult::Ok;
|
||||
const bool failed = !isLoaded;
|
||||
_loadFailed = failed;
|
||||
|
||||
@@ -166,6 +166,7 @@ int32 Engine::Main(const Char* cmdLine)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// App paused logic
|
||||
if (Platform::GetIsPaused())
|
||||
{
|
||||
@@ -202,6 +203,7 @@ int32 Engine::Main(const Char* cmdLine)
|
||||
{
|
||||
OnDraw();
|
||||
Time::OnEndDraw();
|
||||
FrameMark;
|
||||
canDraw = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "Engine/Core/Math/Rectangle.h"
|
||||
#include "Engine/Core/Utilities.h"
|
||||
#if COMPILE_WITH_PROFILER
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#endif
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Engine/CommandLine.h"
|
||||
@@ -165,6 +165,44 @@ void PlatformBase::Exit()
|
||||
{
|
||||
}
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
|
||||
void PlatformBase::OnMemoryAlloc(void* ptr, uint64 size)
|
||||
{
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
#if TRACY_ENABLE
|
||||
// Track memory allocation in Tracy
|
||||
//tracy::Profiler::MemAlloc(ptr, size, false);
|
||||
tracy::Profiler::MemAllocCallstack(ptr, size, 12, false);
|
||||
#endif
|
||||
|
||||
// Register allocation during the current CPU event
|
||||
auto thread = ProfilerCPU::GetCurrentThread();
|
||||
if (thread != nullptr && thread->Buffer.GetCount() != 0)
|
||||
{
|
||||
auto& activeEvent = thread->Buffer.Last().Event();
|
||||
if (activeEvent.End < ZeroTolerance)
|
||||
{
|
||||
activeEvent.NativeMemoryAllocation += (int32)size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlatformBase::OnMemoryFree(void* ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
#if TRACY_ENABLE
|
||||
// Track memory allocation in Tracy
|
||||
tracy::Profiler::MemFree(ptr, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void* PlatformBase::AllocatePages(uint64 numPages, uint64 pageSize)
|
||||
{
|
||||
// Fallback to the default memory allocation
|
||||
@@ -460,15 +498,6 @@ Vector2 PlatformBase::GetVirtualDesktopSize()
|
||||
return Platform::GetVirtualDesktopBounds().Size;
|
||||
}
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
|
||||
void PlatformBase::TrackAllocation(uint64 size)
|
||||
{
|
||||
ProfilerMemory::OnAllocation((uint32)size, false);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void PlatformBase::GetEnvironmentVariables(Dictionary<String, String>& result)
|
||||
{
|
||||
// Not supported
|
||||
|
||||
@@ -299,7 +299,8 @@ public:
|
||||
static void Prefetch(void const* ptr) = delete;
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
static void TrackAllocation(uint64 size);
|
||||
static void OnMemoryAlloc(void* ptr, uint64 size);
|
||||
static void OnMemoryFree(void* ptr);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
#include "Engine/Threading/IRunnable.h"
|
||||
#include "Engine/Threading/ThreadRegistry.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#if TRACY_ENABLE
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include <ThirdParty/tracy/Tracy.h>
|
||||
#endif
|
||||
|
||||
Delegate<Thread*> ThreadBase::ThreadStarting;
|
||||
Delegate<Thread*, int32> ThreadBase::ThreadExiting;
|
||||
@@ -70,6 +74,13 @@ int32 ThreadBase::Run()
|
||||
ASSERT(_runnable);
|
||||
const auto thread = static_cast<Thread*>(this);
|
||||
_id = Platform::GetCurrentThreadID();
|
||||
#if TRACY_ENABLE
|
||||
char threadName[100];
|
||||
const int32 threadNameLength = Math::Min<int32>(ARRAY_COUNT(threadName) - 1, _name.Length());
|
||||
StringUtils::ConvertUTF162ANSI(*_name, threadName, threadNameLength);
|
||||
threadName[threadNameLength] = 0;
|
||||
tracy::SetThreadName(threadName);
|
||||
#endif
|
||||
ThreadRegistry::Add(thread);
|
||||
ThreadStarting(thread);
|
||||
int32 exitCode = 1;
|
||||
|
||||
@@ -305,14 +305,18 @@ void Win32Platform::Prefetch(void const* ptr)
|
||||
|
||||
void* Win32Platform::Allocate(uint64 size, uint64 alignment)
|
||||
{
|
||||
void* ptr = _aligned_malloc((size_t)size, (size_t)alignment);
|
||||
#if COMPILE_WITH_PROFILER
|
||||
TrackAllocation(size);
|
||||
OnMemoryAlloc(ptr, size);
|
||||
#endif
|
||||
return _aligned_malloc((size_t)size, (size_t)alignment);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void Win32Platform::Free(void* ptr)
|
||||
{
|
||||
#if COMPILE_WITH_PROFILER
|
||||
OnMemoryFree(ptr);
|
||||
#endif
|
||||
_aligned_free(ptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,9 +37,30 @@ namespace
|
||||
int32 SystemDpi = 96;
|
||||
#if CRASH_LOG_ENABLE
|
||||
CriticalSection SymLocker;
|
||||
#if TRACY_ENABLE
|
||||
bool SymInitialized = true;
|
||||
#else
|
||||
bool SymInitialized = false;
|
||||
bool SymModulesDirty = true;
|
||||
#endif
|
||||
Array<String> SymbolsPath;
|
||||
|
||||
void OnSymbolsPathModified()
|
||||
{
|
||||
if (!SymInitialized)
|
||||
return;
|
||||
HANDLE process = GetCurrentProcess();
|
||||
SymCleanup(process);
|
||||
String symbolSearchPath;
|
||||
for (auto& path : SymbolsPath)
|
||||
{
|
||||
symbolSearchPath += path;
|
||||
symbolSearchPath += ";";
|
||||
}
|
||||
symbolSearchPath += Platform::GetWorkingDirectory();
|
||||
SymInitializeW(process, *symbolSearchPath, TRUE);
|
||||
//SymSetSearchPathW(process, *symbolSearchPath);
|
||||
//SymRefreshModuleList(process);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -378,6 +399,20 @@ void WindowsPlatform::PreInit(void* hInstance)
|
||||
Error(TEXT("OLE initalization failed!"));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
#if CRASH_LOG_ENABLE
|
||||
TCHAR buffer[MAX_PATH] = { 0 };
|
||||
SymLocker.Lock();
|
||||
if (::GetModuleFileNameW(::GetModuleHandleW(nullptr), buffer, MAX_PATH))
|
||||
SymbolsPath.Add(StringUtils::GetDirectoryName(buffer));
|
||||
if (::GetEnvironmentVariableW(TEXT("_NT_SYMBOL_PATH"), buffer, MAX_PATH))
|
||||
SymbolsPath.Add(StringUtils::GetDirectoryName(buffer));
|
||||
DWORD options = SymGetOptions();
|
||||
options |= SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS;
|
||||
SymSetOptions(options);
|
||||
OnSymbolsPathModified();
|
||||
SymLocker.Unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool WindowsPlatform::IsWindows10()
|
||||
@@ -604,11 +639,13 @@ void WindowsPlatform::Exit()
|
||||
{
|
||||
#if CRASH_LOG_ENABLE
|
||||
SymLocker.Lock();
|
||||
#if !TRACY_ENABLE
|
||||
if (SymInitialized)
|
||||
{
|
||||
SymInitialized = false;
|
||||
SymCleanup(GetCurrentProcess());
|
||||
}
|
||||
#endif
|
||||
SymbolsPath.Resize(0);
|
||||
SymLocker.Unlock();
|
||||
#endif
|
||||
@@ -650,25 +687,20 @@ void WindowsPlatform::SetHighDpiAwarenessEnabled(bool enable)
|
||||
const HMODULE shCoreDll = LoadLibraryW(L"Shcore.dll");
|
||||
if (!shCoreDll)
|
||||
return;
|
||||
|
||||
typedef enum _PROCESS_DPI_AWARENESS
|
||||
{
|
||||
PROCESS_DPI_UNAWARE = 0,
|
||||
PROCESS_SYSTEM_DPI_AWARE = 1,
|
||||
PROCESS_PER_MONITOR_DPI_AWARE = 2
|
||||
} PROCESS_DPI_AWARENESS;
|
||||
|
||||
typedef HRESULT (STDAPICALLTYPE *SetProcessDpiAwarenessProc)(PROCESS_DPI_AWARENESS Value);
|
||||
const SetProcessDpiAwarenessProc setProcessDpiAwareness = (SetProcessDpiAwarenessProc)GetProcAddress(shCoreDll, "SetProcessDpiAwareness");
|
||||
|
||||
if (setProcessDpiAwareness)
|
||||
{
|
||||
setProcessDpiAwareness(enable ? PROCESS_PER_MONITOR_DPI_AWARE : PROCESS_DPI_UNAWARE);
|
||||
}
|
||||
|
||||
SystemDpi = CalculateDpi(shCoreDll);
|
||||
|
||||
FreeLibrary(shCoreDll);
|
||||
::FreeLibrary(shCoreDll);
|
||||
}
|
||||
|
||||
BatteryInfo WindowsPlatform::GetBatteryInfo()
|
||||
@@ -1108,10 +1140,9 @@ void* WindowsPlatform::LoadLibrary(const Char* filename)
|
||||
SymLocker.Lock();
|
||||
const auto folder = StringUtils::GetDirectoryName(filename);
|
||||
if (!SymbolsPath.Contains(folder))
|
||||
SymbolsPath.Add(folder);
|
||||
if (SymInitialized)
|
||||
{
|
||||
SymModulesDirty = true;
|
||||
SymbolsPath.Add(folder);
|
||||
OnSymbolsPathModified();
|
||||
}
|
||||
SymLocker.Unlock();
|
||||
#endif
|
||||
@@ -1131,46 +1162,16 @@ Array<PlatformBase::StackFrame> WindowsPlatform::GetStackFrames(int32 skipCount,
|
||||
if (!SymInitialized)
|
||||
{
|
||||
SymInitialized = true;
|
||||
|
||||
// Build search path
|
||||
String symbolSearchPath;
|
||||
TCHAR ModulePath[MAX_PATH] = { 0 };
|
||||
if (::GetModuleFileName(::GetModuleHandle(nullptr), ModulePath, MAX_PATH))
|
||||
{
|
||||
symbolSearchPath += StringUtils::GetDirectoryName(ModulePath);
|
||||
symbolSearchPath += ";";
|
||||
}
|
||||
for (auto& path : SymbolsPath)
|
||||
{
|
||||
symbolSearchPath += path;
|
||||
symbolSearchPath += ";";
|
||||
}
|
||||
String _NT_SYMBOL_PATH;
|
||||
if (!Platform::GetEnvironmentVariable(TEXT("_NT_SYMBOL_PATH"), _NT_SYMBOL_PATH))
|
||||
{
|
||||
symbolSearchPath += _NT_SYMBOL_PATH;
|
||||
symbolSearchPath += ";";
|
||||
}
|
||||
symbolSearchPath += Platform::GetWorkingDirectory();
|
||||
symbolSearchPath += ";";
|
||||
|
||||
DWORD options = SymGetOptions();
|
||||
options |= SYMOPT_LOAD_LINES;
|
||||
options |= SYMOPT_FAIL_CRITICAL_ERRORS;
|
||||
options |= SYMOPT_DEFERRED_LOADS;
|
||||
options |= SYMOPT_EXACT_SYMBOLS;
|
||||
SymSetOptions(options);
|
||||
|
||||
SymInitializeW(process, *symbolSearchPath, TRUE);
|
||||
}
|
||||
|
||||
// Refresh modules if needed
|
||||
if (SymModulesDirty)
|
||||
{
|
||||
SymModulesDirty = false;
|
||||
SymRefreshModuleList(process);
|
||||
}
|
||||
|
||||
// Capture the context if missing
|
||||
/*EXCEPTION_POINTERS exceptionPointers;
|
||||
CONTEXT contextData;
|
||||
|
||||
@@ -27,5 +27,13 @@ public class Profiler : EngineModule
|
||||
options.PrivateDependencies.Clear();
|
||||
|
||||
options.PublicDefinitions.Add("COMPILE_WITH_PROFILER");
|
||||
|
||||
// Tracy profiling tools
|
||||
switch (options.Platform.Target)
|
||||
{
|
||||
case TargetPlatform.Windows:
|
||||
options.PublicDependencies.Add("tracy");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
#include <ThirdParty/tracy/Tracy.h>
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
|
||||
@@ -393,12 +394,22 @@ struct TIsPODType<ProfilerCPU::Event>
|
||||
};
|
||||
|
||||
// Shortcut macros for profiling a single code block execution on CPU
|
||||
#define PROFILE_CPU_NAMED(name) ScopeProfileBlockCPU ProfileBlockCPU(TEXT(name))
|
||||
// Use ZoneTransient for Tracy for code that can be hot-reloaded (eg. in Editor)
|
||||
|
||||
#if USE_EDITOR
|
||||
#define PROFILE_CPU_NAMED(name) ZoneTransientN(___tracy_scoped_zone, name, true); ScopeProfileBlockCPU ProfileBlockCPU(TEXT(name))
|
||||
#else
|
||||
#define PROFILE_CPU_NAMED(name) ZoneNamedN(___tracy_scoped_zone, name, true); ScopeProfileBlockCPU ProfileBlockCPU(TEXT(name))
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define PROFILE_CPU() ScopeProfileBlockCPU ProfileBlockCPU(TEXT(__FUNCTION__))
|
||||
#if USE_EDITOR
|
||||
#define PROFILE_CPU() ZoneTransient(___tracy_scoped_zone, true); ScopeProfileBlockCPU ProfileBlockCPU(TEXT(__FUNCTION__))
|
||||
#else
|
||||
#define PROFILE_CPU() \
|
||||
#define PROFILE_CPU() ZoneNamed(___tracy_scoped_zone, true); ScopeProfileBlockCPU ProfileBlockCPU(TEXT(__FUNCTION__))
|
||||
#endif
|
||||
#else
|
||||
#define PROFILE_CPU() ZoneTransient(___tracy_scoped_zone, true); \
|
||||
const char* _functionName = __FUNCTION__; \
|
||||
const int32 _functionNameLength = ARRAY_COUNT(__FUNCTION__); \
|
||||
Char _functionNameBuffer[_functionNameLength + 1]; \
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
|
||||
#include "ProfilerMemory.h"
|
||||
#include "ProfilerCPU.h"
|
||||
|
||||
void ProfilerMemory::OnAllocation(int32 bytes, bool isGC)
|
||||
{
|
||||
// Register allocation during the current CPU event
|
||||
auto thread = ProfilerCPU::GetCurrentThread();
|
||||
if (thread != nullptr && thread->Buffer.GetCount() != 0)
|
||||
{
|
||||
auto& activeEvent = thread->Buffer.Last().Event();
|
||||
if (activeEvent.End < ZeroTolerance)
|
||||
{
|
||||
if (isGC)
|
||||
activeEvent.ManagedMemoryAllocation += bytes;
|
||||
else
|
||||
activeEvent.NativeMemoryAllocation += bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/BaseTypes.h"
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
|
||||
/// <summary>
|
||||
/// Provides memory allocations measuring methods.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API ProfilerMemory
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Called on memory allocation.
|
||||
/// </summary>
|
||||
/// <param name="bytes">The allocated bytes count.</param>
|
||||
/// <param name="isGC">True if allocation comes from the Garbage Collector, otherwise false.</param>
|
||||
static void OnAllocation(int32 bytes, bool isGC);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Platform/Thread.h"
|
||||
#include "Engine/Scripting/MException.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include <ThirdParty/mono-2.0/mono/jit/jit.h>
|
||||
#include <ThirdParty/mono-2.0/mono/utils/mono-counters.h>
|
||||
@@ -182,7 +181,16 @@ void OnGCAllocation(MonoProfiler* profiler, MonoObject* obj)
|
||||
#endif
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
ProfilerMemory::OnAllocation(size, true);
|
||||
// Register allocation during the current CPU event
|
||||
auto thread = ProfilerCPU::GetCurrentThread();
|
||||
if (thread != nullptr && thread->Buffer.GetCount() != 0)
|
||||
{
|
||||
auto& activeEvent = thread->Buffer.Last().Event();
|
||||
if (activeEvent.End < ZeroTolerance)
|
||||
{
|
||||
activeEvent.ManagedMemoryAllocation += size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user