aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Ridgers <[email protected]>2023-01-24 14:42:51 +0100
committerMartin Ridgers <[email protected]>2023-01-25 14:52:49 +0100
commitb7ba647e14b56a8f9aedb1e9113d06c6bfdad85a (patch)
treeb8a0da460e02251978895d51eb611a2cb65358cb
parent0.2.2 (diff)
downloadzen-b7ba647e14b56a8f9aedb1e9113d06c6bfdad85a.tar.xz
zen-b7ba647e14b56a8f9aedb1e9113d06c6bfdad85a.zip
Updated Trace from Main at 23846526
-rw-r--r--thirdparty/trace/trace.h1976
1 files changed, 1415 insertions, 561 deletions
diff --git a/thirdparty/trace/trace.h b/thirdparty/trace/trace.h
index d7fbbb71f..7930ce88b 100644
--- a/thirdparty/trace/trace.h
+++ b/thirdparty/trace/trace.h
@@ -6,6 +6,8 @@
#pragma once
+// HEADER_UNIT_SKIP - Not included directly
+
#if !defined(TRACE_UE_COMPAT_LAYER)
# if defined(__UNREAL__) && __UNREAL__
# define TRACE_UE_COMPAT_LAYER 0
@@ -37,16 +39,13 @@
# define PLATFORM_APPLE 1
#endif
-#if PLATFORM_MAC
-#endif
-
// arch defines
#if defined(__amd64__) || defined(_M_X64)
# define PLATFORM_CPU_X86_FAMILY 1
# define PLATFORM_CPU_ARM_FAMILY 0
# define PLATFORM_64BITS 1
# define PLATFORM_CACHE_LINE_SIZE 64
-#elif defined(__arm64__) || defined(_M_ARM64)
+#elif defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
# define PLATFORM_CPU_X86_FAMILY 0
# define PLATFORM_CPU_ARM_FAMILY 1
# define PLATFORM_64BITS 1
@@ -56,9 +55,18 @@
#endif
// external includes
+#if defined(_MSC_VER)
+# define _ENABLE_EXTENDED_ALIGNED_STORAGE
+#endif
+
+#include <algorithm>
#include <cstddef>
#include <cstdint>
+#include <cstring>
+#include <string>
+#include <string_view>
#include <utility>
+#include <vector>
#if PLATFORM_WINDOWS
# if !defined(WIN32_LEAN_AND_MEAN)
@@ -95,7 +103,7 @@ using SIZE_T = size_t;
#define TEXT(x) x
#define TCHAR ANSICHAR
using ANSICHAR = char;
-using WIDECHAR = wchar_t;
+using WIDECHAR = char16_t;
// keywords
#if defined(_MSC_VER)
@@ -130,27 +138,229 @@ using WIDECHAR = wchar_t;
#else
# define TRACELOG_API
#endif
+#define TRACEANALYSIS_API TRACELOG_API
#if !defined(IS_MONOLITHIC)
# define IS_MONOLITHIC 0
#endif
// misc defines
+#define TSAN_SAFE
#define THIRD_PARTY_INCLUDES_END
#define THIRD_PARTY_INCLUDES_START
#define TRACE_ENABLED 1
#define TRACE_PRIVATE_CONTROL_ENABLED 0
#define TRACE_PRIVATE_EXTERNAL_LZ4 1
+#define UE_LAUNDER(x) (x)
+#define UE_DEPRECATED(x, ...)
#define UE_TRACE_ENABLED TRACE_ENABLED
-#define UE_BUILD_SHIPPING 1
+#define PREPROCESSOR_JOIN(a,b) PREPROCESSOR_JOIN_IMPL(a,b)
+#define PREPROCESSOR_JOIN_IMPL(a,b) a##b
+#define DEFINE_LOG_CATEGORY_STATIC(...)
+#define UE_LOG(...)
+#define check(x) do { if (!(x)) __debugbreak(); } while (0)
+#define checkf(x, ...) check(x)
+
+#if !defined(UE_BUILD_SHIPPING)
+# define UE_BUILD_SHIPPING 1
+#endif
+#define UE_BUILD_TEST 0
+
+#if defined(__has_builtin)
+# if __has_builtin(__builtin_trap)
+# define PLATFORM_BREAK() do { __builtin_trap(); } while (0)
+# endif
+#elif defined(_MSC_VER)
+# define PLATFORM_BREAK() do { __debugbreak(); } while (0)
+#endif
+
+#if !defined(PLATFORM_BREAK)
+# define PLATFORM_BREAK() do { *(int*)0x493 = 0x493; } while (0)
+#endif
// api
+template <typename T> inline auto Forward(T t) { return std::forward<T>(t); }
+template <typename T> inline auto MoveTemp(T&& t) { return std::move<T>(t); }
+template <typename T> inline void Swap(T& x, T& y) { return std::swap(x, y); }
+
+
+
+template <typename T, typename ALLOCATOR=void>
+struct TArray
+ : public std::vector<T>
+{
+ using Super = std::vector<T>;
+ using Super::vector;
+ using Super::back;
+ using Super::begin;
+ using Super::clear;
+ using Super::data;
+ using Super::emplace_back;
+ using Super::empty;
+ using Super::end;
+ using Super::erase;
+ using Super::front;
+ using Super::insert;
+ using Super::pop_back;
+ using Super::push_back;
+ using Super::reserve;
+ using Super::resize;
+ using Super::size;
+ void Add(const T& t) { push_back(t); }
+ T& Add_GetRef(const T& t) { push_back(t); return back(); }
+ size_t AddUninitialized(size_t n) { resize(size() + n); return size() - n; }
+ void Emplace() { emplace_back(); }
+ T& Emplace_GetRef() { emplace_back(); return back(); }
+ void Insert(T const& t, size_t i) { insert(begin() + i, t); }
+ void Push(const T& t) { push_back(t); }
+ T Pop(bool Eh=true) { T t = back(); pop_back(); return t; }
+ size_t Num() const { return size(); }
+ void SetNum(size_t num) { resize(num); }
+ void SetNumZeroed(size_t num) { resize(num, 0); }
+ void SetNumUninitialized(size_t num) { resize(num); }
+ void Reserve(size_t num) { reserve(num); }
+ T& Last() { return back(); }
+ T* GetData() { return data(); }
+ T const* GetData() const { return data(); }
+ bool IsEmpty() const { return empty(); }
+ void Empty() { clear(); }
+ void Reset() { clear(); }
+ void RemoveAll(bool (*p)(T const&)) { erase(remove_if(begin(), end(), p), end()); }
+ void RemoveAllSwap(bool (*p)(T const&)) { RemoveAll(p); }
+
+ struct NotLess {
+ bool operator () (T const& Lhs, T const& Rhs) const {
+ return bool(Lhs < Rhs) == false;
+ }
+ };
+ void Heapify() { std::make_heap(begin(), end(), NotLess()); }
+ void HeapPush(T const& t) { Add(t); std::push_heap(begin(), end(), NotLess()); }
+ void HeapPopDiscard() { std::pop_heap(begin(), end(), NotLess()); pop_back(); }
+ T const& HeapTop() const { return front(); }
+};
+
+template <size_t S> struct TInlineAllocator {};
+
+template <typename T>
+struct TArrayView
+{
+ TArrayView() = default;
+ TArrayView(T* data, size_t size) : _data(data), _size(size) {}
+ T* GetData() { return _data; }
+ T const* GetData() const { return _data; }
+ size_t Num() const { return _size; }
+ T* _data = nullptr;
+ size_t _size = 0;
+ using value_type = T;
+};
+
+
+template <typename T>
+struct TStringViewAdapter
+ : public std::basic_string_view<T>
+{
+ using Super = std::basic_string_view<T>;
+ using Super::basic_string_view;
+ using Super::size;
+ using Super::data;
+ size_t Len() const { return size(); }
+ const char* GetData() const { return data(); }
+};
+
+struct FStringProxy
+{
+ FStringProxy() = default;
+ template <typename T> FStringProxy(size_t len, const T* ptr);
+ template <typename T> FStringProxy(const T& r) : FStringProxy(r.size(), r.data()) {}
+ std::string _str;
+ const void* _ptr;
+ uint32_t _len;
+ uint32_t _char_size;
+ std::string_view ToView();
+};
+
template <typename T>
-inline auto Forward(T t)
+inline FStringProxy::FStringProxy(size_t len, const T* ptr)
+: _ptr(ptr)
+, _len(uint32_t(len))
+, _char_size(sizeof(T))
{
- return std::forward<T>(t);
}
+inline std::string_view FStringProxy::ToView()
+{
+ if (_char_size != 1)
+ {
+ _char_size = 1;
+ _str.reserve(_len);
+ char* __restrict cursor = _str.data();
+ for (uint32_t i = 0, n = _len; i < n; ++i)
+ cursor[i] = char(((const char16_t*)_ptr)[i]);
+ _ptr = cursor;
+ }
+
+ return std::string_view((const char*)_ptr, _len);
+}
+
+using FAnsiStringView = TStringViewAdapter<char>;
+using FWideStringView = TStringViewAdapter<char16_t>;
+using FString = struct FStringProxy;
+using ANSITEXTVIEW = FAnsiStringView;
+
+
+
+namespace UECompat
+{
+
+template <typename T>
+inline T Max(T const& a, T const& b) { return std::max(a, b); }
+inline size_t Strlen(const char* str) { return ::strlen(str); }
+inline void* Malloc(size_t size) { return ::malloc(size); }
+inline void* Realloc(void* ptr, size_t size) { return ::realloc(ptr, size); }
+inline void Free(void* ptr) { return ::free(ptr); }
+inline void Memcpy(void* d, const void* s, size_t n){ ::memcpy(d, s, n); }
+
+template <typename T, typename COMPARE=std::less<typename T::value_type>>
+inline void StableSort(T& container, COMPARE&& compare=COMPARE())
+{
+ std::stable_sort(container.GetData(), container.GetData() + container.Num(),
+ std::forward<COMPARE>(compare));
+}
+
+template <typename T, typename COMPARE=std::less<typename T::value_type>>
+inline void Sort(T& container, COMPARE&& compare=COMPARE())
+{
+ std::sort(container.GetData(), container.GetData() + container.Num(),
+ std::forward<COMPARE>(compare));
+}
+
+template <typename T, typename P>
+inline void SortBy(T& container, P const& p)
+{
+ Sort(container, [&p] (typename T::value_type& lhs, typename T::value_type& rhs) {
+ return p(lhs) < p(rhs);
+ });
+}
+
+template <typename T, typename V, typename P>
+inline int LowerBoundBy(T const& container, V const& v, P const& p)
+{
+ auto adapter = [&p] (typename T::value_type const& lhs, V const& v) {
+ return p(lhs) < v;
+ };
+ auto* first = container.GetData();
+ auto* last = first + container.Num();
+ auto iter = std::lower_bound(first, last, v, adapter);
+ return int(ptrdiff_t(iter - first));
+}
+
+} // namespace UeCompat
+
+namespace Algo = UECompat;
+namespace FMath = UECompat;
+namespace FCStringAnsi = UECompat;
+namespace FMemory = UECompat;
+
#endif // TRACE_UE_COMPAT_LAYER
#include <cstring>
@@ -166,7 +376,7 @@ inline auto Forward(T t)
#if !defined(UE_TRACE_ENABLED)
# if !UE_BUILD_SHIPPING && !IS_PROGRAM
-# if PLATFORM_WINDOWS || PLATFORM_UNIX || PLATFORM_APPLE || PLATFORM_ANDROID || PLATFORM_HOLOLENS
+# if PLATFORM_WINDOWS || PLATFORM_UNIX || PLATFORM_APPLE || PLATFORM_ANDROID
# define UE_TRACE_ENABLED 1
# endif
# endif
@@ -175,7 +385,7 @@ inline auto Forward(T t)
# define UE_TRACE_ENABLED 0
#endif
#if UE_TRACE_ENABLED
-# define TRACE_PRIVATE_PROTOCOL_5
+# define TRACE_PRIVATE_PROTOCOL_6
#endif
/* {{{1 Trace.h */
@@ -211,24 +421,36 @@ class FChannel;
#define TRACE_PRIVATE_CHANNELEXPR_IS_ENABLED(ChannelsExpr) \
bool(ChannelsExpr)
#define TRACE_PRIVATE_EVENT_DEFINE(LoggerName, EventName) \
- UE::Trace::Private::FEventNode LoggerName##EventName##Event;
+ static UE::Trace::Private::FEventNode LoggerName##EventName##Event##Impl;\
+ UE::Trace::Private::FEventNode& LoggerName##EventName##Event = LoggerName##EventName##Event##Impl;
#define TRACE_PRIVATE_EVENT_BEGIN(LoggerName, EventName, ...) \
- TRACE_PRIVATE_EVENT_BEGIN_IMPL(static, LoggerName, EventName, ##__VA_ARGS__)
+ TRACE_PRIVATE_EVENT_DEFINE(LoggerName, EventName); \
+ TRACE_PRIVATE_EVENT_BEGIN_IMPL(LoggerName, EventName, ##__VA_ARGS__)
#define TRACE_PRIVATE_EVENT_BEGIN_EXTERN(LoggerName, EventName, ...) \
- TRACE_PRIVATE_EVENT_BEGIN_IMPL(extern, LoggerName, EventName, ##__VA_ARGS__)
-#define TRACE_PRIVATE_EVENT_BEGIN_IMPL(LinkageType, LoggerName, EventName, ...) \
- LinkageType TRACE_PRIVATE_EVENT_DEFINE(LoggerName, EventName) \
+ extern UE::Trace::Private::FEventNode& LoggerName##EventName##Event; \
+ TRACE_PRIVATE_EVENT_BEGIN_IMPL(LoggerName, EventName, ##__VA_ARGS__)
+#define TRACE_PRIVATE_EVENT_BEGIN_IMPL(LoggerName, EventName, ...) \
struct F##LoggerName##EventName##Fields \
{ \
enum \
{ \
Important = UE::Trace::Private::FEventInfo::Flag_Important, \
NoSync = UE::Trace::Private::FEventInfo::Flag_NoSync, \
+ Definition8bit = UE::Trace::Private::FEventInfo::Flag_Definition8, \
+ Definition16bit = UE::Trace::Private::FEventInfo::Flag_Definition16, \
+ Definition32bit = UE::Trace::Private::FEventInfo::Flag_Definition32, \
+ Definition64bit = UE::Trace::Private::FEventInfo::Flag_Definition64, \
+ DefinitionBits = UE::Trace::Private::FEventInfo::DefinitionBits, \
PartialEventFlags = (0, ##__VA_ARGS__), \
}; \
- enum : bool { bIsImportant = ((0, ##__VA_ARGS__) & Important) != 0, }; \
+ enum : bool { bIsImportant = ((0, ##__VA_ARGS__) & Important) != 0, bIsDefinition = ((0, ##__VA_ARGS__) & DefinitionBits) != 0,\
+ bIsDefinition8 = ((0, ##__VA_ARGS__) & Definition8bit) != 0, \
+ bIsDefinition16 = ((0, ##__VA_ARGS__) & Definition16bit) != 0,\
+ bIsDefinition32 = ((0, ##__VA_ARGS__) & Definition32bit) != 0, \
+ bIsDefinition64 = ((0, ##__VA_ARGS__) & Definition64bit) != 0,}; \
+ typedef std::conditional_t<bIsDefinition8, UE::Trace::FEventRef8, std::conditional_t<bIsDefinition16, UE::Trace::FEventRef16 , std::conditional_t<bIsDefinition64, UE::Trace::FEventRef64, UE::Trace::FEventRef32>>> DefinitionType;\
static constexpr uint32 GetSize() { return EventProps_Meta::Size; } \
- static uint32 GetUid() { static uint32 Uid = 0; return (Uid = Uid ? Uid : Initialize()); } \
+ static uint32 TSAN_SAFE GetUid() { static uint32 Uid = 0; return (Uid = Uid ? Uid : Initialize()); } \
static uint32 FORCENOINLINE Initialize() \
{ \
static const uint32 Uid_ThreadSafeInit = [] () \
@@ -240,7 +462,7 @@ class FChannel;
FLiteralName(#LoggerName), \
FLiteralName(#EventName), \
(FFieldDesc*)(&Fields), \
- uint16(sizeof(Fields) / sizeof(FFieldDesc)), \
+ EventProps_Meta::NumFields, \
uint16(EventFlags), \
}; \
return LoggerName##EventName##Event.Initialize(&Info); \
@@ -258,21 +480,41 @@ class FChannel;
typedef UE::Trace::TField< \
FieldName##_Meta::Index + 1, \
FieldName##_Meta::Offset + FieldName##_Meta::Size,
+#define TRACE_PRIVATE_EVENT_REFFIELD(RefLogger, RefEventType, FieldName) \
+ F##RefLogger##RefEventType##Fields::DefinitionType> FieldName##_Meta; \
+ FieldName##_Meta const FieldName##_Field = FieldName##_Meta(UE::Trace::FLiteralName(#FieldName), RefLogger##RefEventType##Event.GetUid()); \
+ template <typename DefinitionType> auto FieldName(UE::Trace::TEventRef<DefinitionType> Reference) const { \
+ checkfSlow(Reference.RefTypeId == F##RefLogger##RefEventType##Fields::GetUid(), TEXT("Incorrect reference type passed to event. Field expected %s with uid %u but got a reference with uid %u"), TEXT(#RefEventType), F##RefLogger##RefEventType##Fields::GetUid(), Reference.RefTypeId);\
+ LogScopeType::FFieldSet<FieldName##_Meta, F##RefLogger##RefEventType##Fields::DefinitionType>::Impl((LogScopeType*)this, Reference); \
+ return true; \
+ } \
+ typedef UE::Trace::TField< \
+ FieldName##_Meta::Index + 1, \
+ FieldName##_Meta::Offset + FieldName##_Meta::Size,
#define TRACE_PRIVATE_EVENT_END() \
- UE::Trace::EventProps> EventProps_Meta; \
+ std::conditional<bIsDefinition != 0, DefinitionType, UE::Trace::DisabledField>::type> DefinitionId_Meta;\
+ DefinitionId_Meta const DefinitionId_Field = UE::Trace::FLiteralName("");\
+ static constexpr uint16 NumDefinitionFields = (bIsDefinition != 0) ? 1 : 0;\
+ template<typename RefType>\
+ auto SetDefinitionId(const RefType& Id) const \
+ { \
+ LogScopeType::FFieldSet<DefinitionId_Meta, RefType>::Impl((LogScopeType*)this, Id); \
+ return true; \
+ } \
+ typedef UE::Trace::TField<DefinitionId_Meta::Index + NumDefinitionFields, DefinitionId_Meta::Offset + DefinitionId_Meta::Size, UE::Trace::EventProps> EventProps_Meta; \
EventProps_Meta const EventProps_Private = {}; \
- typedef std::conditional<bIsImportant, UE::Trace::Private::FImportantLogScope, UE::Trace::Private::FLogScope>::type LogScopeType; \
+ typedef std::conditional<bIsImportant != 0, UE::Trace::Private::FImportantLogScope, UE::Trace::Private::FLogScope>::type LogScopeType; \
explicit operator bool () const { return true; } \
enum { EventFlags = PartialEventFlags|((EventProps_Meta::NumAuxFields != 0) ? UE::Trace::Private::FEventInfo::Flag_MaybeHasAux : 0), }; \
static_assert( \
- !bIsImportant || (uint32(EventFlags) & uint32(UE::Trace::Private::FEventInfo::Flag_NoSync)), \
+ (bIsImportant == 0) || (uint32(EventFlags) & uint32(UE::Trace::Private::FEventInfo::Flag_NoSync)), \
"Trace events flagged as Important events must be marked NoSync" \
); \
};
#define TRACE_PRIVATE_LOG_PRELUDE(EnterFunc, LoggerName, EventName, ChannelsExpr, ...) \
if (TRACE_PRIVATE_CHANNELEXPR_IS_ENABLED(ChannelsExpr)) \
if (auto LogScope = F##LoggerName##EventName##Fields::LogScopeType::EnterFunc<F##LoggerName##EventName##Fields>(__VA_ARGS__)) \
- if (const auto& __restrict EventName = *(F##LoggerName##EventName##Fields*)(&LogScope)) \
+ if (const auto& __restrict EventName = *UE_LAUNDER((F##LoggerName##EventName##Fields*)(&LogScope))) \
((void)EventName),
#define TRACE_PRIVATE_LOG_EPILOG() \
LogScope += LogScope
@@ -289,16 +531,24 @@ class FChannel;
TRACE_PRIVATE_LOG_PRELUDE(ScopedStampedEnter, LoggerName, EventName, ChannelsExpr, ##__VA_ARGS__) \
PREPROCESSOR_JOIN(TheScope, __LINE__).SetActive(), \
TRACE_PRIVATE_LOG_EPILOG()
+#define TRACE_PRIVATE_GET_DEFINITION_TYPE_ID(LoggerName, EventName) \
+ F##LoggerName##EventName##Fields::GetUid()
+#define TRACE_PRIVATE_LOG_DEFINITION(LoggerName, EventName, Id, ChannelsExpr, ...) \
+ UE::Trace::MakeEventRef(Id, TRACE_PRIVATE_GET_DEFINITION_TYPE_ID(LoggerName, EventName)); \
+ TRACE_PRIVATE_LOG(LoggerName, EventName, ChannelsExpr, ##__VA_ARGS__) \
+ << EventName.SetDefinitionId(UE::Trace::MakeEventRef(Id, F##LoggerName##EventName##Fields::GetUid()))
#else
#define TRACE_PRIVATE_CHANNEL(ChannelName, ...)
#define TRACE_PRIVATE_CHANNEL_EXTERN(ChannelName, ...)
#define TRACE_PRIVATE_CHANNEL_DEFINE(ChannelName, ...)
#define TRACE_PRIVATE_CHANNELEXPR_IS_ENABLED(ChannelsExpr) \
false
-#define TRACE_PRIVATE_EVENT_DEFINE(LoggerName, EventName)
+#define TRACE_PRIVATE_EVENT_DEFINE(LoggerName, EventName) \
+ int8* LoggerName##EventName##DummyPtr = nullptr;
#define TRACE_PRIVATE_EVENT_BEGIN(LoggerName, EventName, ...) \
TRACE_PRIVATE_EVENT_BEGIN_IMPL(LoggerName, EventName)
#define TRACE_PRIVATE_EVENT_BEGIN_EXTERN(LoggerName, EventName, ...) \
+ extern int8* LoggerName##EventName##DummyPtr; \
TRACE_PRIVATE_EVENT_BEGIN_IMPL(LoggerName, EventName)
#define TRACE_PRIVATE_EVENT_BEGIN_IMPL(LoggerName, EventName) \
struct F##LoggerName##EventName##Dummy \
@@ -314,6 +564,8 @@ class FChannel;
explicit operator bool () const { return false; }
#define TRACE_PRIVATE_EVENT_FIELD(FieldType, FieldName) \
const FTraceDisabled& FieldName;
+#define TRACE_PRIVATE_EVENT_REFFIELD(RefLogger, RefEventType, FieldName) \
+ const FTraceDisabled& FieldName;
#define TRACE_PRIVATE_EVENT_END() \
};
#define TRACE_PRIVATE_LOG(LoggerName, EventName, ...) \
@@ -325,6 +577,11 @@ class FChannel;
#define TRACE_PRIVATE_LOG_SCOPED_T(LoggerName, EventName, ...) \
if (const auto& EventName = *(F##LoggerName##EventName##Dummy*)1) \
EventName
+#define TRACE_PRIVATE_GET_DEFINITION_TYPE_ID(LoggerName, EventName) \
+ 0
+#define TRACE_PRIVATE_LOG_DEFINITION(LoggerName, EventName, Id, ChannelsExpr, ...) \
+ UE::Trace::MakeEventRef(Id, 0); \
+ TRACE_PRIVATE_LOG(LoggerName, EventName, ChannelsExpr, ##__VA_ARGS__)
#endif // UE_TRACE_ENABLED
/* {{{1 Trace.h */
@@ -339,22 +596,80 @@ namespace UE {
namespace Trace {
enum AnsiString {};
enum WideString {};
+template<typename IdType>
+struct TEventRef
+{
+ using ReferenceType = IdType;
+ TEventRef(IdType InId, uint32 InTypeId)
+ : Id(InId)
+ , RefTypeId(InTypeId)
+ {
+ }
+ IdType Id;
+ uint32 RefTypeId;
+ uint64 GetHash() const;
+private:
+ TEventRef() = delete;
+};
+template <>
+inline uint64 TEventRef<uint8>::GetHash() const
+{
+ return (uint64(RefTypeId) << 32) | Id;
+}
+template <>
+inline uint64 TEventRef<uint16>::GetHash() const
+{
+ return (uint64(RefTypeId) << 32) | Id;
+}
+template <>
+inline uint64 TEventRef<uint32>::GetHash() const
+{
+ return (uint64(RefTypeId) << 32) | Id;
+}
+template <>
+inline uint64 TEventRef<uint64>::GetHash() const
+{
+ return (uint64(RefTypeId) << 32) ^ Id;
+}
+typedef TEventRef<uint8> FEventRef8;
+typedef TEventRef<uint16> FEventRef16;
+typedef TEventRef<uint32> FEventRef32;
+typedef TEventRef<uint64> FEventRef64;
+template<typename IdType>
+TEventRef<IdType> MakeEventRef(IdType InId, uint32 InTypeId)
+{
+ return TEventRef<IdType>(InId, InTypeId);
+}
+using OnConnectFunc = void(void);
struct FInitializeDesc
{
- uint32 TailSizeBytes = 4 << 20;
+ uint32 TailSizeBytes = 4 << 20; // can be set to 0 to disable the tail buffer
+ uint32 ThreadSleepTimeInMS = 0;
bool bUseWorkerThread = true;
bool bUseImportantCache = true;
+ OnConnectFunc* OnConnectionFunc = nullptr;
};
+struct FChannelInfo;
typedef void* AllocFunc(SIZE_T, uint32);
typedef void FreeFunc(void*, SIZE_T);
-typedef void ChannelIterFunc(const ANSICHAR*, bool, void*);
+typedef void ChannelIterFunc(const ANSICHAR*, bool, void*);
+/* The callback provides information about a channel and a user provided pointer.
+ Returning false from the callback will stop the enumeration */
+typedef bool ChannelIterCallback(const FChannelInfo& Info, void*/*User*/);
struct FStatistics
{
uint64 BytesSent;
uint64 BytesTraced;
uint64 MemoryUsed;
- uint32 CacheUsed; // Important-marked events are
- uint32 CacheWaste; // stored in the cache.
+ uint32 CacheAllocated; // Total memory allocated in cache buffers
+ uint32 CacheUsed; // Used cache memory; Important-marked events are stored in the cache.
+ uint32 CacheWaste; // Unused memory from retired cache buffers
+};
+struct FSendFlags
+{
+ static const uint16 None = 0;
+ static const uint16 ExcludeTail = 1 << 0; // do not send the tail of historical events
+ static const uint16 _Reserved = 1 << 15; // this bit is used internally
};
UE_TRACE_API void SetMemoryHooks(AllocFunc Alloc, FreeFunc Free) UE_TRACE_IMPL();
UE_TRACE_API void Initialize(const FInitializeDesc& Desc) UE_TRACE_IMPL();
@@ -362,13 +677,15 @@ UE_TRACE_API void StartWorkerThread() UE_TRACE_IMPL();
UE_TRACE_API void Shutdown() UE_TRACE_IMPL();
UE_TRACE_API void Update() UE_TRACE_IMPL();
UE_TRACE_API void GetStatistics(FStatistics& Out) UE_TRACE_IMPL();
-UE_TRACE_API bool SendTo(const TCHAR* Host, uint32 Port=0) UE_TRACE_IMPL(false);
-UE_TRACE_API bool WriteTo(const TCHAR* Path) UE_TRACE_IMPL(false);
+UE_TRACE_API bool SendTo(const TCHAR* Host, uint32 Port=0, uint16 Flags=FSendFlags::None) UE_TRACE_IMPL(false);
+UE_TRACE_API bool WriteTo(const TCHAR* Path, uint16 Flags=FSendFlags::None) UE_TRACE_IMPL(false);
+UE_TRACE_API bool WriteSnapshotTo(const TCHAR* Path) UE_TRACE_IMPL(false);
UE_TRACE_API bool IsTracing() UE_TRACE_IMPL(false);
UE_TRACE_API bool Stop() UE_TRACE_IMPL(false);
UE_TRACE_API bool IsChannel(const TCHAR* ChanneName) UE_TRACE_IMPL(false);
UE_TRACE_API bool ToggleChannel(const TCHAR* ChannelName, bool bEnabled) UE_TRACE_IMPL(false);
-UE_TRACE_API void EnumerateChannels(ChannelIterFunc IterFunc, void* User);
+UE_TRACE_API void EnumerateChannels(ChannelIterFunc IterFunc, void* User) UE_TRACE_IMPL();
+UE_TRACE_API void EnumerateChannels(ChannelIterCallback IterFunc, void* User) UE_TRACE_IMPL();
UE_TRACE_API void ThreadRegister(const TCHAR* Name, uint32 SystemId, int32 SortHint) UE_TRACE_IMPL();
UE_TRACE_API void ThreadGroupBegin(const TCHAR* Name) UE_TRACE_IMPL();
UE_TRACE_API void ThreadGroupEnd() UE_TRACE_IMPL();
@@ -378,10 +695,13 @@ UE_TRACE_API void ThreadGroupEnd() UE_TRACE_IMPL();
#define UE_TRACE_EVENT_BEGIN(LoggerName, EventName, ...) TRACE_PRIVATE_EVENT_BEGIN(LoggerName, EventName, ##__VA_ARGS__)
#define UE_TRACE_EVENT_BEGIN_EXTERN(LoggerName, EventName, ...) TRACE_PRIVATE_EVENT_BEGIN_EXTERN(LoggerName, EventName, ##__VA_ARGS__)
#define UE_TRACE_EVENT_FIELD(FieldType, FieldName) TRACE_PRIVATE_EVENT_FIELD(FieldType, FieldName)
+#define UE_TRACE_EVENT_REFERENCE_FIELD(RefLogger, RefEvent, FieldName) TRACE_PRIVATE_EVENT_REFFIELD(RefLogger, RefEvent, FieldName)
#define UE_TRACE_EVENT_END() TRACE_PRIVATE_EVENT_END()
#define UE_TRACE_LOG(LoggerName, EventName, ChannelsExpr, ...) TRACE_PRIVATE_LOG(LoggerName, EventName, ChannelsExpr, ##__VA_ARGS__)
#define UE_TRACE_LOG_SCOPED(LoggerName, EventName, ChannelsExpr, ...) TRACE_PRIVATE_LOG_SCOPED(LoggerName, EventName, ChannelsExpr, ##__VA_ARGS__)
#define UE_TRACE_LOG_SCOPED_T(LoggerName, EventName, ChannelsExpr, ...) TRACE_PRIVATE_LOG_SCOPED_T(LoggerName, EventName, ChannelsExpr, ##__VA_ARGS__)
+#define UE_TRACE_GET_DEFINITION_TYPE_ID(LoggerName, EventName) TRACE_PRIVATE_GET_DEFINITION_TYPE_ID(LoggerName, EventName)
+#define UE_TRACE_LOG_DEFINITION(LoggerName, EventName, Id, ChannelsExpr, ...) TRACE_PRIVATE_LOG_DEFINITION(LoggerName, EventName, Id, ChannelsExpr, ##__VA_ARGS__)
#define UE_TRACE_CHANNEL(ChannelName, ...) TRACE_PRIVATE_CHANNEL(ChannelName, ##__VA_ARGS__)
#define UE_TRACE_CHANNEL_EXTERN(ChannelName, ...) TRACE_PRIVATE_CHANNEL_EXTERN(ChannelName, ##__VA_ARGS__)
#define UE_TRACE_CHANNEL_DEFINE(ChannelName, ...) TRACE_PRIVATE_CHANNEL_DEFINE(ChannelName, ##__VA_ARGS__)
@@ -391,7 +711,15 @@ UE_TRACE_API void ThreadGroupEnd() UE_TRACE_IMPL();
#if UE_TRACE_ENABLED
namespace UE {
namespace Trace {
+struct FChannelInfo
+{
+ const ANSICHAR* Name;
+ const ANSICHAR* Desc;
+ bool bIsEnabled;
+ bool bIsReadOnly;
+};
typedef void ChannelIterFunc(const ANSICHAR*, bool, void*);
+typedef bool ChannelIterCallback(const FChannelInfo& OutChannelInfo, void*);
/*
A named channel which can be used to filter trace events. Channels can be
combined using the '|' operator which allows expressions like
@@ -425,7 +753,9 @@ public:
static bool Toggle(const ANSICHAR* ChannelName, bool bEnabled);
static void ToggleAll(bool bEnabled);
static FChannel* FindChannel(const ANSICHAR* ChannelName);
+ UE_DEPRECATED(5.2, "Please use the ChannelIterCallback overload for enumerating channels.")
static void EnumerateChannels(ChannelIterFunc Func, void* User);
+ static void EnumerateChannels(ChannelIterCallback Func, void* User);
bool Toggle(bool bEnabled);
bool IsEnabled() const;
explicit operator bool () const;
@@ -608,22 +938,27 @@ enum : uint8
Field_SpecialMask = 0030,
Field_Pod = 0000,
Field_String = 0010,
- /*Field_Unused_2 = 0020,
+ Field_Signed = 0020,
+ /*Field_Unused_3 = 0030,
...
Field_Unused_7 = 0070,*/
};
enum class EFieldType : uint8
{
- Bool = Field_Pod | Field_Integer | Field_8,
- Int8 = Field_Pod | Field_Integer | Field_8,
- Int16 = Field_Pod | Field_Integer | Field_16,
- Int32 = Field_Pod | Field_Integer | Field_32,
- Int64 = Field_Pod | Field_Integer | Field_64,
- Pointer = Field_Pod | Field_Integer | Field_Ptr,
- Float32 = Field_Pod | Field_Float | Field_32,
- Float64 = Field_Pod | Field_Float | Field_64,
- AnsiString = Field_String | Field_Integer|Field_Array | Field_8,
- WideString = Field_String | Field_Integer|Field_Array | Field_16,
+ Bool = Field_Pod | Field_Integer | Field_8,
+ Int8 = Field_Pod | Field_Integer|Field_Signed | Field_8,
+ Int16 = Field_Pod | Field_Integer|Field_Signed | Field_16,
+ Int32 = Field_Pod | Field_Integer|Field_Signed | Field_32,
+ Int64 = Field_Pod | Field_Integer|Field_Signed | Field_64,
+ Uint8 = Field_Pod | Field_Integer | Field_8,
+ Uint16 = Field_Pod | Field_Integer | Field_16,
+ Uint32 = Field_Pod | Field_Integer | Field_32,
+ Uint64 = Field_Pod | Field_Integer | Field_64,
+ Pointer = Field_Pod | Field_Integer | Field_Ptr,
+ Float32 = Field_Pod | Field_Float | Field_32,
+ Float64 = Field_Pod | Field_Float | Field_64,
+ AnsiString = Field_String | Field_Integer|Field_Array | Field_8,
+ WideString = Field_String | Field_Integer|Field_Array | Field_16,
Array = Field_Array,
};
struct FNewEventEvent
@@ -891,6 +1226,74 @@ static_assert(sizeof(FAuxHeader) == 4, "Struct layout assumption doesn't match e
} // namespace Protocol5
} // namespace Trace
} // namespace UE
+/* {{{1 Protocol6.h */
+
+namespace UE {
+namespace Trace {
+#if defined(TRACE_PRIVATE_PROTOCOL_6)
+inline
+#endif
+namespace Protocol6
+{
+enum EProtocol : uint8 { Id = 6 };
+using Protocol5::EFieldType;
+using Protocol5::FEventHeader;
+using Protocol5::FImportantEventHeader;
+using Protocol5::FEventHeaderSync;
+using Protocol5::FAuxHeader;
+using Protocol5::EKnownEventUids;
+enum class EEventFlags : uint8
+{
+ Important = 1 << 0,
+ MaybeHasAux = 1 << 1,
+ NoSync = 1 << 2,
+ Definition = 1 << 3,
+};
+enum EFieldFamily : uint8
+{
+ Regular,
+ Reference,
+ DefinitionId,
+};
+struct FNewEventEvent
+{
+ uint16 EventUid;
+ uint8 FieldCount;
+ uint8 Flags;
+ uint8 LoggerNameSize;
+ uint8 EventNameSize;
+ struct
+ {
+ uint8 FieldType;
+ union
+ {
+ struct
+ {
+ uint16 Offset;
+ uint16 Size;
+ uint8 TypeInfo;
+ uint8 NameSize;
+ } Regular;
+ struct
+ {
+ uint16 Offset;
+ uint16 RefUid;
+ uint8 TypeInfo;
+ uint8 NameSize;
+ } Reference;
+ struct
+ {
+ uint16 Offset;
+ uint16 Unused1;
+ uint8 Unused2;
+ uint8 TypeInfo;
+ } DefinitionId;
+ };
+ } Fields[];
+};
+} // namespace Protocol6
+} // namespace Trace
+} // namespace UE
/* {{{1 Protocol.h */
#if defined(_MSC_VER)
@@ -908,20 +1311,19 @@ namespace Trace {
namespace Private {
struct FWriteBuffer
{
- uint8 Overflow[6];
- uint16 Size;
+ uint8 Overflow[8];
uint64 PrevTimestamp;
FWriteBuffer* __restrict NextThread;
- FWriteBuffer* __restrict NextBuffer;
+ FWriteBuffer* volatile NextBuffer;
uint8* __restrict Cursor;
uint8* __restrict volatile Committed;
uint8* __restrict Reaped;
int32 volatile EtxOffset;
- int16 Partial;
+ uint16 Size;
uint16 ThreadId;
};
TRACELOG_API uint64 TimeGetTimestamp();
-TRACELOG_API FWriteBuffer* Writer_NextBuffer(int32);
+TRACELOG_API FWriteBuffer* Writer_NextBuffer();
TRACELOG_API FWriteBuffer* Writer_GetBuffer();
#if IS_MONOLITHIC
extern thread_local FWriteBuffer* GTlsWriteBuffer;
@@ -955,17 +1357,20 @@ UE_TRACE_API void Field_WriteAuxData(uint32, const uint8*, int32);
UE_TRACE_API void Field_WriteStringAnsi(uint32, const ANSICHAR*, int32);
UE_TRACE_API void Field_WriteStringAnsi(uint32, const WIDECHAR*, int32);
UE_TRACE_API void Field_WriteStringWide(uint32, const WIDECHAR*, int32);
+class FEventNode;
} // namespace Private
+enum DisabledField {};
template <typename Type> struct TFieldType;
+template <> struct TFieldType<DisabledField>{ enum { Tid = 0, Size = 0 }; };
template <> struct TFieldType<bool> { enum { Tid = int(EFieldType::Bool), Size = sizeof(bool) }; };
template <> struct TFieldType<int8> { enum { Tid = int(EFieldType::Int8), Size = sizeof(int8) }; };
template <> struct TFieldType<int16> { enum { Tid = int(EFieldType::Int16), Size = sizeof(int16) }; };
template <> struct TFieldType<int32> { enum { Tid = int(EFieldType::Int32), Size = sizeof(int32) }; };
template <> struct TFieldType<int64> { enum { Tid = int(EFieldType::Int64), Size = sizeof(int64) }; };
-template <> struct TFieldType<uint8> { enum { Tid = int(EFieldType::Int8), Size = sizeof(uint8) }; };
-template <> struct TFieldType<uint16> { enum { Tid = int(EFieldType::Int16), Size = sizeof(uint16) }; };
-template <> struct TFieldType<uint32> { enum { Tid = int(EFieldType::Int32), Size = sizeof(uint32) }; };
-template <> struct TFieldType<uint64> { enum { Tid = int(EFieldType::Int64), Size = sizeof(uint64) }; };
+template <> struct TFieldType<uint8> { enum { Tid = int(EFieldType::Uint8), Size = sizeof(uint8) }; };
+template <> struct TFieldType<uint16> { enum { Tid = int(EFieldType::Uint16), Size = sizeof(uint16) }; };
+template <> struct TFieldType<uint32> { enum { Tid = int(EFieldType::Uint32), Size = sizeof(uint32) }; };
+template <> struct TFieldType<uint64> { enum { Tid = int(EFieldType::Uint64), Size = sizeof(uint64) }; };
template <> struct TFieldType<float> { enum { Tid = int(EFieldType::Float32),Size = sizeof(float) }; };
template <> struct TFieldType<double> { enum { Tid = int(EFieldType::Float64),Size = sizeof(double) }; };
template <class T> struct TFieldType<T*> { enum { Tid = int(EFieldType::Pointer),Size = sizeof(void*) }; };
@@ -1005,12 +1410,13 @@ struct FLiteralName
};
struct FFieldDesc
{
- FFieldDesc(const FLiteralName& Name, uint8 Type, uint16 Offset, uint16 Size)
+ FFieldDesc(const FLiteralName& Name, uint8 Type, uint16 Offset, uint16 Size, uint32 ReferencedUid = 0)
: Name(Name.Ptr)
, ValueOffset(Offset)
, ValueSize(Size)
, NameSize(Name.Length)
, TypeInfo(Type)
+ , Reference(ReferencedUid)
{
}
const ANSICHAR* Name;
@@ -1018,6 +1424,7 @@ struct FFieldDesc
uint16 ValueSize;
uint8 NameSize;
uint8 TypeInfo;
+ uint32 Reference;
};
template <int InIndex, int InOffset, typename Type> struct TField;
enum class EIndexPack
@@ -1065,6 +1472,16 @@ struct TField<InIndex, InOffset, WideString>
{
TRACE_PRIVATE_FIELD(InIndex + int(EIndexPack::AuxFieldCounter), InOffset, WideString);
};
+template <int InIndex, int InOffset, typename DefinitionType>
+struct TField<InIndex, InOffset, TEventRef<DefinitionType>>
+{
+ TRACE_PRIVATE_FIELD(InIndex, InOffset, DefinitionType);
+public:
+ TField(const FLiteralName& Name, uint32 ReferencedUid)
+ : FieldDesc(Name, Tid, Offset, Size, ReferencedUid)
+ {
+ }
+};
template <int InIndex, int InOffset, typename Type>
struct TField
{
@@ -1099,6 +1516,11 @@ struct FEventInfo
Flag_Important = 1 << 0,
Flag_MaybeHasAux = 1 << 1,
Flag_NoSync = 1 << 2,
+ Flag_Definition8 = 1 << 3,
+ Flag_Definition16 = 1 << 4,
+ Flag_Definition32 = 1 << 5,
+ Flag_Definition64 = 1 << 6,
+ DefinitionBits = Flag_Definition8 | Flag_Definition16 | Flag_Definition32 | Flag_Definition64,
};
FLiteralName LoggerName;
FLiteralName EventName;
@@ -1114,6 +1536,7 @@ public:
const FEventNode* GetNext();
void* Inner;
};
+ static FIter Read();
static FIter ReadNew();
static void OnConnect();
TRACELOG_API uint32 Initialize(const FEventInfo* InInfo);
@@ -1194,7 +1617,7 @@ TRACELOG_API FNextSharedBuffer Writer_NextSharedBuffer(FSharedBuffer*, int32,
template <class T>
FORCENOINLINE FImportantLogScope FImportantLogScope::Enter(uint32 ArrayDataSize)
{
- static_assert(uint32(T::EventFlags) & uint32(FEventInfo::Flag_MaybeHasAux), "Only important trace events with array-type fields need a size parameter to UE_TRACE_LOG()");
+ static_assert(!!(uint32(T::EventFlags) & uint32(FEventInfo::Flag_MaybeHasAux)), "Only important trace events with array-type fields need a size parameter to UE_TRACE_LOG()");
ArrayDataSize += sizeof(FAuxHeader) * T::EventProps_Meta::NumAuxFields;
ArrayDataSize += 1; // for AuxDataTerminal
uint32 Size = T::GetSize();
@@ -1227,11 +1650,10 @@ inline FImportantLogScope FImportantLogScope::EnterImpl(uint32 Uid, uint32 Size)
}
int32 Bias = (RegionStart >> FSharedBuffer::CursorShift);
uint8* Out = (uint8*)Buffer - Bias;
- auto* Header = (FImportantEventHeader*)Out;
- Header->Uid = uint16(Uid);
- Header->Size = uint16(Size);
+ uint16 Values16[] = { uint16(Uid), uint16(Size) };
+ memcpy(Out, Values16, sizeof(Values16)); /* FImportantEventHeader::Uid,Size */
FImportantLogScope Ret;
- Ret.Ptr = Header->Data;
+ Ret.Ptr = Out + sizeof(FImportantEventHeader);
Ret.BufferOffset = int32(PTRINT(Buffer) - PTRINT(Ret.Ptr));
Ret.AuxCursor = 0;
return Ret;
@@ -1256,11 +1678,12 @@ struct FImportantLogScope::FFieldSet<FieldMeta, Type[]>
static void Impl(FImportantLogScope* Scope, Type const* Data, int32 Num)
{
uint32 Size = Num * sizeof(Type);
- auto* Header = (FAuxHeader*)(Scope->Ptr + Scope->AuxCursor);
- Header->Pack = Size << FAuxHeader::SizeShift;
- Header->Pack |= (FieldMeta::Index & int32(EIndexPack::NumFieldsMask)) << FAuxHeader::FieldShift;
- Header->Uid = uint8(EKnownEventUids::AuxData);
- memcpy(Header + 1, Data, Size);
+ uint32 Pack = Size << FAuxHeader::SizeShift;
+ Pack |= (FieldMeta::Index & int32(EIndexPack::NumFieldsMask)) << FAuxHeader::FieldShift;
+ uint8* Out = Scope->Ptr + Scope->AuxCursor;
+ memcpy(Out, &Pack, sizeof(Pack)); /* FAuxHeader::Pack */
+ Out[0] = uint8(EKnownEventUids::AuxData); /* FAuxHeader::Uid */
+ memcpy(Out + sizeof(FAuxHeader), Data, Size);
Scope->AuxCursor += sizeof(FAuxHeader) + Size;
Scope->Ptr[Scope->AuxCursor] = uint8(EKnownEventUids::AuxDataTerminal);
}
@@ -1274,11 +1697,12 @@ struct FImportantLogScope::FFieldSet<FieldMeta, AnsiString>
{
Length = int32(strlen(String));
}
- auto* Header = (FAuxHeader*)(Scope->Ptr + Scope->AuxCursor);
- Header->Pack = Length << FAuxHeader::SizeShift;
- Header->Pack |= (FieldMeta::Index & int32(EIndexPack::NumFieldsMask)) << FAuxHeader::FieldShift;
- Header->Uid = uint8(EKnownEventUids::AuxData);
- memcpy(Header + 1, String, Length);
+ uint32 Pack = Length << FAuxHeader::SizeShift;
+ Pack |= (FieldMeta::Index & int32(EIndexPack::NumFieldsMask)) << FAuxHeader::FieldShift;
+ uint8* Out = Scope->Ptr + Scope->AuxCursor;
+ memcpy(Out, &Pack, sizeof(Pack)); /* FAuxHeader::FieldIndex_Size */
+ Out[0] = uint8(EKnownEventUids::AuxData); /* FAuxHeader::Uid */
+ memcpy(Out + sizeof(FAuxHeader), String, Length);
Scope->AuxCursor += sizeof(FAuxHeader) + Length;
Scope->Ptr[Scope->AuxCursor] = uint8(EKnownEventUids::AuxDataTerminal);
}
@@ -1289,11 +1713,12 @@ struct FImportantLogScope::FFieldSet<FieldMeta, AnsiString>
Length = 0;
for (const WIDECHAR* c = String; *c; ++c, ++Length);
}
- auto* Header = (FAuxHeader*)(Scope->Ptr + Scope->AuxCursor);
- Header->Pack = Length << FAuxHeader::SizeShift;
- Header->Pack |= (FieldMeta::Index & int32(EIndexPack::NumFieldsMask)) << FAuxHeader::FieldShift;
- Header->Uid = uint8(EKnownEventUids::AuxData);
- auto* Out = (int8*)(Header + 1);
+ uint32 Pack = Length << FAuxHeader::SizeShift;
+ Pack |= (FieldMeta::Index & int32(EIndexPack::NumFieldsMask)) << FAuxHeader::FieldShift;
+ uint8* Out = Scope->Ptr + Scope->AuxCursor;
+ memcpy(Out, &Pack, sizeof(Pack)); /* FAuxHeader::FieldIndex_Size */
+ Out[0] = uint8(EKnownEventUids::AuxData); /* FAuxHeader::Uid */
+ Out += sizeof(FAuxHeader);
for (int32 i = 0; i < Length; ++i)
{
*Out = int8(*String);
@@ -1315,15 +1740,24 @@ struct FImportantLogScope::FFieldSet<FieldMeta, WideString>
for (const WIDECHAR* c = String; *c; ++c, ++Length);
}
uint32 Size = Length * sizeof(WIDECHAR);
- auto* Header = (FAuxHeader*)(Scope->Ptr + Scope->AuxCursor);
- Header->Pack = Size << FAuxHeader::SizeShift;
- Header->Pack |= (FieldMeta::Index & int32(EIndexPack::NumFieldsMask)) << FAuxHeader::FieldShift;
- Header->Uid = uint8(EKnownEventUids::AuxData);
- memcpy(Header + 1, String, Size);
+ uint32 Pack = Size << FAuxHeader::SizeShift;
+ Pack |= (FieldMeta::Index & int32(EIndexPack::NumFieldsMask)) << FAuxHeader::FieldShift;
+ uint8* Out = Scope->Ptr + Scope->AuxCursor;
+ memcpy(Out, &Pack, sizeof(Pack));
+ Out[0] = uint8(EKnownEventUids::AuxData);
+ memcpy(Out + sizeof(FAuxHeader), String, Size);
Scope->AuxCursor += sizeof(FAuxHeader) + Size;
Scope->Ptr[Scope->AuxCursor] = uint8(EKnownEventUids::AuxDataTerminal);
}
};
+template <typename FieldMeta, typename DefinitionType>
+struct FImportantLogScope::FFieldSet<FieldMeta, TEventRef<DefinitionType>>
+{
+ static void Impl(FImportantLogScope* Scope, const TEventRef<DefinitionType>& Reference)
+ {
+ FFieldSet<FieldMeta, DefinitionType>::Impl(Scope, Reference.Id);
+ }
+};
} // namespace Private
} // namespace Trace
} // namespace UE
@@ -1426,25 +1860,33 @@ inline void FLogScope::EnterPrelude(uint32 Size)
{
uint32 AllocSize = sizeof(HeaderType) + Size;
Buffer = Writer_GetBuffer();
- Buffer->Cursor += AllocSize;
- if (UNLIKELY(Buffer->Cursor > (uint8*)Buffer))
+ if (UNLIKELY(Buffer->Cursor + AllocSize > (uint8*)Buffer))
{
- Buffer = Writer_NextBuffer(AllocSize);
+ Buffer = Writer_NextBuffer();
}
- Ptr = Buffer->Cursor - Size;
+#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST
+ if (AllocSize >= Buffer->Size)
+ {
+ PLATFORM_BREAK();
+ }
+#endif
+ Ptr = Buffer->Cursor + sizeof(HeaderType);
+ Buffer->Cursor += AllocSize;
}
inline void FLogScope::Enter(uint32 Uid, uint32 Size)
{
EnterPrelude<FEventHeaderSync>(Size);
- auto* Header = (uint16*)(Ptr - sizeof(FEventHeaderSync::SerialHigh));
- *(uint32*)(Header - 1) = uint32(AtomicAddRelaxed(&GLogSerial, 1u));
- Header[-2] = uint16(Uid)|int32(EKnownEventUids::Flag_TwoByteUid);
+ uint16 Uid16 = uint16(Uid) | int32(EKnownEventUids::Flag_TwoByteUid);
+ uint32 Serial = uint32(AtomicAddRelaxed(&GLogSerial, 1u));
+ memcpy(Ptr - 3, &Serial, sizeof(Serial)); /* FEventHeaderSync::SerialHigh,SerialLow */
+ memcpy(Ptr - 5, &Uid16, sizeof(Uid16)); /* FEventHeaderSync::Uid */
}
inline void FLogScope::EnterNoSync(uint32 Uid, uint32 Size)
{
EnterPrelude<FEventHeader>(Size);
+ uint16 Uid16 = uint16(Uid) | int32(EKnownEventUids::Flag_TwoByteUid);
auto* Header = (uint16*)(Ptr);
- Header[-1] = uint16(Uid)|int32(EKnownEventUids::Flag_TwoByteUid);
+ memcpy(Header - 1, &Uid16, sizeof(Uid16)); /* FEventHeader::Uid */
}
template </*bMaybeHasAux*/>
inline void TLogScope<false>::operator += (const FLogScope&) const
@@ -1469,7 +1911,7 @@ inline FScopedLogScope::~FScopedLogScope()
FWriteBuffer* Buffer = Writer_GetBuffer();
if (UNLIKELY(int32((uint8*)Buffer - Buffer->Cursor) < int32(sizeof(LeaveUid))))
{
- Buffer = Writer_NextBuffer(0);
+ Buffer = Writer_NextBuffer();
}
Buffer->Cursor[0] = LeaveUid;
Buffer->Cursor += sizeof(LeaveUid);
@@ -1489,7 +1931,7 @@ inline FScopedStampedLogScope::~FScopedStampedLogScope()
uint64 Stamp = Writer_GetTimestamp(Buffer);
if (UNLIKELY(int32((uint8*)Buffer - Buffer->Cursor) < int32(sizeof(Stamp))))
{
- Buffer = Writer_NextBuffer(0);
+ Buffer = Writer_NextBuffer();
}
Stamp <<= 8;
Stamp += uint8(EKnownEventUids::LeaveScope_T) << EKnownEventUids::_UidShift;
@@ -1515,7 +1957,7 @@ FORCENOINLINE auto FLogScope::ScopedEnter()
FWriteBuffer* Buffer = Writer_GetBuffer();
if (UNLIKELY(int32((uint8*)Buffer - Buffer->Cursor) < int32(sizeof(EnterUid))))
{
- Buffer = Writer_NextBuffer(0);
+ Buffer = Writer_NextBuffer();
}
Buffer->Cursor[0] = EnterUid;
Buffer->Cursor += sizeof(EnterUid);
@@ -1529,7 +1971,7 @@ FORCENOINLINE auto FLogScope::ScopedStampedEnter()
FWriteBuffer* Buffer = Writer_GetBuffer();
if (UNLIKELY(int32((uint8*)Buffer - Buffer->Cursor) < int32(sizeof(Stamp))))
{
- Buffer = Writer_NextBuffer(0);
+ Buffer = Writer_NextBuffer();
}
Stamp = Writer_GetTimestamp(Buffer);
Stamp <<= 8;
@@ -1602,6 +2044,14 @@ struct FLogScope::FFieldSet<FieldMeta, WideString>
Field_WriteStringWide(Index, String, Length);
}
};
+template <typename FieldMeta, typename DefinitionType>
+struct FLogScope::FFieldSet<FieldMeta, TEventRef<DefinitionType>>
+{
+ static void Impl(FLogScope* Scope, const TEventRef<DefinitionType>& Reference)
+ {
+ FFieldSet<FieldMeta, DefinitionType>::Impl(Scope, Reference.Id);
+ }
+};
} // namespace Private
} // namespace Trace
} // namespace UE
@@ -1638,7 +2088,7 @@ struct FTidPacketBase
enum : uint16
{
EncodedMarker = 0x8000,
- PartialMarker = 0x4000,
+ PartialMarker = 0x4000, // now unused. fragmented aux-data has an event header
ThreadIdMask = PartialMarker - 1,
};
uint16 PacketSize;
@@ -1698,9 +2148,11 @@ template <int BufferSize>
class TWriteBufferRedirect
{
public:
+ enum : uint16 { ActiveRedirection = 0xffff };
TWriteBufferRedirect();
~TWriteBufferRedirect();
void Close();
+ void Abandon();
uint8* GetData();
uint32 GetSize() const;
uint32 GetCapacity() const;
@@ -1716,6 +2168,8 @@ inline TWriteBufferRedirect<BufferSize>::TWriteBufferRedirect()
Reset();
PrevBuffer = GTlsWriteBuffer;
GTlsWriteBuffer = &Buffer;
+ Buffer.Size = uint16(BufferSize);
+ Buffer.ThreadId = ActiveRedirection;
}
template <int BufferSize>
inline TWriteBufferRedirect<BufferSize>::~TWriteBufferRedirect()
@@ -1733,6 +2187,11 @@ inline void TWriteBufferRedirect<BufferSize>::Close()
PrevBuffer = nullptr;
}
template <int BufferSize>
+inline void TWriteBufferRedirect<BufferSize>::Abandon()
+{
+ PrevBuffer = nullptr;
+}
+template <int BufferSize>
inline uint8* TWriteBufferRedirect<BufferSize>::GetData()
{
return Buffer.Reaped;
@@ -1785,7 +2244,7 @@ T_ALIGN static UPTRINT volatile GPoolFutex; // = 0
T_ALIGN static FPoolPage* volatile GPoolPageList; // = nullptr;
static uint32 GPoolUsage; // = 0;
#undef T_ALIGN
-static FPoolBlockList Writer_AddPageToPool(uint32 PageSize)
+static FPoolBlockList Writer_AllocateBlockList(uint32 PageSize)
{
uint8* PageBase = (uint8*)Writer_MemoryAllocate(PageSize, PLATFORM_CACHE_LINE_SIZE);
GPoolUsage += PageSize;
@@ -1802,7 +2261,7 @@ static FPoolBlockList Writer_AddPageToPool(uint32 PageSize)
{
break;
}
- Buffer->NextBuffer = (FWriteBuffer*)(Block + GPoolBlockSize);
+ AtomicStoreRelaxed(&(Buffer->NextBuffer), (FWriteBuffer*)(Block + GPoolBlockSize));
Block += GPoolBlockSize;
}
FWriteBuffer* NextBuffer = (FWriteBuffer*)FirstBlock;
@@ -1821,7 +2280,8 @@ FWriteBuffer* Writer_AllocateBlockFromPool()
FWriteBuffer* Owned = AtomicLoadRelaxed(&GPoolFreeList);
if (Owned != nullptr)
{
- if (!AtomicCompareExchangeRelaxed(&GPoolFreeList, Owned->NextBuffer, Owned))
+ FWriteBuffer* OwnedNext = AtomicLoadRelaxed(&(Owned->NextBuffer));
+ if (!AtomicCompareExchangeAcquire(&GPoolFreeList, OwnedNext, Owned))
{
PlatformYield();
continue;
@@ -1838,12 +2298,13 @@ FWriteBuffer* Writer_AllocateBlockFromPool()
ThreadSleep(0);
continue;
}
- FPoolBlockList BlockList = Writer_AddPageToPool(GPoolPageSize);
+ FPoolBlockList BlockList = Writer_AllocateBlockList(GPoolPageSize);
Ret = BlockList.Head;
for (auto* ListNode = BlockList.Tail;; PlatformYield())
{
- ListNode->NextBuffer = AtomicLoadRelaxed(&GPoolFreeList);
- if (AtomicCompareExchangeRelease(&GPoolFreeList, Ret->NextBuffer, ListNode->NextBuffer))
+ FWriteBuffer* FreeListValue = AtomicLoadRelaxed(&GPoolFreeList);
+ AtomicStoreRelaxed(&(ListNode->NextBuffer), FreeListValue);
+ if (AtomicCompareExchangeRelease(&GPoolFreeList, Ret->NextBuffer, FreeListValue))
{
break;
}
@@ -1863,8 +2324,9 @@ void Writer_FreeBlockListToPool(FWriteBuffer* Head, FWriteBuffer* Tail)
{
for (FWriteBuffer* ListNode = Tail;; PlatformYield())
{
- ListNode->NextBuffer = AtomicLoadRelaxed(&GPoolFreeList);
- if (AtomicCompareExchangeRelease(&GPoolFreeList, Head, ListNode->NextBuffer))
+ FWriteBuffer* FreeListValue = AtomicLoadRelaxed(&GPoolFreeList);
+ AtomicStoreRelaxed(&(ListNode->NextBuffer), FreeListValue);
+ if (AtomicCompareExchangeRelease(&GPoolFreeList, Head, FreeListValue))
{
break;
}
@@ -1872,7 +2334,6 @@ void Writer_FreeBlockListToPool(FWriteBuffer* Head, FWriteBuffer* Tail)
}
void Writer_InitializePool()
{
- Writer_AddPageToPool(GPoolBlockSize);
static_assert(GPoolPageSize >= 0x10000, "Page growth must be >= 64KB");
static_assert(GPoolInitPageSize >= 0x10000, "Initial page size must be >= 64KB");
}
@@ -1915,7 +2376,7 @@ UE_TRACE_EVENT_BEGIN(Trace, ChannelToggle, NoSync|Important)
UE_TRACE_EVENT_END()
static FChannel* volatile GHeadChannel; // = nullptr;
static FChannel* volatile GNewChannelList; // = nullptr;
-static bool GInitialized;
+static bool GChannelsInitialized;
static uint32 GetChannelHash(const ANSICHAR* Input, int32 Length)
{
if (Length > 0 && (Input[Length - 1] | 0x20) == 's')
@@ -2002,7 +2463,7 @@ void FChannel::Setup(const ANSICHAR* InChannelName, const InitArgs& InArgs)
break;
}
}
- if (GInitialized)
+ if (GChannelsInitialized)
{
Enabled = -1;
}
@@ -2018,7 +2479,7 @@ void FChannel::Announce() const
void FChannel::Initialize()
{
ToggleAll(false);
- GInitialized = true;
+ GChannelsInitialized = true;
}
void FChannel::ToggleAll(bool bEnabled)
{
@@ -2074,6 +2535,31 @@ void FChannel::EnumerateChannels(ChannelIterFunc Func, void* User)
}
}
}
+void FChannel::EnumerateChannels(ChannelIterCallback Func, void* User)
+{
+ using namespace Private;
+ FChannel* ChannelLists[] =
+ {
+ AtomicLoadAcquire(&GNewChannelList),
+ AtomicLoadAcquire(&GHeadChannel),
+ };
+ FChannelInfo Info;
+ for (FChannel* Channel : ChannelLists)
+ {
+ for (; Channel != nullptr; Channel = Channel->Next)
+ {
+ Info.Name = Channel->Name.Ptr;
+ Info.Desc = Channel->Args.Desc;
+ Info.bIsEnabled = Channel->IsEnabled();
+ Info.bIsReadOnly = Channel->Args.bReadOnly;
+ bool Result = Func(Info, User);
+ if (!Result)
+ {
+ return;
+ }
+ }
+ }
+}
bool FChannel::Toggle(bool bEnabled)
{
using namespace Private;
@@ -2144,8 +2630,8 @@ namespace UE {
namespace Trace {
namespace Private {
#if !defined(TRACE_PRIVATE_CONTROL_ENABLED) || TRACE_PRIVATE_CONTROL_ENABLED
-bool Writer_SendTo(const ANSICHAR*, uint32=0);
-bool Writer_WriteTo(const ANSICHAR*);
+bool Writer_SendTo(const ANSICHAR*, uint32=0, uint32=0);
+bool Writer_WriteTo(const ANSICHAR*, uint32=0);
bool Writer_Stop();
enum class EControlState : uint8
{
@@ -2170,7 +2656,7 @@ static FControlCommands GControlCommands;
static UPTRINT GControlListen = 0;
static UPTRINT GControlSocket = 0;
static EControlState GControlState; // = EControlState::Closed;
-static uint32 GControlPort = 1985;
+static uint16 GControlPort = 1985;
static uint32 Writer_ControlHash(const ANSICHAR* Word)
{
uint32 Hash = 5381;
@@ -2218,7 +2704,7 @@ static bool Writer_ControlListen()
uint32 Seed = uint32(TimeGetTimestamp());
for (uint32 i = 0; i < 10 && !GControlListen; Seed *= 13, ++i)
{
- uint32 Port = (Seed & 0x1fff) + 0x8000;
+ uint16 Port((Seed & 0x1fff) + 0x8000);
GControlListen = TcpSocketListen(Port);
if (GControlListen)
{
@@ -2445,6 +2931,18 @@ const FEventNode* FEventNode::FIter::GetNext()
}
return Ret;
}
+FEventNode::FIter FEventNode::Read()
+{
+ if (GEventListHead)
+ {
+ return { GEventListHead };
+ }
+ if (GNewEventList)
+ {
+ return { GNewEventList };
+ }
+ return {};
+}
FEventNode::FIter FEventNode::ReadNew()
{
FEventNode* EventList = AtomicExchangeAcquire(&GNewEventList, (FEventNode*)nullptr);
@@ -2498,6 +2996,7 @@ void FEventNode::Describe() const
{
const FLiteralName& LoggerName = Info->LoggerName;
const FLiteralName& EventName = Info->EventName;
+ const uint32 DefinitionIdFieldIdx = Info->FieldCount - ((Info->Flags & FEventInfo::DefinitionBits) ? 1 : 0);
uint32 NamesSize = LoggerName.Length + EventName.Length;
for (uint32 i = 0; i < Info->FieldCount; ++i)
{
@@ -2506,6 +3005,7 @@ void FEventNode::Describe() const
uint32 EventSize = sizeof(FNewEventEvent);
EventSize += sizeof(FNewEventEvent::Fields[0]) * Info->FieldCount;
EventSize += NamesSize;
+ EventSize = (EventSize + 1) & ~1; // align to 2 to keep UBSAN happy
FLogScope LogScope = FLogScope::EnterImpl<FEventInfo::Flag_NoSync>(0, EventSize + sizeof(uint16));
auto* Ptr = (uint16*)(LogScope.GetPointer());
Ptr[-1] = EKnownEventUids::NewEvent; // Make event look like an important one. Ideally they are sent
@@ -2515,19 +3015,38 @@ void FEventNode::Describe() const
Event.LoggerNameSize = LoggerName.Length;
Event.EventNameSize = EventName.Length;
Event.Flags = 0;
- uint32 Flags = Info->Flags;
+ const uint32 Flags = Info->Flags;
if (Flags & FEventInfo::Flag_Important) Event.Flags |= uint8(EEventFlags::Important);
if (Flags & FEventInfo::Flag_MaybeHasAux) Event.Flags |= uint8(EEventFlags::MaybeHasAux);
if (Flags & FEventInfo::Flag_NoSync) Event.Flags |= uint8(EEventFlags::NoSync);
+ if (Flags & FEventInfo::DefinitionBits) Event.Flags |= uint8(EEventFlags::Definition);
Event.FieldCount = uint8(Info->FieldCount);
for (uint32 i = 0; i < Info->FieldCount; ++i)
{
const FFieldDesc& Field = Info->Fields[i];
auto& Out = Event.Fields[i];
- Out.Offset = Field.ValueOffset;
- Out.Size = Field.ValueSize;
- Out.TypeInfo = Field.TypeInfo;
- Out.NameSize = Field.NameSize;
+ if (i == DefinitionIdFieldIdx)
+ {
+ Out.FieldType = EFieldFamily::DefinitionId;
+ Out.DefinitionId.Offset = Field.ValueOffset;
+ Out.DefinitionId.TypeInfo = Field.TypeInfo;
+ }
+ else if (Field.Reference != 0)
+ {
+ Out.FieldType = EFieldFamily::Reference;
+ Out.Reference.Offset = Field.ValueOffset;
+ Out.Reference.TypeInfo = Field.TypeInfo;
+ Out.Reference.NameSize = Field.NameSize;
+ Out.Reference.RefUid = uint16(Field.Reference) >> EKnownEventUids::_UidShift;
+ }
+ else
+ {
+ Out.FieldType = EFieldFamily::Regular;
+ Out.Regular.Offset = Field.ValueOffset;
+ Out.Regular.Size = Field.ValueSize;
+ Out.Regular.TypeInfo = Field.TypeInfo;
+ Out.Regular.NameSize = Field.NameSize;
+ }
}
uint8* Cursor = (uint8*)(Event.Fields + Info->FieldCount);
auto WriteName = [&Cursor] (const ANSICHAR* Data, uint32 Size)
@@ -2567,7 +3086,7 @@ template <typename CallbackType>
static void Field_WriteAuxData(uint32 Index, int32 Size, CallbackType&& Callback)
{
static_assert(
- sizeof(Private::FWriteBuffer::Overflow) >= sizeof(FAuxHeader) + sizeof(uint8 /*AuxDataTerminal*/),
+ sizeof(Private::FWriteBuffer::Overflow) >= 1 + sizeof(FAuxHeader) + sizeof(uint8 /*AuxDataTerminal*/),
"FWriteBuffer::Overflow is not large enough"
);
if (Size == 0)
@@ -2575,26 +3094,33 @@ static void Field_WriteAuxData(uint32 Index, int32 Size, CallbackType&& Callback
return;
}
FWriteBuffer* Buffer = Writer_GetBuffer();
- auto* Header = (FAuxHeader*)(Buffer->Cursor);
- Header->Pack = Size << FAuxHeader::SizeShift;
- Header->Pack |= Index << FAuxHeader::FieldShift;
- Header->Uid = uint8(EKnownEventUids::AuxData) << EKnownEventUids::_UidShift;
- Buffer->Cursor += sizeof(FAuxHeader);
- bool bCommit = ((uint8*)Header == Buffer->Committed);
- while (true)
+ bool bCommit = (Buffer->Cursor == Buffer->Committed);
+ int32 Remaining = int32(ptrdiff_t((uint8*)Buffer - Buffer->Cursor));
+ auto NextBuffer = [&Buffer, &Remaining, &bCommit] ()
{
- if (Buffer->Cursor >= (uint8*)Buffer)
+ if (bCommit)
{
- if (bCommit)
- {
- AtomicStoreRelease(&(uint8* volatile&)(Buffer->Committed), Buffer->Cursor);
- }
- Buffer = Writer_NextBuffer(0);
- Buffer->Partial = 1;
- bCommit = true;
+ AtomicStoreRelease(&(uint8* volatile&)(Buffer->Committed), Buffer->Cursor);
}
- int32 Remaining = int32((uint8*)Buffer - Buffer->Cursor);
+ bCommit = true;
+ Buffer = Writer_NextBuffer();
+ Remaining = int32(ptrdiff_t((uint8*)Buffer - Buffer->Cursor));
+ };
+ if (Remaining <= 0)
+ {
+ NextBuffer();
+ }
+ while (true)
+ {
+ Remaining += sizeof(FWriteBuffer::Overflow);
+ Remaining -= 1; // for the aux-terminal
+ Remaining -= sizeof(FAuxHeader); // header also assume to always fit
int32 SegmentSize = (Remaining < Size) ? Remaining : Size;
+ uint32 Pack = SegmentSize << FAuxHeader::SizeShift;
+ Pack |= Index << FAuxHeader::FieldShift;
+ memcpy(Buffer->Cursor, &Pack, sizeof(uint32)); /* FAuxHeader::Pack */
+ Buffer->Cursor[0] = uint8(EKnownEventUids::AuxData) << EKnownEventUids::_UidShift; /* FAuxHeader::Uid */
+ Buffer->Cursor += sizeof(FAuxHeader);
Callback(Buffer->Cursor, SegmentSize);
Buffer->Cursor += SegmentSize;
Size -= SegmentSize;
@@ -2602,6 +3128,7 @@ static void Field_WriteAuxData(uint32 Index, int32 Size, CallbackType&& Callback
{
break;
}
+ NextBuffer();
}
if (bCommit)
{
@@ -2782,7 +3309,7 @@ FTidPacketBase* FPacketRing::AppendImpl(uint32 InSize)
return TidPacket;
}
static FPacketRing GPacketRing; // = {};
-void Writer_TailAppend(uint32 ThreadId, uint8* __restrict Data, uint32 Size, bool bPartial)
+void Writer_TailAppend(uint32 ThreadId, uint8* __restrict Data, uint32 Size)
{
if (!GPacketRing.IsActive())
{
@@ -2794,7 +3321,6 @@ void Writer_TailAppend(uint32 ThreadId, uint8* __restrict Data, uint32 Size, boo
return Writer_SendData(ThreadId, Data, Size);
}
ThreadId &= FTidPacketBase::ThreadIdMask;
- ThreadId |= bPartial ? FTidPacketBase::PartialMarker : 0;
if (Size <= 384)
{
auto* Packet = GPacketRing.Append<FTidPacket>(Size);
@@ -2843,6 +3369,10 @@ void Writer_InitializeTail(int32 BufferSize)
}
GPacketRing.Initialize(BufferSize);
}
+bool Writer_IsTailing()
+{
+ return GPacketRing.IsActive();
+}
void Writer_ShutdownTail()
{
GPacketRing.Shutdown();
@@ -2857,10 +3387,6 @@ static void StressRingPacket()
{
FTidPacket* Packet = Ring.Append<FTidPacket>((Bits & 0x1f) + 6);
Packet->ThreadId = i;
- if ((Bits & 0x15) == 0)
- {
- Packet->ThreadId |= FTidPacketBase::PartialMarker;
- }
Ring.IterateRanges([] (const FPacketRing::FRange&)
{
/* nop */
@@ -2911,7 +3437,7 @@ as if the buffer was being filled for the first time.
namespace UE {
namespace Trace {
namespace Private {
-void Writer_TailAppend(uint32, uint8* __restrict, uint32, bool);
+void Writer_TailAppend(uint32, uint8* __restrict, uint32);
FWriteBuffer* Writer_AllocateBlockFromPool();
uint32 Writer_GetThreadId();
void Writer_FreeBlockListToPool(FWriteBuffer*, FWriteBuffer*);
@@ -2921,7 +3447,7 @@ UE_TRACE_EVENT_BEGIN($Trace, ThreadTiming, NoSync)
UE_TRACE_EVENT_FIELD(uint64, BaseTimestamp)
UE_TRACE_EVENT_END()
#define T_ALIGN alignas(PLATFORM_CACHE_LINE_SIZE)
-static FWriteBuffer GNullWriteBuffer = { {}, 0, 0, nullptr, nullptr, (uint8*)&GNullWriteBuffer };
+static FWriteBuffer GNullWriteBuffer = { {}, 0, nullptr, nullptr, (uint8*)&GNullWriteBuffer, nullptr, nullptr, 0, 0, 0 };
thread_local FWriteBuffer* GTlsWriteBuffer = &GNullWriteBuffer;
static FWriteBuffer* __restrict GActiveThreadList; // = nullptr;
T_ALIGN static FWriteBuffer* volatile GNewThreadList; // = nullptr;
@@ -2932,21 +3458,32 @@ TRACELOG_API FWriteBuffer* Writer_GetBuffer()
return GTlsWriteBuffer;
}
#endif
-static FWriteBuffer* Writer_NextBufferInternal()
+static FWriteBuffer* Writer_NextBufferInternal(FWriteBuffer* CurrentBuffer)
{
+ TWriteBufferRedirect<2048> TraceData;
+#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST
+ if (CurrentBuffer->ThreadId == decltype(TraceData)::ActiveRedirection)
+ {
+ PLATFORM_BREAK();
+ }
+#endif
FWriteBuffer* NextBuffer = Writer_AllocateBlockFromPool();
NextBuffer->Cursor = (uint8*)NextBuffer - NextBuffer->Size;
- NextBuffer->Committed = NextBuffer->Cursor;
NextBuffer->Reaped = NextBuffer->Cursor;
NextBuffer->EtxOffset = 0 - int32(sizeof(FWriteBuffer));
- NextBuffer->NextBuffer = nullptr;
- FWriteBuffer* CurrentBuffer = GTlsWriteBuffer;
+ AtomicStoreRelaxed(&(NextBuffer->NextBuffer), (FWriteBuffer*)nullptr);
+ if (uint32 RedirectSize = TraceData.GetSize())
+ {
+ memcpy(NextBuffer->Cursor, TraceData.GetData(), RedirectSize);
+ NextBuffer->Cursor += RedirectSize;
+ }
+ TraceData.Abandon();
+ GTlsWriteBuffer = NextBuffer;
+ NextBuffer->Committed = NextBuffer->Cursor;
if (CurrentBuffer == &GNullWriteBuffer)
{
NextBuffer->ThreadId = uint16(Writer_GetThreadId());
NextBuffer->PrevTimestamp = TimeGetTimestamp();
- NextBuffer->Partial = 0;
- GTlsWriteBuffer = NextBuffer;
UE_TRACE_LOG($Trace, ThreadTiming, TraceLogChannel)
<< ThreadTiming.BaseTimestamp(NextBuffer->PrevTimestamp - GStartCycle);
for (;; PlatformYield())
@@ -2960,42 +3497,28 @@ static FWriteBuffer* Writer_NextBufferInternal()
}
else
{
- CurrentBuffer->NextBuffer = NextBuffer;
NextBuffer->ThreadId = CurrentBuffer->ThreadId;
NextBuffer->PrevTimestamp = CurrentBuffer->PrevTimestamp;
- NextBuffer->Partial = 0;
- GTlsWriteBuffer = NextBuffer;
+ AtomicStoreRelease(&(CurrentBuffer->NextBuffer), NextBuffer);
int32 EtxOffset = int32(PTRINT((uint8*)(CurrentBuffer) - CurrentBuffer->Cursor));
AtomicStoreRelease(&(CurrentBuffer->EtxOffset), EtxOffset);
}
return NextBuffer;
}
-TRACELOG_API FWriteBuffer* Writer_NextBuffer(int32 Size)
+TRACELOG_API FWriteBuffer* Writer_NextBuffer()
{
FWriteBuffer* CurrentBuffer = GTlsWriteBuffer;
- if (CurrentBuffer != &GNullWriteBuffer)
- {
- CurrentBuffer->Cursor -= Size;
- }
- FWriteBuffer* NextBuffer = Writer_NextBufferInternal();
- if (Size >= NextBuffer->Size)
- {
- return nullptr;
- }
- NextBuffer->Cursor += Size;
- return NextBuffer;
+ return Writer_NextBufferInternal(CurrentBuffer);
}
static bool Writer_DrainBuffer(uint32 ThreadId, FWriteBuffer* Buffer)
{
- uint8* Committed = AtomicLoadRelaxed((uint8**)&Buffer->Committed);
+ uint8* Committed = AtomicLoadAcquire((uint8**)&Buffer->Committed);
if (uint32 SizeToReap = uint32(Committed - Buffer->Reaped))
{
#if TRACE_PRIVATE_STATISTICS
GTraceStatistics.BytesTraced += SizeToReap;
#endif
- bool bPartial = (Buffer->Partial == 1);
- bPartial &= UPTRINT(Buffer->Reaped + Buffer->Size) == UPTRINT(Buffer);
- Writer_TailAppend(ThreadId, Buffer->Reaped, SizeToReap, bPartial);
+ Writer_TailAppend(ThreadId, Buffer->Reaped, SizeToReap);
Buffer->Reaped = Committed;
}
int32 EtxOffset = AtomicLoadAcquire(&Buffer->EtxOffset);
@@ -3009,7 +3532,7 @@ void Writer_DrainBuffers()
FWriteBuffer* __restrict Tail = nullptr;
void Insert(FWriteBuffer* __restrict Buffer)
{
- Buffer->NextBuffer = Head;
+ AtomicStoreRelaxed(&(Buffer->NextBuffer), Head);
Head = Buffer;
Tail = (Tail != nullptr) ? Tail : Head;
}
@@ -3039,7 +3562,7 @@ void Writer_DrainBuffers()
{
break;
}
- NextBuffer = Buffer->NextBuffer;
+ NextBuffer = AtomicLoadAcquire(&(Buffer->NextBuffer));
RetireList.Insert(Buffer);
}
if (Buffer != nullptr)
@@ -3054,6 +3577,58 @@ void Writer_DrainBuffers()
Writer_FreeBlockListToPool(RetireList.Head, RetireList.Tail);
}
}
+void Writer_DrainLocalBuffers()
+{
+ if (GTlsWriteBuffer == &GNullWriteBuffer)
+ {
+ return;
+ }
+ const uint32 LocalThreadId = GTlsWriteBuffer->ThreadId;
+ struct FRetireList
+ {
+ FWriteBuffer* __restrict Head = nullptr;
+ FWriteBuffer* __restrict Tail = nullptr;
+ void Insert(FWriteBuffer* __restrict Buffer)
+ {
+ AtomicStoreRelaxed(&(Buffer->NextBuffer), Head);
+ Head = Buffer;
+ Tail = (Tail != nullptr) ? Tail : Head;
+ }
+ };
+ FRetireList RetireList;
+ FWriteBuffer* __restrict ActiveThreadList = GActiveThreadList;
+ GActiveThreadList = nullptr;
+ {
+ FWriteBuffer* __restrict Buffer = ActiveThreadList;
+ FWriteBuffer* __restrict NextThread;
+ for (; Buffer != nullptr; Buffer = NextThread)
+ {
+ NextThread = Buffer->NextThread;
+ uint32 ThreadId = Buffer->ThreadId;
+ if (ThreadId == LocalThreadId)
+ {
+ for (FWriteBuffer* __restrict NextBuffer; Buffer != nullptr; Buffer = NextBuffer)
+ {
+ if (Writer_DrainBuffer(ThreadId, Buffer))
+ {
+ break;
+ }
+ NextBuffer = AtomicLoadAcquire(&(Buffer->NextBuffer));
+ RetireList.Insert(Buffer);
+ }
+ }
+ if (Buffer != nullptr)
+ {
+ Buffer->NextThread = GActiveThreadList;
+ GActiveThreadList = Buffer;
+ }
+ }
+ }
+ if (RetireList.Head != nullptr)
+ {
+ Writer_FreeBlockListToPool(RetireList.Head, RetireList.Tail);
+ }
+}
void Writer_EndThreadBuffer()
{
if (GTlsWriteBuffer == &GNullWriteBuffer)
@@ -3079,8 +3654,9 @@ void Writer_Initialize(const FInitializeDesc&);
void Writer_WorkerCreate();
void Writer_Shutdown();
void Writer_Update();
-bool Writer_SendTo(const ANSICHAR*, uint32);
-bool Writer_WriteTo(const ANSICHAR*);
+bool Writer_SendTo(const ANSICHAR*, uint32, uint32);
+bool Writer_WriteTo(const ANSICHAR*, uint32);
+bool Writer_WriteSnapshotTo(const ANSICHAR*);
bool Writer_IsTracing();
bool Writer_Stop();
uint32 Writer_GetThreadId();
@@ -3122,17 +3698,23 @@ void GetStatistics(FStatistics& Out)
{
Out = Private::GTraceStatistics;
}
-bool SendTo(const TCHAR* InHost, uint32 Port)
+bool SendTo(const TCHAR* InHost, uint32 Port, uint16 Flags)
{
char Host[256];
ToAnsiCheap(Host, InHost);
- return Private::Writer_SendTo(Host, Port);
+ return Private::Writer_SendTo(Host, Flags, Port);
}
-bool WriteTo(const TCHAR* InPath)
+bool WriteTo(const TCHAR* InPath, uint16 Flags)
{
char Path[512];
ToAnsiCheap(Path, InPath);
- return Private::Writer_WriteTo(Path);
+ return Private::Writer_WriteTo(Path, Flags);
+}
+bool WriteSnapshotTo(const TCHAR* InPath)
+{
+ char Path[512];
+ ToAnsiCheap(Path, InPath);
+ return Private::Writer_WriteSnapshotTo(Path);
}
bool IsTracing()
{
@@ -3156,6 +3738,23 @@ bool ToggleChannel(const TCHAR* ChannelName, bool bEnabled)
}
void EnumerateChannels(ChannelIterFunc IterFunc, void* User)
{
+ struct FCallbackDataWrapper
+ {
+ ChannelIterFunc* Func;
+ void* User;
+ };
+ FCallbackDataWrapper Wrapper;
+ Wrapper.Func = IterFunc;
+ Wrapper.User = User;
+ FChannel::EnumerateChannels([](const FChannelInfo& Info, void* User)
+ {
+ FCallbackDataWrapper* Wrapper = (FCallbackDataWrapper*)User;
+ (*Wrapper).Func(Info.Name, Info.bIsEnabled, (*Wrapper).User);
+ return true;
+ }, &Wrapper);
+}
+void EnumerateChannels(ChannelIterCallback IterFunc, void* User)
+{
FChannel::EnumerateChannels(IterFunc, User);
}
void StartWorkerThread()
@@ -3230,26 +3829,34 @@ void Writer_UpdateSharedBuffers();
void Writer_InitializeCache();
void Writer_ShutdownCache();
void Writer_CacheOnConnect();
+void Writer_CallbackOnConnect();
void Writer_InitializePool();
void Writer_ShutdownPool();
void Writer_DrainBuffers();
+void Writer_DrainLocalBuffers();
void Writer_EndThreadBuffer();
uint32 Writer_GetControlPort();
void Writer_UpdateControl();
void Writer_InitializeControl();
void Writer_ShutdownControl();
-bool Writer_IsTracing();
+bool Writer_IsTailing();
+static bool Writer_SessionPrologue();
+void Writer_FreeBlockListToPool(FWriteBuffer*, FWriteBuffer*);
UE_TRACE_EVENT_BEGIN($Trace, NewTrace, Important|NoSync)
UE_TRACE_EVENT_FIELD(uint64, StartCycle)
UE_TRACE_EVENT_FIELD(uint64, CycleFrequency)
UE_TRACE_EVENT_FIELD(uint16, Endian)
UE_TRACE_EVENT_FIELD(uint8, PointerSize)
UE_TRACE_EVENT_END()
-static bool GInitialized; // = false;
+static volatile bool GInitialized; // = false;
FStatistics GTraceStatistics; // = {};
uint64 GStartCycle; // = 0;
TRACELOG_API uint32 volatile GLogSerial; // = 0;
static uint32 GUpdateCounter; // = 0;
+#if !defined(UE_TRACE_USE_TLS_CONTEXT_OBJECT)
+# define UE_TRACE_USE_TLS_CONTEXT_OBJECT 1
+#endif
+#if UE_TRACE_USE_TLS_CONTEXT_OBJECT
struct FWriteTlsContext
{
~FWriteTlsContext();
@@ -3259,7 +3866,7 @@ private:
};
FWriteTlsContext::~FWriteTlsContext()
{
- if (GInitialized)
+ if (AtomicLoadRelaxed(&GInitialized))
{
Writer_EndThreadBuffer();
}
@@ -3279,6 +3886,21 @@ uint32 Writer_GetThreadId()
{
return GTlsContext.GetThreadId();
}
+#else // UE_TRACE_USE_TLS_CONTEXT_OBJECT
+void ThreadOnThreadExit(void (*)());
+uint32 Writer_GetThreadId()
+{
+ static thread_local uint32 ThreadId;
+ if (ThreadId)
+ {
+ return ThreadId;
+ }
+ ThreadOnThreadExit([] () { Writer_EndThreadBuffer(); });
+ static uint32 volatile Counter;
+ ThreadId = AtomicAddRelaxed(&Counter, 1u) + ETransportTid::Bias;
+ return ThreadId;
+}
+#endif // UE_TRACE_USE_TLS_CONTEXT_OBJECT
void* (*AllocHook)(SIZE_T, uint32); // = nullptr
void (*FreeHook)(void*, SIZE_T); // = nullptr
void Writer_MemorySetHooks(decltype(AllocHook) Alloc, decltype(FreeHook) Free)
@@ -3288,7 +3910,6 @@ void Writer_MemorySetHooks(decltype(AllocHook) Alloc, decltype(FreeHook) Free)
}
void* Writer_MemoryAllocate(SIZE_T Size, uint32 Alignment)
{
- TWriteBufferRedirect<1 << 10> TraceData;
void* Ret = nullptr;
#if TRACE_PRIVATE_STOMP
static uint8* Base;
@@ -3340,7 +3961,6 @@ void Writer_MemoryFree(void* Address, uint32 Size)
DWORD Unused;
VirtualProtect(MemInfo.BaseAddress, MemInfo.RegionSize, PAGE_READONLY, &Unused);
#else // TRACE_PRIVATE_STOMP
- TWriteBufferRedirect<1 << 10> TraceData;
if (FreeHook != nullptr)
{
FreeHook(Address, Size);
@@ -3359,7 +3979,7 @@ void Writer_MemoryFree(void* Address, uint32 Size)
#endif
}
static UPTRINT GDataHandle; // = 0
-UPTRINT GPendingDataHandle; // = 0
+static volatile UPTRINT GPendingDataHandle; // = 0
#if TRACE_PRIVATE_BUFFER_SEND
static const SIZE_T GSendBufferSize = 1 << 20; // 1Mb
uint8* GSendBuffer; // = nullptr;
@@ -3448,10 +4068,9 @@ void Writer_SendData(uint32 ThreadId, uint8* __restrict Data, uint32 Size)
Packet.PacketSize += sizeof(FTidPacketEncoded);
Writer_SendDataImpl(&Packet, Packet.PacketSize);
}
-static void Writer_DescribeEvents()
+static void Writer_DescribeEvents(FEventNode::FIter Iter)
{
TWriteBufferRedirect<4096> TraceData;
- FEventNode::FIter Iter = FEventNode::ReadNew();
while (const FEventNode* Event = Iter.GetNext())
{
Event->Describe();
@@ -3481,10 +4100,11 @@ static void Writer_DescribeAnnounce()
return;
}
Writer_AnnounceChannels();
- Writer_DescribeEvents();
+ Writer_DescribeEvents(FEventNode::ReadNew());
}
static int8 GSyncPacketCountdown; // = 0
static const int8 GNumSyncPackets = 3;
+static OnConnectFunc* GOnConnection = nullptr;
static void Writer_SendSync()
{
if (GSyncPacketCountdown <= 0)
@@ -3495,36 +4115,67 @@ static void Writer_SendSync()
Writer_SendDataImpl(&SyncPacket, sizeof(SyncPacket));
--GSyncPacketCountdown;
}
+static void Writer_Close()
+{
+ if (GDataHandle)
+ {
+ Writer_FlushSendBuffer();
+ IoClose(GDataHandle);
+ }
+ GDataHandle = 0;
+}
static bool Writer_UpdateConnection()
{
- if (!GPendingDataHandle)
+ UPTRINT PendingDataHandle = AtomicLoadRelaxed(&GPendingDataHandle);
+ if (!PendingDataHandle)
{
return false;
}
- static const uint32 CloseInertia = 2;
- if (GPendingDataHandle >= (~0ull - CloseInertia))
+ static int32 CloseInertia = 0;
+ if (PendingDataHandle == ~UPTRINT(0))
{
- --GPendingDataHandle;
- if (GPendingDataHandle == (~0ull -CloseInertia))
+ if (CloseInertia <= 0)
+ CloseInertia = 2;
+ --CloseInertia;
+ if (CloseInertia <= 0)
{
- if (GDataHandle)
- {
- Writer_FlushSendBuffer();
- IoClose(GDataHandle);
- }
- GDataHandle = 0;
- GPendingDataHandle = 0;
+ Writer_Close();
+ AtomicStoreRelaxed(&GPendingDataHandle, UPTRINT(0));
}
return true;
}
+ AtomicStoreRelaxed(&GPendingDataHandle, UPTRINT(0));
+ uint32 SendFlags = uint32(PendingDataHandle >> 48ull);
+ PendingDataHandle &= 0x0000'ffff'ffff'ffffull;
if (GDataHandle)
{
- IoClose(GPendingDataHandle);
- GPendingDataHandle = 0;
+ IoClose(PendingDataHandle);
+ return false;
+ }
+ GDataHandle = PendingDataHandle;
+ if (!Writer_SessionPrologue())
+ {
+ return false;
+ }
+ GTraceStatistics.BytesSent = 0;
+ GTraceStatistics.BytesTraced = 0;
+ FEventNode::OnConnect();
+ Writer_DescribeEvents(FEventNode::ReadNew());
+ Writer_CacheOnConnect();
+ Writer_CallbackOnConnect();
+ if ((SendFlags & FSendFlags::ExcludeTail) == 0)
+ {
+ Writer_TailOnConnect();
+ }
+ GSyncPacketCountdown = GNumSyncPackets;
+ return true;
+}
+static bool Writer_SessionPrologue()
+{
+ if (!GDataHandle)
+ {
return false;
}
- GDataHandle = GPendingDataHandle;
- GPendingDataHandle = 0;
#if TRACE_PRIVATE_BUFFER_SEND
if (!GSendBuffer)
{
@@ -3532,20 +4183,32 @@ static bool Writer_UpdateConnection()
}
GSendBufferCursor = GSendBuffer;
#endif
+#define UE_TRACE_ROTATE 1
struct FHandshake
{
uint32 Magic = '2' | ('C' << 8) | ('R' << 16) | ('T' << 24);
- uint16 MetadataSize = uint16(4); // = sizeof(MetadataField0 + ControlPort)
+ uint16 MetadataSize;
uint16 MetadataField0 = uint16(sizeof(ControlPort) | (ControlPortFieldId << 8));
uint16 ControlPort = uint16(Writer_GetControlPort());
+#if UE_TRACE_ROTATE
+ uint16 MetadataField1 = uint16(sizeof(RotationParams) | (RotatingTraceId << 8));
+ uint16 RotationParams = uint16(5 /*rotate-num*/ | (4/*50*/ /*size-MiB*/ << 8));
+#endif
enum
{
- Size = 10,
ControlPortFieldId = 0,
+ RotatingTraceId = 1,
};
};
FHandshake Handshake;
- bool bOk = IoWrite(GDataHandle, &Handshake, FHandshake::Size);
+#if UE_TRACE_ROTATE
+ Handshake.MetadataSize = 8;
+#else
+ Handshake.MetadataSize = 4;
+#endif
+ uint32 WriteSize = sizeof(FHandshake::Magic) + sizeof(FHandshake::MetadataSize) + Handshake.MetadataSize;
+ bool bOk = IoWrite(GDataHandle, &Handshake, WriteSize);
+#undef UE_TRACE_ROTATE
const struct {
uint8 TransportVersion = ETransport::TidPacketSync;
uint8 ProtocolVersion = EProtocol::Id;
@@ -3557,24 +4220,26 @@ static bool Writer_UpdateConnection()
GDataHandle = 0;
return false;
}
- GTraceStatistics.BytesSent = 0;
- GTraceStatistics.BytesTraced = 0;
- FEventNode::OnConnect();
- Writer_DescribeEvents();
- Writer_CacheOnConnect();
- Writer_TailOnConnect();
- GSyncPacketCountdown = GNumSyncPackets;
return true;
}
-static UPTRINT GWorkerThread; // = 0;
-static volatile bool GWorkerThreadQuit; // = false;
-static volatile unsigned int GUpdateInProgress = 1; // Don't allow updates until initalized
-static void Writer_WorkerUpdate()
+void Writer_CallbackOnConnect()
{
- if (!AtomicCompareExchangeAcquire(&GUpdateInProgress, 1u, 0u))
+ if (!GOnConnection)
{
return;
}
+ UPTRINT DataHandle = GDataHandle;
+ GDataHandle = 0;
+ Writer_DrainLocalBuffers();
+ GDataHandle = DataHandle;
+ GOnConnection();
+}
+static UPTRINT GWorkerThread; // = 0;
+static volatile bool GWorkerThreadQuit; // = false;
+static uint32 GSleepTimeInMS = 17;
+static volatile uint32 GUpdateInProgress = 1; // Don't allow updates until initialized
+static void Writer_WorkerUpdateInternal()
+{
Writer_UpdateControl();
Writer_UpdateConnection();
Writer_DescribeAnnounce();
@@ -3588,16 +4253,23 @@ static void Writer_WorkerUpdate()
Writer_FlushSendBuffer();
}
#endif
+}
+static void Writer_WorkerUpdate()
+{
+ if (!AtomicCompareExchangeAcquire(&GUpdateInProgress, 1u, 0u))
+ {
+ return;
+ }
+ Writer_WorkerUpdateInternal();
AtomicExchangeRelease(&GUpdateInProgress, 0u);
}
static void Writer_WorkerThread()
{
ThreadRegister(TEXT("Trace"), 0, INT_MAX);
- while (!GWorkerThreadQuit)
+ while (!AtomicLoadRelaxed(&GWorkerThreadQuit))
{
Writer_WorkerUpdate();
- const uint32 SleepMs = 17;
- ThreadSleep(SleepMs);
+ ThreadSleep(GSleepTimeInMS);
}
}
void Writer_WorkerCreate()
@@ -3614,7 +4286,7 @@ static void Writer_WorkerJoin()
{
return;
}
- GWorkerThreadQuit = true;
+ AtomicStoreRelaxed(&GWorkerThreadQuit, true);
ThreadJoin(GWorkerThread);
ThreadDestroy(GWorkerThread);
Writer_WorkerUpdate();
@@ -3622,15 +4294,15 @@ static void Writer_WorkerJoin()
}
static void Writer_InternalInitializeImpl()
{
- if (GInitialized)
+ if (AtomicLoadRelaxed(&GInitialized))
{
return;
}
- GInitialized = true;
GStartCycle = TimeGetTimestamp();
Writer_InitializeSharedBuffers();
Writer_InitializePool();
Writer_InitializeControl();
+ AtomicStoreRelaxed(&GInitialized, true);
UE_TRACE_LOG($Trace, NewTrace, TraceLogChannel)
<< NewTrace.StartCycle(GStartCycle)
<< NewTrace.CycleFrequency(TimeGetFrequency())
@@ -3639,7 +4311,7 @@ static void Writer_InternalInitializeImpl()
}
static void Writer_InternalShutdown()
{
- if (!GInitialized)
+ if (!AtomicLoadRelaxed(&GInitialized))
{
return;
}
@@ -3663,30 +4335,31 @@ static void Writer_InternalShutdown()
GSendBufferCursor = nullptr;
}
#endif
- GInitialized = false;
+ AtomicStoreRelaxed(&GInitialized, false);
}
void Writer_InternalInitialize()
{
using namespace Private;
- if (!GInitialized)
+ if (AtomicLoadRelaxed(&GInitialized))
{
- static struct FInitializer
- {
- FInitializer()
- {
- Writer_InternalInitializeImpl();
- }
- ~FInitializer()
- {
- /* We'll not shut anything down here so we can hopefully capture
- * any subsequent events. However, we will shutdown the worker
- * thread and leave it for something else to call update() (mem
- * tracing at time of writing). Windows will have already done
- * this implicitly in ExitProcess() anyway. */
- Writer_WorkerJoin();
- }
- } Initializer;
+ return;
}
+ static struct FInitializer
+ {
+ FInitializer()
+ {
+ Writer_InternalInitializeImpl();
+ }
+ ~FInitializer()
+ {
+ /* We'll not shut anything down here so we can hopefully capture
+ * any subsequent events. However, we will shutdown the worker
+ * thread and leave it for something else to call update() (mem
+ * tracing at time of writing). Windows will have already done
+ * this implicitly in ExitProcess() anyway. */
+ Writer_WorkerJoin();
+ }
+ } Initializer;
}
void Writer_Initialize(const FInitializeDesc& Desc)
{
@@ -3695,11 +4368,16 @@ void Writer_Initialize(const FInitializeDesc& Desc)
{
Writer_InitializeCache();
}
+ if (Desc.ThreadSleepTimeInMS != 0)
+ {
+ GSleepTimeInMS = Desc.ThreadSleepTimeInMS;
+ }
if (Desc.bUseWorkerThread)
{
Writer_WorkerCreate();
}
- GUpdateInProgress = 0;
+ GOnConnection = Desc.OnConnectionFunc;
+ AtomicStoreRelease(&GUpdateInProgress, uint32(0));
}
void Writer_Shutdown()
{
@@ -3712,9 +4390,18 @@ void Writer_Update()
Writer_WorkerUpdate();
}
}
-bool Writer_SendTo(const ANSICHAR* Host, uint32 Port)
+static UPTRINT Writer_PackSendFlags(UPTRINT DataHandle, uint32 Flags)
{
- if (GPendingDataHandle || GDataHandle)
+ if (DataHandle & 0xffff'0000'0000'0000ull)
+ {
+ IoClose(DataHandle);
+ return 0;
+ }
+ return DataHandle | (UPTRINT(Flags) << 48ull);
+}
+bool Writer_SendTo(const ANSICHAR* Host, uint32 Flags, uint32 Port)
+{
+ if (AtomicLoadRelaxed(&GPendingDataHandle))
{
return false;
}
@@ -3725,12 +4412,17 @@ bool Writer_SendTo(const ANSICHAR* Host, uint32 Port)
{
return false;
}
- GPendingDataHandle = DataHandle;
+ DataHandle = Writer_PackSendFlags(DataHandle, Flags);
+ if (!DataHandle)
+ {
+ return false;
+ }
+ AtomicStoreRelaxed(&GPendingDataHandle, DataHandle);
return true;
}
-bool Writer_WriteTo(const ANSICHAR* Path)
+bool Writer_WriteTo(const ANSICHAR* Path, uint32 Flags)
{
- if (GPendingDataHandle || GDataHandle)
+ if (AtomicLoadRelaxed(&GPendingDataHandle))
{
return false;
}
@@ -3740,7 +4432,102 @@ bool Writer_WriteTo(const ANSICHAR* Path)
{
return false;
}
- GPendingDataHandle = DataHandle;
+ DataHandle = Writer_PackSendFlags(DataHandle, Flags);
+ if (!DataHandle)
+ {
+ return false;
+ }
+ AtomicStoreRelaxed(&GPendingDataHandle, DataHandle);
+ return true;
+}
+struct WorkerUpdateLock
+{
+ WorkerUpdateLock()
+ {
+ CyclesPerSecond = TimeGetFrequency();
+ StartSeconds = GetTime();
+ while (!AtomicCompareExchangeAcquire(&GUpdateInProgress, 1u, 0u))
+ {
+ ThreadSleep(0);
+ if (TimedOut())
+ {
+ break;
+ }
+ }
+ }
+ ~WorkerUpdateLock()
+ {
+ AtomicExchangeRelease(&GUpdateInProgress, 0u);
+ }
+ double GetTime()
+ {
+ return static_cast<double>(TimeGetTimestamp()) / static_cast<double>(CyclesPerSecond);
+ }
+ bool TimedOut()
+ {
+ const double WaitTime = GetTime() - StartSeconds;
+ return WaitTime > MaxWaitSeconds;
+ }
+ uint64 CyclesPerSecond;
+ double StartSeconds;
+ inline const static double MaxWaitSeconds = 1.0;
+};
+template <typename Type>
+struct TStashGlobal
+{
+ TStashGlobal(Type& Global)
+ : Variable(Global)
+ , Stashed(Global)
+ {
+ Variable = {};
+ }
+ TStashGlobal(Type& Global, const Type& Value)
+ : Variable(Global)
+ , Stashed(Global)
+ {
+ Variable = Value;
+ }
+ ~TStashGlobal()
+ {
+ Variable = Stashed;
+ }
+private:
+ Type& Variable;
+ Type Stashed;
+};
+bool Writer_WriteSnapshotTo(const ANSICHAR* Path)
+{
+ if (!Writer_IsTailing())
+ {
+ return false;
+ }
+ WorkerUpdateLock UpdateLock;
+ if (UpdateLock.TimedOut())
+ {
+ return false;
+ }
+ Writer_WorkerUpdateInternal();
+ {
+ TStashGlobal DataHandle(GDataHandle);
+ TStashGlobal PendingDataHandle(GPendingDataHandle);
+ TStashGlobal SyncPacketCountdown(GSyncPacketCountdown, GNumSyncPackets);
+ TStashGlobal TraceStatistics(GTraceStatistics);
+ GDataHandle = FileOpen(Path);
+ if (!GDataHandle || !Writer_SessionPrologue())
+ {
+ return false;
+ }
+ Writer_DescribeEvents(FEventNode::Read());
+ Writer_CacheOnConnect();
+ Writer_CallbackOnConnect();
+ Writer_TailOnConnect();
+ GSyncPacketCountdown = GNumSyncPackets;
+ while (GSyncPacketCountdown > 0)
+ {
+ Writer_SendSync();
+ }
+ Writer_Close();
+ }
return true;
}
bool Writer_IsTracing()
@@ -3753,7 +4540,7 @@ bool Writer_Stop()
{
return false;
}
- GPendingDataHandle = ~UPTRINT(0);
+ AtomicStoreRelaxed(&GPendingDataHandle, ~UPTRINT(0));
return true;
}
} // namespace Private
@@ -4131,203 +4918,6 @@ UPTRINT FileOpen(const ANSICHAR* Path)
} // namespace Trace
} // namespace UE
#endif // UE_TRACE_ENABLED
-/* {{{1 HoloLensTrace.cpp */
-
-#if UE_TRACE_ENABLED && PLATFORM_HOLOLENS
-# define _WINSOCK_DEPRECATED_NO_WARNINGS
-# include <winsock2.h>
-# include <ws2tcpip.h>
-# pragma comment(lib, "ws2_32.lib")
-#pragma warning(push)
-#pragma warning(disable : 6031) // WSAStartup() return ignore - we're error tolerant
-namespace UE {
-namespace Trace {
-namespace Private {
-UPTRINT ThreadCreate(const ANSICHAR* Name, void (*Entry)())
-{
- DWORD (WINAPI *WinApiThunk)(void*) = [] (void* Param) -> DWORD
- {
- typedef void (*EntryType)(void);
- (EntryType(Param))();
- return 0;
- };
- HANDLE Handle = CreateThread(nullptr, 0, WinApiThunk, (void*)Entry, 0, nullptr);
- return UPTRINT(Handle);
-}
-void ThreadSleep(uint32 Milliseconds)
-{
- Sleep(Milliseconds);
-}
-void ThreadJoin(UPTRINT Handle)
-{
- WaitForSingleObject(HANDLE(Handle), INFINITE);
-}
-void ThreadDestroy(UPTRINT Handle)
-{
- CloseHandle(HANDLE(Handle));
-}
-uint64 TimeGetFrequency()
-{
- LARGE_INTEGER Value;
- QueryPerformanceFrequency(&Value);
- return Value.QuadPart;
-}
-TRACELOG_API uint64 TimeGetTimestamp()
-{
- LARGE_INTEGER Value;
- QueryPerformanceCounter(&Value);
- return Value.QuadPart;
-}
-static void TcpSocketInitialize()
-{
- WSADATA WsaData;
- WSAStartup(MAKEWORD(2, 2), &WsaData);
-}
-static bool TcpSocketSetNonBlocking(SOCKET Socket, bool bNonBlocking)
-{
- unsigned long NonBlockingMode = !!bNonBlocking;
- return ioctlsocket(Socket, FIONBIO, &NonBlockingMode) != SOCKET_ERROR;
-}
-UPTRINT TcpSocketConnect(const ANSICHAR* Host, uint16 Port)
-{
- TcpSocketInitialize();
- struct FAddrInfoPtr
- {
- ~FAddrInfoPtr() { freeaddrinfo(Value); }
- addrinfo* operator -> () { return Value; }
- addrinfo** operator & () { return &Value; }
- addrinfo* Value;
- };
- FAddrInfoPtr Info;
- addrinfo Hints = {};
- Hints.ai_family = AF_INET;
- Hints.ai_socktype = SOCK_STREAM;
- Hints.ai_protocol = IPPROTO_TCP;
- if (getaddrinfo(Host, nullptr, &Hints, &Info))
- {
- return 0;
- }
- if (&Info == nullptr)
- {
- return 0;
- }
- auto* SockAddr = (sockaddr_in*)Info->ai_addr;
- SockAddr->sin_port = htons(Port);
- SOCKET Socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_NO_HANDLE_INHERIT);
- if (Socket == INVALID_SOCKET)
- {
- return 0;
- }
- int Result = connect(Socket, Info->ai_addr, int(Info->ai_addrlen));
- if (Result == SOCKET_ERROR)
- {
- closesocket(Socket);
- return 0;
- }
- if (!TcpSocketSetNonBlocking(Socket, 0))
- {
- closesocket(Socket);
- return 0;
- }
- return UPTRINT(Socket) + 1;
-}
-UPTRINT TcpSocketListen(uint16 Port)
-{
- TcpSocketInitialize();
- SOCKET Socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_NO_HANDLE_INHERIT);
- if (Socket == INVALID_SOCKET)
- {
- return 0;
- }
- sockaddr_in SockAddr;
- SockAddr.sin_family = AF_INET;
- SockAddr.sin_addr.s_addr = 0;
- SockAddr.sin_port = htons(Port);
- int Result = bind(Socket, (SOCKADDR*)&SockAddr, sizeof(SockAddr));
- if (Result == INVALID_SOCKET)
- {
- closesocket(Socket);
- return 0;
- }
- Result = listen(Socket, 1);
- if (Result == INVALID_SOCKET)
- {
- closesocket(Socket);
- return 0;
- }
- if (!TcpSocketSetNonBlocking(Socket, 1))
- {
- closesocket(Socket);
- return 0;
- }
- return UPTRINT(Socket) + 1;
-}
-int32 TcpSocketAccept(UPTRINT Socket, UPTRINT& Out)
-{
- SOCKET Inner = Socket - 1;
- Inner = accept(Inner, nullptr, nullptr);
- if (Inner == INVALID_SOCKET)
- {
- return (WSAGetLastError() == WSAEWOULDBLOCK) - 1; // 0 if would block else -1
- }
- if (!TcpSocketSetNonBlocking(Inner, 0))
- {
- closesocket(Inner);
- return 0;
- }
- Out = UPTRINT(Inner) + 1;
- return 1;
-}
-bool TcpSocketHasData(UPTRINT Socket)
-{
- SOCKET Inner = Socket - 1;
- fd_set FdSet = { 1, { Inner }, };
- TIMEVAL TimeVal = {};
- return (select(0, &FdSet, nullptr, nullptr, &TimeVal) != 0);
-}
-bool IoWrite(UPTRINT Handle, const void* Data, uint32 Size)
-{
- HANDLE Inner = HANDLE(Handle - 1);
- DWORD BytesWritten = 0;
- if (!WriteFile(Inner, (const char*)Data, Size, &BytesWritten, nullptr))
- {
- return false;
- }
- return (BytesWritten == Size);
-}
-int32 IoRead(UPTRINT Handle, void* Data, uint32 Size)
-{
- HANDLE Inner = HANDLE(Handle - 1);
- DWORD BytesRead = 0;
- if (!ReadFile(Inner, (char*)Data, Size, &BytesRead, nullptr))
- {
- return -1;
- }
- return BytesRead;
-}
-void IoClose(UPTRINT Handle)
-{
- HANDLE Inner = HANDLE(Handle - 1);
- CloseHandle(Inner);
-}
-UPTRINT FileOpen(const ANSICHAR* Path)
-{
- DWORD Access = GENERIC_WRITE;
- DWORD Share = FILE_SHARE_READ;
- DWORD Disposition = CREATE_ALWAYS;
- DWORD Flags = FILE_ATTRIBUTE_NORMAL;
- HANDLE Out = CreateFile2((LPCWSTR)Path, Access, Share, Disposition, nullptr);
- if (Out == INVALID_HANDLE_VALUE)
- {
- return 0;
- }
- return UPTRINT(Out) + 1;
-}
-} // namespace Private
-} // namespace Trace
-} // namespace UE
-#pragma warning(pop)
-#endif // UE_TRACE_ENABLED
/* {{{1 UnixTrace.cpp */
#if UE_TRACE_ENABLED && PLATFORM_UNIX
@@ -4756,6 +5346,9 @@ static FCacheBuffer* GCacheHeadBuffer; // = nullptr;
extern FStatistics GTraceStatistics;
static FCacheBuffer* Writer_CacheCreateBuffer(uint32 Size)
{
+#if TRACE_PRIVATE_STATISTICS
+ GTraceStatistics.CacheAllocated += Size;
+#endif
void* Block = Writer_MemoryAllocate(sizeof(FCacheBuffer) + Size, alignof(FCacheBuffer));
auto* Buffer = (FCacheBuffer*)Block;
Buffer->Size = Size;
@@ -5005,6 +5598,8 @@ void Writer_ShutdownSharedBuffers()
// Copyright Epic Games, Inc. All Rights Reserved.
+// HEADER_UNIT_SKIP - Not included directly
+
// {{{1 amalgamation-tail //////////////////////////////////////////////////////
#if PLATFORM_WINDOWS
@@ -5013,6 +5608,19 @@ void Writer_ShutdownSharedBuffers()
#if TRACE_UE_COMPAT_LAYER
+namespace trace {
+
+#if defined(TRACE_HAS_ANALYSIS)
+
+inline void SerializeToCborImpl(TArray<uint8>&, const IAnalyzer::FEventData&, uint32)
+{
+ *(int32*)0 = 0; // unsupported
+}
+
+#endif // TRACE_HAS_ANALYSIS
+
+} // namespace trace
+
#if PLATFORM_WINDOWS
# if defined(UNICODE) || defined(_UNICODE)
# undef TEXT
@@ -5041,7 +5649,12 @@ void Writer_ShutdownSharedBuffers()
#define TRACE_CHANNEL_EXTERN UE_TRACE_CHANNEL_EXTERN
#define TRACE_CHANNEL_DEFINE UE_TRACE_CHANNEL_DEFINE
-namespace trace = UE::Trace;
+namespace trace {
+ using namespace UE::Trace;
+ namespace detail {
+ using namespace UE::Trace::Private;
+ }
+}
#define TRACE_PRIVATE_CONCAT_(x, y) x##y
#define TRACE_PRIVATE_CONCAT(x, y) TRACE_PRIVATE_CONCAT_(x, y)
@@ -5051,8 +5664,7 @@ namespace trace = UE::Trace;
// {{{1 session-header /////////////////////////////////////////////////////////
-namespace UE {
-namespace Trace {
+namespace trace {
enum class Build
{
@@ -5070,16 +5682,14 @@ void DescribeSession(
const std::string_view& CommandLine="",
const std::string_view& BuildVersion="unknown_ver");
-} // namespace Trace
-} // namespace UE
+} // namespace trace
// {{{1 session-source /////////////////////////////////////////////////////////
#if TRACE_IMPLEMENT
-namespace UE {
-namespace Trace {
-namespace Private {
+namespace trace {
+namespace detail {
TRACE_EVENT_BEGIN(Diagnostics, Session2, NoSync|Important)
TRACE_EVENT_FIELD(uint8, ConfigurationType)
@@ -5089,7 +5699,7 @@ TRACE_EVENT_BEGIN(Diagnostics, Session2, NoSync|Important)
TRACE_EVENT_FIELD(trace::AnsiString, CommandLine)
TRACE_EVENT_END()
-} // namespace Private
+} // namespace detail
////////////////////////////////////////////////////////////////////////////////
void DescribeSession(
@@ -5098,7 +5708,7 @@ void DescribeSession(
const std::string_view& CommandLine,
const std::string_view& BuildVersion)
{
- using namespace Private;
+ using namespace detail;
using namespace std::literals;
std::string_view Platform;
@@ -5112,22 +5722,21 @@ void DescribeSession(
Platform = "Unknown"sv;
#endif
- int DataSize = 0;
- DataSize += AppName.size();
- DataSize += BuildVersion.size();
- DataSize += Platform.size();
- DataSize += CommandLine.size();
+ int32 DataSize = 0;
+ DataSize += int32(AppName.size());
+ DataSize += int32(BuildVersion.size());
+ DataSize += int32(Platform.size());
+ DataSize += int32(CommandLine.size());
TRACE_LOG(Diagnostics, Session2, true, DataSize)
- << Session2.AppName(AppName.data(), int(AppName.size()))
- << Session2.BuildVersion(BuildVersion.data(), int(BuildVersion.size()))
- << Session2.Platform(Platform.data(), int(Platform.size()))
- << Session2.CommandLine(CommandLine.data(), int(CommandLine.size()))
+ << Session2.AppName(AppName.data(), int32(AppName.size()))
+ << Session2.BuildVersion(BuildVersion.data(), int32(BuildVersion.size()))
+ << Session2.Platform(Platform.data(), int32(Platform.size()))
+ << Session2.CommandLine(CommandLine.data(), int32(CommandLine.size()))
<< Session2.ConfigurationType(uint8(Variant));
}
-} // namespace Trace
-} // namespace UE
+} // namespace trace
#endif // TRACE_IMPLEMENT
@@ -5137,10 +5746,9 @@ void DescribeSession(
TRACE_CHANNEL_EXTERN(CpuChannel)
-namespace UE {
-namespace Trace {
+namespace trace {
-enum CpuScopeFlags : int
+enum CpuScopeFlags : int32
{
CpuFlush = 1 << 0,
};
@@ -5148,20 +5756,26 @@ enum CpuScopeFlags : int
struct TraceCpuScope
{
~TraceCpuScope();
- void Enter(int ScopeId, int Flags=0);
- int _ScopeId = 0;
+ void Enter(int32 ScopeId, int32 Flags=0);
+ int32 _ScopeId = 0;
};
-int ScopeNew(const std::string_view& Name);
+int32 ScopeNew(const std::string_view& Name);
-} // namespace Trace
-} // namespace UE
+class Lane;
+bool LaneIsTracing();
+Lane* LaneNew(const std::string_view& Name);
+void LaneDelete(Lane* Handle);
+void LaneEnter(Lane* Handle, int32 ScopeId);
+void LaneLeave();
+
+} // namespace trace
#define TRACE_CPU_SCOPE(name, ...) \
trace::TraceCpuScope TRACE_PRIVATE_UNIQUE_VAR(cpu_scope); \
if (CpuChannel) { \
using namespace std::literals; \
- static int TRACE_PRIVATE_UNIQUE_VAR(scope_id); \
+ static int32 TRACE_PRIVATE_UNIQUE_VAR(scope_id); \
if (0 == TRACE_PRIVATE_UNIQUE_VAR(scope_id)) \
TRACE_PRIVATE_UNIQUE_VAR(scope_id) = trace::ScopeNew(name##sv); \
TRACE_PRIVATE_UNIQUE_VAR(cpu_scope).Enter(TRACE_PRIVATE_UNIQUE_VAR(scope_id), ##__VA_ARGS__); \
@@ -5174,35 +5788,38 @@ int ScopeNew(const std::string_view& Name);
TRACE_CHANNEL_DEFINE(CpuChannel)
-namespace UE {
-namespace Trace {
-namespace Private {
+namespace trace {
+namespace detail {
TRACE_EVENT_BEGIN(CpuProfiler, EventSpec, NoSync|Important)
TRACE_EVENT_FIELD(uint32, Id)
TRACE_EVENT_FIELD(trace::AnsiString, Name)
TRACE_EVENT_END()
+TRACE_EVENT_BEGIN(CpuProfiler, NextBatchContext, NoSync)
+ TRACE_EVENT_FIELD(uint16, ThreadId)
+TRACE_EVENT_END()
+
TRACE_EVENT_BEGIN(CpuProfiler, EventBatch, NoSync)
TRACE_EVENT_FIELD(uint8[], Data)
TRACE_EVENT_END()
////////////////////////////////////////////////////////////////////////////////
-static int32_t encode32_7bit(int32_t value, void* __restrict out)
+static int32 encode32_7bit(int32 value, void* __restrict out)
{
// Calculate the number of bytes
- int32_t length = 1;
+ int32 length = 1;
length += (value >= (1 << 7));
length += (value >= (1 << 14));
length += (value >= (1 << 21));
// Add a gap every eigth bit for the continuations
- int32_t ret = value;
+ int32 ret = value;
ret = (ret & 0x0000'3fff) | ((ret & 0x0fff'c000) << 2);
ret = (ret & 0x007f'007f) | ((ret & 0x3f80'3f80) << 1);
// Set the bits indicating another byte follows
- int32_t continuations = 0x0080'8080;
+ int32 continuations = 0x0080'8080;
continuations >>= (sizeof(value) - length) * 8;
ret |= continuations;
@@ -5212,10 +5829,10 @@ static int32_t encode32_7bit(int32_t value, void* __restrict out)
}
////////////////////////////////////////////////////////////////////////////////
-static int32_t encode64_7bit(int64_t value, void* __restrict out)
+static int32 encode64_7bit(int64 value, void* __restrict out)
{
// Calculate the output length
- uint32_t length = 1;
+ uint32 length = 1;
length += (value >= (1ll << 7));
length += (value >= (1ll << 14));
length += (value >= (1ll << 21));
@@ -5225,13 +5842,13 @@ static int32_t encode64_7bit(int64_t value, void* __restrict out)
length += (value >= (1ll << 49));
// Add a gap every eigth bit for the continuations
- int64_t ret = value;
+ int64 ret = value;
ret = (ret & 0x0000'0000'0fff'ffffull) | ((ret & 0x00ff'ffff'f000'0000ull) << 4);
ret = (ret & 0x0000'3fff'0000'3fffull) | ((ret & 0x0fff'c000'0fff'c000ull) << 2);
ret = (ret & 0x007f'007f'007f'007full) | ((ret & 0x3f80'3f80'3f80'3f80ull) << 1);
// Set the bits indicating another byte follows
- int64_t continuations = 0x0080'8080'8080'8080ull;
+ int64 continuations = 0x0080'8080'8080'8080ull;
continuations >>= (sizeof(value) - length) * 8;
ret |= continuations;
@@ -5241,17 +5858,15 @@ static int32_t encode64_7bit(int64_t value, void* __restrict out)
}
////////////////////////////////////////////////////////////////////////////////
-class ThreadBuffer
+class ScopeBuffer
{
public:
- static void Enter(uint64_t Timestamp, uint32_t ScopeId, int Flags);
- static void Leave(uint64_t Timestamp);
+ void SetThreadId(uint32 Value) { ThreadIdOverride = Value; }
+ void Flush(bool Force);
+ void Enter(uint64 Timestamp, uint32 ScopeId, int32 Flag=0);
+ void Leave(uint64 Timestamp);
private:
- ~ThreadBuffer();
- void Flush(bool Force);
- void EnterImpl(uint64_t Timestamp, uint32_t ScopeId, int Flags);
- void LeaveImpl(uint64_t Timestamp);
enum
{
BufferSize = 256,
@@ -5259,41 +5874,27 @@ private:
EnterLsb = 1,
LeaveLsb = 0,
};
- uint64_t PrevTimestamp = 0;
- uint8_t* Cursor = Buffer;
- uint8_t Buffer[BufferSize];
-
- static thread_local ThreadBuffer TlsInstance;
+ uint64 PrevTimestamp = 0;
+ uint8* Cursor = Buffer;
+ uint32 ThreadIdOverride = 0;
+ uint8 Buffer[BufferSize];
};
-thread_local ThreadBuffer ThreadBuffer::TlsInstance;
-
-////////////////////////////////////////////////////////////////////////////////
-inline void ThreadBuffer::Enter(uint64_t Timestamp, uint32_t ScopeId, int Flags)
-{
- TlsInstance.EnterImpl(Timestamp, ScopeId, Flags);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-inline void ThreadBuffer::Leave(uint64_t Timestamp)
-{
- TlsInstance.LeaveImpl(Timestamp);
-}
-
////////////////////////////////////////////////////////////////////////////////
-ThreadBuffer::~ThreadBuffer()
+void ScopeBuffer::Flush(bool Force)
{
- Flush(true);
-}
+ using namespace detail;
-////////////////////////////////////////////////////////////////////////////////
-void ThreadBuffer::Flush(bool Force)
-{
- using namespace Private;
+ if (Cursor == Buffer)
+ return;
if (!Force && (Cursor <= (Buffer + BufferSize - Overflow)))
return;
+ if (ThreadIdOverride)
+ TRACE_LOG(CpuProfiler, NextBatchContext, true)
+ << NextBatchContext.ThreadId(uint16(ThreadIdOverride));
+
TRACE_LOG(CpuProfiler, EventBatch, true)
<< EventBatch.Data(Buffer, uint32(ptrdiff_t(Cursor - Buffer)));
@@ -5302,7 +5903,7 @@ void ThreadBuffer::Flush(bool Force)
}
////////////////////////////////////////////////////////////////////////////////
-void ThreadBuffer::EnterImpl(uint64_t Timestamp, uint32_t ScopeId, int Flags)
+void ScopeBuffer::Enter(uint64 Timestamp, uint32 ScopeId, int32 Flags)
{
Timestamp -= PrevTimestamp;
PrevTimestamp += Timestamp;
@@ -5314,7 +5915,7 @@ void ThreadBuffer::EnterImpl(uint64_t Timestamp, uint32_t ScopeId, int Flags)
}
////////////////////////////////////////////////////////////////////////////////
-void ThreadBuffer::LeaveImpl(uint64_t Timestamp)
+void ScopeBuffer::Leave(uint64 Timestamp)
{
Timestamp -= PrevTimestamp;
PrevTimestamp += Timestamp;
@@ -5323,17 +5924,98 @@ void ThreadBuffer::LeaveImpl(uint64_t Timestamp)
Flush(false);
}
-} // namespace Private
+////////////////////////////////////////////////////////////////////////////////
+class ThreadBuffer
+{
+public:
+ static void Enter(uint64 Timestamp, uint32 ScopeId, int32 Flags);
+ static void Leave(uint64 Timestamp);
+
+private:
+ ~ThreadBuffer();
+ ScopeBuffer Inner;
+
+ static thread_local ThreadBuffer TlsInstance;
+};
+
+thread_local ThreadBuffer ThreadBuffer::TlsInstance;
////////////////////////////////////////////////////////////////////////////////
-int ScopeNew(const std::string_view& Name)
+inline void ThreadBuffer::Enter(uint64 Timestamp, uint32 ScopeId, int32 Flags)
{
- using namespace Private;
+ TlsInstance.Inner.Enter(Timestamp, ScopeId, Flags);
+}
- static int volatile NextSpecId = 1;
- int SpecId = AtomicAddRelaxed(&NextSpecId, 1);
+////////////////////////////////////////////////////////////////////////////////
+inline void ThreadBuffer::Leave(uint64 Timestamp)
+{
+ TlsInstance.Inner.Leave(Timestamp);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+ThreadBuffer::~ThreadBuffer()
+{
+ Inner.Flush(true);
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+class Lane
+{
+public:
+ Lane(const std::string_view& Name);
+ ~Lane();
+ void Enter(int32 ScopeId);
+ void Leave();
+
+private:
+ ScopeBuffer Buffer;
+ uint32 Id;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+Lane::Lane(const std::string_view& Name)
+: Id(ScopeNew(Name))
+{
+ Buffer.SetThreadId(Id);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+Lane::~Lane()
+{
+ Buffer.Flush(true);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void Lane::Enter(int32 ScopeId)
+{
+ uint64 Timestamp = detail::TimeGetTimestamp();
+ Buffer.Enter(Timestamp, ScopeId);
+ Buffer.Flush(false);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void Lane::Leave()
+{
+ uint64 Timestamp = detail::TimeGetTimestamp();
+ Buffer.Leave(Timestamp);
+ Buffer.Flush(false);
+}
+
+} // namespace detail
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+int32 ScopeNew(const std::string_view& Name)
+{
+ using namespace detail;
+
+ static int32 volatile NextSpecId = 1;
+ int32 SpecId = AtomicAddRelaxed(&NextSpecId, 1);
uint32 NameSize = uint32(Name.size());
TRACE_LOG(CpuProfiler, EventSpec, true, NameSize)
@@ -5346,9 +6028,24 @@ int ScopeNew(const std::string_view& Name)
////////////////////////////////////////////////////////////////////////////////
+class Lane
+ : public detail::Lane
+{
+ using detail::Lane::Lane;
+};
+
+bool LaneIsTracing() { return bool(CpuChannel); }
+Lane* LaneNew(const std::string_view& Name) { return new Lane(Name); }
+void LaneDelete(Lane* Handle) { delete Handle; }
+void LaneEnter(Lane* Handle, int32 ScopeId) { Handle->Enter(ScopeId); }
+void LaneLeave(Lane* Handle) { Handle->Leave(); }
+
+
+
+////////////////////////////////////////////////////////////////////////////////
TraceCpuScope::~TraceCpuScope()
{
- using namespace Private;
+ using namespace detail;
if (!_ScopeId)
return;
@@ -5358,53 +6055,127 @@ TraceCpuScope::~TraceCpuScope()
}
////////////////////////////////////////////////////////////////////////////////
-void TraceCpuScope::Enter(int ScopeId, int Flags)
+void TraceCpuScope::Enter(int32 ScopeId, int32 Flags)
{
- using namespace Private;
+ using namespace detail;
_ScopeId = ScopeId;
uint64 Timestamp = TimeGetTimestamp();
ThreadBuffer::Enter(Timestamp, ScopeId, Flags);
}
-} // namespace Trace
-} // namespace UE
+} // namespace trace
#endif // TRACE_IMPLEMENT
+// {{{1 fmt-args-header ////////////////////////////////////////////////////////
+
+namespace trace::detail {
+
+template <typename T> concept IsIntegral = std::is_integral<T>::value;
+template <typename T> concept IsFloat = std::is_floating_point<T>::value;
+
+////////////////////////////////////////////////////////////////////////////////
+class ArgPacker
+{
+public:
+ template <typename... Types> ArgPacker(Types... Args);
+ const uint8* GetData() const { return Buffer; }
+ uint32 GetSize() const { return uint32(ptrdiff_t(Cursor - Buffer)); }
+
+private:
+ template <typename T> struct TypeId {};
+ template <typename T> requires IsIntegral<T> struct TypeId<T> { enum { Value = 1 << 6 }; };
+ template <typename T> requires IsFloat<T> struct TypeId<T> { enum { Value = 2 << 6 }; };
+
+ enum {
+ BufferSize = 512,
+ TypeIdStr = 3 << 6,
+ };
+ template <typename Type> uint32 PackValue(Type&& Value);
+ template <typename Type, typename... U> void Pack(Type&& Value, U... Next);
+ void Pack() {}
+ uint8* Cursor = Buffer;
+ const uint8* End = Buffer + BufferSize;
+ uint8 Buffer[BufferSize];
+};
+
+////////////////////////////////////////////////////////////////////////////////
+template <typename Type>
+uint32 ArgPacker::PackValue(Type&& Value)
+{
+ uint32 Size = sizeof(Type);
+ if (Cursor + Size > End)
+ return 0;
+
+ std::memcpy(Cursor, &Value, sizeof(Type));
+ Cursor += Size;
+ return TypeId<Type>::Value | sizeof(Type);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+template <typename... Types>
+ArgPacker::ArgPacker(Types... Args)
+{
+ static_assert(sizeof...(Args) <= 0xff);
+
+ int32 ArgCount = sizeof...(Args);
+ if (ArgCount == 0)
+ return;
+
+ *Cursor = uint8(ArgCount);
+ Cursor += ArgCount + 1;
+
+ Pack(std::forward<Types>(Args)...);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+template <typename T, typename... U>
+void ArgPacker::Pack(T&& Value, U... Next)
+{
+ uint8* TypeCursor = Buffer + Buffer[0] - sizeof...(Next);
+ if ((*TypeCursor = uint8(PackValue(std::forward<T>(Value)))) != 0)
+ return Pack(std::forward<U>(Next)...);
+
+ while (++TypeCursor < Buffer + Buffer[0] + 1)
+ *TypeCursor = 0;
+}
+
+} // namespace trace::detail
+
// {{{1 log-header /////////////////////////////////////////////////////////////
TRACE_CHANNEL_EXTERN(LogChannel)
-namespace UE {
-namespace Trace {
-namespace Private {
+namespace trace::detail {
-void LogMessageImpl(int Id, const void* ParamBuffer, int ParamSize);
-int LogMessageNew(const std::string_view& Format, const std::string_view& File, int Line);
+////////////////////////////////////////////////////////////////////////////////
+void LogMessageImpl(int32 Id, const uint8* ParamBuffer, int32 ParamSize);
+int32 LogMessageNew(const std::string_view& Format, const std::string_view& File, int32 Line);
-template <typename... ARGS>
-void LogMessage(int Id, ARGS&&... Args)
+////////////////////////////////////////////////////////////////////////////////
+template <typename... Types>
+void LogMessage(int32 Id, Types&&... Args)
{
- LogMessageImpl(Id, nullptr, 0);
+ ArgPacker Packer(std::forward<Types>(Args)...);
+ LogMessageImpl(Id, Packer.GetData(), Packer.GetSize());
}
-} // namespace Private
-} // namespace Trace
-} // namespace UE
+} // namespace trace::detail
+////////////////////////////////////////////////////////////////////////////////
#define TRACE_LOG_MESSAGE(format, ...) \
if (LogChannel) { \
using namespace std::literals; \
- static int message_id; \
+ static int32 message_id; \
if (message_id == 0) \
- message_id = trace::Private::LogMessageNew( \
+ message_id = trace::detail::LogMessageNew( \
format##sv, \
TRACE_PRIVATE_CONCAT(__FILE__, sv), \
__LINE__); \
- trace::Private::LogMessage(message_id, ##__VA_ARGS__); \
+ trace::detail::LogMessage(message_id, ##__VA_ARGS__); \
} \
do {} while (0)
@@ -5414,15 +6185,14 @@ void LogMessage(int Id, ARGS&&... Args)
TRACE_CHANNEL_DEFINE(LogChannel)
-namespace UE {
-namespace Trace {
-namespace Private {
+namespace trace::detail {
+////////////////////////////////////////////////////////////////////////////////
#if 0
TRACE_EVENT_BEGIN(Logging, LogCategory, NoSync|Important)
TRACE_EVENT_FIELD(const void*, CategoryPointer)
TRACE_EVENT_FIELD(uint8, DefaultVerbosity)
- TRACE_EVENT_FIELD(UE::Trace::AnsiString, Name)
+ TRACE_EVENT_FIELD(trace::AnsiString, Name)
TRACE_EVENT_END()
#endif
@@ -5430,8 +6200,8 @@ TRACE_EVENT_BEGIN(Logging, LogMessageSpec, NoSync|Important)
TRACE_EVENT_FIELD(uint32, LogPoint)
//TRACE_EVENT_FIELD(uint16, CategoryPointer)
TRACE_EVENT_FIELD(uint16, Line)
- TRACE_EVENT_FIELD(UE::Trace::AnsiString, FileName)
- TRACE_EVENT_FIELD(UE::Trace::AnsiString, FormatString)
+ TRACE_EVENT_FIELD(trace::AnsiString, FileName)
+ TRACE_EVENT_FIELD(trace::AnsiString, FormatString)
TRACE_EVENT_END()
TRACE_EVENT_BEGIN(Logging, LogMessage, NoSync)
@@ -5441,44 +6211,128 @@ TRACE_EVENT_BEGIN(Logging, LogMessage, NoSync)
TRACE_EVENT_END()
////////////////////////////////////////////////////////////////////////////////
-void LogMessageImpl(int Id, const void* ParamBuffer, int ParamSize)
+void LogMessageImpl(int32 Id, const uint8* ParamBuffer, int32 ParamSize)
{
- (void)ParamBuffer;
- (void)ParamSize;
-
uint64 Timestamp = TimeGetTimestamp();
TRACE_LOG(Logging, LogMessage, true)
<< LogMessage.LogPoint(Id)
- << LogMessage.Cycle(Timestamp);
+ << LogMessage.Cycle(Timestamp)
+ << LogMessage.FormatArgs(ParamBuffer, ParamSize);
}
////////////////////////////////////////////////////////////////////////////////
-int LogMessageNew(
+int32 LogMessageNew(
const std::string_view& Format,
const std::string_view& File,
- int Line)
+ int32 Line)
{
- static int volatile NextId = 1;
- int Id = AtomicAddRelaxed(&NextId, 1);
+ static int32 volatile NextId = 1;
+ int32 Id = AtomicAddRelaxed(&NextId, 1);
- int DataSize = 0;
- DataSize += Format.size();
- DataSize += File.size();
+ int32 DataSize = 0;
+ DataSize += int32(Format.size());
+ DataSize += int32(File.size());
TRACE_LOG(Logging, LogMessageSpec, true, DataSize)
<< LogMessageSpec.LogPoint(Id)
<< LogMessageSpec.Line(uint16(Line))
- << LogMessageSpec.FileName(File.data(), int(File.size()))
- << LogMessageSpec.FormatString(Format.data(), int(Format.size()));
+ << LogMessageSpec.FileName(File.data(), int32(File.size()))
+ << LogMessageSpec.FormatString(Format.data(), int32(Format.size()));
return Id;
}
-} // namespace Private
-} // namespace Trace
-} // namespace UE
+} // namespace trace::detail
#endif // TRACE_IMPLEMENT
+
+
+// {{{1 bookmark-header ////////////////////////////////////////////////////////
+
+namespace trace::detail {
+
+////////////////////////////////////////////////////////////////////////////////
+void BookmarkImpl(uint32 Id, const uint8* ParamBuffer, uint32 ParamSize);
+uint32 BookmarkNew(const std::string_view& Format, const std::string_view& File, uint32 Line);
+
+template <typename... Types>
+void Bookmark(uint32 Id, Types&&... Args)
+{
+ ArgPacker Packer(std::forward<Types>(Args)...);
+ BookmarkImpl(Id, Packer.GetData(), Packer.GetSize());
+}
+
+} // namespace trace::detail
+
+////////////////////////////////////////////////////////////////////////////////
+#define TRACE_BOOKMARK(format, ...) \
+ if (LogChannel) { \
+ using namespace std::literals; \
+ static int32 bookmark_id; \
+ if (bookmark_id == 0) \
+ bookmark_id = trace::detail::BookmarkNew( \
+ format##sv, \
+ TRACE_PRIVATE_CONCAT(__FILE__, sv), \
+ __LINE__); \
+ trace::detail::Bookmark(bookmark_id, ##__VA_ARGS__); \
+ } \
+ do {} while (0)
+
+// {{{1 bookmark-source ////////////////////////////////////////////////////////
+
+#if TRACE_IMPLEMENT
+
+namespace trace::detail {
+
+////////////////////////////////////////////////////////////////////////////////
+TRACE_EVENT_BEGIN(Misc, BookmarkSpec, NoSync|Important)
+ TRACE_EVENT_FIELD(uint32, BookmarkPoint)
+ TRACE_EVENT_FIELD(int32, Line)
+ TRACE_EVENT_FIELD(trace::AnsiString, FormatString)
+ TRACE_EVENT_FIELD(trace::AnsiString, FileName)
+TRACE_EVENT_END()
+
+TRACE_EVENT_BEGIN(Misc, Bookmark, NoSync)
+ TRACE_EVENT_FIELD(uint64, Cycle)
+ TRACE_EVENT_FIELD(uint32, BookmarkPoint)
+ TRACE_EVENT_FIELD(uint8[], FormatArgs)
+TRACE_EVENT_END()
+
+////////////////////////////////////////////////////////////////////////////////
+void BookmarkImpl(uint32 Id, const uint8* ParamBuffer, uint32 ParamSize)
+{
+ uint64 Timestamp = TimeGetTimestamp();
+
+ TRACE_LOG(Misc, Bookmark, true)
+ << Bookmark.Cycle(Timestamp)
+ << Bookmark.BookmarkPoint(Id)
+ << Bookmark.FormatArgs(ParamBuffer, ParamSize);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+uint32 BookmarkNew(const std::string_view& Format, const std::string_view& File, uint32 Line)
+{
+ uint32 Id = uint32(uintptr_t(Format.data()) >> 2);
+
+ int32 DataSize = 0;
+ DataSize += int32(Format.size());
+ DataSize += int32(File.size());
+
+ TRACE_LOG(Misc, BookmarkSpec, true, DataSize)
+ << BookmarkSpec.BookmarkPoint(Id)
+ << BookmarkSpec.Line(uint16(Line))
+ << BookmarkSpec.FormatString(Format.data(), int32(Format.size()))
+ << BookmarkSpec.FileName(File.data(), int32(File.size()));
+
+ return Id;
+}
+
+} // namespace trace::detail
+
+#endif // TRACE_IMPLEMENT
+
+// }}}
+
/* vim: set noet foldlevel=1 foldmethod=marker : */