Files
FC1/CryCommon/FrameProfiler.h
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

441 lines
13 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: frameprofiler.h
// Version: v1.00
// Created: 24/6/2003 by Timur,Sergey,Wouter.
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef __frameprofiler_h__
#define __frameprofiler_h__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define USE_FRAME_PROFILER // comment this define to remove most profiler related code in the engine
enum EProfiledSubsystem
{
PROFILE_ANY,
PROFILE_RENDERER,
PROFILE_3DENGINE,
PROFILE_AI,
PROFILE_ANIMATION,
PROFILE_MOVIE,
PROFILE_ENTITY,
PROFILE_FONT,
PROFILE_NETWORK,
PROFILE_PHYSICS,
PROFILE_SCRIPT,
PROFILE_SOUND,
PROFILE_EDITOR,
PROFILE_SYSTEM,
PROFILE_GAME,
//////////////////////////////////////////////////////////////////////////
// This enumes used for Network traffic profilers.
// They record bytes transferred instead of time.
//////////////////////////////////////////////////////////////////////////
PROFILE_NETWORK_TRAFFIC,
PROFILE_LAST_SUBSYSTEM // Must always be last.
};
#include "platform.h"
#include "ISystem.h"
class CFrameProfiler;
class CFrameProfilerSection;
class CCustomProfilerSection;
//////////////////////////////////////////////////////////////////////////
/*! This callback will be called for Profiling Peaks.
*/
struct IFrameProfilePeakCallback
{
//! Called when peak is detected for this profiler.
//! @param fPeakTime peak time in milliseconds.
virtual void OnFrameProfilerPeak( CFrameProfiler *pProfiler,float fPeakTime ) = 0;
};
//////////////////////////////////////////////////////////////////////////
//! IFrameProfileSystem interface.
//! the system which does the gathering of stats
struct IFrameProfileSystem
{
enum EDisplayQuantity
{
SELF_TIME,
TOTAL_TIME,
SELF_TIME_EXTENDED,
TOTAL_TIME_EXTENDED,
PEAK_TIME,
SUBSYSTEM_INFO,
COUNT_INFO,
};
//! Reset all profiling data.
virtual void Reset() = 0;
//! Add new frame profiler.
virtual void AddFrameProfiler( CFrameProfiler *pProfiler ) = 0;
//! Must be called at the start of the frame.
virtual void StartFrame() = 0;
//! Must be called at the end of the frame.
virtual void EndFrame() = 0;
//! Get number of registered frame profilers.
virtual int GetProfilerCount() const = 0;
//! Get frame profiler at specified index.
//! @param index must be 0 <= index < GetProfileCount()
virtual CFrameProfiler* GetProfiler( int index ) const = 0;
virtual void Enable( bool bCollect,bool bDisplay ) = 0;
virtual void SetSubsystemFilter( bool bFilterSubsystem,EProfiledSubsystem subsystem ) = 0;
//! True if profiler is turned off (even if collection is paused).
virtual bool IsEnabled() const = 0;
//! True if profiler must collect profiling data.
virtual bool IsProfiling() const = 0;
virtual void SetDisplayQuantity( EDisplayQuantity quantity ) = 0;
// For custom frame profilers.
virtual void StartCustomSection( CCustomProfilerSection *pSection ) = 0;
virtual void EndCustomSection( CCustomProfilerSection *pSection ) = 0;
//! Register peak listener callback to be called when peak value is greater then this.
virtual void AddPeaksListener( IFrameProfilePeakCallback *pPeakCallback ) = 0;
virtual void RemovePeaksListener( IFrameProfilePeakCallback *pPeakCallback ) = 0;
};
//////////////////////////////////////////////////////////////////////////
//! CFrameProfilerSamplesHistory provides information on history of sample values
//! for profiler counters.
//////////////////////////////////////////////////////////////////////////
template <class T, int TCount>
class CFrameProfilerSamplesHistory
{
public:
CFrameProfilerSamplesHistory() : m_nHistoryNext (0),m_nHistoryCount(0) {}
//! Add a new sample to history.
void Add( T sample )
{
m_history[m_nHistoryNext] = sample;
m_nHistoryNext = (m_nHistoryNext+TCount-1) % TCount;
if (m_nHistoryCount < TCount)
++m_nHistoryCount;
}
//! cleans up the data history
void Clear()
{
m_nHistoryNext = 0;
m_nHistoryCount = 0;
}
//! Get last sample value.
T GetLast()
{
if (m_nHistoryCount)
return m_history[(m_nHistoryNext+1)%TCount];
else
return 0;
}
//! calculates average sample value for at most the given number of frames (less if so many unavailable)
T GetAverage( int nCount = TCount )
{
if (m_nHistoryCount)
{
T fSum = 0;
if (nCount > m_nHistoryCount)
nCount = m_nHistoryCount;
for (int i = 1; i <= nCount; ++i)
{
fSum += m_history[(m_nHistoryNext+i) % (sizeof(m_history)/sizeof((m_history)[0]))];
}
return fSum / nCount;
}
else
return 0;
}
//! calculates average sample value for at most the given number of frames (less if so many unavailable),
//! multiplied by the Poisson function
T GetAveragePoisson(int nCount, float fMultiplier)
{
if (m_nHistoryCount)
{
float fSum = 0, fCurrMult = 1, fSumWeight = 0;
if (nCount > m_nHistoryCount)
nCount = m_nHistoryCount;
for (int i = 1; i <= nCount; ++i)
{
fSum += m_history[(m_nHistoryNext+i)%TCount] * fCurrMult;
fSumWeight += fCurrMult;
fCurrMult *= fMultiplier;
}
return (T)(fSum / fSumWeight);
}
else
return 0;
}
//! calculates Standart deviation of values.
//! stdev = Sqrt( Sum((X-Xave)^2)/(n-1) )
T GetStdDeviation( int nCount = TCount )
{
if (m_nHistoryCount)
{
T fAve = GetAverage(nCount);
T fVal = 0;
T fSumVariance = 0;
if (nCount > m_nHistoryCount)
nCount = m_nHistoryCount;
for (int i = 1; i <= nCount; ++i)
{
fVal = m_history[(m_nHistoryNext+i) % (sizeof(m_history)/sizeof((m_history)[0]))];
fSumVariance = (fVal - fAve)*(fVal - fAve); // (X-Xave)^2
}
return sqrtf( fSumVariance/(nCount-1) );
}
else
return 0;
}
//! calculates max sample value for at most the given number of frames (less if so many unavailable)
T GetMax(int nCount=TCount)
{
if (m_nHistoryCount)
{
T fMax;
if (nCount > m_nHistoryCount)
nCount = m_nHistoryCount;
for (int i = 1; i <= nCount; ++i)
{
T fCur = m_history[(m_nHistoryNext+i) % (sizeof(m_history)/sizeof((m_history)[0]))];
if (i == 1 || fCur > fMax)
fMax = fCur;
}
return fMax;
}
else
return 0;
}
//! calculates min sample value for at most the given number of frames (less if so many unavailable)
T GetMin(int nCount = TCount)
{
if (m_nHistoryCount)
{
T fMin;
if (nCount > m_nHistoryCount)
nCount = m_nHistoryCount;
for (int i = 1; i <= nCount; ++i)
{
T fCur = m_history[(m_nHistoryNext+i) % (sizeof(m_history)/sizeof((m_history)[0]))];
if (i == 1 || fCur < fMin)
fMin = fCur;
}
return fMin;
}
else
return 0;
}
protected:
// the timer values for the last frames
T m_history[TCount];
// the current pointer in the timer history, decreases
int m_nHistoryNext;
// the currently collected samples in the timer history
int m_nHistoryCount;
// adds the entry to the timer history (current timer value)
};
//////////////////////////////////////////////////////////////////////////
class CFrameProfilerGraph
{
public:
int m_x;
int m_y;
int m_width;
int m_height;
std::vector<unsigned char> m_data;
};
//////////////////////////////////////////////////////////////////////////
class CFrameProfilerOfflineHistory
{
public:
//! Self time in microseconds.
std::vector<unsigned int> m_selfTime;
//! Number of calls.
std::vector<unsigned short> m_count;
};
//////////////////////////////////////////////////////////////////////////
//! CFrameProfiler is a single profiler counter with unique name and data.
//! Multiple Sections can be executed for this profiler, they all will be merged in this class.
//! CFrameProfileSection must reference pointer to instance of this counter, to collect the sampling data.
//!
class CFrameProfiler
{
public:
ISystem *m_pISystem;
const char *m_name;
//! Total time spent in this counter including time of child profilers in current frame.
int64 m_totalTime;
//! Self frame time spent only in this counter (But includes recursive calls to same counter) in current frame.
int64 m_selfTime;
//! How many times this profiler counter was executed.
int m_count;
//! Total time spent in this counter during all profiling period.
int64 m_sumTotalTime;
//! Total self time spent in this counter during all profiling period.
int64 m_sumSelfTime;
//! Displayed quantity (interpolated or avarage).
float m_displayedValue;
//! Displayed quantity (current frame value).
float m_displayedCurrentValue;
//! How variant this value.
float m_variance;
//! Current parent profiler in last frame.
CFrameProfiler *m_pParent;
//! Expended or collapsed displaying state.
bool m_bExpended;
bool m_bHaveChildren;
EProfiledSubsystem m_subsystem;
CFrameProfilerSamplesHistory<float,64> m_totalTimeHistory;
CFrameProfilerSamplesHistory<float,64> m_selfTimeHistory;
CFrameProfilerSamplesHistory<int,64> m_countHistory;
//! Graph data for this frame profiler.
//! Graph associated with this profiler.
CFrameProfilerGraph* m_pGraph;
CFrameProfilerOfflineHistory *m_pOfflineHistory;
CFrameProfiler( ISystem *pSystem,const char *sCollectorName,EProfiledSubsystem subsystem=PROFILE_ANY )
{
m_pParent = 0;
m_pGraph = 0;
m_bExpended = false;
m_bHaveChildren = false;
m_pOfflineHistory = 0;
m_subsystem = subsystem;
m_totalTime = m_selfTime = 0;
m_sumTotalTime = m_sumSelfTime = 0;
m_count = 0;
m_pISystem = pSystem;
m_name = sCollectorName;
m_pISystem->GetIProfileSystem()->AddFrameProfiler( this );
}
};
//////////////////////////////////////////////////////////////////////////
//! CFrameProfilerSection is an auto class placed where code block need to be profiled.
//! Every time this object is constructed and destruted the time between constructor
//! and destructur is merged into the referenced CFrameProfiler instance.
//!
class CFrameProfilerSection
{
public:
int64 m_startTime;
int64 m_excludeTime;
CFrameProfiler *m_pFrameProfiler;
CFrameProfilerSection *m_pParent;
__forceinline CFrameProfilerSection( CFrameProfiler *profiler )
{
m_pFrameProfiler = profiler;
if (profiler)
m_pFrameProfiler->m_pISystem->StartProfilerSection( this );
}
__forceinline ~CFrameProfilerSection()
{
if (m_pFrameProfiler)
m_pFrameProfiler->m_pISystem->EndProfilerSection( this );
}
};
//////////////////////////////////////////////////////////////////////////
//! CCustomProfilerSection is an auto class placed where any custom data need to be profiled.
//! Works similary to CFrameProfilerSection, but records any custom data, instead of elapsed time.
//!
class CCustomProfilerSection
{
public:
int *m_pValue;
int m_excludeValue;
CFrameProfiler *m_pFrameProfiler;
CCustomProfilerSection *m_pParent;
//! pValue pointer must remain valid until after calling destructor of this custom profiler section.
__forceinline CCustomProfilerSection( CFrameProfiler *profiler,int *pValue )
{
m_pValue = pValue;
m_pFrameProfiler = profiler;
if (profiler)
m_pFrameProfiler->m_pISystem->GetIProfileSystem()->StartCustomSection( this );
}
__forceinline ~CCustomProfilerSection()
{
if (m_pFrameProfiler)
m_pFrameProfiler->m_pISystem->GetIProfileSystem()->EndCustomSection( this );
}
};
//USE_FRAME_PROFILER
#if defined(USE_FRAME_PROFILER) && (!defined(_RELEASE) || defined(WIN64))
//////////////////////////////////////////////////////////////////////////
//! Place this macro when you need to profile a function.
//!
//! void CTest::Func() {
//! FUNCTION_PROFILER( GetISystem() );
//! // function body will be profiled.
//! }
#define FUNCTION_PROFILER( pISystem,subsystem ) \
static CFrameProfiler staticFrameProfiler( pISystem,__FUNCTION__,subsystem ); \
CFrameProfilerSection frameProfilerSection( &staticFrameProfiler );
#define FUNCTION_PROFILER_FAST( pISystem,subsystem,bProfileEnabled ) \
static CFrameProfiler staticFrameProfiler( pISystem,__FUNCTION__,subsystem ); \
CFrameProfilerSection frameProfilerSection( (bProfileEnabled)?&staticFrameProfiler:NULL );
//////////////////////////////////////////////////////////////////////////
//! Place this macro when you need to profile any code block.
//! {
//! ... some code ...
//! {
//! FRAME_PROFILER( GetISystem(),"MyCode" );
//! ... more code ... // This code will be profiled with counter named "MyCode"
//! }
//! }
#define FRAME_PROFILER( szProfilerName,pISystem,subsystem ) \
static CFrameProfiler staticFrameProfiler( pISystem,szProfilerName,subsystem ); \
CFrameProfilerSection frameProfilerSection( &staticFrameProfiler );
//! Faster version of FRAME_PROFILE macro, also accept a pointer to boolean variable which turn on/off profiler.
#define FRAME_PROFILER_FAST( szProfilerName,pISystem,subsystem,bProfileEnabled ) \
static CFrameProfiler staticFrameProfiler( pISystem,szProfilerName,subsystem ); \
CFrameProfilerSection frameProfilerSection( (bProfileEnabled)?&staticFrameProfiler:NULL );
#else //#if !defined(_RELEASE) || defined(WIN64)
#define FUNCTION_PROFILER( pISystem,subsystem )
#define FUNCTION_PROFILER_FAST( pISystem,subsystem,bProfileEnabled )
#define FRAME_PROFILER( szProfilerName,pISystem,subsystem )
#define FRAME_PROFILER_FAST( szProfilerName,pISystem,subsystem,bProfileEnabled )
;
#endif //USE_FRAME_PROFILER
#endif // __frameprofiler_h__