Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

415 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Trace/Config.h"
#if TRACE_PRIVATE_MINIMAL_ENABLED
#include "Atomic.h"
#include "EventNode.h"
#include "HAL/Platform.h" // for PLATFORM_BREAK
#include "LogScope.h"
#include "Protocol.h"
#include "Writer.inl"
#include "AutoRTFM.h"
namespace UE {
namespace Trace {
namespace Private {
////////////////////////////////////////////////////////////////////////////////
extern TRACELOG_API uint64 GStartCycle;
extern TRACELOG_API uint32 volatile GLogSerial;
////////////////////////////////////////////////////////////////////////////////
UE_AUTORTFM_ALWAYS_OPEN
inline void FLogScope::Commit() const
{
AtomicStoreRelease((uint8**) &(Buffer->Committed), Buffer->Cursor);
}
////////////////////////////////////////////////////////////////////////////////
UE_AUTORTFM_ALWAYS_OPEN
inline void FLogScope::Commit(FWriteBuffer* __restrict LatestBuffer) const
{
if (LatestBuffer != Buffer)
{
AtomicStoreRelease((uint8**) &(LatestBuffer->Committed), LatestBuffer->Cursor);
}
Commit();
}
////////////////////////////////////////////////////////////////////////////////
template <uint32 Flags>
UE_AUTORTFM_ALWAYS_OPEN
inline auto FLogScope::EnterImpl(uint32 Uid, uint32 Size)
{
TLogScope<(Flags & FEventInfo::Flag_MaybeHasAux) != 0> Ret;
if ((Flags & FEventInfo::Flag_NoSync) != 0)
{
Ret.EnterNoSync(Uid, Size);
}
else
{
Ret.Enter(Uid, Size);
}
return Ret;
}
////////////////////////////////////////////////////////////////////////////////
template <class HeaderType>
UE_AUTORTFM_ALWAYS_OPEN
inline void FLogScope::EnterPrelude(uint32 Size)
{
uint32 AllocSize = sizeof(HeaderType) + Size;
Buffer = Writer_GetBuffer();
if (UNLIKELY(Buffer->Cursor + AllocSize > (uint8*)Buffer))
{
Buffer = Writer_NextBuffer();
}
#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST
if (AllocSize >= Buffer->Size)
{
// This situation is terminal. Someone's trying to trace an event that
// is far too large. This should never happen as 'maximum_field_count *
// largest_field_size' won't exceed Buffer.Size.
PLATFORM_BREAK();
}
#endif
Ptr = Buffer->Cursor + sizeof(HeaderType);
Buffer->Cursor += AllocSize;
}
////////////////////////////////////////////////////////////////////////////////
UE_AUTORTFM_ALWAYS_OPEN
inline void FLogScope::Enter(uint32 Uid, uint32 Size)
{
EnterPrelude<FEventHeaderSync>(Size);
uint16 Uid16 = uint16(Uid) | int32(EKnownEventUids::Flag_TwoByteUid);
uint32 Serial = uint32(AtomicAddRelaxed(&GLogSerial, 1u));
// Event header FEventHeaderSync
memcpy(Ptr - 3, &Serial, sizeof(Serial)); /* FEventHeaderSync::SerialHigh,SerialLow */
memcpy(Ptr - 5, &Uid16, sizeof(Uid16)); /* FEventHeaderSync::Uid */
}
////////////////////////////////////////////////////////////////////////////////
UE_AUTORTFM_ALWAYS_OPEN
inline void FLogScope::EnterNoSync(uint32 Uid, uint32 Size)
{
EnterPrelude<FEventHeader>(Size);
uint16 Uid16 = uint16(Uid) | int32(EKnownEventUids::Flag_TwoByteUid);
// Event header FEventHeader
auto* Header = (uint16*)(Ptr);
memcpy(Header - 1, &Uid16, sizeof(Uid16)); /* FEventHeader::Uid */
}
////////////////////////////////////////////////////////////////////////////////
template <bool bMaybeHasAux>
UE_AUTORTFM_ALWAYS_OPEN
inline void TLogScope<bMaybeHasAux>::operator += (const FLogScope&) const
{
if constexpr (bMaybeHasAux)
{
FWriteBuffer* LatestBuffer = Writer_GetBuffer();
LatestBuffer->Cursor[0] = uint8(EKnownEventUids::AuxDataTerminal << EKnownEventUids::_UidShift);
LatestBuffer->Cursor++;
Commit(LatestBuffer);
}
else
{
Commit();
}
}
////////////////////////////////////////////////////////////////////////////////
inline void FScopedLogScope::Deinit()
{
if (!bActive)
{
return;
}
if (AutoRTFM::IsClosed())
{
// If we are operating closed (in a transaction) we have to forget about
// our previously registered on-abort handler, because we're currently
// about to close out the scope within the transaction.
AutoRTFM::PopOnAbortHandler(this);
AutoRTFM::Open([this] { this->Deinit(); });
return;
}
uint8 LeaveUid = uint8(EKnownEventUids::LeaveScope << EKnownEventUids::_UidShift);
FWriteBuffer* Buffer = Writer_GetBuffer();
if (UNLIKELY(int32((uint8*)Buffer - Buffer->Cursor) < int32(sizeof(LeaveUid))))
{
Buffer = Writer_NextBuffer();
}
Buffer->Cursor[0] = LeaveUid;
Buffer->Cursor += sizeof(LeaveUid);
AtomicStoreRelease((uint8**) &(Buffer->Committed), Buffer->Cursor);
}
////////////////////////////////////////////////////////////////////////////////
inline FScopedLogScope::~FScopedLogScope()
{
Deinit();
}
////////////////////////////////////////////////////////////////////////////////
inline void FScopedLogScope::SetActive()
{
if (bActive)
{
// We don't want to re-activate an already active scope!
return;
}
if (AutoRTFM::IsClosed())
{
// If we are operating closed (in a transaction) we could abort before
// `this` hits its destructor. In that case we need to remember when
// we abort to close out the scoped trace event.
AutoRTFM::PushOnAbortHandler(this, [this] { this->Deinit(); });
AutoRTFM::Open([this] { this->SetActive(); });
return;
}
bActive = true;
}
////////////////////////////////////////////////////////////////////////////////
inline void FScopedStampedLogScope::Deinit()
{
if (!bActive)
{
return;
}
if (AutoRTFM::IsClosed())
{
// If we are operating closed (in a transaction) we have to forget about
// our previously registered on-abort handler, because we're currently
// about to close out the scope within the transaction.
AutoRTFM::PopOnAbortHandler(this);
AutoRTFM::Open([this] { this->Deinit(); });
return;
}
uint64 Stamp = TimeGetTimestamp() - GStartCycle;
FWriteBuffer* Buffer = Writer_GetBuffer();
if (UNLIKELY(int32((uint8*)Buffer - Buffer->Cursor) < int32(sizeof(Stamp))))
{
Buffer = Writer_NextBuffer();
}
Stamp <<= 8;
Stamp += uint8(EKnownEventUids::LeaveScope_TB) << EKnownEventUids::_UidShift;
memcpy((uint64*)(Buffer->Cursor), &Stamp, sizeof(Stamp));
Buffer->Cursor += sizeof(Stamp);
AtomicStoreRelease((uint8**) &(Buffer->Committed), Buffer->Cursor);
}
////////////////////////////////////////////////////////////////////////////////
inline FScopedStampedLogScope::~FScopedStampedLogScope()
{
Deinit();
}
////////////////////////////////////////////////////////////////////////////////
inline void FScopedStampedLogScope::SetActive()
{
if (bActive)
{
// We don't want to re-activate an already active scope!
return;
}
if (AutoRTFM::IsClosed())
{
// If we are operating closed (in a transaction) we could abort before
// `this` hits its destructor. In that case we need to remember when
// we abort to close out the scoped trace event.
AutoRTFM::PushOnAbortHandler(this, [this] { this->Deinit(); });
AutoRTFM::Open([this] { this->SetActive(); });
return;
}
bActive = true;
}
////////////////////////////////////////////////////////////////////////////////
template <class EventType>
UE_AUTORTFM_ALWAYS_OPEN
FORCENOINLINE auto FLogScope::Enter()
{
uint32 Size = EventType::GetSize();
uint32 Uid = EventType::GetUid();
return EnterImpl<EventType::EventFlags>(Uid, Size);
}
////////////////////////////////////////////////////////////////////////////////
template <class EventType>
UE_AUTORTFM_ALWAYS_OPEN
FORCENOINLINE auto FLogScope::ScopedEnter()
{
uint8 EnterUid = uint8(EKnownEventUids::EnterScope << EKnownEventUids::_UidShift);
FWriteBuffer* Buffer = Writer_GetBuffer();
constexpr int32 EventHeaderSize = (EventType::EventFlags & FEventInfo::Flag_NoSync) != 0 ? sizeof(FEventHeader) : sizeof(FEventHeaderSync);
constexpr int32 RequiredSize = sizeof(EnterUid) + EventHeaderSize + EventType::GetSize();
if (UNLIKELY(int32((uint8*)Buffer - Buffer->Cursor) < RequiredSize))
{
Buffer = Writer_NextBuffer();
}
Buffer->Cursor[0] = EnterUid;
Buffer->Cursor += sizeof(EnterUid);
AtomicStoreRelease((uint8**) &(Buffer->Committed), Buffer->Cursor);
return Enter<EventType>();
}
////////////////////////////////////////////////////////////////////////////////
template <class EventType>
UE_AUTORTFM_ALWAYS_OPEN
FORCENOINLINE auto FLogScope::ScopedStampedEnter()
{
uint64 Stamp;
FWriteBuffer* Buffer = Writer_GetBuffer();
constexpr int32 EventHeaderSize = (EventType::EventFlags & FEventInfo::Flag_NoSync) != 0 ? sizeof(FEventHeader) : sizeof(FEventHeaderSync);
constexpr int32 RequiredSize = sizeof(Stamp) + EventHeaderSize + EventType::GetSize();
if (UNLIKELY(int32((uint8*)Buffer - Buffer->Cursor) < RequiredSize))
{
Buffer = Writer_NextBuffer();
}
Stamp = TimeGetTimestamp() - GStartCycle;
Stamp <<= 8;
Stamp += uint8(EKnownEventUids::EnterScope_TB) << EKnownEventUids::_UidShift;
memcpy((uint64*)(Buffer->Cursor), &Stamp, sizeof(Stamp));
Buffer->Cursor += sizeof(Stamp);
AtomicStoreRelease((uint8**) &(Buffer->Committed), Buffer->Cursor);
return Enter<EventType>();
}
////////////////////////////////////////////////////////////////////////////////
template <typename FieldMeta, typename Type>
struct FLogScope::FFieldSet
{
UE_AUTORTFM_ALWAYS_OPEN
static void Impl(FLogScope* Scope, const Type& Value)
{
uint8* Dest = (uint8*)(Scope->Ptr) + FieldMeta::Offset;
::memcpy(Dest, &Value, sizeof(Type));
}
};
////////////////////////////////////////////////////////////////////////////////
template <typename FieldMeta, typename Type>
struct FLogScope::FFieldSet<FieldMeta, Type[]>
{
UE_AUTORTFM_ALWAYS_OPEN
static void Impl(FLogScope*, Type const* Data, int32 Num)
{
static const uint32 Index = FieldMeta::Index & int32(EIndexPack::NumFieldsMask);
int32 Size = (Num * sizeof(Type)) & (FAuxHeader::SizeLimit - 1) & ~(sizeof(Type) - 1);
Field_WriteAuxData(Index, (const uint8*)Data, Size);
}
};
#if STATICALLY_SIZED_ARRAY_FIELDS_SUPPORT
////////////////////////////////////////////////////////////////////////////////
template <typename FieldMeta, typename Type, int32 Count>
struct FLogScope::FFieldSet<FieldMeta, Type[Count]>
{
static void Impl(FLogScope*, Type const* Data, int32 Num=-1) = delete;
};
#endif // STATICALLY_SIZED_ARRAY_FIELDS_SUPPORT
////////////////////////////////////////////////////////////////////////////////
template <typename FieldMeta>
struct FLogScope::FFieldSet<FieldMeta, AnsiString>
{
UE_AUTORTFM_ALWAYS_OPEN
static void Impl(FLogScope*, const ANSICHAR* String, int32 Length=-1)
{
if (Length < 0)
{
Length = int32(strlen(String));
}
static const uint32 Index = FieldMeta::Index & int32(EIndexPack::NumFieldsMask);
Field_WriteStringAnsi(Index, String, Length);
}
UE_AUTORTFM_ALWAYS_OPEN
static void Impl(FLogScope*, const WIDECHAR* String, int32 Length=-1)
{
if (Length < 0)
{
Length = 0;
for (const WIDECHAR* c = String; *c; ++c, ++Length);
}
static const uint32 Index = FieldMeta::Index & int32(EIndexPack::NumFieldsMask);
Field_WriteStringAnsi(Index, String, Length);
}
};
////////////////////////////////////////////////////////////////////////////////
template <typename FieldMeta>
struct FLogScope::FFieldSet<FieldMeta, WideString>
{
UE_AUTORTFM_ALWAYS_OPEN
static void Impl(FLogScope*, const WIDECHAR* String, int32 Length=-1)
{
if (Length < 0)
{
Length = 0;
for (const WIDECHAR* c = String; *c; ++c, ++Length);
}
static const uint32 Index = FieldMeta::Index & int32(EIndexPack::NumFieldsMask);
Field_WriteStringWide(Index, String, Length);
}
};
////////////////////////////////////////////////////////////////////////////////
template <typename FieldMeta, typename DefinitionType>
struct FLogScope::FFieldSet<FieldMeta, TEventRef<DefinitionType>>
{
UE_AUTORTFM_ALWAYS_OPEN
static void Impl(FLogScope* Scope, const TEventRef<DefinitionType>& Reference)
{
FFieldSet<FieldMeta, DefinitionType>::Impl(Scope, Reference.Id);
}
};
} // namespace Private
} // namespace Trace
} // namespace UE
#endif // TRACE_PRIVATE_MINIMAL_ENABLED