123
This commit is contained in:
440
CryCommon/FrameProfiler.h
Normal file
440
CryCommon/FrameProfiler.h
Normal file
@@ -0,0 +1,440 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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__
|
||||
Reference in New Issue
Block a user