123
This commit is contained in:
293
CryAnimation/SimpleFrameProfiler.h
Normal file
293
CryAnimation/SimpleFrameProfiler.h
Normal file
@@ -0,0 +1,293 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// A simple profiler useful for collecting multiple call times per frame
|
||||
// and displaying their different average statistics.
|
||||
// For usage, see the bottom of the file
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef _SIMPLE_FRAME_PROFILER_HDR_
|
||||
#define _SIMPLE_FRAME_PROFILER_HDR_
|
||||
|
||||
// OBSOLETE
|
||||
#if 0
|
||||
#define ENABLE_FRAME_PROFILER 0
|
||||
|
||||
|
||||
class CProfilerTimer
|
||||
{
|
||||
public:
|
||||
static void init(); // called once
|
||||
static void getTicks(__int64* nTime);
|
||||
static __int64 getTicks() {__int64 nTime; getTicks(&nTime); return nTime;}
|
||||
static float ticksToSeconds (__int64 nTime);
|
||||
static float ticksToMilliseconds (__int64 nTime);
|
||||
protected:
|
||||
static __int64 g_nTicksPerSecond;
|
||||
static double g_fSecondsPerTick;
|
||||
static double g_fMilliSecondsPerTick;
|
||||
|
||||
// CPU speed, in Herz
|
||||
static unsigned g_nCPUHerz;
|
||||
};
|
||||
|
||||
extern CProfilerTimer g_ProfilerTimer;
|
||||
|
||||
template <typename TValue, int g_nCount>
|
||||
class CProfilerTimerHistory
|
||||
{
|
||||
public:
|
||||
CProfilerTimerHistory():
|
||||
m_nTimerHistoryNext (0),
|
||||
m_nTimerHistoryCount (0)
|
||||
{
|
||||
}
|
||||
|
||||
void add(float fTimer)
|
||||
{
|
||||
m_fTimerHistory[m_nTimerHistoryNext] = fTimer;
|
||||
m_nTimerHistoryNext = (m_nTimerHistoryNext+g_nCount-1)%g_nCount;
|
||||
if (m_nTimerHistoryCount < g_nCount)
|
||||
++m_nTimerHistoryCount;
|
||||
}
|
||||
// cleans up the timer history
|
||||
void clear()
|
||||
{
|
||||
m_nTimerHistoryNext = 0;
|
||||
m_nTimerHistoryCount = 0;
|
||||
}
|
||||
TValue getLast()
|
||||
{
|
||||
if (m_nTimerHistoryCount)
|
||||
return m_fTimerHistory[(m_nTimerHistoryNext+1)%g_nCount];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
// calculates average time for at most the given number of frames (less if so many unavailable)
|
||||
float getAve (int nCount = g_nCount)
|
||||
{
|
||||
if (m_nTimerHistoryCount)
|
||||
{
|
||||
float fSum = 0;
|
||||
if (nCount > m_nTimerHistoryCount)
|
||||
nCount = m_nTimerHistoryCount;
|
||||
for (int i = 1; i <= nCount; ++i)
|
||||
{
|
||||
fSum += m_fTimerHistory[(m_nTimerHistoryNext+i)%SIZEOF_ARRAY(m_fTimerHistory)];
|
||||
}
|
||||
return fSum / nCount;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
// calculates average time for at most the given number of frames (less if so many unavailable),
|
||||
// multiplied by the Poisson function
|
||||
float getAvePoisson (int nCount, float fMultiplier)
|
||||
{
|
||||
if (m_nTimerHistoryCount)
|
||||
{
|
||||
float fSum = 0, fCurrMult = 1, fSumWeight = 0;
|
||||
if (nCount > m_nTimerHistoryCount)
|
||||
nCount = m_nTimerHistoryCount;
|
||||
for (int i = 1; i <= nCount; ++i)
|
||||
{
|
||||
fSum += m_fTimerHistory[(m_nTimerHistoryNext+i)%g_nCount] * fCurrMult;
|
||||
fSumWeight += fCurrMult;
|
||||
fCurrMult *= fMultiplier;
|
||||
}
|
||||
return fSum / fSumWeight;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
// calculates max time for at most the given number of frames (less if so many unavailable)
|
||||
float getMax(int nCount=g_nCount)
|
||||
{
|
||||
if (m_nTimerHistoryCount)
|
||||
{
|
||||
float fMax;
|
||||
if (nCount > m_nTimerHistoryCount)
|
||||
nCount = m_nTimerHistoryCount;
|
||||
for (int i = 1; i <= nCount; ++i)
|
||||
{
|
||||
float fCur = m_fTimerHistory[(m_nTimerHistoryNext+i)%SIZEOF_ARRAY(m_fTimerHistory)];
|
||||
if (i == 1 || fCur > fMax)
|
||||
fMax = fCur;
|
||||
}
|
||||
return fMax;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
// calculates min time for at most the given number of frames (less if so many unavailable)
|
||||
float getMin(int nCount = g_nCount)
|
||||
{
|
||||
if (m_nTimerHistoryCount)
|
||||
{
|
||||
float fMin;
|
||||
if (nCount > m_nTimerHistoryCount)
|
||||
nCount = m_nTimerHistoryCount;
|
||||
for (int i = 1; i <= nCount; ++i)
|
||||
{
|
||||
float fCur = m_fTimerHistory[(m_nTimerHistoryNext+i)%SIZEOF_ARRAY(m_fTimerHistory)];
|
||||
if (i == 1 || fCur < fMin)
|
||||
fMin = fCur;
|
||||
}
|
||||
return fMin;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
protected:
|
||||
// the timer values for the last frames
|
||||
TValue m_fTimerHistory[g_nCount];
|
||||
// the current pointer in the timer history, decreases
|
||||
int m_nTimerHistoryNext;
|
||||
// the currently collected samples in the timer history
|
||||
int m_nTimerHistoryCount;
|
||||
// adds the entry to the timer history (current timer value)
|
||||
};
|
||||
|
||||
// this is the accumulator - static object that will hold the profile info
|
||||
class CSimpleFrameProfilerInfo: public CryAnimationBase
|
||||
{
|
||||
public:
|
||||
CSimpleFrameProfilerInfo (const char* szName);
|
||||
|
||||
void startInterval();
|
||||
void endInterval();
|
||||
|
||||
void startDelay();
|
||||
void endDelay();
|
||||
|
||||
void flush();
|
||||
protected:
|
||||
void drawHeaderLabel ();
|
||||
void drawStatistics (float fRow, float* fColor, const char* szLabel, CProfilerTimerHistory<float,64>& rProfiler);
|
||||
void drawLabel(float fRow, float* fColor, const char* szText);
|
||||
|
||||
protected:
|
||||
|
||||
__int64 m_nTickTimer; // accumulates the time spent on this frame
|
||||
unsigned m_nCounter; // accumulates the number of times the interval has been measured during the last frame
|
||||
float m_fCounter; // accumulates the
|
||||
int m_nFrame;
|
||||
const char* m_szName;
|
||||
int m_nIndex; // the index of this object
|
||||
|
||||
CProfilerTimerHistory<float,64> m_HistTime, m_HistCount;
|
||||
static int g_nCount; // count of such objects ever created
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// this is a simple class facilitating profiling within one frame:
|
||||
// during the frame, it collects the profile info, and when the frame
|
||||
// changes, it displays the result and flushes it to start over again
|
||||
// It doesn't take the recursiveness into account
|
||||
class CSimpleFrameProfiler
|
||||
{
|
||||
public:
|
||||
CSimpleFrameProfiler (CSimpleFrameProfilerInfo* pInfo):
|
||||
m_pInfo (pInfo)
|
||||
{
|
||||
if (pInfo)
|
||||
pInfo->startInterval();
|
||||
}
|
||||
~CSimpleFrameProfiler ()
|
||||
{
|
||||
if (m_pInfo)
|
||||
m_pInfo->endInterval();
|
||||
}
|
||||
|
||||
protected:
|
||||
CSimpleFrameProfilerInfo* m_pInfo;
|
||||
};
|
||||
|
||||
// this is a class facilitating profiling within one frame, taking recursiveness
|
||||
// into account:
|
||||
// during the frame, it collects the profile info, and when the frame
|
||||
// changes, it displays the result and flushes it to start over again
|
||||
// If one block is nested into another, it delays profiling of the parent block
|
||||
class CRecursiveFrameProfiler
|
||||
{
|
||||
// the depth of the profilers' stack
|
||||
enum {nStackDepth = 32};
|
||||
public:
|
||||
CRecursiveFrameProfiler (CSimpleFrameProfilerInfo* pInfo):
|
||||
m_pInfo (pInfo)
|
||||
{
|
||||
if (pInfo)
|
||||
{
|
||||
pInfo->startInterval();
|
||||
if (g_nStackTop > 0)
|
||||
g_arrStack[g_nStackTop-1]->startDelay();
|
||||
g_arrStack[g_nStackTop] = this;
|
||||
++g_nStackTop;
|
||||
assert (g_nStackTop < nStackDepth);
|
||||
}
|
||||
}
|
||||
~CRecursiveFrameProfiler ()
|
||||
{
|
||||
if (m_pInfo)
|
||||
{
|
||||
m_pInfo->endInterval();
|
||||
--g_nStackTop;
|
||||
if (g_nStackTop > 0)
|
||||
g_arrStack[g_nStackTop-1]->endDelay();
|
||||
assert (g_nStackTop >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void startDelay()
|
||||
{
|
||||
// this is only called for the profilers on the stack; only the profilers
|
||||
// with non-NULL profiler info are placed on the stack
|
||||
assert (m_pInfo);
|
||||
m_pInfo->startDelay();
|
||||
}
|
||||
|
||||
void endDelay()
|
||||
{
|
||||
// this is only called for the profilers on the stack; only the profilers
|
||||
// with non-NULL profiler info are placed on the stack
|
||||
assert (m_pInfo);
|
||||
m_pInfo->endDelay();
|
||||
}
|
||||
protected:
|
||||
|
||||
CSimpleFrameProfilerInfo* m_pInfo;
|
||||
// the profilers' stack
|
||||
static CRecursiveFrameProfiler* g_arrStack[nStackDepth];
|
||||
// the profiler stack pointer (the top of the stack, the stack grows up)
|
||||
static int g_nStackTop;
|
||||
};
|
||||
|
||||
// USAGE: declare in someplace:
|
||||
// static DECLARE_FRAME_PROFILER(a123,"my name");
|
||||
// in all the profiled blocks, put the following:
|
||||
// PROFILE_FRAME(a123, true);
|
||||
|
||||
// set #if 0 here if you don't want profiling to be compiled in the code
|
||||
#if ENABLE_FRAME_PROFILER
|
||||
#include "CVars.h"
|
||||
#define DECLARE_FRAME_PROFILER(id,name) extern CSimpleFrameProfilerInfo __##id##_frame_profiler
|
||||
#define DEFINE_FRAME_PROFILER(id,name) CSimpleFrameProfilerInfo __##id##_frame_profiler(name)
|
||||
#define PROFILE_FRAME_SELF(id) CRecursiveFrameProfiler __##id##_auto_frame_profile_locker(CryAnimationBase::GetCVars()->ca_Profile()?&__##id##_frame_profiler:NULL)
|
||||
#define PROFILE_FRAME_TOTAL(id) CSimpleFrameProfiler __##id##_auto_frame_profile_locker(CryAnimationBase::GetCVars()->ca_Profile()?&__##id##_frame_profiler:NULL)
|
||||
#define PROFILE_FRAME(id) PROFILE_FRAME_SELF(id)
|
||||
// flushes the given profiler: makes sure it's called this frame (to draw)
|
||||
#define FLUSH_PROFILER(id) do{if (CryAnimationBase::GetCVars()->ca_Profile())__##id##_frame_profiler.flush();}while(false)
|
||||
#else
|
||||
#define DECLARE_FRAME_PROFILER(id,name)
|
||||
#define DEFINE_FRAME_PROFILER(id,name)
|
||||
#define PROFILE_FRAME_SELF(id)
|
||||
#define PROFILE_FRAME_TOTAL(id)
|
||||
#define PROFILE_FRAME(id)
|
||||
// flushes the given profiler: makes sure it's called this frame (to draw)
|
||||
#define FLUSH_PROFILER(id)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
Reference in New Issue
Block a user