Files
bullet3/src/LinearMath/btQuickprof.h
2008-04-02 17:23:52 +00:00

360 lines
8.9 KiB
C++

/***************************************************************************************************
**
** Real-Time Hierarchical Profiling for Game Programming Gems 3
**
** by Greg Hjelstrom & Byon Garrabrant
**
***************************************************************************************************/
// Credits: The Clock class was inspired by the Timer classes in
// Ogre (www.ogre3d.org).
#ifndef QUICK_PROF_H
#define QUICK_PROF_H
#include "btScalar.h"
//To disable built-in profiling, please comment out next line
//#define BT_NO_PROFILE 1
//if you don't need btClock, you can comment next line
#define USE_BT_CLOCK 1
#ifdef USE_BT_CLOCK
#ifdef __CELLOS_LV2__
#include <sys/sys_time.h>
#include <sys/time_util.h>
#include <stdio.h>
typedef uint64_t __int64;
#endif
#if defined (SUNOS) || defined (__SUNOS__)
#include <stdio.h>
#endif
#if defined(WIN32) || defined(_WIN32)
#define USE_WINDOWS_TIMERS
#define WIN32_LEAN_AND_MEAN
#define NOWINRES
#define NOMCX
#define NOIME
#ifdef _XBOX
#include <Xtl.h>
#else
#include <windows.h>
#endif
#include <time.h>
#else
#include <sys/time.h>
#endif
#define mymin(a,b) (a > b ? a : b)
/// basic clock
class btClock
{
public:
btClock()
{
#ifdef USE_WINDOWS_TIMERS
QueryPerformanceFrequency(&mClockFrequency);
#endif
reset();
}
~btClock()
{
}
/// Resets the initial reference time.
void reset()
{
#ifdef USE_WINDOWS_TIMERS
QueryPerformanceCounter(&mStartTime);
mStartTick = GetTickCount();
mPrevElapsedTime = 0;
#else
#ifdef __CELLOS_LV2__
typedef uint64_t __int64;
typedef __int64 ClockSize;
ClockSize newTime;
//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
SYS_TIMEBASE_GET( newTime );
mStartTime = newTime;
#else
gettimeofday(&mStartTime, 0);
#endif
#endif
}
/// Returns the time in ms since the last call to reset or since
/// the btClock was created.
unsigned long int getTimeMilliseconds()
{
#ifdef USE_WINDOWS_TIMERS
LARGE_INTEGER currentTime;
QueryPerformanceCounter(&currentTime);
LONGLONG elapsedTime = currentTime.QuadPart -
mStartTime.QuadPart;
// Compute the number of millisecond ticks elapsed.
unsigned long msecTicks = (unsigned long)(1000 * elapsedTime /
mClockFrequency.QuadPart);
// Check for unexpected leaps in the Win32 performance counter.
// (This is caused by unexpected data across the PCI to ISA
// bridge, aka south bridge. See Microsoft KB274323.)
unsigned long elapsedTicks = GetTickCount() - mStartTick;
signed long msecOff = (signed long)(msecTicks - elapsedTicks);
if (msecOff < -100 || msecOff > 100)
{
// Adjust the starting time forwards.
LONGLONG msecAdjustment = mymin(msecOff *
mClockFrequency.QuadPart / 1000, elapsedTime -
mPrevElapsedTime);
mStartTime.QuadPart += msecAdjustment;
elapsedTime -= msecAdjustment;
// Recompute the number of millisecond ticks elapsed.
msecTicks = (unsigned long)(1000 * elapsedTime /
mClockFrequency.QuadPart);
}
// Store the current elapsed time for adjustments next time.
mPrevElapsedTime = elapsedTime;
return msecTicks;
#else
#ifdef __CELLOS_LV2__
__int64 freq=sys_time_get_timebase_frequency();
double dFreq=((double) freq) / 1000.0;
typedef uint64_t __int64;
typedef __int64 ClockSize;
ClockSize newTime;
SYS_TIMEBASE_GET( newTime );
//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
return (newTime-mStartTime) / dFreq;
#else
struct timeval currentTime;
gettimeofday(&currentTime, 0);
return (currentTime.tv_sec - mStartTime.tv_sec) * 1000 +
(currentTime.tv_usec - mStartTime.tv_usec) / 1000;
#endif //__CELLOS_LV2__
#endif
}
/// Returns the time in us since the last call to reset or since
/// the Clock was created.
unsigned long int getTimeMicroseconds()
{
#ifdef USE_WINDOWS_TIMERS
LARGE_INTEGER currentTime;
QueryPerformanceCounter(&currentTime);
LONGLONG elapsedTime = currentTime.QuadPart -
mStartTime.QuadPart;
// Compute the number of millisecond ticks elapsed.
unsigned long msecTicks = (unsigned long)(1000 * elapsedTime /
mClockFrequency.QuadPart);
// Check for unexpected leaps in the Win32 performance counter.
// (This is caused by unexpected data across the PCI to ISA
// bridge, aka south bridge. See Microsoft KB274323.)
unsigned long elapsedTicks = GetTickCount() - mStartTick;
signed long msecOff = (signed long)(msecTicks - elapsedTicks);
if (msecOff < -100 || msecOff > 100)
{
// Adjust the starting time forwards.
LONGLONG msecAdjustment = mymin(msecOff *
mClockFrequency.QuadPart / 1000, elapsedTime -
mPrevElapsedTime);
mStartTime.QuadPart += msecAdjustment;
elapsedTime -= msecAdjustment;
}
// Store the current elapsed time for adjustments next time.
mPrevElapsedTime = elapsedTime;
// Convert to microseconds.
unsigned long usecTicks = (unsigned long)(1000000 * elapsedTime /
mClockFrequency.QuadPart);
return usecTicks;
#else
#ifdef __CELLOS_LV2__
__int64 freq=sys_time_get_timebase_frequency();
double dFreq=((double) freq)/ 1000000.0;
typedef uint64_t __int64;
typedef __int64 ClockSize;
ClockSize newTime;
//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
SYS_TIMEBASE_GET( newTime );
return (newTime-mStartTime) / dFreq;
#else
struct timeval currentTime;
gettimeofday(&currentTime, 0);
return (currentTime.tv_sec - mStartTime.tv_sec) * 1000000 +
(currentTime.tv_usec - mStartTime.tv_usec);
#endif//__CELLOS_LV2__
#endif
}
private:
#ifdef USE_WINDOWS_TIMERS
LARGE_INTEGER mClockFrequency;
DWORD mStartTick;
LONGLONG mPrevElapsedTime;
LARGE_INTEGER mStartTime;
#else
#ifdef __CELLOS_LV2__
uint64_t mStartTime;
#else
struct timeval mStartTime;
#endif
#endif //__CELLOS_LV2__
};
#endif //USE_BT_CLOCK
/*
** A node in the Profile Hierarchy Tree
*/
class CProfileNode {
public:
CProfileNode( const char * name, CProfileNode * parent );
~CProfileNode( void );
CProfileNode * Get_Sub_Node( const char * name );
CProfileNode * Get_Parent( void ) { return Parent; }
CProfileNode * Get_Sibling( void ) { return Sibling; }
CProfileNode * Get_Child( void ) { return Child; }
void Reset( void );
void Call( void );
bool Return( void );
const char * Get_Name( void ) { return Name; }
int Get_Total_Calls( void ) { return TotalCalls; }
float Get_Total_Time( void ) { return TotalTime; }
protected:
const char * Name;
int TotalCalls;
float TotalTime;
unsigned long int StartTime;
int RecursionCounter;
CProfileNode * Parent;
CProfileNode * Child;
CProfileNode * Sibling;
};
/*
** An iterator to navigate through the tree
*/
class CProfileIterator
{
public:
// Access all the children of the current parent
void First(void);
void Next(void);
bool Is_Done(void);
bool Is_Root(void) { return (CurrentParent->Get_Parent() == 0); }
void Enter_Child( int index ); // Make the given child the new parent
void Enter_Largest_Child( void ); // Make the largest child the new parent
void Enter_Parent( void ); // Make the current parent's parent the new parent
// Access the current child
const char * Get_Current_Name( void ) { return CurrentChild->Get_Name(); }
int Get_Current_Total_Calls( void ) { return CurrentChild->Get_Total_Calls(); }
float Get_Current_Total_Time( void ) { return CurrentChild->Get_Total_Time(); }
// Access the current parent
const char * Get_Current_Parent_Name( void ) { return CurrentParent->Get_Name(); }
int Get_Current_Parent_Total_Calls( void ) { return CurrentParent->Get_Total_Calls(); }
float Get_Current_Parent_Total_Time( void ) { return CurrentParent->Get_Total_Time(); }
protected:
CProfileNode * CurrentParent;
CProfileNode * CurrentChild;
CProfileIterator( CProfileNode * start );
friend class CProfileManager;
};
/*
** The Manager for the Profile system
*/
class CProfileManager {
public:
static void Start_Profile( const char * name );
static void Stop_Profile( void );
static void Reset( void );
static void Increment_Frame_Counter( void );
static int Get_Frame_Count_Since_Reset( void ) { return FrameCounter; }
static float Get_Time_Since_Reset( void );
static CProfileIterator * Get_Iterator( void ) { return new CProfileIterator( &Root ); }
static void Release_Iterator( CProfileIterator * iterator ) { delete iterator; }
private:
static CProfileNode Root;
static CProfileNode * CurrentNode;
static int FrameCounter;
static unsigned long int ResetTime;
};
/*
** ProfileSampleClass is a simple way to profile a function's scope
** Use the BT_PROFILE macro at the start of scope to time
*/
class CProfileSample {
public:
CProfileSample( const char * name )
{
CProfileManager::Start_Profile( name );
}
~CProfileSample( void )
{
CProfileManager::Stop_Profile();
}
};
#if !defined(BT_NO_PROFILE)
#define BT_PROFILE( name ) CProfileSample __profile( name )
#else
#define BT_PROFILE( name )
#endif
#endif //QUICK_PROF_H