You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
369 lines
10 KiB
369 lines
10 KiB
//========= Copyright c 1996-2008, Valve Corporation, All rights reserved. ============
|
|
// This will contain things like helper functions to measure tick count of small pieces
|
|
// of code precisely; or measure performance counters (L2 misses, mispredictions etc.)
|
|
// on different hardware.
|
|
//=====================================================================================
|
|
|
|
// this class defines a section of code to measure
|
|
|
|
#ifndef TIER0_MINIPROFILER_HDR
|
|
#define TIER0_MINIPROFILER_HDR
|
|
|
|
#include "microprofiler.h"
|
|
|
|
|
|
#define ENABLE_MINI_PROFILER 0 // ENABLE_MICRO_PROFILER
|
|
|
|
class CMiniProfiler;
|
|
class CLinkedMiniProfiler;
|
|
|
|
extern "C"
|
|
{
|
|
#if defined( STATIC_LINK )
|
|
#define MINIPROFILER_DLL_LINKAGE extern
|
|
#elif defined( TIER0_DLL_EXPORT )
|
|
#define MINIPROFILER_DLL_LINKAGE DLL_EXPORT
|
|
#else
|
|
#define MINIPROFILER_DLL_LINKAGE DLL_IMPORT
|
|
#endif
|
|
MINIPROFILER_DLL_LINKAGE CMiniProfiler *g_pLastMiniProfiler;
|
|
MINIPROFILER_DLL_LINKAGE CMiniProfiler *g_pRootMiniProfiler;
|
|
MINIPROFILER_DLL_LINKAGE CLinkedMiniProfiler *g_pGlobalMiniProfilers;
|
|
MINIPROFILER_DLL_LINKAGE CLinkedMiniProfiler *g_pAssertMiniProfilers;
|
|
MINIPROFILER_DLL_LINKAGE uint32 g_nMiniProfilerFrame;
|
|
MINIPROFILER_DLL_LINKAGE void PublishAll( CLinkedMiniProfiler * pList, uint32 nHistoryMax );
|
|
MINIPROFILER_DLL_LINKAGE CMiniProfiler* PushMiniProfilerTS( CMiniProfiler *pProfiler );
|
|
MINIPROFILER_DLL_LINKAGE void PopMiniProfilerTS( CMiniProfiler *pProfiler );
|
|
MINIPROFILER_DLL_LINKAGE void AppendMiniProfilerToList( CLinkedMiniProfiler *pProfiler, CLinkedMiniProfiler **ppList );
|
|
MINIPROFILER_DLL_LINKAGE void RemoveMiniProfilerFromList( CLinkedMiniProfiler *pProfiler );
|
|
}
|
|
|
|
#if ENABLE_MINI_PROFILER
|
|
|
|
typedef CMicroProfilerSample CMiniProfilerSample;
|
|
class CMiniProfiler: public CMicroProfiler
|
|
{
|
|
protected:
|
|
uint64 m_numTimeBaseTicksInCallees; // this is the time to subtract from m_numTimeBaseTicks to get the "exclusive" time in this block
|
|
public:
|
|
CMiniProfiler()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
explicit CMiniProfiler( const CMicroProfiler &profiler ):
|
|
CMicroProfiler( profiler ),
|
|
m_numTimeBaseTicksInCallees( 0 )
|
|
{
|
|
|
|
}
|
|
|
|
CMiniProfiler &operator=( const CMiniProfiler &other )
|
|
{
|
|
*(CMicroProfiler *)this = (const CMicroProfiler &)other;
|
|
m_numTimeBaseTicksInCallees = other.m_numTimeBaseTicksInCallees;
|
|
return *this;
|
|
}
|
|
|
|
void SubCallee( int64 numTimeBaseTicks )
|
|
{
|
|
m_numTimeBaseTicksInCallees += numTimeBaseTicks;
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
CMicroProfiler::Reset();
|
|
m_numTimeBaseTicksInCallees = 0;
|
|
}
|
|
|
|
uint64 GetNumTimeBaseTicksInCallees() const
|
|
{
|
|
return m_numTimeBaseTicksInCallees;
|
|
}
|
|
|
|
int64 GetNumTimeBaseTicksExclusive( ) const
|
|
{
|
|
return m_numTimeBaseTicks - m_numTimeBaseTicksInCallees;
|
|
}
|
|
|
|
|
|
void Accumulate( const CMiniProfiler &other )
|
|
{
|
|
CMicroProfiler::Accumulate( other );
|
|
m_numTimeBaseTicksInCallees += other.m_numTimeBaseTicksInCallees;
|
|
}
|
|
|
|
DLL_CLASS_EXPORT void Publish( const char *szMessage, ... );
|
|
};
|
|
|
|
#else
|
|
|
|
class CMiniProfilerSample
|
|
{
|
|
public:
|
|
int GetElapsed()const
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
class CMiniProfiler: public CMicroProfiler
|
|
{
|
|
public:
|
|
CMiniProfiler() {}
|
|
explicit CMiniProfiler( const CMicroProfiler &profiler ) :
|
|
CMicroProfiler( profiler ){}
|
|
CMiniProfiler &operator=( const CMiniProfiler &other ) { return *this; }
|
|
void SubCallee( int64 numTimeBaseTicks ) {}
|
|
uint64 GetNumTimeBaseTicksInCallees() const { return 0; }
|
|
int64 GetNumTimeBaseTicksExclusive() const { return 0; }
|
|
void Accumulate( const CMiniProfiler &other ) {}
|
|
void Reset() {}
|
|
void Damp( int shift = 1 ) {}
|
|
void Publish( const char *szMessage, ... ) {}
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CLinkedMiniProfiler: public CMiniProfiler
|
|
{
|
|
public:
|
|
#if ENABLE_MINI_PROFILER
|
|
CLinkedMiniProfiler *m_pNext, **m_ppPrev;
|
|
const char *m_pName;
|
|
const char *m_pLocation;
|
|
CMiniProfiler *m_pLastParent; // for dynamic tracking of an approximate call tree
|
|
CMiniProfiler *m_pDeclaredParent; // for static tracking of the logical dependency tree
|
|
//uint32 m_nId;
|
|
#endif
|
|
public:
|
|
CLinkedMiniProfiler( const char *pName, CLinkedMiniProfiler**ppList = &g_pGlobalMiniProfilers, CMiniProfiler *pDeclaredParent = NULL )
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
m_pName = pName;
|
|
m_pLocation = NULL;
|
|
// NOTE: m_pNext and m_ppPrev have to be NULLs the first time around. This constructor can be called multiple times
|
|
// from multiple threads, and there's no way to ensure the constructor isn't called twice. CNetworkGameServerBase::SV_PackEntity()
|
|
// is an example of the function that enters from 2 threads and collides with itself in this constructor
|
|
AppendMiniProfilerToList( this, ppList );
|
|
m_pLastParent = NULL;
|
|
m_pDeclaredParent = pDeclaredParent;
|
|
#endif
|
|
}
|
|
|
|
CLinkedMiniProfiler( const char *pName, const char *pLocation )
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
m_pName = pName;
|
|
m_pLocation = pLocation;
|
|
// NOTE: m_pNext and m_ppPrev have to be NULLs the first time around. This constructor can be called multiple times
|
|
// from multiple threads, and there's no way to ensure the constructor isn't called twice. CNetworkGameServerBase::SV_PackEntity()
|
|
// is an example of the function that enters from 2 threads and collides with itself in this constructor
|
|
AppendMiniProfilerToList( this, &g_pGlobalMiniProfilers );
|
|
m_pLastParent = NULL;
|
|
m_pDeclaredParent = NULL;
|
|
#endif
|
|
}
|
|
|
|
#if ENABLE_MINI_PROFILER
|
|
CLinkedMiniProfiler *GetNext() { return m_pNext; }
|
|
const char *GetName() const { return m_pName; }
|
|
const char *GetLocation( )const { return m_pLocation; }
|
|
#else
|
|
CLinkedMiniProfiler *GetNext() { return NULL; }
|
|
const char *GetName() const { return "DISABLED"; }
|
|
const char *GetLocation( )const { return NULL; }
|
|
#endif
|
|
|
|
~CLinkedMiniProfiler()
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
RemoveMiniProfilerFromList( this );
|
|
#endif
|
|
}
|
|
void Publish( uint nHistoryMax );
|
|
void PurgeHistory();
|
|
};
|
|
|
|
class CAssertMiniProfiler: public CLinkedMiniProfiler
|
|
{
|
|
public:
|
|
CAssertMiniProfiler( const char *pFunction, const char *pFile, int nLine ): CLinkedMiniProfiler( pFunction, &g_pAssertMiniProfilers )
|
|
{
|
|
m_pFile = pFile;
|
|
m_nLine = nLine;
|
|
m_bAsserted = false;
|
|
}
|
|
~CAssertMiniProfiler()
|
|
{
|
|
}
|
|
operator bool& () { return m_bAsserted; }
|
|
void operator = ( bool bAsserted ){ m_bAsserted = bAsserted; }
|
|
void operator = ( int bAsserted ) { m_bAsserted = (bAsserted != 0); }
|
|
|
|
public:
|
|
const char *m_pFile;
|
|
int m_nLine;
|
|
|
|
public:
|
|
bool m_bAsserted;
|
|
};
|
|
|
|
|
|
|
|
template < class Sampler, bool bThreadSafe >
|
|
class TMiniProfilerGuard: public Sampler
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
CMiniProfiler *m_pProfiler, *m_pLastProfiler;
|
|
int m_numCallsToAdd;
|
|
#endif
|
|
public:
|
|
void Begin( CMiniProfiler *pProfiler, int numCallsToAdd )
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
m_numCallsToAdd = numCallsToAdd;
|
|
m_pProfiler = pProfiler;
|
|
if ( bThreadSafe )
|
|
{
|
|
m_pLastProfiler = PushMiniProfilerTS( pProfiler );
|
|
}
|
|
else
|
|
{
|
|
m_pLastProfiler = g_pLastMiniProfiler;
|
|
g_pLastMiniProfiler = pProfiler;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void SetCallCount( int numCalls )
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
m_numCallsToAdd = numCalls;
|
|
#endif
|
|
}
|
|
void AddCallCount( int addCalls )
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
m_numCallsToAdd += addCalls;
|
|
#endif
|
|
}
|
|
|
|
TMiniProfilerGuard( CLinkedMiniProfiler *pProfiler, int numCallsToAdd = 1 )
|
|
{
|
|
Begin( pProfiler, numCallsToAdd );
|
|
#if ENABLE_MINI_PROFILER
|
|
pProfiler->m_pLastParent = m_pLastProfiler;
|
|
#endif
|
|
}
|
|
|
|
TMiniProfilerGuard( CMiniProfiler *pProfiler, int numCallsToAdd = 1 )
|
|
{
|
|
Begin( pProfiler, numCallsToAdd );
|
|
}
|
|
~TMiniProfilerGuard( )
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
int64 nElapsed = GetElapsed( );
|
|
m_pProfiler->Add( nElapsed, m_numCallsToAdd );
|
|
m_pLastProfiler->SubCallee( nElapsed );
|
|
if ( bThreadSafe )
|
|
{
|
|
PopMiniProfilerTS( m_pLastProfiler );
|
|
}
|
|
else
|
|
{
|
|
g_pLastMiniProfiler = m_pLastProfiler;
|
|
}
|
|
#endif
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef TMiniProfilerGuard<CMiniProfilerSample, false> CMiniProfilerGuardFast; // default guard uses rdtsc
|
|
typedef TMiniProfilerGuard<CMiniProfilerSample, true> CMiniProfilerGuard, CMiniProfilerGuardTS; // default guard uses rdtsc
|
|
|
|
|
|
|
|
class CMiniProfilerGuardSimple: public CMiniProfilerSample
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
CMiniProfiler *m_pProfiler, *m_pLastProfiler;
|
|
#endif
|
|
public:
|
|
|
|
CMiniProfilerGuardSimple( CLinkedMiniProfiler *pProfiler )
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
m_pProfiler = pProfiler;
|
|
pProfiler->m_pLastParent = m_pLastProfiler = PushMiniProfilerTS( pProfiler ); // = g_pLastMiniProfiler; g_pLastMiniProfiler = pProfiler;
|
|
#endif
|
|
}
|
|
|
|
~CMiniProfilerGuardSimple()
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
// Note: we measure both push and pop as if they belonged to the measured function
|
|
PopMiniProfilerTS( m_pLastProfiler ); // g_pLastMiniProfiler = m_pLastProfiler;
|
|
int64 nElapsed = GetElapsed( );
|
|
m_pProfiler->Add( nElapsed );
|
|
m_pLastProfiler->SubCallee( nElapsed );
|
|
#endif
|
|
}
|
|
};
|
|
|
|
|
|
class CMiniProfilerAntiGuard: public CMiniProfilerSample
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
CMiniProfiler *m_pProfiler;
|
|
#endif
|
|
public:
|
|
CMiniProfilerAntiGuard( CMiniProfiler *pProfiler )
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
m_pProfiler = pProfiler;
|
|
#endif
|
|
}
|
|
~CMiniProfilerAntiGuard( )
|
|
{
|
|
#if ENABLE_MINI_PROFILER
|
|
m_pProfiler->Add( -GetElapsed( ) );
|
|
#endif
|
|
}
|
|
};
|
|
|
|
#define MPROF_VAR_NAME_INTERNAL_CAT(a, b) a##b
|
|
#define MPROF_VAR_NAME_INTERNAL( a, b ) MPROF_VAR_NAME_INTERNAL_CAT( a, b )
|
|
#define MPROF_VAR_NAME( a ) MPROF_VAR_NAME_INTERNAL( a, __LINE__ )
|
|
#define MPROF_TO_STRING_0( a ) #a
|
|
#define MPROF_TO_STRING( a ) MPROF_TO_STRING_0(a)
|
|
|
|
#ifdef PROJECTNAME
|
|
#define MPROF_PROJECTNAME_STRING MPROF_TO_STRING(PROJECTNAME)
|
|
#else
|
|
#define MPROF_PROJECTNAME_STRING ""
|
|
#endif
|
|
|
|
#if ENABLE_MINI_PROFILER
|
|
#define MPROF_GR( item, group ) static CLinkedMiniProfiler MPROF_VAR_NAME(miniProfilerNode)( ( item ), group "\n" __FUNCTION__ "\n" __FILE__ "\n" MPROF_TO_STRING( __LINE__ ) "\n" MPROF_PROJECTNAME_STRING ); CMiniProfilerGuardSimple MPROF_VAR_NAME( miniProfilerGuard )( &MPROF_VAR_NAME( miniProfilerNode ) )
|
|
#else
|
|
#define MPROF_GR( item, group )
|
|
#endif
|
|
|
|
#define MPROF_NODE( name, item, group ) CLinkedMiniProfiler miniprofiler_##name( ( item ), group "\n\n" __FILE__ "\n" MPROF_TO_STRING( __LINE__ ) "\n" MPROF_PROJECTNAME_STRING );
|
|
#define MPROF_AUTO( name ) CMiniProfilerGuardSimple MPROF_VAR_NAME(miniProfiler_##name##_auto)( &miniprofiler_##name )
|
|
#define MPROF_AUTO_FAST( name ) CMicroProfilerGuard MPROF_VAR_NAME(microProfiler_##name##_auto)( &miniprofiler_##name )
|
|
#define MPROF_AUTO_FAST_COUNT( NAME, COUNT ) CMicroProfilerGuardWithCount MPROF_VAR_NAME(microProfiler_##NAME##_auto)( &miniprofiler_##NAME, COUNT )
|
|
|
|
#define MPROF( item ) MPROF_GR( item, "" )
|
|
#define MPROF_FN() MPROF( __FUNCTION__ )
|
|
|
|
|
|
#endif
|