232 lines
6.2 KiB
C++
232 lines
6.2 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Trace/Detail/EventNode.h"
|
|
|
|
#if TRACE_PRIVATE_MINIMAL_ENABLED
|
|
|
|
#include "Trace/Detail/Atomic.h"
|
|
#include "Trace/Detail/LogScope.inl"
|
|
|
|
namespace UE {
|
|
namespace Trace {
|
|
namespace Private {
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void Writer_InternalInitialize();
|
|
FEventNode* volatile GNewEventList; // = nullptr;
|
|
FEventNode* GEventListHead;// = nullptr;
|
|
FEventNode* GEventListTail;// = nullptr;
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
const FEventNode* FEventNode::FIter::GetNext()
|
|
{
|
|
auto* Ret = (FEventNode*)Inner;
|
|
if (Ret != nullptr)
|
|
{
|
|
Inner = Ret->Next;
|
|
|
|
if (Inner == nullptr)
|
|
{
|
|
GEventListTail = Ret;
|
|
}
|
|
}
|
|
return Ret;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
FEventNode::FIter FEventNode::Read()
|
|
{
|
|
// This is the current event list as of the last ReadNew() call
|
|
if (GEventListHead)
|
|
{
|
|
return { GEventListHead };
|
|
}
|
|
|
|
// This is the current event list if ReadNew() has never been called
|
|
if (GNewEventList)
|
|
{
|
|
return { GNewEventList };
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
FEventNode::FIter FEventNode::ReadNew()
|
|
{
|
|
FEventNode* EventList = AtomicExchangeAcquire(&GNewEventList, (FEventNode*)nullptr);
|
|
if (EventList == nullptr)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
if (GEventListHead == nullptr)
|
|
{
|
|
GEventListHead = EventList;
|
|
}
|
|
else
|
|
{
|
|
GEventListTail->Next = EventList;
|
|
}
|
|
|
|
return { EventList };
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
uint32 FEventNode::Initialize(const FEventInfo* InInfo)
|
|
{
|
|
if (Uid != 0)
|
|
{
|
|
return Uid;
|
|
}
|
|
|
|
// If we're initializing an event we're about to trace it
|
|
Writer_InternalInitialize();
|
|
|
|
// Assign a unique ID for this event
|
|
static uint32 volatile EventUidCounter; // = 0;
|
|
uint32 NewUid = AtomicAddRelaxed(&EventUidCounter, 1u) + EKnownEventUids::User;
|
|
if (NewUid >= uint32(EKnownEventUids::Max))
|
|
{
|
|
return Uid = EKnownEventUids::Invalid;
|
|
}
|
|
|
|
// Calculate Uid's flags and pack it.
|
|
uint32 UidFlags = 0;
|
|
if (NewUid >= (1 << (8 - EKnownEventUids::_UidShift)))
|
|
{
|
|
UidFlags |= EKnownEventUids::Flag_TwoByteUid;
|
|
}
|
|
|
|
NewUid <<= EKnownEventUids::_UidShift;
|
|
NewUid |= UidFlags;
|
|
|
|
Info = InInfo;
|
|
Uid = uint16(NewUid);
|
|
|
|
// Make this new event instance visible.
|
|
for (;; PlatformYield())
|
|
{
|
|
Next = AtomicLoadRelaxed(&GNewEventList);
|
|
if (AtomicCompareExchangeRelease(&GNewEventList, this, Next))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Uid;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void FEventNode::Describe() const
|
|
{
|
|
const FLiteralName& LoggerName = Info->LoggerName;
|
|
const FLiteralName& EventName = Info->EventName;
|
|
|
|
// Definition events adds an extra field containing the definition id to the end.
|
|
const uint32 DefinitionIdFieldIdx = Info->FieldCount - ((Info->Flags & FEventInfo::DefinitionBits) ? 1 : 0);
|
|
|
|
// Calculate the number of fields and size of name data.
|
|
uint32 NamesSize = LoggerName.Length + EventName.Length;
|
|
for (uint32 i = 0; i < Info->FieldCount; ++i)
|
|
{
|
|
NamesSize += Info->Fields[i].NameSize;
|
|
}
|
|
|
|
// Allocate the new event event in the log stream.
|
|
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
|
|
Ptr[ 0] = uint16(EventSize); // as important and not Writer_DescribeEvents()'s redirected buf.
|
|
|
|
// Write event's main properties.
|
|
auto& Event = *(FNewEventEvent*)(Ptr + 1);
|
|
Event.EventUid = uint16(Uid) >> EKnownEventUids::_UidShift;
|
|
Event.LoggerNameSize = LoggerName.Length;
|
|
Event.EventNameSize = EventName.Length;
|
|
Event.Flags = 0;
|
|
|
|
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);
|
|
|
|
// Write details about event's fields
|
|
Event.FieldCount = uint8(Info->FieldCount);
|
|
for (uint32 i = 0; i < Info->FieldCount; ++i)
|
|
{
|
|
const FFieldDesc& Field = Info->Fields[i];
|
|
auto& Out = Event.Fields[i];
|
|
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;
|
|
// todo: What if the referenced type has not been initialized yet?
|
|
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;
|
|
}
|
|
}
|
|
|
|
// Write names
|
|
uint8* Cursor = (uint8*)(Event.Fields + Info->FieldCount);
|
|
auto WriteName = [&Cursor] (const ANSICHAR* Data, uint32 Size)
|
|
{
|
|
memcpy(Cursor, Data, Size);
|
|
Cursor += Size;
|
|
};
|
|
|
|
WriteName(LoggerName.Ptr, LoggerName.Length);
|
|
WriteName(EventName.Ptr, EventName.Length);
|
|
for (uint32 i = 0; i < Info->FieldCount; ++i)
|
|
{
|
|
const FFieldDesc& Field = Info->Fields[i];
|
|
WriteName(Field.Name, Field.NameSize);
|
|
}
|
|
|
|
LogScope.Commit();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void FEventNode::OnConnect()
|
|
{
|
|
// Re-add known events back as new events so that they get described again
|
|
if (GEventListHead == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GEventListTail->Next = AtomicExchangeAcquire(&GNewEventList, GEventListHead);
|
|
|
|
GEventListHead = GEventListTail = nullptr;
|
|
}
|
|
|
|
} // namespace Private
|
|
} // namespace Trace
|
|
} // namespace UE
|
|
|
|
#endif // TRACE_PRIVATE_MINIMAL_ENABLED
|
|
|