// Bounded, opt-in startup trace for the complete streaming path. // The trace is deliberately independent of the shared Unreal log: callers provide an // absolute output path and every record is one JSON object per line. #pragma once #include "CoreMinimal.h" namespace VoxelForgeStartupTrace { struct VOXELFORGE_API FTileSample { int32 TileX = 0; int32 TileY = 0; int32 TileZ = 0; int32 Level = -1; int32 WorkPriority = 0; int32 Verdict = -1; // Mixed=0, AllSolid=1, AllAir=2, -1=not classified (early path) uint64 RequestOrdinal = 0; uint64 GenerationOrdinal = 0; uint64 RequestStartCycles = 0; uint64 WorkerTaskStartCycles = 0; uint64 WorkerTaskEndCycles = 0; uint32 WorkerThreadId = 0; bool bResidentAtRequest = false; bool bSealedSolidProof = false; bool bEmpty = true; int32 Vertices = 0; int32 Triangles = 0; uint64 GeometryBytes = 0; // This is worker-result -> game-thread mesh submission. Collision readiness is a later // per-tile RMC completion event recorded separately as collision_ready. double RequestToApplySeconds = 0.0; double QueueWaitSeconds = 0.0; double WorkerQueueSeconds = 0.0; double ResultQueueSeconds = 0.0; double WorkerTaskSeconds = 0.0; double GenerationSeconds = 0.0; double CoreGenerateSeconds = 0.0; double MeshCopySeconds = 0.0; double StreamBuildSeconds = 0.0; double ClassifySeconds = 0.0; double MeshSeconds = 0.0; double StreamSeconds = 0.0; double ApplySeconds = 0.0; }; struct VOXELFORGE_API FApplyFrameSample { uint64 Frame = 0; double FrameSeconds = 0.0; double SpeedCmPerSecond = 0.0; double ApplySeconds = 0.0; double DrainSeconds = 0.0; int32 ActiveTasks = 0; int32 RunningWorkerTasks = 0; int32 TaskCap = 0; int32 PendingTiles = 0; int32 PendingResultsEstimate = 0; int32 ResultsDrained = 0; int32 ApplyResultsByLevelTotal = 0; int32 MeshesApplied = 0; int32 MaxApplies = 0; double ApplyBudgetMilliseconds = 0.0; bool bCountLimitReached = false; bool bTimeLimitReached = false; TStaticArray PendingByLevel{}; TStaticArray ApplyResultsByLevel{}; TStaticArray MeshesAppliedByLevel{}; TStaticArray ApplySecondsByLevel{}; }; struct VOXELFORGE_API FWriteMetrics { double JsonWriteMilliseconds = 0.0; double ArchiveSerializeMilliseconds = 0.0; }; /** Starts when -voxel.StartupTraceFile= is present. */ VOXELFORGE_API void BeginFromCommandLine(); VOXELFORGE_API bool IsActive(); /** Returns and resets startup-trace writes performed by the current game-thread frame. */ VOXELFORGE_API FWriteMetrics ConsumeCurrentThreadWriteMetrics(); /** FieldsJson is the contents after the type/timestamp object prefix, without braces. */ VOXELFORGE_API void RecordEvent(const TCHAR* Type, const FString& FieldsJson = FString()); VOXELFORGE_API void RecordRequest(const FTileSample& Sample, uint32 Epoch); VOXELFORGE_API void StageBegin(const TCHAR* Name); VOXELFORGE_API void StageEnd(const TCHAR* Name); VOXELFORGE_API void RecordTile(const FTileSample& Sample); /** One game-thread result-drain sample, including worker occupancy and per-LOD applies. */ /** Echantillon de vidage des resultats, avec occupation des travailleurs et applications par LOD. */ VOXELFORGE_API void RecordApplyFrame(const FApplyFrameSample& Sample); /** Writes the final bounded summary and closes the file. Safe to call more than once. */ VOXELFORGE_API void Finish(const TCHAR* Reason); /** RAII helper for stages which have early-return failure paths. */ class VOXELFORGE_API FStageScope { public: explicit FStageScope(const TCHAR* InName); ~FStageScope(); FStageScope(const FStageScope&) = delete; FStageScope& operator=(const FStageScope&) = delete; private: FString Name; bool bActive = false; }; }