Files
UnrealEngine/Engine/Source/Programs/TraceAnalyzer/Private/TextSerializer.h
2025-05-18 13:04:45 +08:00

287 lines
7.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreTypes.h"
#include "Trace/Trace.h" // TraceLog, for UE::Trace::FEventRef8
#include "Io.h"
namespace UE
{
namespace TraceAnalyzer
{
////////////////////////////////////////////////////////////////////////////////////////////////////
class FTextSerializer
{
public:
FTextSerializer();
virtual ~FTextSerializer();
virtual void AppendChar(const ANSICHAR Value) = 0;
virtual void Append(const ANSICHAR* Text, int32 Len) = 0;
virtual void Append(const ANSICHAR* Text) = 0;
virtual void Appendf(const char* Format, ...) = 0;
virtual bool Commit() = 0;
//////////////////////////////////////////////////
// Attributes
void BeginAttributeSet()
{
AttributeCount = 0;
}
void BeginAttribute()
{
if (AttributeCount == 0)
{
AppendChar('\t');
}
else
{
AppendChar(' ');
}
++AttributeCount;
}
void EndAttribute()
{
}
//////////////////////////////////////////////////
// NEW_EVENT
void BeginNewEventHeader()
{
BeginAttributeSet();
if (bWriteEventHeader)
{
#if !UE_TRACE_ANALYSIS_DEBUG
// Add an empty line before a NEW_EVENT (if previous was an EVENT) to make it more visible.
if (!bLastWasNewEvent)
{
AppendChar('\n');
}
#endif
bLastWasNewEvent = true;
BeginAttribute();
Append("NEW_EVENT :");
EndAttribute();
}
}
void EndNewEventHeader()
{
if (AttributeCount > 0)
{
AppendChar('\n');
}
}
void BeginNewEventFields()
{
}
void BeginField()
{
BeginAttributeSet();
if (bWriteEventHeader)
{
AppendChar('\t');
}
BeginAttribute();
Append("FIELD :");
EndAttribute();
}
void EndField()
{
AppendChar('\n');
}
void EndNewEventFields()
{
// Add an extra empty line make each NEW_EVENT more visible.
AppendChar('\n');
}
//////////////////////////////////////////////////
// EVENT
bool IsWriteEventHeaderEnabled() const { return bWriteEventHeader; }
void BeginEvent(uint32 CtxThreadId)
{
BeginAttributeSet();
if (bWriteEventHeader)
{
bLastWasNewEvent = false;
BeginAttribute();
if (CtxThreadId != (uint32)-1)
{
Appendf("EVENT [%u]", CtxThreadId);
}
else
{
Append("EVENT");
}
EndAttribute();
}
}
void WriteEventName(const char* LoggerName, const char* Name)
{
if (bWriteEventHeader)
{
BeginAttribute();
Appendf("%s.%s :", LoggerName, Name);
EndAttribute();
}
}
void EndEvent()
{
if (AttributeCount > 0)
{
AppendChar('\n');
}
}
//////////////////////////////////////////////////
// Array: [1 2 3...]
void BeginArray()
{
AppendChar('[');
}
void NextArrayElement()
{
AppendChar(' ');
}
void EndArray()
{
AppendChar(']');
}
//////////////////////////////////////////////////
// Values
void WriteValueString(const char* Value)
{
AppendChar('\"');
Append(Value);
AppendChar('\"');
}
void WriteValueString(const char* Value, uint32 Len)
{
AppendChar('\"');
Append(Value, Len);
AppendChar('\"');
}
void WriteValueReference(const UE::Trace::FEventRef8& Value) { Appendf("R(%u,%u)", Value.RefTypeId, uint32(Value.Id)); }
void WriteValueReference(const UE::Trace::FEventRef16& Value) { Appendf("R(%u,%u)", Value.RefTypeId, uint32(Value.Id)); }
void WriteValueReference(const UE::Trace::FEventRef32& Value) { Appendf("R(%u,%u)", Value.RefTypeId, Value.Id); }
void WriteValueReference(const UE::Trace::FEventRef64& Value) { Appendf("R(%u,%llu)", Value.RefTypeId, Value.Id); }
void WriteValueBool(bool Value) { Append(Value ? "true" : "false"); }
void WriteValueInt8(int8 Value) { Appendf("%i", int32(Value)); }
void WriteValueInt16(int16 Value) { Appendf("%i", int32(Value)); }
void WriteValueInt32(int32 Value) { Appendf("%i", Value); }
void WriteValueInt64(int64 Value) { Appendf("%lli", Value); }
void WriteValueUInt8(uint8 Value) { Appendf("%u", uint32(Value)); }
void WriteValueUInt16(uint16 Value) { Appendf("%u", uint32(Value)); }
void WriteValueUInt32(uint32 Value) { Appendf("%u", Value); }
void WriteValueUInt64(uint64 Value) { Appendf("%llu", Value); }
void WriteValueHex8(uint8 Value) { Appendf("0x%X", uint32(Value)); }
void WriteValueHex16(uint16 Value) { Appendf("0x%X", uint32(Value)); }
void WriteValueHex32(uint32 Value) { Appendf("0x%X", Value); }
void WriteValueHex64(uint64 Value) { Appendf("0x%llX", Value); }
void WriteValueInt64Auto(int64 Value);
void WriteValueUInt64Auto(uint64 Value);
void WriteValueFloat(float Value) { Appendf("%f", Value); }
void WriteValueDouble(double Value) { Appendf("%f", Value); }
void WriteValueTime(double Time) { Appendf("%f", Time); }
void WriteValueNull() { Append("null"); }
void WriteValueBinary(const void* Data, uint32 Size);
//////////////////////////////////////////////////
// Key and Values
void WriteKey(const ANSICHAR* Name)
{
Append(Name);
AppendChar('=');
}
void WriteAttributeString(const ANSICHAR* Name, const ANSICHAR* Value) { BeginAttribute(); WriteKey(Name); WriteValueString(Value); EndAttribute(); }
void WriteAttributeString(const ANSICHAR* Name, const ANSICHAR* Value, uint32 Len) { BeginAttribute(); WriteKey(Name); WriteValueString(Value, Len); EndAttribute(); }
void WriteAttributeBool(const ANSICHAR* Name, bool Value) { BeginAttribute(); WriteKey(Name); WriteValueBool(Value); EndAttribute(); }
void WriteAttributeInteger(const ANSICHAR* Name, int64 Value) { BeginAttribute(); WriteKey(Name); WriteValueInt64(Value); EndAttribute(); }
void WriteAttributeIntegerHex(const ANSICHAR* Name, int64 Value) { BeginAttribute(); WriteKey(Name); WriteValueHex64(uint64(Value)); EndAttribute(); }
void WriteAttributeFloat(const ANSICHAR* Name, float Value) { BeginAttribute(); WriteKey(Name); WriteValueFloat(Value); EndAttribute(); }
void WriteAttributeDouble(const ANSICHAR* Name, double Value) { BeginAttribute(); WriteKey(Name); WriteValueDouble(Value); EndAttribute(); }
void WriteAttributeNull(const ANSICHAR* Name) { BeginAttribute(); WriteKey(Name); WriteValueNull(); EndAttribute(); }
void WriteAttributeBinary(const ANSICHAR* Name, const void* Data, uint32 Size) { BeginAttribute(); WriteKey(Name); WriteValueBinary(Data, Size); EndAttribute(); }
protected:
bool bWriteEventHeader = true;
bool bLastWasNewEvent = false;
uint32 AttributeCount = 0;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
class FStdoutTextSerializer : public FTextSerializer
{
public:
FStdoutTextSerializer();
virtual ~FStdoutTextSerializer() {}
virtual void AppendChar(const ANSICHAR Value) override;
virtual void Append(const ANSICHAR* Text, int32 Len) override;
virtual void Append(const ANSICHAR* Text) override;
virtual void Appendf(const char* Format, ...) override;
virtual bool Commit() override;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
class FFileTextSerializer : public FTextSerializer
{
public:
FFileTextSerializer(FileHandle InHandle);
virtual ~FFileTextSerializer();
virtual void AppendChar(const ANSICHAR Value) override;
virtual void Append(const ANSICHAR* Text, int32 Len) override;
virtual void Append(const ANSICHAR* Text) override;
virtual void Appendf(const char* Format, ...) override;
virtual bool Commit() override;
private:
void* GetPointer(uint32 RequiredSize);
private:
FileHandle Handle = -1;
static constexpr int BufferSize = 1024 * 1024;
void* Buffer = nullptr;
static constexpr int FormatBufferSize = 64 * 1024;
void* FormatBuffer = nullptr;
uint32 Used = 0;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace TraceAnalyzer
} // namespace UE