104 lines
3.4 KiB
C++
104 lines
3.4 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "Trace/Analyzer.h"
|
|
#include "Containers/Map.h"
|
|
#include "Containers/UnrealString.h"
|
|
#include "TraceServices/Model/TimingProfiler.h"
|
|
#include "Model/MonotonicTimeline.h"
|
|
|
|
namespace TraceServices
|
|
{
|
|
|
|
class IAnalysisSession;
|
|
class IEditableTimingProfilerProvider;
|
|
class IEditableThreadProvider;
|
|
|
|
class FCpuProfilerAnalyzer
|
|
: public UE::Trace::IAnalyzer
|
|
{
|
|
public:
|
|
FCpuProfilerAnalyzer(IAnalysisSession& Session, IEditableTimingProfilerProvider& InEditableTimingProfilerProvider, IEditableThreadProvider& InEditableThreadProvider);
|
|
~FCpuProfilerAnalyzer();
|
|
virtual void OnAnalysisBegin(const FOnAnalysisContext& Context) override;
|
|
virtual void OnAnalysisEnd(/*const FOnAnalysisEndContext& Context*/) override;
|
|
virtual bool OnEvent(uint16 RouteId, EStyle Style, const FOnEventContext& Context) override;
|
|
|
|
private:
|
|
struct FEventScopeState
|
|
{
|
|
uint64 StartCycle;
|
|
uint32 EventTypeId;
|
|
};
|
|
|
|
struct FPendingEvent
|
|
{
|
|
uint64 Cycle;
|
|
double Time;
|
|
uint32 TimerId;
|
|
};
|
|
|
|
struct FThreadState
|
|
{
|
|
uint32 ThreadId = 0;
|
|
TArray<FEventScopeState> ScopeStack;
|
|
TArray<FPendingEvent> PendingEvents;
|
|
IEditableTimeline<FTimingProfilerEvent>* Timeline = nullptr;
|
|
uint64 LastCycle = 0;
|
|
bool bShouldIgnorePendingEvents = false; // becomes true when we detect first pending event with incorrect timestamp (i.e < LastCycle)
|
|
double LastPendingEventTime = 0;
|
|
int32 MetadataEventsDepth = 0;
|
|
};
|
|
|
|
struct FTimerInfo
|
|
{
|
|
uint32 Id;
|
|
uint32 Count;
|
|
};
|
|
|
|
enum : uint16
|
|
{
|
|
RouteId_EventSpec,
|
|
RouteId_EndThread,
|
|
RouteId_EventBatchV3,
|
|
RouteId_EventBatchV2, // backward compatibility
|
|
RouteId_EventBatch, // backward compatibility
|
|
RouteId_EndCapture, // backward compatibility
|
|
RouteId_CpuScope,
|
|
RouteId_MetadataSpec,
|
|
RouteId_Metadata,
|
|
};
|
|
|
|
void ProcessBuffer(const FEventTime& EventTime, FThreadState& ThreadState, const uint8* BufferPtr, uint32 BufferSize);
|
|
void ProcessBufferV2(const FEventTime& EventTime, FThreadState& ThreadState, const uint8* BufferPtr, uint32 BufferSize, int32 Version);
|
|
void DispatchPendingEvents(uint64& LastCycle, uint64 CurrentCycle, FThreadState& ThreadState, const FPendingEvent*& PendingCursor, int32& RemainingPending, bool bIsBeginEvent);
|
|
void DispatchRemainingPendingEvents(FThreadState& ThreadState);
|
|
void EndOpenEvents(FThreadState& ThreadState, double Timestamp);
|
|
void OnCpuScopeEnter(const FOnEventContext& Context);
|
|
void OnCpuScopeLeave(const FOnEventContext& Context);
|
|
uint32 DefineTimer(uint32 SpecId, const TCHAR* TimerName, const TCHAR* File, uint32 Line, bool bMergeByName); // returns the TimerId
|
|
uint32 DefineNewTimerChecked(uint32 SpecId, const TCHAR* TimerName, const TCHAR* File = nullptr, uint32 Line = 0); // returns the TimerId
|
|
uint32 GetTimerId(uint32 SpecId);
|
|
FThreadState& GetThreadState(uint32 ThreadId);
|
|
|
|
private:
|
|
IAnalysisSession& Session;
|
|
IEditableTimingProfilerProvider& EditableTimingProfilerProvider;
|
|
IEditableThreadProvider& EditableThreadProvider;
|
|
|
|
TMap<uint32, FThreadState*> ThreadStatesMap;
|
|
TMap<uint32, uint32> SpecIdToTimerIdMap; // SpecId --> TimerId
|
|
TMap<uint64, FTimerInfo> ScopeNameToTimerIdMap; // (uint64)Name --> FTimerInfo
|
|
TMap<uint32, uint32> MetadataIdToTimerIdMap; // MetadataId --> TimerId
|
|
|
|
uint32 CoroutineTimerId = ~0;
|
|
uint32 CoroutineUnknownTimerId = ~0;
|
|
uint32 MetadataUnknownTimerId = ~0;
|
|
uint64 TotalEventSize = 0;
|
|
uint64 TotalScopeCount = 0;
|
|
double BytesPerScope = 0.0;
|
|
};
|
|
|
|
} // namespace TraceServices
|