143 lines
4.1 KiB
C++
143 lines
4.1 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Trace/Detail/Field.h" // :(
|
|
|
|
#if TRACE_PRIVATE_MINIMAL_ENABLED
|
|
|
|
#include "Trace/Detail/Writer.inl"
|
|
|
|
namespace UE {
|
|
namespace Trace {
|
|
namespace Private {
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
template <typename CallbackType>
|
|
static void Field_WriteAuxData(uint32 Index, int32 Size, CallbackType&& Callback)
|
|
{
|
|
static_assert(
|
|
// "1+" is so we've at least space to write one byte of payload
|
|
sizeof(Private::FWriteBuffer::Overflow) >= 1 + sizeof(FAuxHeader) + sizeof(uint8 /*AuxDataTerminal*/),
|
|
"FWriteBuffer::Overflow is not large enough"
|
|
);
|
|
|
|
// Early-out if there would be nothing to write
|
|
if (Size == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FWriteBuffer* Buffer = Writer_GetBuffer();
|
|
|
|
// We are writing fields of an event. The event writing will move Commited
|
|
// along. However, if we're writing a second aux field where the first fetched
|
|
// a new buffer then it is a different buffer to the one the event's written
|
|
// into, thus it is us that needs to update Committed.
|
|
bool bCommit = (Buffer->Cursor == Buffer->Committed);
|
|
|
|
// Do we have enough space to write at least [header][overflow-1] bytes of payload?
|
|
int32 Remaining = int32(ptrdiff_t((uint8*)Buffer - Buffer->Cursor));
|
|
auto NextBuffer = [&Buffer, &Remaining, &bCommit] ()
|
|
{
|
|
if (bCommit)
|
|
{
|
|
AtomicStoreRelease(&(uint8* volatile&)(Buffer->Committed), Buffer->Cursor);
|
|
}
|
|
bCommit = true;
|
|
|
|
Buffer = Writer_NextBuffer();
|
|
Remaining = int32(ptrdiff_t((uint8*)Buffer - Buffer->Cursor));
|
|
};
|
|
|
|
if (Remaining <= 0)
|
|
{
|
|
NextBuffer();
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
// Buffers have a small overflow which we can use. It means we can write
|
|
// some elements unconditionally. What remains is free for payload data.
|
|
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;
|
|
|
|
// Write header
|
|
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);
|
|
|
|
// Write payload data
|
|
Callback(Buffer->Cursor, SegmentSize);
|
|
Buffer->Cursor += SegmentSize;
|
|
|
|
// Bounds check
|
|
Size -= SegmentSize;
|
|
if (Size <= 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
NextBuffer();
|
|
}
|
|
|
|
if (bCommit)
|
|
{
|
|
AtomicStoreRelease(&(uint8* volatile&)(Buffer->Committed), Buffer->Cursor);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void Field_WriteAuxData(uint32 Index, const uint8* Data, int32 Size)
|
|
{
|
|
auto MemcpyLambda = [&Data] (uint8* Cursor, int32 NumBytes)
|
|
{
|
|
memcpy(Cursor, Data, NumBytes);
|
|
Data += NumBytes;
|
|
};
|
|
return Field_WriteAuxData(Index, Size, MemcpyLambda);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void Field_WriteStringAnsi(uint32 Index, const WIDECHAR* String, int32 Length)
|
|
{
|
|
int32 Size = Length;
|
|
Size &= (FAuxHeader::SizeLimit - 1);
|
|
|
|
auto WriteLambda = [&String] (uint8* Cursor, int32 NumBytes)
|
|
{
|
|
for (int32 i = 0; i < NumBytes; ++i)
|
|
{
|
|
*Cursor = uint8(*String & 0x7f);
|
|
Cursor++;
|
|
String++;
|
|
}
|
|
};
|
|
|
|
return Field_WriteAuxData(Index, Size, WriteLambda);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void Field_WriteStringAnsi(uint32 Index, const ANSICHAR* String, int32 Length)
|
|
{
|
|
int32 Size = Length * sizeof(String[0]);
|
|
Size &= (FAuxHeader::SizeLimit - 1); // a very crude "clamp"
|
|
return Field_WriteAuxData(Index, (const uint8*)String, Size);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void Field_WriteStringWide(uint32 Index, const WIDECHAR* String, int32 Length)
|
|
{
|
|
int32 Size = Length * sizeof(String[0]);
|
|
Size &= (FAuxHeader::SizeLimit - 1); // (see above)
|
|
return Field_WriteAuxData(Index, (const uint8*)String, Size);
|
|
}
|
|
|
|
} // namespace Private
|
|
} // namespace Trace
|
|
} // namespace UE
|
|
|
|
#endif // TRACE_PRIVATE_MINIMAL_ENABLED
|