// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreTypes.h" #include "Containers/Map.h" // TraceServices #include "Common/PagedArray.h" #include "Common/ProviderLock.h" #include "Model/MonotonicTimeline.h" #include "TraceServices/Model/AnalysisSession.h" #include "TraceServices/Model/StackSamples.h" #include "TraceServices/Model/TimingProfiler.h" namespace TraceServices { class IModuleProvider; extern thread_local FProviderLock::FThreadLocalState GStackSamplesProviderLockState; typedef TMonotonicTimeline FStackSamplesTimeline; class FStackSamplesProviderThread { friend class FStackSamplesProvider; public: FStackSamplesProviderThread(uint32 InSystemThreadId) : SystemThreadId(InSystemThreadId) { } ~FStackSamplesProviderThread() { } uint32 GetSystemThreadId() const { return SystemThreadId; } const TCHAR* GetName() const { return Name; } FStackSamplesTimeline* GetTimeline() const { return Timeline.Get(); } private: uint32 SystemThreadId = 0; const TCHAR* Name = nullptr; TSharedPtr Timeline; TArray LastSampleStack; double LastSampleTime = 0.0; }; class FStackSamplesProvider : public IStackSamplesProvider , public IEditableProvider { public: explicit FStackSamplesProvider(IAnalysisSession& Session); virtual ~FStackSamplesProvider(); ////////////////////////////////////////////////// // Read operations virtual void BeginRead() const override { Lock.BeginRead(GStackSamplesProviderLockState); } virtual void EndRead() const override { Lock.EndRead(GStackSamplesProviderLockState); } virtual void ReadAccessCheck() const override { Lock.ReadAccessCheck(GStackSamplesProviderLockState); } virtual uint32 GetStackFrameCount() const override; virtual void EnumerateStackFrames(TFunctionRef Callback) const override; virtual uint32 GetThreadCount() const override; virtual void EnumerateThreads(TFunctionRef Callback) const override; virtual uint32 GetTimelineCount() const override; virtual void EnumerateTimelines(TFunctionRef Callback) const override; virtual const FStackSampleTimeline* GetTimeline(uint32 SystemThreadId) const override; ////////////////////////////////////////////////// // Edit operations virtual void BeginEdit() const override { Lock.BeginWrite(GStackSamplesProviderLockState); } virtual void EndEdit() const override { Lock.EndWrite(GStackSamplesProviderLockState); } virtual void EditAccessCheck() const override { Lock.WriteAccessCheck(GStackSamplesProviderLockState); } void SetSamplingInterval(uint32 Microseconds); void AddThreadName(uint32 SystemThreadId, uint32 SystemProcessId, FStringView Name); void AddStackSample(uint32 SystemThreadId, double Time, uint32 Count, const uint64* Addresses); double OnAnalysisEnd(); bool UpdatePendingTimers(); ////////////////////////////////////////////////// private: FStackSamplesProviderThread& GetOrAddThread(uint32 SystemThreadId); FStackSampleFrame& GetOrAddStackFrame(uint64 Address); void CreateTimer(FStackSampleFrame& StackFrame); bool UpdateTimerName(FStackSampleFrame& StackFrame, bool bFirstTime); private: mutable FProviderLock Lock; IAnalysisSession& Session; IEditableTimingProfilerProvider* EditableTimingProfilerProvider = nullptr; IModuleProvider* ModuleProvider = nullptr; TPagedArray Threads; TArray Timelines; // the threads with a valid timeline TMap ThreadsBySystemId; // SystemThreadId --> FThreadSamplingData* TPagedArray StackFrames; TMap StackFramesByAddress; // Address --> FStackSampleFrame* TMap StackFramesByTimerId; // TimerId --> FStackSampleFrame* TArray PendingTimers; double MaxSampleDuration = 0.0;// [seconds] uint32 SamplingIntervalUsec = 0;// [microseconds] int32 MaxStackSize = 0; uint64 TotalNumFrames = 0; uint64 TotalNumSamples = 0; }; } // namespace TraceServices