diff --git a/Source/Editor/Windows/Profiler/CPU.cs b/Source/Editor/Windows/Profiler/CPU.cs index 9e79832ab..d33325fa3 100644 --- a/Source/Editor/Windows/Profiler/CPU.cs +++ b/Source/Editor/Windows/Profiler/CPU.cs @@ -5,6 +5,29 @@ using FlaxEditor.GUI; using FlaxEngine; using FlaxEngine.GUI; +namespace FlaxEngine +{ + partial class ProfilerCPU + { + partial struct Event + { + /// + /// Gets the event name. + /// + public unsafe string Name + { + get + { + fixed (char* name = &Name0) + { + return new string(name); + } + } + } + } + } +} + namespace FlaxEditor.Windows.Profiler { /// @@ -204,7 +227,7 @@ namespace FlaxEditor.Windows.Profiler { var e = events[i]; - if (e.Depth == 0 && new string(e.Name) == "Update") + if (e.Depth == 0 && e.Name == "Update") { return new ViewRange(ref e); } @@ -225,7 +248,7 @@ namespace FlaxEditor.Windows.Profiler double scale = 100.0; float x = (float)((e.Start - startTime) * scale); float width = (float)(length * scale); - string name = new string(e.Name).Replace("::", "."); + string name = e.Name.Replace("::", "."); var control = new Timeline.Event(x + xOffset, e.Depth + depthOffset, width) { @@ -399,7 +422,7 @@ namespace FlaxEditor.Windows.Profiler subEventsMemoryTotal += sub.ManagedMemoryAllocation + e.NativeMemoryAllocation; } - string name = new string(e.Name).Replace("::", "."); + string name = e.Name.Replace("::", "."); var row = new Row { diff --git a/Source/Engine/Profiler/ProfilerCPU.cpp b/Source/Engine/Profiler/ProfilerCPU.cpp index eab1a0210..574028af1 100644 --- a/Source/Engine/Profiler/ProfilerCPU.cpp +++ b/Source/Engine/Profiler/ProfilerCPU.cpp @@ -10,6 +10,20 @@ THREADLOCAL ProfilerCPU::Thread* ProfilerCPU::Thread::Current = nullptr; Array> ProfilerCPU::Threads; bool ProfilerCPU::Enabled = false; +ProfilerCPU::EventBuffer::EventBuffer() +{ + _capacity = Math::RoundUpToPowerOf2(10 * 1000); + _capacityMask = _capacity - 1; + _data = NewArray(_capacity); + _head = 0; + _count = 0; +} + +ProfilerCPU::EventBuffer::~EventBuffer() +{ + DeleteArray(_data, _capacity); +} + void ProfilerCPU::EventBuffer::Extract(Array& data, bool withRemove) { data.Clear(); @@ -87,28 +101,23 @@ void ProfilerCPU::EventBuffer::Extract(Array& data, bool withRemove) Platform::MemoryCopy(data.Get() + spaceLeftCount, &_data[0], overflow * sizeof(Event)); } -int32 ProfilerCPU::Thread::BeginEvent(const Char* name) +int32 ProfilerCPU::Thread::BeginEvent() { const double time = Platform::GetTimeSeconds() * 1000.0; const auto index = Buffer.Add(); - Event& e = Buffer.Get(index); e.Start = time; e.End = 0; e.Depth = _depth++; e.NativeMemoryAllocation = 0; e.ManagedMemoryAllocation = 0; - e.Name = name; - return index; } void ProfilerCPU::Thread::EndEvent(int32 index) { const double time = Platform::GetTimeSeconds() * 1000.0; - _depth--; - Event& e = Buffer.Get(index); e.End = time; } @@ -123,7 +132,7 @@ ProfilerCPU::Thread* ProfilerCPU::GetCurrentThread() return Enabled ? Thread::Current : nullptr; } -int32 ProfilerCPU::BeginEvent(const Char* name) +int32 ProfilerCPU::BeginEvent() { if (!Enabled) return -1; @@ -142,8 +151,45 @@ int32 ProfilerCPU::BeginEvent(const Char* name) Thread::Current = thread; Threads.Add(thread); } + return thread->BeginEvent(); +} - return thread->BeginEvent(name); +int32 ProfilerCPU::BeginEvent(const Char* name, bool transient) +{ + if (!Enabled) + return -1; + const auto index = BeginEvent(); + const auto thread = Thread::Current; + auto& e = thread->Buffer.Get(index); + auto dst = e.Name; + auto src = name; + if (src) + { + auto end = dst + ARRAY_COUNT(e.Name) - 1; + while (*src && dst != end) + *dst++ = *src++; + } + *dst = 0; + return index; +} + +int32 ProfilerCPU::BeginEvent(const char* name, bool transient) +{ + if (!Enabled) + return -1; + const auto index = BeginEvent(); + const auto thread = Thread::Current; + auto& e = thread->Buffer.Get(index); + auto dst = e.Name; + auto src = name; + if (src) + { + auto end = dst + ARRAY_COUNT(e.Name) - 1; + while (*src && dst != end) + *dst++ = *src++; + } + *dst = 0; + return index; } void ProfilerCPU::EndEvent(int32 index) diff --git a/Source/Engine/Profiler/ProfilerCPU.h b/Source/Engine/Profiler/ProfilerCPU.h index d5cd55f07..129219b66 100644 --- a/Source/Engine/Profiler/ProfilerCPU.h +++ b/Source/Engine/Profiler/ProfilerCPU.h @@ -5,17 +5,13 @@ #include "Engine/Platform/Platform.h" #include "Engine/Core/NonCopyable.h" #include "Engine/Core/Types/String.h" -#include "Engine/Core/Collections/Array.h" #include "Engine/Core/Math/Math.h" +#include "Engine/Core/Collections/Array.h" #include "Engine/Scripting/ScriptingType.h" #include #if COMPILE_WITH_PROFILER -// Profiler events buffers capacity (tweaked manually) -#define PROFILER_CPU_EVENTS_FRAMES 10 -#define PROFILER_CPU_EVENTS_PER_FRAME 1000 - /// /// Provides CPU performance measuring methods. /// @@ -56,10 +52,7 @@ public: /// API_FIELD() int32 ManagedMemoryAllocation; - /// - /// The name of the event. - /// - API_FIELD() const Char* Name; + API_FIELD(Private, NoArray) Char Name[100]; }; /// @@ -77,26 +70,14 @@ public: public: - EventBuffer() - { - _capacity = Math::RoundUpToPowerOf2(PROFILER_CPU_EVENTS_FRAMES * PROFILER_CPU_EVENTS_PER_FRAME); - _capacityMask = _capacity - 1; - _data = NewArray(_capacity); - _head = 0; - _count = 0; - } - - ~EventBuffer() - { - DeleteArray(_data, _capacity); - } + EventBuffer(); + ~EventBuffer(); public: /// /// Gets the amount of the events in the buffer. /// - /// The events count. FORCE_INLINE int32 GetCount() const { return _count; @@ -170,9 +151,8 @@ public: public: /// - /// Checks if iterator is in the end of the collection + /// Checks if iterator is in the end of the collection. /// - /// True if is in the end, otherwise false bool IsEnd() const { ASSERT(_buffer); @@ -180,9 +160,8 @@ public: } /// - /// Checks if iterator is not in the end of the collection + /// Checks if iterator is not in the end of the collection. /// - /// True if is not in the end, otherwise false bool IsNotEnd() const { ASSERT(_buffer); @@ -287,7 +266,6 @@ public: /// /// Gets the name. /// - /// The name. FORCE_INLINE const String& GetName() const { return _name; @@ -303,9 +281,8 @@ public: /// /// Begins the event running on a this thread. Call EndEvent with index parameter equal to the returned value by BeginEvent function. /// - /// The event name. /// The event token. - int32 BeginEvent(const Char* name); + int32 BeginEvent(); /// /// Ends the event running on a this thread. @@ -331,21 +308,34 @@ public: /// /// Determines whether the current (calling) thread is being profiled by the service (it may has no active profile block but is registered). /// - /// true if service is profiling the current thread; otherwise, false. static bool IsProfilingCurrentThread(); /// /// Gets the current thread (profiler service shadow object). /// - /// The current thread object or null if not profiled yet. static Thread* GetCurrentThread(); /// /// Begins the event. Call EndEvent with index parameter equal to the returned value by BeginEvent function. /// - /// The event name. /// The event token. - static int32 BeginEvent(const Char* name); + static int32 BeginEvent(); + + /// + /// Begins the event. Call EndEvent with index parameter equal to the returned value by BeginEvent function. + /// + /// The event name. + /// True if name is transient and should be cached by allocator (not static). + /// The event token. + static int32 BeginEvent(const Char* name, bool transient = false); + + /// + /// Begins the event. Call EndEvent with index parameter equal to the returned value by BeginEvent function. + /// + /// The event name. + /// True if name is transient and should be cached by allocator (not static). + /// The event token. + static int32 BeginEvent(const char* name, bool transient = false); /// /// Ends the event. @@ -354,7 +344,7 @@ public: static void EndEvent(int32 index); /// - /// Releases resources. Calls to the profiling API after Dispose are not valid + /// Releases resources. Calls to the profiling API after Dispose are not valid. /// static void Dispose(); }; @@ -364,24 +354,19 @@ public: /// struct ScopeProfileBlockCPU { - /// - /// The event token index. - /// int32 Index; - /// - /// Initializes a new instance of the struct. - /// - /// The event name. - ScopeProfileBlockCPU(const Char* name) + FORCE_INLINE ScopeProfileBlockCPU(const Char* name, bool transient = false) { - Index = ProfilerCPU::BeginEvent(name); + Index = ProfilerCPU::BeginEvent(name, transient); } - /// - /// Finalizes an instance of the class. - /// - ~ScopeProfileBlockCPU() + FORCE_INLINE ScopeProfileBlockCPU(const char* name, bool transient = false) + { + Index = ProfilerCPU::BeginEvent(name, transient); + } + + FORCE_INLINE ~ScopeProfileBlockCPU() { ProfilerCPU::EndEvent(Index); } @@ -394,28 +379,27 @@ struct TIsPODType }; // Shortcut macros for profiling a single code block execution on CPU -// Use ZoneTransient for Tracy for code that can be hot-reloaded (eg. in Editor) +// Use ZoneTransient for Tracy for code that can be hot-reloaded (eg. in Editor) or if name can be a variable -#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 +#define PROFILE_CPU_NAMED(name) ZoneTransientN(___tracy_scoped_zone, name, true); ScopeProfileBlockCPU ProfileBlockCPU(name, true) #if defined(_MSC_VER) + #if USE_EDITOR -#define PROFILE_CPU() ZoneTransient(___tracy_scoped_zone, true); ScopeProfileBlockCPU ProfileBlockCPU(TEXT(__FUNCTION__)) +#define PROFILE_CPU() ZoneTransient(___tracy_scoped_zone, true); ScopeProfileBlockCPU ProfileBlockCPU(TEXT(__FUNCTION__), false) #else #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]; \ - StringUtils::ConvertANSI2UTF16(_functionName, _functionNameBuffer, _functionNameLength); \ - _functionNameBuffer[_functionNameLength] = 0; \ - ScopeProfileBlockCPU ProfileBlockCPU(_functionNameBuffer) + +#if USE_EDITOR +#define PROFILE_CPU() ZoneTransient(___tracy_scoped_zone, true); ScopeProfileBlockCPU ProfileBlockCPU(__FUNCTION__) +#else +#define PROFILE_CPU() ZoneNamed(___tracy_scoped_zone, true); ScopeProfileBlockCPU ProfileBlockCPU(_functionNameBuffer) +#endif + #endif #else