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