// Copyright Epic Games, Inc. All Rights Reserved. #include "TraceServices/Model/Counters.h" #include "Model/CountersPrivate.h" #include "AnalysisServicePrivate.h" namespace TraceServices { FCounter::FCounter(ILinearAllocator& Allocator, const TArray64& InFrameStartTimes) : FrameStartTimes(InFrameStartTimes) , IntCounterData(Allocator) , DoubleCounterData(Allocator) { } void FCounter::SetIsFloatingPoint(bool bInIsFloatingPoint) { check(!ModCount); bIsFloatingPoint = bInIsFloatingPoint; } template static void EnumerateCounterValuesInternal(const TCounterData& CounterData, const TArray64& FrameStartTimes, bool bResetEveryFrame, double IntervalStart, double IntervalEnd, bool bIncludeExternalBounds, TFunctionRef Callback) { if (!CounterData.Num()) { return; } TArray64 NoFrameStartTimes; auto CounterIterator = bResetEveryFrame ? CounterData.GetIterator(FrameStartTimes) : CounterData.GetIterator(NoFrameStartTimes); bool bFirstValue = true; bool bFirstEnumeratedValue = true; double LastTime = 0.0; CounterType LastValue = CounterType(); while (CounterIterator) { const double Time = CounterIterator.GetCurrentTime(); const CounterType CurrentValue = CounterIterator.GetCurrentValue(); if (Time >= IntervalStart) { if (bFirstEnumeratedValue) { if (!bFirstValue && bIncludeExternalBounds) { Callback(LastTime, static_cast(LastValue)); } bFirstEnumeratedValue = false; } if (Time > IntervalEnd) { if (bIncludeExternalBounds) { Callback(Time, static_cast(CurrentValue)); } break; } Callback(Time, static_cast(CurrentValue)); } LastTime = Time; LastValue = CurrentValue; bFirstValue = false; ++CounterIterator; } } void FCounter::EnumerateValues(double IntervalStart, double IntervalEnd, bool bIncludeExternalBounds, TFunctionRef Callback) const { if (bIsFloatingPoint) { EnumerateCounterValuesInternal(DoubleCounterData, FrameStartTimes, bIsResetEveryFrame, IntervalStart, IntervalEnd, bIncludeExternalBounds, Callback); } else { EnumerateCounterValuesInternal(IntCounterData, FrameStartTimes, bIsResetEveryFrame, IntervalStart, IntervalEnd, bIncludeExternalBounds, Callback); } } void FCounter::EnumerateFloatValues(double IntervalStart, double IntervalEnd, bool bIncludeExternalBounds, TFunctionRef Callback) const { if (bIsFloatingPoint) { EnumerateCounterValuesInternal(DoubleCounterData, FrameStartTimes, bIsResetEveryFrame, IntervalStart, IntervalEnd, bIncludeExternalBounds, Callback); } else { EnumerateCounterValuesInternal(IntCounterData, FrameStartTimes, bIsResetEveryFrame, IntervalStart, IntervalEnd, bIncludeExternalBounds, Callback); } } template static void EnumerateCounterOpsInternal(const TCounterData& CounterData, const TArray64& FrameStartTimes, bool bResetEveryFrame, double IntervalStart, double IntervalEnd, bool bIncludeExternalBounds, TFunctionRef Callback) { if (!CounterData.Num()) { return; } TArray64 NoFrameStartTimes; auto CounterIterator = bResetEveryFrame ? CounterData.GetIterator(FrameStartTimes) : CounterData.GetIterator(NoFrameStartTimes); bool bFirstValue = true; bool bFirstEnumeratedValue = true; double LastTime = 0.0; ECounterOpType LastOp = ECounterOpType::Set; CounterType LastOpArgument = CounterType(); while (CounterIterator) { const double Time = CounterIterator.GetCurrentTime(); const ECounterOpType CurrentOp = CounterIterator.GetCurrentOp(); const CounterType CurrentOpArgument = CounterIterator.GetCurrentOpArgument(); if (Time >= IntervalStart) { if (bFirstEnumeratedValue) { if (!bFirstValue && bIncludeExternalBounds) { Callback(LastTime, LastOp, static_cast(LastOpArgument)); } bFirstEnumeratedValue = false; } if (Time > IntervalEnd) { if (bIncludeExternalBounds) { Callback(Time, CurrentOp, static_cast(CurrentOpArgument)); } break; } Callback(Time, CurrentOp, static_cast(CurrentOpArgument)); } LastTime = Time; LastOp = CurrentOp; LastOpArgument = CurrentOpArgument; bFirstValue = false; ++CounterIterator; } } void FCounter::EnumerateOps(double IntervalStart, double IntervalEnd, bool bIncludeExternalBounds, TFunctionRef Callback) const { if (bIsFloatingPoint) { EnumerateCounterOpsInternal(DoubleCounterData, FrameStartTimes, bIsResetEveryFrame, IntervalStart, IntervalEnd, bIncludeExternalBounds, Callback); } else { EnumerateCounterOpsInternal(IntCounterData, FrameStartTimes, bIsResetEveryFrame, IntervalStart, IntervalEnd, bIncludeExternalBounds, Callback); } } void FCounter::EnumerateFloatOps(double IntervalStart, double IntervalEnd, bool bIncludeExternalBounds, TFunctionRef Callback) const { if (bIsFloatingPoint) { EnumerateCounterOpsInternal(DoubleCounterData, FrameStartTimes, bIsResetEveryFrame, IntervalStart, IntervalEnd, bIncludeExternalBounds, Callback); } else { EnumerateCounterOpsInternal(IntCounterData, FrameStartTimes, bIsResetEveryFrame, IntervalStart, IntervalEnd, bIncludeExternalBounds, Callback); } } void FCounter::AddValue(double Time, int64 Value) { if (bIsFloatingPoint) { DoubleCounterData.InsertOp(Time, ECounterOpType::Add, double(Value)); } else { IntCounterData.InsertOp(Time, ECounterOpType::Add, Value); } ++ModCount; } void FCounter::AddValue(double Time, double Value) { if (bIsFloatingPoint) { DoubleCounterData.InsertOp(Time, ECounterOpType::Add, Value); } else { IntCounterData.InsertOp(Time, ECounterOpType::Add, int64(Value)); } ++ModCount; } void FCounter::SetValue(double Time, int64 Value) { if (bIsFloatingPoint) { DoubleCounterData.InsertOp(Time, ECounterOpType::Set, double(Value)); } else { IntCounterData.InsertOp(Time, ECounterOpType::Set, Value); } ++ModCount; } void FCounter::SetValue(double Time, double Value) { if (bIsFloatingPoint) { DoubleCounterData.InsertOp(Time, ECounterOpType::Set, Value); } else { IntCounterData.InsertOp(Time, ECounterOpType::Set, int64(Value)); } ++ModCount; } FCounterProvider::FCounterProvider(IAnalysisSession& InSession, IFrameProvider& InFrameProvider) : Session(InSession) , FrameProvider(InFrameProvider) { } FCounterProvider::~FCounterProvider() { for (const ICounter* Counter : Counters) { delete Counter; } } void FCounterProvider::EnumerateCounters(TFunctionRef Callback) const { uint32 Id = 0; for (const ICounter* Counter : Counters) { Callback(Id++, *Counter); } } bool FCounterProvider::ReadCounter(uint32 CounterId, TFunctionRef Callback) const { if (CounterId >= uint32(Counters.Num())) { return false; } Callback(*Counters[CounterId]); return true; } const ICounter* FCounterProvider::GetCounter(IEditableCounter* EditableCounter) { return static_cast(EditableCounter); } IEditableCounter* FCounterProvider::CreateEditableCounter() { FCounter* Counter = new FCounter(Session.GetLinearAllocator(), FrameProvider.GetFrameStartTimes(TraceFrameType_Game)); Counters.Add(Counter); return Counter; } void FCounterProvider::AddCounter(const ICounter* Counter) { Counters.Add(Counter); } FName GetCounterProviderName() { static const FName Name("CounterProvider"); return Name; } const ICounterProvider& ReadCounterProvider(const IAnalysisSession& Session) { return *Session.ReadProvider(GetCounterProviderName()); } IEditableCounterProvider& EditCounterProvider(IAnalysisSession& Session) { return *Session.EditProvider(GetCounterProviderName()); } } // namespace TraceServices