aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2023-01-26 10:02:16 +0100
committerStefan Boberg <[email protected]>2023-01-26 10:02:16 +0100
commit283ef719ac57339f9338765bf2013ee110897396 (patch)
tree1d61eb02327edbc693c9907b7a14b3f2b6fb2aaf
parentremoved experimental mesh code (diff)
parentFixed macro leaking out (diff)
downloadzen-283ef719ac57339f9338765bf2013ee110897396.tar.xz
zen-283ef719ac57339f9338765bf2013ee110897396.zip
merge
-rw-r--r--CHANGELOG.md21
-rw-r--r--VERSION.txt2
-rw-r--r--thirdparty/trace/trace.h1978
-rw-r--r--xmake.lua23
-rw-r--r--zen/cmds/run.cpp189
-rw-r--r--zen/cmds/run.h30
-rw-r--r--zen/xmake.lua2
-rw-r--r--zen/zen.cpp15
-rw-r--r--zen/zen.rc33
-rw-r--r--zenserver-test/zenserver-test.cpp175
-rw-r--r--zenserver/experimental/usnjournal.cpp351
-rw-r--r--zenserver/experimental/usnjournal.h69
-rw-r--r--zenserver/experimental/vfs.cpp3
-rw-r--r--zenserver/experimental/vfs.h5
-rw-r--r--zenserver/testing/launch.cpp565
-rw-r--r--zenserver/testing/launch.h48
-rw-r--r--zenserver/xmake.lua2
-rw-r--r--zenserver/zenserver.cpp31
-rw-r--r--zenserver/zenserver.rc24
19 files changed, 1504 insertions, 2062 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2211b8404..61265733d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,18 +6,23 @@
- Feature: Added project store oplog info: `markerpath`, `totalsize`, `opcount`, `expired` on GET requests for oplog
- Feature: Added project store project info: `expired` on GET requests for project
- Feature :Added project store root route `/prj` which is identical to `/prj/list`
-- Feature: zen command line tool `cache-info` to show cache, namespace or bucket info
-- Feature: zen command line tool `project-info` to show store, project or oplog info
-- Feature: zen command line tool `project-drop` to drop project or oplog
-- Feature: zen command line tool `gc` to trigger a GC run
-- Feature: zen command line tool `gc-info` to check status of GC
+- Feature: Zen command line tool `cache-info` to show cache, namespace or bucket info
+- Feature: Zen command line tool `project-info` to show store, project or oplog info
+- Feature: Zen command line tool `project-drop` to drop project or oplog
+- Feature: Zen command line tool `gc` to trigger a GC run
+- Feature: Zen command line tool `gc-info` to check status of GC
+- Feature: Added version information to zenserver and zen command line tool executables
- Bugfix: Don't log "time to next GC" if time to next GC is not set
- Improvement: Don't wait for GC monitor interval before doing first GC check
-- Improvement: zen command line tool now fails on any unrecognized arguments
-- Improvement: zen command line tool now displays extra help for all sub-commands
-- Improvement: host address can now be configured for zen command line tool `drop` command
+- Improvement: Zen command line tool now fails on any unrecognized arguments
+- Improvement: Zen command line tool now displays extra help for all sub-commands
+- Improvement: Host address can now be configured for zen command line tool `drop` command
+- Improvement: Added precommit xmake task `xmake precommit` to run precommit checks
- Changed: Default GC interval set to 1 hour
- Changed: Default GC cache duration set to 2 weeks
+- Changed: Removed HttpLaunchService and related code
+- Changed: Removed dead/experimental file system related code
+- Changed: Removed faux vfs config option
## 0.2.1
- Feature: Oplog level GC in project store. If gc marker file path is given by UE, oplogs will be GC:d when marker file is deleted (and GC is triggered)
diff --git a/VERSION.txt b/VERSION.txt
index 7dff5b892..f4778493c 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1 +1 @@
-0.2.1 \ No newline at end of file
+0.2.2 \ No newline at end of file
diff --git a/thirdparty/trace/trace.h b/thirdparty/trace/trace.h
index d7fbbb71f..612173ce1 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 (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 (GPendingDataHandle || GDataHandle)
+ 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
@@ -5021,6 +5629,8 @@ void Writer_ShutdownSharedBuffers()
# endif
#endif
+#undef check
+
#endif // TRACE_UE_COMPAT_LAYER
@@ -5041,7 +5651,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 +5666,7 @@ namespace trace = UE::Trace;
// {{{1 session-header /////////////////////////////////////////////////////////
-namespace UE {
-namespace Trace {
+namespace trace {
enum class Build
{
@@ -5070,16 +5684,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 +5701,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 +5710,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 +5724,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 +5748,9 @@ void DescribeSession(
TRACE_CHANNEL_EXTERN(CpuChannel)
-namespace UE {
-namespace Trace {
+namespace trace {
-enum CpuScopeFlags : int
+enum CpuScopeFlags : int32
{
CpuFlush = 1 << 0,
};
@@ -5148,20 +5758,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 +5790,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 +5831,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 +5844,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 +5860,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 +5876,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 +5905,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 +5917,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 +5926,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 +6030,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 +6057,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 +6187,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 +6202,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 +6213,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 : */
diff --git a/xmake.lua b/xmake.lua
index 30dedf0c3..7844f75b9 100644
--- a/xmake.lua
+++ b/xmake.lua
@@ -105,14 +105,6 @@ if not is_arch("arm64") then
end
if is_os("windows") then
- option("vfs")
- -- note: this is an old prototype and is not functional at all at the moment
- set_default(false)
- set_showmenu(false)
- set_description("Enable VFS functionality")
- option_end()
- add_define_by_config("ZEN_WITH_VFS", "vfs")
-
option("httpsys")
set_default(true)
set_showmenu(true)
@@ -135,12 +127,6 @@ option("compute")
option_end()
add_define_by_config("ZEN_WITH_COMPUTE_SERVICES", "compute")
-option("exec")
- set_default(is_os("windows"))
- set_showmenu(true)
- set_description("Enable exec services endpoint")
-option_end()
-add_define_by_config("ZEN_WITH_EXEC_SERVICES", "exec")
option("zentrace")
set_default(true)
@@ -176,6 +162,15 @@ task("bundle")
bundle()
end)
+task("precommit")
+ set_menu {
+ usage = "xmake precommit",
+ description = "Run required pre-commit steps (clang-format, etc)",
+ }
+ on_run(function ()
+ print(os.exec("pre-commit run --all-files"))
+ end)
+
task("test")
set_menu {
usage = "xmake runtest [core|store|server|integration|all]",
diff --git a/zen/cmds/run.cpp b/zen/cmds/run.cpp
deleted file mode 100644
index 6ba74e2fd..000000000
--- a/zen/cmds/run.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#define _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS // for <cstdbool> include warning triggered by cpr
-
-#include "run.h"
-
-#if ZEN_WITH_EXEC_SERVICES
-
-# include <zencore/compactbinarybuilder.h>
-# include <zencore/except.h>
-# include <zencore/filesystem.h>
-# include <zencore/fmtutils.h>
-# include <zencore/iohash.h>
-# include <zencore/logging.h>
-# include <zencore/stream.h>
-# include <zencore/string.h>
-# include <zencore/timer.h>
-# include <zenutil/zenserverprocess.h>
-
-# include <filesystem>
-
-ZEN_THIRD_PARTY_INCLUDES_START
-# include <cpr/cpr.h>
-ZEN_THIRD_PARTY_INCLUDES_END
-
-# if ZEN_PLATFORM_WINDOWS
-# pragma comment(lib, "Crypt32.lib")
-# pragma comment(lib, "Wldap32.lib")
-# pragma comment(lib, "Ws2_32.lib")
-# endif
-
-//////////////////////////////////////////////////////////////////////////
-
-namespace zen {
-
-using namespace std::literals;
-
-RunCommand::RunCommand()
-{
- m_Options.add_options()("h,host", "Host to run on", cxxopts::value<std::string>(m_TargetHost))("d,dir",
- "Tree to run",
- cxxopts::value<std::string>(m_ExeTree));
-}
-
-RunCommand::~RunCommand() = default;
-
-void
-CreateTreeManifest(std::filesystem::path RootPath)
-{
- ZEN_UNUSED(RootPath);
-}
-
-int
-RunCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
-{
- if (GlobalOptions.PassthroughV.empty())
- {
- throw cxxopts::OptionParseException("run command requires a command to run!");
- }
-
- ZenServerEnvironment TestEnv;
- std::filesystem::path ProgramBaseDir = std::filesystem::path(argv[0]).parent_path();
- std::filesystem::path TestBaseDir = ProgramBaseDir.parent_path().parent_path() / ".test";
- TestEnv.InitializeForTest(ProgramBaseDir, TestBaseDir);
-
- std::filesystem::path TestDir = TestEnv.CreateNewTestDir();
-
- ZenServerInstance Zen1(TestEnv);
- Zen1.SetTestDir(TestDir);
- Zen1.SpawnServer(13337);
-
- if (!ParseOptions(argc, argv))
- {
- return 0;
- }
- auto result = m_Options.parse(argc, argv);
-
- std::filesystem::path TreePath{m_ExeTree};
-
- struct Visitor : public zen::FileSystemTraversal::TreeVisitor
- {
- const std::filesystem::path& m_RootPath;
-
- Visitor(const std::filesystem::path& RootPath) : m_RootPath(RootPath) {}
-
- virtual void VisitFile(const std::filesystem::path& Parent, const path_view& FileName, uint64_t FileSize) override
- {
- std::filesystem::path FullPath = Parent / FileName;
-
- zen::IoHashStream Ios;
- zen::ScanFile(FullPath, 64 * 1024, [&](const void* Data, size_t Size) { Ios.Append(Data, Size); });
- zen::IoHash Hash = Ios.GetHash();
-
- path_string RelativePath = FullPath.lexically_relative(m_RootPath).native();
- // ZEN_INFO("File: {:32} => {} ({})", zen::WideToUtf8(RelativePath), Hash, FileSize);
-
- FileEntry& Entry = m_Files[RelativePath];
- Entry.Hash = Hash;
- Entry.Size = FileSize;
-
- m_HashToFile[Hash] = FullPath;
- }
-
- virtual bool VisitDirectory(const std::filesystem::path& Parent, const path_view& DirectoryName) override
- {
- std::filesystem::path FullPath = Parent / DirectoryName;
-
- if (DirectoryName.starts_with('.'))
- {
- return false;
- }
-
- return true;
- }
-
- struct FileEntry
- {
- uint64_t Size;
- zen::IoHash Hash;
- };
-
- std::map<path_string, FileEntry> m_Files;
- std::unordered_map<zen::IoHash, std::filesystem::path, zen::IoHash::Hasher> m_HashToFile;
- };
-
- zen::FileSystemTraversal Traversal;
- Visitor Visit(TreePath);
- Traversal.TraverseFileSystem(TreePath, Visit);
-
- zen::CbObjectWriter PrepReq;
- PrepReq << "cmd" << GlobalOptions.PassthroughV[0];
- PrepReq << "args" << GlobalOptions.PassthroughArgs;
- PrepReq.BeginArray("files");
-
- for (const auto& Kv : Visit.m_Files)
- {
- PrepReq.BeginObject();
- PrepReq << "file" << zen::PathToUtf8(Kv.first) << "size" << Kv.second.Size << "hash" << Kv.second.Hash;
- PrepReq.EndObject();
- }
- PrepReq.EndArray();
-
- zen::BinaryWriter MemOut;
- PrepReq.Save(MemOut);
-
- Zen1.WaitUntilReady();
-
- cpr::Response Response =
- cpr::Post(cpr::Url("http://localhost:13337/exec/jobs/prep"), cpr::Body((const char*)MemOut.Data(), MemOut.Size()));
-
- if (Response.status_code < 300)
- {
- zen::IoBuffer Payload(zen::IoBuffer::Clone, Response.text.data(), Response.text.size());
- zen::CbObject Result = zen::LoadCompactBinaryObject(Payload);
-
- for (auto& Need : Result["need"])
- {
- zen::IoHash NeedHash = Need.AsHash();
-
- if (auto It = Visit.m_HashToFile.find(NeedHash); It != Visit.m_HashToFile.end())
- {
- zen::IoBuffer FileData = zen::IoBufferBuilder::MakeFromFile(It->second);
-
- cpr::Response CasResponse =
- cpr::Post(cpr::Url("http://localhost:13337/cid"), cpr::Body((const char*)FileData.Data(), FileData.Size()));
-
- if (CasResponse.status_code >= 300)
- {
- ZEN_ERROR("CAS put failed with {}", CasResponse.status_code);
- }
- }
- else
- {
- ZEN_ERROR("unknown hash in 'need' list: {}", NeedHash);
- }
- }
- }
-
- cpr::Response JobResponse =
- cpr::Post(cpr::Url("http://localhost:13337/exec/jobs"), cpr::Body((const char*)MemOut.Data(), MemOut.Size()));
-
- ZEN_CONSOLE("job exec: {}", JobResponse.status_code);
-
- return 0;
-}
-
-} // namespace zen
-
-#endif // ZEN_WITH_EXEC_SERVICES
diff --git a/zen/cmds/run.h b/zen/cmds/run.h
deleted file mode 100644
index 440ea4ea4..000000000
--- a/zen/cmds/run.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#pragma once
-
-#include "../zen.h"
-
-#if ZEN_WITH_EXEC_SERVICES
-
-namespace zen {
-
-/** Execute a command (using Zen)
- */
-class RunCommand : public ZenCmdBase
-{
-public:
- RunCommand();
- ~RunCommand();
-
- virtual int Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
- virtual cxxopts::Options& Options() override { return m_Options; }
-
-private:
- cxxopts::Options m_Options{"run", "Run command"};
- std::string m_TargetHost;
- std::string m_ExeTree;
-};
-
-} // namespace zen
-
-#endif // ZEN_WITH_EXEC_SERVICES
diff --git a/zen/xmake.lua b/zen/xmake.lua
index 6f4d74f0e..86d95406e 100644
--- a/zen/xmake.lua
+++ b/zen/xmake.lua
@@ -13,8 +13,10 @@ target("zen")
end
if is_plat("windows") then
+ add_files("zen.rc")
add_ldflags("/subsystem:console,5.02")
add_ldflags("/LTCG")
+ add_ldflags("crypt32.lib", "wldap32.lib", "Ws2_32.lib")
end
if is_plat("macosx") then
diff --git a/zen/zen.cpp b/zen/zen.cpp
index b4159df3a..e02f3a510 100644
--- a/zen/zen.cpp
+++ b/zen/zen.cpp
@@ -14,7 +14,6 @@
#include "cmds/importproject.h"
#include "cmds/print.h"
#include "cmds/projectstore.h"
-#include "cmds/run.h"
#include "cmds/scrub.h"
#include "cmds/status.h"
#include "cmds/top.h"
@@ -144,13 +143,10 @@ main(int argc, char** argv)
auto _ = zen::MakeGuard([] { spdlog::shutdown(); });
- HashCommand HashCmd;
- CopyCommand CopyCmd;
- DedupCommand DedupCmd;
- DropCommand DropCmd;
-#if ZEN_WITH_EXEC_SERVICES
- RunCommand RunCmd;
-#endif
+ HashCommand HashCmd;
+ CopyCommand CopyCmd;
+ DedupCommand DedupCmd;
+ DropCommand DropCmd;
StatusCommand StatusCmd;
TopCommand TopCmd;
PrintCommand PrintCmd;
@@ -187,9 +183,6 @@ main(int argc, char** argv)
{"import-project", &ImportProjectCmd, "Import project store oplog"},
{"print", &PrintCmd, "Print compact binary object"},
{"printpackage", &PrintPkgCmd, "Print compact binary package"},
-#if ZEN_WITH_EXEC_SERVICES
- {"run", &RunCmd, "Remote execution"},
-#endif // ZEN_WITH_EXEC_SERVICES
{"status", &StatusCmd, "Show zen status"},
{"ps", &PsCmd, "Enumerate running zen server instances"},
{"top", &TopCmd, "Monitor zen server activity"},
diff --git a/zen/zen.rc b/zen/zen.rc
new file mode 100644
index 000000000..14a9afb70
--- /dev/null
+++ b/zen/zen.rc
@@ -0,0 +1,33 @@
+#include "zencore/config.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+101 ICON "..\\UnrealEngine.ico"
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION ZEN_CFG_VERSION_MAJOR,ZEN_CFG_VERSION_MINOR,ZEN_CFG_VERSION_ALTER,0
+PRODUCTVERSION ZEN_CFG_VERSION_MAJOR,ZEN_CFG_VERSION_MINOR,ZEN_CFG_VERSION_ALTER,0
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904b0"
+ {
+ VALUE "CompanyName", "Epic Games Inc\0"
+ VALUE "FileDescription", "CLI utility for Zen Storage Service\0"
+ VALUE "FileVersion", ZEN_CFG_VERSION "\0"
+ VALUE "LegalCopyright", "Copyright Epic Games Inc. All Rights Reserved\0"
+ VALUE "OriginalFilename", "zen.exe\0"
+ VALUE "ProductName", "Zen Storage Server\0"
+ VALUE "ProductVersion", ZEN_CFG_VERSION_BUILD_STRING_FULL "\0"
+ }
+ }
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x409, 1200
+ }
+}
diff --git a/zenserver-test/zenserver-test.cpp b/zenserver-test/zenserver-test.cpp
index c08ad8e0a..5c7e150ce 100644
--- a/zenserver-test/zenserver-test.cpp
+++ b/zenserver-test/zenserver-test.cpp
@@ -2317,181 +2317,6 @@ TEST_CASE("zcache.rpc.allpolicies")
}
}
-# if ZEN_WITH_EXEC_SERVICES
-
-struct RemoteExecutionRequest
-{
- RemoteExecutionRequest(std::string_view Host, int Port, std::filesystem::path& TreePath)
- : m_HostName(Host)
- , m_PortNumber(Port)
- , m_TreePath(TreePath)
- {
- }
-
- void Build(std::string_view Command, std::string_view Arguments)
- {
- zen::FileSystemTraversal Traversal;
- Traversal.TraverseFileSystem(m_TreePath, m_Visit);
-
- zen::CbObjectWriter PrepReq;
-
- PrepReq << "cmd" << Command;
- PrepReq << "args" << Arguments;
-
- PrepReq.BeginArray("files");
-
- for (const auto& Kv : m_Visit.m_Files)
- {
- PrepReq.BeginObject();
- PrepReq << "file" << zen::PathToUtf8(Kv.first) << "size" << Kv.second.Size << "hash" << Kv.second.Hash;
- PrepReq.EndObject();
- }
- PrepReq.EndArray();
-
- PrepReq.Save(m_MemOut);
- }
-
- void Prep()
- {
- cpr::Response Response =
- cpr::Post(cpr::Url(fmt::format("{}/prep", m_BaseUri)), cpr::Body((const char*)m_MemOut.Data(), m_MemOut.Size()));
-
- if (Response.status_code < 300)
- {
- zen::IoBuffer Payload(zen::IoBuffer::Clone, Response.text.data(), Response.text.size());
- zen::CbObject Result = zen::LoadCompactBinaryObject(Payload);
-
- for (auto& Need : Result["need"])
- {
- zen::IoHash NeedHash = Need.AsHash();
-
- if (auto It = m_Visit.m_HashToFile.find(NeedHash); It != m_Visit.m_HashToFile.end())
- {
- zen::IoBuffer FileData = zen::IoBufferBuilder::MakeFromFile(It->second);
-
- cpr::Response CidResponse = cpr::Post(cpr::Url(m_CidUri), cpr::Body((const char*)FileData.Data(), FileData.Size()));
-
- if (CidResponse.status_code >= 300)
- {
- ZEN_ERROR("CID put failed with {}", CidResponse.status_code);
- }
- }
- else
- {
- ZEN_ERROR("unknown hash in 'need' list: {}", NeedHash);
- }
- }
- }
- }
-
- zen::CbObject Exec()
- {
- cpr::Response JobResponse = cpr::Post(cpr::Url(m_BaseUri), cpr::Body((const char*)m_MemOut.Data(), m_MemOut.Size()));
-
- if (JobResponse.status_code < 300)
- {
- zen::IoBuffer Payload(zen::IoBuffer::Clone, JobResponse.text.data(), JobResponse.text.size());
- return zen::LoadCompactBinaryObject(std::move(Payload));
- }
-
- ZEN_INFO("job exec: {}", JobResponse.status_code);
- return {};
- }
-
-private:
- struct Visitor : public zen::FileSystemTraversal::TreeVisitor
- {
- const std::filesystem::path& m_RootPath;
-
- Visitor(const std::filesystem::path& RootPath) : m_RootPath(RootPath) {}
-
- virtual void VisitFile(const std::filesystem::path& Parent, const path_view& FileName, uint64_t FileSize) override
- {
- std::filesystem::path FullPath = Parent / FileName;
-
- zen::IoHashStream Ios;
- zen::ScanFile(FullPath, 64 * 1024, [&](const void* Data, size_t Size) { Ios.Append(Data, Size); });
- zen::IoHash Hash = Ios.GetHash();
-
- auto RelativePath = FullPath.lexically_relative(m_RootPath).native();
- // ZEN_INFO("File: {:32} => {} ({})", zen::PathToUtf8(RelativePath), Hash, FileSize);
-
- FileEntry& Entry = m_Files[RelativePath];
- Entry.Hash = Hash;
- Entry.Size = FileSize;
-
- m_HashToFile[Hash] = FullPath;
- }
-
- virtual bool VisitDirectory(const std::filesystem::path& Parent, const path_view& DirectoryName) override
- {
- std::filesystem::path FullPath = Parent / DirectoryName;
-
- if (DirectoryName.starts_with('.'))
- {
- return false;
- }
-
- return true;
- }
-
- struct FileEntry
- {
- uint64_t Size;
- zen::IoHash Hash;
- };
-
- std::map<std::filesystem::path::string_type, FileEntry> m_Files;
- std::unordered_map<zen::IoHash, std::filesystem::path, zen::IoHash::Hasher> m_HashToFile;
- };
-
- std::string m_HostName;
- int m_PortNumber;
- std::filesystem::path m_TreePath;
- const std::string m_BaseUri = fmt::format("http://{}:{}/exec/jobs", m_HostName, m_PortNumber);
- const std::string m_CidUri = fmt::format("http://{}:{}/cid", m_HostName, m_PortNumber);
- Visitor m_Visit{m_TreePath};
- zen::BinaryWriter m_MemOut;
-};
-
-TEST_CASE(".exec.basic")
-{
- if (true)
- {
- return;
- }
- using namespace std::literals;
-
- std::filesystem::path TestDir = TestEnv.CreateNewTestDir();
-
- const uint16_t PortNumber = 13337;
-
- ZenServerInstance Zen1(TestEnv);
- Zen1.SetTestDir(TestDir);
- Zen1.SpawnServer(PortNumber);
- Zen1.WaitUntilReady();
-
- std::filesystem::path TreePath = TestEnv.GetTestRootDir("test/remote1");
-
- {
- RemoteExecutionRequest RemoteRequest("localhost", PortNumber, TreePath);
- RemoteRequest.Build("zentest-appstub.exe", "");
- RemoteRequest.Prep();
- zen::CbObject Result = RemoteRequest.Exec();
-
- CHECK(Result["exitcode"sv].AsInt32(-1) == 0);
- }
-
- {
- RemoteExecutionRequest RemoteRequest("localhost", PortNumber, TreePath);
- RemoteRequest.Build("zentest-appstub.exe", "-f=1");
- RemoteRequest.Prep();
- zen::CbObject Result = RemoteRequest.Exec();
- CHECK(Result["exitcode"sv].AsInt32(-1) == 1);
- }
-}
-# endif // ZEN_WITH_EXEC_SERVICES
-
class ZenServerTestHelper
{
public:
diff --git a/zenserver/experimental/usnjournal.cpp b/zenserver/experimental/usnjournal.cpp
deleted file mode 100644
index 580d71e45..000000000
--- a/zenserver/experimental/usnjournal.cpp
+++ /dev/null
@@ -1,351 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#include <zencore/zencore.h>
-
-#if ZEN_PLATFORM_WINDOWS
-
-# include "usnjournal.h"
-
-# include <zencore/except.h>
-# include <zencore/logging.h>
-# include <zencore/timer.h>
-
-ZEN_THIRD_PARTY_INCLUDES_START
-# include <atlfile.h>
-ZEN_THIRD_PARTY_INCLUDES_END
-
-# include <filesystem>
-
-namespace zen {
-
-UsnJournalReader::UsnJournalReader()
-{
-}
-
-UsnJournalReader::~UsnJournalReader()
-{
- delete[] m_JournalReadBuffer;
-}
-
-bool
-UsnJournalReader::Initialize(std::filesystem::path VolumePath)
-{
- TCHAR VolumeName[MAX_PATH];
- TCHAR VolumePathName[MAX_PATH];
-
- {
- auto NativePath = VolumePath.native();
- BOOL Success = GetVolumePathName(NativePath.c_str(), VolumePathName, ZEN_ARRAY_COUNT(VolumePathName));
-
- if (!Success)
- {
- zen::ThrowLastError("GetVolumePathName failed");
- }
-
- Success = GetVolumeNameForVolumeMountPoint(VolumePathName, VolumeName, ZEN_ARRAY_COUNT(VolumeName));
-
- if (!Success)
- {
- zen::ThrowLastError("GetVolumeNameForVolumeMountPoint failed");
- }
-
- // Chop off trailing slash since we want to open a volume handle, not a handle to the volume root directory
-
- const size_t VolumeNameLength = wcslen(VolumeName);
-
- if (VolumeNameLength)
- {
- VolumeName[VolumeNameLength - 1] = '\0';
- }
- }
-
- m_VolumeHandle = CreateFile(VolumeName,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- nullptr, /* no custom security */
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS,
- nullptr); /* template */
-
- if (m_VolumeHandle == INVALID_HANDLE_VALUE)
- {
- ThrowLastError("Volume handle open failed");
- }
-
- // Figure out which file system is in use for volume
-
- {
- WCHAR InfoVolumeName[MAX_PATH + 1]{};
- WCHAR FileSystemName[MAX_PATH + 1]{};
- DWORD MaximumComponentLength = 0;
- DWORD FileSystemFlags = 0;
-
- BOOL Success = GetVolumeInformationByHandleW(m_VolumeHandle,
- InfoVolumeName,
- MAX_PATH + 1,
- NULL,
- &MaximumComponentLength,
- &FileSystemFlags,
- FileSystemName,
- ZEN_ARRAY_COUNT(FileSystemName));
-
- if (!Success)
- {
- ThrowLastError("Failed to get volume information");
- }
-
- ZEN_DEBUG("File system type is {}", WideToUtf8(FileSystemName));
-
- if (wcscmp(L"ReFS", FileSystemName) == 0)
- {
- m_FileSystemType = FileSystemType::ReFS;
- }
- else if (wcscmp(L"NTFS", FileSystemName) == 0)
- {
- m_FileSystemType = FileSystemType::NTFS;
- }
- else
- {
- // Unknown file system type!
- }
- }
-
- // Determine if volume is on fast storage, where seeks aren't so expensive
-
- {
- STORAGE_PROPERTY_QUERY StorageQuery{};
- StorageQuery.PropertyId = StorageDeviceSeekPenaltyProperty;
- StorageQuery.QueryType = PropertyStandardQuery;
- DWORD BytesWritten;
- DEVICE_SEEK_PENALTY_DESCRIPTOR Result{};
-
- if (DeviceIoControl(m_VolumeHandle,
- IOCTL_STORAGE_QUERY_PROPERTY,
- &StorageQuery,
- sizeof(StorageQuery),
- &Result,
- sizeof(Result),
- &BytesWritten,
- nullptr))
- {
- m_IncursSeekPenalty = !!Result.IncursSeekPenalty;
- }
- }
-
- // Query Journal
-
- USN_JOURNAL_DATA_V2 UsnData{};
-
- {
- DWORD BytesWritten = 0;
-
- const BOOL Success =
- DeviceIoControl(m_VolumeHandle, FSCTL_QUERY_USN_JOURNAL, nullptr, 0, &UsnData, sizeof UsnData, &BytesWritten, nullptr);
-
- if (!Success)
- {
- switch (DWORD Error = GetLastError())
- {
- case ERROR_JOURNAL_NOT_ACTIVE:
- ZEN_INFO("No USN journal active on drive");
-
- // TODO: optionally activate USN journal on drive?
-
- ThrowSystemException(HRESULT_FROM_WIN32(Error), "No USN journal active on drive");
- break;
-
- default:
- ThrowSystemException(HRESULT_FROM_WIN32(Error), "FSCTL_QUERY_USN_JOURNAL failed");
- }
- }
- }
-
- m_JournalReadBuffer = new uint8_t[m_ReadBufferSize];
-
- // Catch up to USN start
-
- CAtlFile VolumeRootDir;
- HRESULT hRes =
- VolumeRootDir.Create(VolumePathName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS);
-
- if (FAILED(hRes))
- {
- ThrowSystemException(hRes, "Failed to open handle to volume root");
- }
-
- FILE_ID_INFO FileInformation{};
- BOOL Success = GetFileInformationByHandleEx(VolumeRootDir, FileIdInfo, &FileInformation, sizeof FileInformation);
-
- if (!Success)
- {
- ThrowLastError("GetFileInformationByHandleEx failed");
- }
-
- const Frn VolumeRootFrn = FileInformation.FileId;
-
- // Enumerate MFT (but not for ReFS)
-
- if (m_FileSystemType == FileSystemType::NTFS)
- {
- ZEN_INFO("Enumerating MFT for {}", WideToUtf8(VolumePathName));
-
- zen::Stopwatch Timer;
- uint64_t MftBytesProcessed = 0;
-
- MFT_ENUM_DATA_V1 MftEnumData{.StartFileReferenceNumber = 0, .LowUsn = 0, .HighUsn = 0, .MinMajorVersion = 2, .MaxMajorVersion = 3};
-
- BYTE MftBuffer[64 * 1024 + sizeof(DWORDLONG)];
- DWORD BytesWritten = 0;
-
- for (;;)
- {
- Success = DeviceIoControl(m_VolumeHandle,
- FSCTL_ENUM_USN_DATA,
- &MftEnumData,
- sizeof MftEnumData,
- MftBuffer,
- sizeof MftBuffer,
- &BytesWritten,
- nullptr);
-
- if (!Success)
- {
- DWORD Error = GetLastError();
-
- if (Error == ERROR_HANDLE_EOF)
- {
- break;
- }
-
- ThrowSystemException(HRESULT_FROM_WIN32(Error), "FSCTL_ENUM_USN_DATA failed");
- }
-
- void* BufferEnd = (void*)&MftBuffer[BytesWritten];
-
- // The enumeration call returns the next FRN ahead of the other data in the buffer
- MftEnumData.StartFileReferenceNumber = ((DWORDLONG*)MftBuffer)[0];
-
- PUSN_RECORD_UNION CommonRecord = PUSN_RECORD_UNION(&((DWORDLONG*)MftBuffer)[1]);
-
- while (CommonRecord < BufferEnd)
- {
- switch (CommonRecord->Header.MajorVersion)
- {
- case 2:
- {
- USN_RECORD_V2& Record = CommonRecord->V2;
-
- const Frn FileReference = Record.FileReferenceNumber;
- const Frn ParentReference = Record.ParentFileReferenceNumber;
- std::wstring_view FileName{Record.FileName, Record.FileNameLength};
- }
- break;
- case 3:
- {
- USN_RECORD_V3& Record = CommonRecord->V3;
-
- const Frn FileReference = Record.FileReferenceNumber;
- const Frn ParentReference = Record.ParentFileReferenceNumber;
- std::wstring_view FileName{Record.FileName, Record.FileNameLength};
- }
- break;
- case 4:
- {
- // This captures file modification ranges. We do not yet support this however
- USN_RECORD_V4& Record = CommonRecord->V4;
- ZEN_UNUSED(Record);
- }
- break;
- }
-
- const DWORD RecordLength = CommonRecord->Header.RecordLength;
- CommonRecord = PUSN_RECORD_UNION(((uint8_t*)CommonRecord) + RecordLength);
- MftBytesProcessed += RecordLength;
- }
- }
-
- const auto ElapsedMs = Timer.GetElapsedTimeMs();
-
- ZEN_INFO("MFT enumeration of {} completed after {} ({})",
- zen::NiceBytes(MftBytesProcessed),
- zen::NiceTimeSpanMs(ElapsedMs),
- zen::NiceByteRate(MftBytesProcessed, ElapsedMs));
- }
-
- // Populate by traversal
- if (m_FileSystemType == FileSystemType::ReFS)
- {
- uint64_t FileInfoBuffer[8 * 1024];
-
- FILE_INFO_BY_HANDLE_CLASS FibClass = FileIdBothDirectoryRestartInfo;
- bool Continue = true;
-
- while (Continue)
- {
- Success = GetFileInformationByHandleEx(VolumeRootDir, FibClass, FileInfoBuffer, sizeof FileInfoBuffer);
- FibClass = FileIdBothDirectoryInfo; // Set up for next iteration
-
- uint64_t EntryOffset = 0;
-
- if (!Success)
- {
- // Report failure?
-
- break;
- }
-
- do
- {
- const FILE_ID_BOTH_DIR_INFO* DirInfo =
- reinterpret_cast<const FILE_ID_BOTH_DIR_INFO*>(reinterpret_cast<const uint8_t*>(FileInfoBuffer) + EntryOffset);
-
- const uint64_t NextOffset = DirInfo->NextEntryOffset;
-
- if (NextOffset == 0)
- {
- if (EntryOffset == 0)
- {
- // First and last - end of iteration
- Continue = false;
- }
- break;
- }
-
- if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- {
- // TODO Directory
- }
- else if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DEVICE)
- {
- // TODO Device
- }
- else
- {
- // TODO File
- }
-
- EntryOffset += DirInfo->NextEntryOffset;
- } while (EntryOffset);
- }
- }
-
- // Initialize journal reading
-
- m_ReadUsnJournalData = {.StartUsn = UsnData.FirstUsn,
- .ReasonMask = USN_REASON_BASIC_INFO_CHANGE | USN_REASON_CLOSE | USN_REASON_DATA_EXTEND |
- USN_REASON_DATA_OVERWRITE | USN_REASON_DATA_TRUNCATION | USN_REASON_FILE_CREATE |
- USN_REASON_FILE_DELETE | USN_REASON_HARD_LINK_CHANGE | USN_REASON_RENAME_NEW_NAME |
- USN_REASON_RENAME_OLD_NAME | USN_REASON_REPARSE_POINT_CHANGE,
- .ReturnOnlyOnClose = true,
- .Timeout = 0,
- .BytesToWaitFor = 0,
- .UsnJournalID = UsnData.UsnJournalID,
- .MinMajorVersion = 0,
- .MaxMajorVersion = 0};
-
- return false;
-}
-
-} // namespace zen
-
-#endif // ZEN_PLATFORM_WINDOWS
diff --git a/zenserver/experimental/usnjournal.h b/zenserver/experimental/usnjournal.h
deleted file mode 100644
index 910eb7d06..000000000
--- a/zenserver/experimental/usnjournal.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#pragma once
-
-#if ZEN_PLATFORM_WINDOWS
-
-# include <zencore/windows.h>
-# include <zencore/zencore.h>
-
-ZEN_THIRD_PARTY_INCLUDES_START
-# include <winioctl.h>
-ZEN_THIRD_PARTY_INCLUDES_END
-
-# include <filesystem>
-
-namespace zen {
-
-class UsnJournalReader
-{
-public:
- UsnJournalReader();
- ~UsnJournalReader();
-
- bool Initialize(std::filesystem::path VolumePath);
-
-private:
- void* m_VolumeHandle;
- READ_USN_JOURNAL_DATA_V1 m_ReadUsnJournalData;
- bool m_IncursSeekPenalty = true;
-
- uint8_t* m_JournalReadBuffer = nullptr;
- uint64_t m_ReadBufferSize = 64 * 1024;
-
- struct Frn
- {
- uint8_t IdBytes[16];
-
- Frn() = default;
-
- Frn(const FILE_ID_128& Rhs) { memcpy(IdBytes, Rhs.Identifier, sizeof IdBytes); }
- Frn& operator=(const FILE_ID_128& Rhs) { memcpy(IdBytes, Rhs.Identifier, sizeof IdBytes); }
-
- Frn(const uint64_t& Rhs)
- {
- memcpy(IdBytes, &Rhs, sizeof Rhs);
- memset(&IdBytes[8], 0, 8);
- }
-
- Frn& operator=(const uint64_t& Rhs)
- {
- memcpy(IdBytes, &Rhs, sizeof Rhs);
- memset(&IdBytes[8], 0, 8);
- }
-
- std::strong_ordering operator<=>(const Frn&) const = default;
- };
-
- enum class FileSystemType
- {
- ReFS,
- NTFS
- };
-
- FileSystemType m_FileSystemType = FileSystemType::NTFS;
-};
-
-} // namespace zen
-
-#endif // ZEN_PLATFORM_WINDOWS
diff --git a/zenserver/experimental/vfs.cpp b/zenserver/experimental/vfs.cpp
deleted file mode 100644
index 1af9d70a7..000000000
--- a/zenserver/experimental/vfs.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#include "vfs.h"
diff --git a/zenserver/experimental/vfs.h b/zenserver/experimental/vfs.h
deleted file mode 100644
index 1aeefe481..000000000
--- a/zenserver/experimental/vfs.h
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#pragma once
-
-#include <zencore/zencore.h>
diff --git a/zenserver/testing/launch.cpp b/zenserver/testing/launch.cpp
deleted file mode 100644
index b26f9e437..000000000
--- a/zenserver/testing/launch.cpp
+++ /dev/null
@@ -1,565 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#include "launch.h"
-
-#if ZEN_WITH_EXEC_SERVICES
-
-# include <zencore/compactbinary.h>
-# include <zencore/compactbinarybuilder.h>
-# include <zencore/compress.h>
-# include <zencore/filesystem.h>
-# include <zencore/fmtutils.h>
-# include <zencore/iobuffer.h>
-# include <zencore/iohash.h>
-# include <zencore/logging.h>
-# include <zencore/windows.h>
-# include <zenstore/cidstore.h>
-
-ZEN_THIRD_PARTY_INCLUDES_START
-# include <AccCtrl.h>
-# include <AclAPI.h>
-# include <UserEnv.h>
-# include <atlbase.h>
-# include <sddl.h>
-ZEN_THIRD_PARTY_INCLUDES_END
-# pragma comment(lib, "UserEnv.lib")
-
-# include <filesystem>
-# include <span>
-
-using namespace std::literals;
-
-namespace zen {
-
-struct BasicJob
-{
-public:
- BasicJob() = default;
- ~BasicJob();
-
- void SetWorkingDirectory(const std::filesystem::path& WorkingDirectory) { m_WorkingDirectory = WorkingDirectory; }
- bool SpawnJob(std::filesystem::path ExePath, std::wstring CommandLine);
- bool Wait(uint32_t TimeoutMs = ~0);
- int ExitCode();
-
-private:
- std::filesystem::path m_WorkingDirectory;
- int m_ProcessId = 0;
- CHandle m_ProcessHandle;
-};
-
-BasicJob::~BasicJob()
-{
- Wait();
-}
-
-bool
-BasicJob::SpawnJob(std::filesystem::path ExePath, std::wstring CommandLine)
-{
- STARTUPINFOEX StartupInfo = {sizeof(STARTUPINFOEX)};
- PROCESS_INFORMATION ProcessInfo{};
-
- std::wstring ExePathNative = ExePath.native();
- std::wstring WorkingDirNative = m_WorkingDirectory.native();
-
- BOOL Created = ::CreateProcess(ExePathNative.data() /* ApplicationName */,
- CommandLine.data() /* Command Line */,
- nullptr /* Process Attributes */,
- nullptr /* Security Attributes */,
- FALSE /* InheritHandles */,
- 0 /* Flags */,
- nullptr /* Environment */,
- WorkingDirNative.data() /* Current Directory */,
- (LPSTARTUPINFO)&StartupInfo,
- &ProcessInfo);
-
- if (!Created)
- {
- throw std::system_error(::GetLastError(), std::system_category(), fmt::format("Failed to create process '{}'", ExePath).c_str());
- }
-
- m_ProcessId = ProcessInfo.dwProcessId;
- m_ProcessHandle.Attach(ProcessInfo.hProcess);
- ::CloseHandle(ProcessInfo.hThread);
-
- ZEN_INFO("Created process {}", m_ProcessId);
-
- return true;
-}
-
-bool
-BasicJob::Wait(uint32_t TimeoutMs)
-{
- if (!m_ProcessHandle)
- {
- return true;
- }
-
- DWORD WaitResult = WaitForSingleObject(m_ProcessHandle, TimeoutMs);
-
- if (WaitResult == WAIT_TIMEOUT)
- {
- return false;
- }
-
- if (WaitResult == WAIT_OBJECT_0)
- {
- return true;
- }
-
- throw std::runtime_error("Failed wait on process handle");
-}
-
-int
-BasicJob::ExitCode()
-{
- DWORD Ec = 0;
- BOOL Success = GetExitCodeProcess(m_ProcessHandle, &Ec);
-
- if (!Success)
- {
- ZEN_WARN("failed getting exit code");
- }
-
- if (Ec == STILL_ACTIVE)
- {
- ZEN_WARN("getting exit code but process is STILL_ACTIVE");
- }
-
- return gsl::narrow_cast<int>(Ec);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-struct SandboxedJob
-{
- SandboxedJob() = default;
- ~SandboxedJob() = default;
-
- void SetWorkingDirectory(const std::filesystem::path& WorkingDirectory) { m_WorkingDirectory = WorkingDirectory; }
- void Initialize(std::string_view AppContainerId);
- bool SpawnJob(std::filesystem::path ExePath);
- void AddWhitelistFile(const std::filesystem::path& FilePath) { m_WhitelistFiles.push_back(FilePath); }
-
-private:
- bool GrantNamedObjectAccess(PWSTR Name, SE_OBJECT_TYPE Type, ACCESS_MASK AccessMask, bool Recursive);
-
- std::filesystem::path m_WorkingDirectory;
- std::vector<std::filesystem::path> m_WhitelistFiles;
- std::vector<std::wstring> m_WhitelistRegistryKeys;
- PSID m_AppContainerSid = nullptr;
- bool m_IsInitialized = false;
-};
-
-bool
-SandboxedJob::GrantNamedObjectAccess(PWSTR ObjectName, SE_OBJECT_TYPE ObjectType, ACCESS_MASK AccessMask, bool Recursive)
-{
- DWORD Status;
- PACL NewAcl = nullptr;
-
- DWORD grfInhericance = 0;
-
- if (Recursive)
- {
- grfInhericance = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
- }
-
- EXPLICIT_ACCESS Access{.grfAccessPermissions = AccessMask,
- .grfAccessMode = GRANT_ACCESS,
- .grfInheritance = grfInhericance,
- .Trustee = {.pMultipleTrustee = nullptr,
- .MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE,
- .TrusteeForm = TRUSTEE_IS_SID,
- .TrusteeType = TRUSTEE_IS_GROUP,
- .ptstrName = (PWSTR)m_AppContainerSid}};
-
- PACL OldAcl = nullptr;
-
- Status = GetNamedSecurityInfo(ObjectName /* ObjectName */,
- ObjectType /* ObjectType */,
- DACL_SECURITY_INFORMATION /* SecurityInfo */,
- nullptr /* ppsidOwner */,
- nullptr /* ppsidGroup */,
- &OldAcl /* ppDacl */,
- nullptr /* ppSacl */,
- nullptr /* ppSecurityDescriptor */);
- if (Status != ERROR_SUCCESS)
- return false;
-
- Status = SetEntriesInAcl(1 /* CountOfExplicitEntries */, &Access /* pListOfExplicitEntries */, OldAcl, &NewAcl);
- if (Status != ERROR_SUCCESS)
- return false;
-
- Status = SetNamedSecurityInfo(ObjectName /* ObjectName */,
- ObjectType /* ObjectType */,
- DACL_SECURITY_INFORMATION /*SecurityInfo */,
- nullptr /* psidOwner */,
- nullptr /* psidGroup */,
- NewAcl /* pDacl */,
- nullptr /* pSacl */);
- if (NewAcl)
- ::LocalFree(NewAcl);
-
- return Status == ERROR_SUCCESS;
-}
-
-void
-SandboxedJob::Initialize(std::string_view AppContainerId)
-{
- if (m_IsInitialized)
- {
- return;
- }
-
- std::wstring ContainerName = zen::Utf8ToWide(AppContainerId);
-
- HRESULT hRes = ::CreateAppContainerProfile(ContainerName.c_str(),
- ContainerName.c_str() /* Display Name */,
- ContainerName.c_str() /* Description */,
- nullptr /* Capabilities */,
- 0 /* Capability Count */,
- &m_AppContainerSid);
-
- if (FAILED(hRes))
- {
- hRes = ::DeriveAppContainerSidFromAppContainerName(ContainerName.c_str(), &m_AppContainerSid);
-
- if (FAILED(hRes))
- {
- ZEN_ERROR("Failed creating app container SID");
- }
- }
-
- // Debugging context
-
- PWSTR Str = nullptr;
- ::ConvertSidToStringSid(m_AppContainerSid, &Str);
-
- ZEN_INFO("AppContainer SID : '{}'", WideToUtf8(Str));
-
- PWSTR Path = nullptr;
- if (SUCCEEDED(::GetAppContainerFolderPath(Str, &Path)))
- {
- ZEN_INFO("AppContainer folder: '{}'", WideToUtf8(Path));
-
- ::CoTaskMemFree(Path);
- }
- ::LocalFree(Str);
-
- m_IsInitialized = true;
-}
-
-bool
-SandboxedJob::SpawnJob(std::filesystem::path ExePath)
-{
- // Build process attributes
-
- SECURITY_CAPABILITIES Sc = {0};
- Sc.AppContainerSid = m_AppContainerSid;
-
- STARTUPINFOEX StartupInfo = {sizeof(STARTUPINFOEX)};
- PROCESS_INFORMATION ProcessInfo{};
- SIZE_T Size = 0;
-
- ::InitializeProcThreadAttributeList(nullptr, 1, 0, &Size);
-
- auto AttrBuffer = std::make_unique<uint8_t[]>(Size);
- StartupInfo.lpAttributeList = reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(AttrBuffer.get());
-
- if (!::InitializeProcThreadAttributeList(StartupInfo.lpAttributeList, 1, 0, &Size))
- {
- return false;
- }
-
- if (!::UpdateProcThreadAttribute(StartupInfo.lpAttributeList,
- 0,
- PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES,
- &Sc,
- sizeof Sc,
- nullptr,
- nullptr))
- {
- return false;
- }
-
- // Set up security for files/folders/registry
-
- for (const std::filesystem::path& File : m_WhitelistFiles)
- {
- std::wstring NativeFileName = File.native();
- GrantNamedObjectAccess(NativeFileName.data(), SE_FILE_OBJECT, FILE_ALL_ACCESS, true);
- }
-
- for (std::wstring& RegKey : m_WhitelistRegistryKeys)
- {
- GrantNamedObjectAccess(RegKey.data(), SE_REGISTRY_WOW64_32KEY, KEY_ALL_ACCESS, true);
- }
-
- std::wstring ExePathNative = ExePath.native();
- std::wstring WorkingDirNative = m_WorkingDirectory.native();
-
- BOOL Created = ::CreateProcess(nullptr /* ApplicationName */,
- ExePathNative.data() /* Command line */,
- nullptr /* Process Attributes */,
- nullptr /* Security Attributes */,
- FALSE /* InheritHandles */,
- EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE /* Flags */,
- nullptr /* Environment */,
- WorkingDirNative.data() /* Current Directory */,
- (LPSTARTUPINFO)&StartupInfo,
- &ProcessInfo);
-
- DeleteProcThreadAttributeList(StartupInfo.lpAttributeList);
-
- if (!Created)
- {
- return false;
- }
-
- ZEN_INFO("Created process {}", ProcessInfo.dwProcessId);
-
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-HttpLaunchService::HttpLaunchService(CidStore& Store, const std::filesystem::path& SandboxBaseDir)
-: m_Log(logging::Get("exec"))
-, m_CidStore(Store)
-, m_SandboxPath(SandboxBaseDir)
-{
- m_Router.AddPattern("job", "([[:digit:]]+)");
-
- m_Router.RegisterRoute(
- "jobs/{job}",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
-
- switch (HttpReq.RequestVerb())
- {
- case HttpVerb::kGet:
- break;
-
- case HttpVerb::kPost:
- break;
-
- default:
- break;
- }
- },
- HttpVerb::kGet | HttpVerb::kPost);
-
- // Experimental
-
-# if 0
- m_Router.RegisterRoute(
- "jobs/sandbox",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
-
- switch (HttpReq.RequestVerb())
- {
- case HttpVerb::kGet:
- break;
-
- case HttpVerb::kPost:
- {
- SandboxedJob Job;
- Job.Initialize("zen_test");
- Job.SetWorkingDirectory("c:\\temp\\sandbox1");
- Job.AddWhitelistFile("c:\\temp\\sandbox1");
- Job.SpawnJob("c:\\windows\\system32\\cmd.exe");
- }
- break;
-
- default:
- break;
- }
- },
- HttpVerb::kGet | HttpVerb::kPost);
-# endif
-
- m_Router.RegisterRoute(
- "jobs/prep",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
-
- switch (HttpReq.RequestVerb())
- {
- case HttpVerb::kPost:
- {
- // This operation takes the proposed job spec and identifies which
- // chunks are not present on this server. This list is then returned in
- // the "need" list in the response
-
- IoBuffer Payload = HttpReq.ReadPayload();
- CbObject RequestObject = LoadCompactBinaryObject(Payload);
-
- std::vector<IoHash> NeedList;
-
- for (auto Entry : RequestObject["files"sv])
- {
- CbObjectView Ob = Entry.AsObjectView();
-
- const IoHash FileHash = Ob["hash"sv].AsHash();
-
- if (!m_CidStore.FindChunkByCid(FileHash))
- {
- ZEN_DEBUG("NEED: {} {} {}", FileHash, Ob["file"sv].AsString(), Ob["size"sv].AsUInt64());
-
- NeedList.push_back(FileHash);
- }
- }
-
- CbObjectWriter Cbo;
- Cbo.BeginArray("need");
-
- for (const IoHash& Hash : NeedList)
- {
- Cbo << Hash;
- }
-
- Cbo.EndArray();
- CbObject Response = Cbo.Save();
-
- return HttpReq.WriteResponse(HttpResponseCode::OK, Response);
- }
- break;
-
- default:
- break;
- }
- },
- HttpVerb::kPost);
-
- m_Router.RegisterRoute(
- "jobs",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
-
- switch (HttpReq.RequestVerb())
- {
- case HttpVerb::kGet:
- break;
-
- case HttpVerb::kPost:
- {
- IoBuffer Payload = HttpReq.ReadPayload();
- CbObject RequestObject = LoadCompactBinaryObject(Payload);
-
- bool AllOk = true;
-
- std::vector<IoHash> NeedList;
-
- std::filesystem::path SandboxDir{CreateNewSandbox()};
-
- ZEN_DEBUG("setting up job in sandbox '{}'", SandboxDir);
-
- zen::DeleteDirectories(SandboxDir);
- zen::CreateDirectories(SandboxDir);
-
- for (auto Entry : RequestObject["files"sv])
- {
- CbObjectView Ob = Entry.AsObjectView();
-
- std::string_view FileName = Ob["file"sv].AsString();
- const IoHash FileHash = Ob["hash"sv].AsHash();
- uint64_t FileSize = Ob["size"sv].AsUInt64();
-
- if (IoBuffer Chunk = m_CidStore.FindChunkByCid(FileHash); !Chunk)
- {
- ZEN_DEBUG("MISSING: {} {} {}", FileHash, FileName, FileSize);
- AllOk = false;
-
- NeedList.push_back(FileHash);
- }
- else
- {
- std::filesystem::path FullPath = SandboxDir / FileName;
-
- IoHash RawHash;
- uint64_t RawSize;
- CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Chunk), RawHash, RawSize);
- ZEN_ASSERT(Compressed);
- ZEN_ASSERT(FileHash == RawHash);
- CompositeBuffer CompositeBuffer = Compressed.DecompressToComposite();
- std::span<const SharedBuffer> Segments = CompositeBuffer.GetSegments();
- std::vector<IoBuffer> Chunks(Segments.size());
- std::vector<IoBuffer*> ChunkPtrs(Segments.size());
- for (size_t Index = 0; Index < Segments.size(); ++Index)
- {
- Chunks[Index] = std::move(Segments[Index].AsIoBuffer());
- ChunkPtrs[Index] = &Chunks[Index];
- }
-
- zen::WriteFile(FullPath, ChunkPtrs.data(), ChunkPtrs.size());
- }
- }
-
- if (!AllOk)
- {
- // TODO: Could report all the missing pieces in the response here
- return HttpReq.WriteResponse(HttpResponseCode::NotFound);
- }
-
- std::string Executable8{RequestObject["cmd"].AsString()};
- std::string Args8{RequestObject["args"].AsString()};
-
- std::wstring Executable = Utf8ToWide(Executable8);
- std::wstring Args = Utf8ToWide(Args8);
-
- ZEN_DEBUG("spawning job in sandbox '{}': '{}' '{}'", SandboxDir, Executable8, Args8);
-
- std::filesystem::path ExeName = SandboxDir / Executable;
-
- BasicJob Job;
- Job.SetWorkingDirectory(SandboxDir);
- Job.SpawnJob(ExeName, Args);
- Job.Wait();
-
- CbObjectWriter Response;
-
- Response << "exitcode" << Job.ExitCode();
-
- return HttpReq.WriteResponse(HttpResponseCode::OK, Response.Save());
- }
- break;
-
- default:
- break;
- }
- },
- HttpVerb::kGet | HttpVerb::kPost);
-}
-
-HttpLaunchService::~HttpLaunchService()
-{
-}
-
-const char*
-HttpLaunchService::BaseUri() const
-{
- return "/exec/";
-}
-
-void
-HttpLaunchService::HandleRequest(HttpServerRequest& Request)
-{
- if (m_Router.HandleRequest(Request) == false)
- {
- ZEN_WARN("No route found for {0}", Request.RelativeUri());
- }
-}
-
-std::filesystem::path
-HttpLaunchService::CreateNewSandbox()
-{
- std::string UniqueId = std::to_string(++m_SandboxCount);
- std::filesystem::path Path = m_SandboxPath / UniqueId;
- zen::CreateDirectories(Path);
- return Path;
-}
-
-} // namespace zen
-
-#endif // ZEN_WITH_EXEC_SERVICES
diff --git a/zenserver/testing/launch.h b/zenserver/testing/launch.h
deleted file mode 100644
index f44618bfb..000000000
--- a/zenserver/testing/launch.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#pragma once
-
-#include <zencore/zencore.h>
-
-#if !defined(ZEN_WITH_EXEC_SERVICES)
-# define ZEN_WITH_EXEC_SERVICES ZEN_PLATFORM_WINDOWS
-#endif
-
-#if ZEN_WITH_EXEC_SERVICES
-
-# include <zencore/logging.h>
-# include <zenhttp/httpserver.h>
-
-# include <filesystem>
-
-namespace zen {
-
-class CidStore;
-
-/**
- * Process launcher for test executables
- */
-class HttpLaunchService : public HttpService
-{
-public:
- HttpLaunchService(CidStore& Store, const std::filesystem::path& SandboxBaseDir);
- ~HttpLaunchService();
-
- virtual const char* BaseUri() const override;
- virtual void HandleRequest(HttpServerRequest& Request) override;
-
-private:
- inline spdlog::logger& Log() { return m_Log; }
-
- spdlog::logger& m_Log;
- HttpRequestRouter m_Router;
- CidStore& m_CidStore;
- std::filesystem::path m_SandboxPath;
- std::atomic<int> m_SandboxCount{0};
-
- std::filesystem::path CreateNewSandbox();
-};
-
-} // namespace zen
-
-#endif // ZEN_WITH_EXEC_SERVICES
diff --git a/zenserver/xmake.lua b/zenserver/xmake.lua
index 2174ad679..8b18bf9f9 100644
--- a/zenserver/xmake.lua
+++ b/zenserver/xmake.lua
@@ -16,6 +16,7 @@ target("zenserver")
add_ldflags("/subsystem:console,5.02")
add_ldflags("/MANIFEST:EMBED")
add_ldflags("/LTCG")
+ add_files("zenserver.rc")
else
remove_files("windows/**")
end
@@ -30,7 +31,6 @@ target("zenserver")
add_syslinks("bsm")
end
- add_options("vfs")
add_options("compute")
add_options("exec")
diff --git a/zenserver/zenserver.cpp b/zenserver/zenserver.cpp
index c1e82f404..526e27152 100644
--- a/zenserver/zenserver.cpp
+++ b/zenserver/zenserver.cpp
@@ -105,13 +105,11 @@ ZEN_THIRD_PARTY_INCLUDES_END
#include "cidstore.h"
#include "compute/function.h"
#include "diag/diagsvcs.h"
-#include "experimental/usnjournal.h"
#include "frontend/frontend.h"
#include "monitoring/httpstats.h"
#include "monitoring/httpstatus.h"
#include "projectstore.h"
#include "testing/httptest.h"
-#include "testing/launch.h"
#include "upstream/upstream.h"
#include "zenstore/gc.h"
@@ -266,23 +264,6 @@ public:
m_ProjectStore = new zen::ProjectStore(*m_CidStore, m_DataRoot / "projects", m_GcManager);
m_HttpProjectService.reset(new zen::HttpProjectService{*m_CidStore, m_ProjectStore});
-#if ZEN_WITH_EXEC_SERVICES
-
- if (ServerOptions.ExecServiceEnabled)
- {
- ZEN_INFO("instantiating exec service");
-
- std::filesystem::path SandboxDir = m_DataRoot / "exec" / "sandbox";
- zen::CreateDirectories(SandboxDir);
- m_HttpLaunchService = std::make_unique<zen::HttpLaunchService>(*m_CidStore, SandboxDir);
- }
- else
- {
- ZEN_INFO("NOT instantiating exec services");
- }
-
-#endif // ZEN_WITH_EXEC_SERVICES
-
#if ZEN_WITH_COMPUTE_SERVICES
if (ServerOptions.ComputeServiceEnabled)
{
@@ -319,15 +300,6 @@ public:
m_Http->RegisterService(*m_CidService);
-#if ZEN_WITH_EXEC_SERVICES
- if (ServerOptions.ExecServiceEnabled)
- {
- if (m_HttpLaunchService != nullptr)
- {
- m_Http->RegisterService(*m_HttpLaunchService);
- }
- }
-#endif // ZEN_WITH_EXEC_SERVICES
#if ZEN_WITH_COMPUTE_SERVICES
if (ServerOptions.ComputeServiceEnabled)
{
@@ -592,9 +564,6 @@ private:
std::unique_ptr<zen::HttpStructuredCacheService> m_StructuredCacheService;
zen::HttpAdminService m_AdminService{m_GcScheduler};
zen::HttpHealthService m_HealthService;
-#if ZEN_WITH_EXEC_SERVICES
- std::unique_ptr<zen::HttpLaunchService> m_HttpLaunchService;
-#endif // ZEN_WITH_EXEC_SERVICES
#if ZEN_WITH_COMPUTE_SERVICES
std::unique_ptr<zen::HttpFunctionService> m_HttpFunctionService;
#endif // ZEN_WITH_COMPUTE_SERVICES
diff --git a/zenserver/zenserver.rc b/zenserver/zenserver.rc
index c063436ef..6d31e2c6e 100644
--- a/zenserver/zenserver.rc
+++ b/zenserver/zenserver.rc
@@ -2,6 +2,8 @@
//
#include "resource.h"
+#include "zencore/config.h"
+
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
@@ -79,3 +81,25 @@ END
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION ZEN_CFG_VERSION_MAJOR,ZEN_CFG_VERSION_MINOR,ZEN_CFG_VERSION_ALTER,0
+PRODUCTVERSION ZEN_CFG_VERSION_MAJOR,ZEN_CFG_VERSION_MINOR,ZEN_CFG_VERSION_ALTER,0
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904b0"
+ {
+ VALUE "CompanyName", "Epic Games Inc\0"
+ VALUE "FileDescription", "Local Storage Service for Unreal Engine\0"
+ VALUE "FileVersion", ZEN_CFG_VERSION "\0"
+ VALUE "LegalCopyright", "Copyright Epic Games Inc. All Rights Reserved\0"
+ VALUE "OriginalFilename", "zenserver.exe\0"
+ VALUE "ProductName", "Zen Storage Server\0"
+ VALUE "ProductVersion", ZEN_CFG_VERSION_BUILD_STRING_FULL "\0"
+ }
+ }
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x409, 1200
+ }
+}