257 lines
5.4 KiB
C
257 lines
5.4 KiB
C
|
//========= 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 L4D_TIER0_MINIPROFILER_HDR
|
||
|
#define L4D_TIER0_MINIPROFILER_HDR
|
||
|
|
||
|
#include <tier0/cache_hints.h>
|
||
|
|
||
|
#ifdef IS_WINDOWS_PC
|
||
|
#include <intrin.h> // get __rdtsc
|
||
|
#endif
|
||
|
|
||
|
#if !defined(_CERT) && ( defined( WIN32 ) || defined( _X360 ) ) // && !defined(_LINUX)
|
||
|
#define ENABLE_HARDWARE_PROFILER 1
|
||
|
#else
|
||
|
#define ENABLE_HARDWARE_PROFILER 0
|
||
|
#endif
|
||
|
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
|
||
|
#ifdef _LINUX
|
||
|
inline int GetHardwareClockFast( void )
|
||
|
{
|
||
|
unsigned long long int nRet;
|
||
|
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (nRet));
|
||
|
return ( int ) nRet;
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
inline int GetHardwareClockFast()
|
||
|
{
|
||
|
#ifdef _X360
|
||
|
return __mftb32();
|
||
|
#else
|
||
|
return __rdtsc();
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
class CMiniProfiler;
|
||
|
class CLinkedMiniProfiler;
|
||
|
|
||
|
#ifdef TIER0_DLL_EXPORT
|
||
|
extern "C"
|
||
|
{
|
||
|
DLL_EXPORT CMiniProfiler *g_pLastMiniProfiler;
|
||
|
DLL_EXPORT uint32 g_nMiniProfilerFrame;
|
||
|
}
|
||
|
#else
|
||
|
DLL_IMPORT void PublishAll(CLinkedMiniProfiler*pList, uint32 nHistoryMax);
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
DLL_IMPORT CMiniProfiler *g_pLastMiniProfiler;
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
|
||
|
class CMiniProfilerSample
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
int m_nTimeBaseBegin; // time base is kept here instead of using -= and += for better reliability and to avoid a cache miss at the beginning of the profiled section
|
||
|
#endif
|
||
|
|
||
|
public:
|
||
|
CMiniProfilerSample()
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
m_nTimeBaseBegin = GetHardwareClockFast();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int GetElapsed()const
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
return GetHardwareClockFast() - m_nTimeBaseBegin;
|
||
|
#else
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
class CMiniProfiler
|
||
|
{
|
||
|
public:
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
// numTicks is
|
||
|
uint32 m_numTimeBaseTicks; // this will be totally screwed between Begin() and End()
|
||
|
uint32 m_numCalls;
|
||
|
uint32 m_numTimeBaseTicksInCallees; // this is the time to subtract from m_numTimeBaseTicks to get the "exclusive" time in this block
|
||
|
#endif
|
||
|
public:
|
||
|
CMiniProfiler()
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
Reset();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void Begin()
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
m_numTimeBaseTicks -= GetHardwareClockFast();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void End()
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
m_numTimeBaseTicks += GetHardwareClockFast();
|
||
|
m_numCalls ++;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void Add(int numTimeBaseTicks, int numCalls = 1)
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
m_numTimeBaseTicks += numTimeBaseTicks;
|
||
|
m_numCalls += numCalls;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void Add(const CMiniProfilerSample &sample)
|
||
|
{
|
||
|
Add(sample.GetElapsed());
|
||
|
}
|
||
|
|
||
|
void SubCallee(int numTimeBaseTicks)
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
m_numTimeBaseTicksInCallees += numTimeBaseTicks;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void Reset()
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
m_numTimeBaseTicks = 0;
|
||
|
m_numCalls = 0;
|
||
|
m_numTimeBaseTicksInCallees = 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void Damp(int shift = 1)
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
m_numTimeBaseTicks >>= shift;
|
||
|
m_numCalls >>= shift;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
DLL_CLASS_EXPORT void Publish(const char *szMessage, ...);
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
class CMiniProfilerGuard: public CMiniProfilerSample
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
CMiniProfiler *m_pProfiler, *m_pLastProfiler;
|
||
|
int m_numCallsToAdd;
|
||
|
#endif
|
||
|
public:
|
||
|
CMiniProfilerGuard(CMiniProfiler *pProfiler, int numCallsToAdd = 1)
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
PREFETCH_CACHE_LINE(pProfiler,0);
|
||
|
m_numCallsToAdd = numCallsToAdd;
|
||
|
m_pProfiler = pProfiler;
|
||
|
m_pLastProfiler = g_pLastMiniProfiler;
|
||
|
g_pLastMiniProfiler = pProfiler;
|
||
|
#endif
|
||
|
}
|
||
|
~CMiniProfilerGuard()
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
int nElapsed = GetElapsed();
|
||
|
m_pProfiler->Add(nElapsed, m_numCallsToAdd);
|
||
|
m_pLastProfiler->SubCallee(nElapsed);
|
||
|
g_pLastMiniProfiler = m_pLastProfiler;
|
||
|
#endif
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class CMiniProfilerAntiGuard: public CMiniProfilerSample
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
CMiniProfiler *m_pProfiler;
|
||
|
#endif
|
||
|
public:
|
||
|
CMiniProfilerAntiGuard(CMiniProfiler *pProfiler)
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
m_pProfiler = pProfiler;
|
||
|
#endif
|
||
|
}
|
||
|
~CMiniProfilerAntiGuard()
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
m_pProfiler->Add(-GetElapsed());
|
||
|
#endif
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
class CLinkedMiniProfiler: public CMiniProfiler
|
||
|
{
|
||
|
public:
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
CLinkedMiniProfiler *m_pNext, **m_ppPrev;
|
||
|
const char *m_szName;
|
||
|
uint m_nHistoryMax, m_nHistoryLength;
|
||
|
CMiniProfiler *m_pHistory;
|
||
|
uint32 m_nFrameHistoryBegins;
|
||
|
#endif
|
||
|
public:
|
||
|
CLinkedMiniProfiler(const char *szName, CLinkedMiniProfiler**ppList)
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
m_nFrameHistoryBegins = 0;
|
||
|
m_pNext = *ppList;
|
||
|
m_ppPrev = ppList;
|
||
|
*ppList = this;
|
||
|
m_szName = szName;
|
||
|
m_pHistory = NULL;
|
||
|
m_nHistoryLength = 0;
|
||
|
m_nHistoryMax = 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
~CLinkedMiniProfiler()
|
||
|
{
|
||
|
#if ENABLE_HARDWARE_PROFILER
|
||
|
// We need to remove miniprofiler from the list properly. This is an issue because we unload DLLs sometimes.
|
||
|
*m_ppPrev = m_pNext; // that's it: we just remove this object from the list by linking previous object with the next
|
||
|
if(m_pNext)
|
||
|
m_pNext->m_ppPrev = m_ppPrev;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void Publish(uint nHistoryMax);
|
||
|
void PurgeHistory();
|
||
|
};
|
||
|
|
||
|
#endif
|