194 lines
6.2 KiB
C++
194 lines
6.2 KiB
C++
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "TraceServices/Model/TimingProfiler.h"
|
|
|
|
namespace TraceTimer
|
|
{
|
|
/** 导出列标志位枚举 */
|
|
enum class EExportField : uint32
|
|
{
|
|
None = 0,
|
|
Name = 1 << 0,
|
|
Start = 1 << 1,
|
|
End = 1 << 2,
|
|
Duration = 1 << 3,
|
|
Depth = 1 << 4,
|
|
ThreadId = 1 << 5,
|
|
Metadata = 1 << 6,
|
|
TimerId = 1 << 7,
|
|
All = 0xFFFFFFFF
|
|
};
|
|
ENUM_CLASS_FLAGS(EExportField);
|
|
|
|
/** 导出数据载体:兼容平铺模式与树状模式 */
|
|
struct FEventExportData
|
|
{
|
|
const Trace::FTimingProfilerTimer* Timer = nullptr;
|
|
double Start = 0;
|
|
double End = 0;
|
|
uint32 Depth = 0;
|
|
uint32 ThreadId = 0;
|
|
TArrayView<const uint8> Metadata;
|
|
TArray<TSharedPtr<FEventExportData>> Children;
|
|
|
|
void MoveTo(FEventExportData& OutTarget)
|
|
{
|
|
OutTarget.Timer = Timer;
|
|
OutTarget.Start = Start;
|
|
OutTarget.End = End;
|
|
OutTarget.Depth = Depth;
|
|
OutTarget.ThreadId = ThreadId;
|
|
OutTarget.Metadata = Metadata;
|
|
OutTarget.Children = MoveTemp(Children);
|
|
}
|
|
};
|
|
|
|
/** 导出过滤配置 */
|
|
struct FExportFilter
|
|
{
|
|
FString FuncName;
|
|
TOptional<double> StartTime;
|
|
TOptional<double> EndTime;
|
|
EExportField Fields = EExportField::All;
|
|
uint32 TrackIndex = UINT32_MAX;
|
|
bool bOnlyMetadata = false;
|
|
double MinDurationMs = 0.0;
|
|
|
|
FExportFilter(FString InFuncName): FuncName(InFuncName) {};
|
|
double GetStartTime() const { return StartTime.Get(0.0); }
|
|
double GetEndTime() const { return EndTime.Get(DBL_MAX); }
|
|
bool ShouldFilterByTrack(uint32 TimelineIndex) const
|
|
{
|
|
return TrackIndex != UINT32_MAX && TrackIndex != TimelineIndex;
|
|
}
|
|
bool ShouldFilterByEvent(FEventExportData& Node) const;
|
|
};
|
|
|
|
/** 物理文件分块配置 */
|
|
struct FExportConfig
|
|
{
|
|
static constexpr uint32 DefaultMaxMemSize = 512 * 1024;
|
|
FString Folder;
|
|
FString BaseName;
|
|
FString Extension;
|
|
uint32 EventsPerChunk = 1000000;
|
|
uint32 MaxMemSize = DefaultMaxMemSize;
|
|
FExportConfig() = default;
|
|
FExportConfig(const FString& Filename);
|
|
};
|
|
class IEventWriter;
|
|
/** 物理分块写入管理器 */
|
|
class ChunkingFileWriter
|
|
{
|
|
public:
|
|
ChunkingFileWriter() = default;
|
|
~ChunkingFileWriter();
|
|
|
|
void Initialize(const FExportConfig& InConfig);
|
|
FArchive* GetCurrentArchive();
|
|
void FlushToDisk();
|
|
void Close();
|
|
|
|
uint32 GetWrittenEventCount() const { return WrittenEventCount; }
|
|
void NotifyEventWritten() { WrittenEventCount++; }
|
|
void WriteEvent(IEventWriter* Writer, const FEventExportData& Data);
|
|
void SwitchToNextChunk(IEventWriter* Writer);
|
|
const FExportConfig& GetConfig() const { return Config; }
|
|
|
|
private:
|
|
void CheckFlush(IEventWriter* Writer);
|
|
|
|
FExportConfig Config;
|
|
TArray<uint8> PersistentBuffer;
|
|
TUniquePtr<FMemoryWriter> MemAr;
|
|
TUniquePtr<FArchive> FileAr;
|
|
uint32 ChunkIndex = 1;
|
|
uint32 WrittenEventCount = 0;
|
|
FString CurrentFilename;
|
|
};
|
|
|
|
/** 导出器抽象基类 */
|
|
class IEventWriter
|
|
{
|
|
public:
|
|
IEventWriter(const EExportField& InFields): Fields(InFields) {};
|
|
virtual ~IEventWriter() = default;
|
|
virtual bool WantsStructuredPath() const { return false; }
|
|
virtual void WriteHeader(FArchive& Ar) {}
|
|
virtual void WriteFooter(FArchive& Ar) {}
|
|
|
|
/** 统一写入接口:子类根据需要处理 Data 中的 Children 递归数据 */
|
|
virtual void ProcessEvent(FArchive& Ar, const FEventExportData& Data) = 0;
|
|
|
|
protected:
|
|
EExportField Fields = EExportField::All;
|
|
};
|
|
|
|
/** CSV 实现:仅处理平铺数据 */
|
|
class CsvEventWriter: public IEventWriter
|
|
{
|
|
public:
|
|
using IEventWriter::IEventWriter;
|
|
virtual void WriteHeader(FArchive& Ar) override;
|
|
virtual void ProcessEvent(FArchive& Ar, const FEventExportData& Data) override;
|
|
};
|
|
|
|
/** JSON Lines 实现:支持深度嵌套递归 */
|
|
class JsonEventWriter: public IEventWriter
|
|
{
|
|
public:
|
|
using IEventWriter::IEventWriter;
|
|
virtual bool WantsStructuredPath() const override { return true; }
|
|
virtual void ProcessEvent(FArchive& Ar, const FEventExportData& Data) override;
|
|
|
|
void WriteNode(FArchive& Ar, const FEventExportData& Node);
|
|
};
|
|
|
|
/** 导出上下文:管理 Trace Session 的元数据映射 */
|
|
struct FExportContext
|
|
{
|
|
const Trace::IAnalysisSession& Session;
|
|
const Trace::ITimingProfilerProvider* Provider = nullptr;
|
|
const Trace::ITimingProfilerTimerReader* TimerReader = nullptr;
|
|
TMap<uint32, uint32> TimelineIndexToThreadId;
|
|
|
|
FExportContext(const Trace::IAnalysisSession& InSession);
|
|
bool Initialize(const Trace::ITimingProfilerProvider* InProvider);
|
|
uint32 GetThreadId(uint32 TimelineIndex) const;
|
|
};
|
|
|
|
/** 核心导出处理器 */
|
|
class FTraceExportProcessor
|
|
{
|
|
public:
|
|
FTraceExportProcessor(FExportContext& InContext, IEventWriter& InWriter, ChunkingFileWriter& InChunkWriter, const FExportFilter& InFilter);
|
|
void Run();
|
|
|
|
static void DecodeMetadataToString(FString& Str,const TArrayView<const uint8>& Metadata);
|
|
|
|
private:
|
|
void ProcessTimeline(uint32 TimelineIndex);
|
|
void EnumerateFlat(const Trace::ITimingProfilerProvider::Timeline& Timeline, uint32 ThreadId);
|
|
void EnumerateStructured(const Trace::ITimingProfilerProvider::Timeline& Timeline, uint32 ThreadId);
|
|
|
|
FExportContext& Context;
|
|
IEventWriter& Writer;
|
|
ChunkingFileWriter& ChunkWriter;
|
|
const FExportFilter& Filter;
|
|
};
|
|
} // namespace TraceTimer
|
|
|
|
/** 静态入口类 */
|
|
class FMinimalTimerExporter
|
|
{
|
|
public:
|
|
static bool ExportTimersToCSV(const Trace::IAnalysisSession& Session, const FString& Filename);
|
|
static bool ExportMetadataToCSV(const Trace::IAnalysisSession& Session, const FString& Filename, const TraceTimer::FExportFilter& InFilter);
|
|
static bool ExportTimingEventsToCSV(const Trace::IAnalysisSession& Session, const FString& Filename, const TraceTimer::FExportFilter& InFilter);
|
|
static bool ExportTimingEventsToJSON(const Trace::IAnalysisSession& Session, const FString& Filename, const TraceTimer::FExportFilter& InFilter);
|
|
|
|
private:
|
|
static bool ExecuteTimingExport(const Trace::IAnalysisSession& Session, const FString& Filename, TraceTimer::FExportFilter& Filter, TraceTimer::IEventWriter& Writer);
|
|
};
|