790 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			790 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | /*
 | ||
|  | 
 | ||
|  | *************************************************************************************************** | ||
|  | ** | ||
|  | ** profile.cpp | ||
|  | ** | ||
|  | ** 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).
 | ||
|  | 
 | ||
|  | #include "btQuickprof.h"
 | ||
|  | #include "btThreads.h"
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #ifdef __CELLOS_LV2__
 | ||
|  | #include <sys/sys_time.h>
 | ||
|  | #include <sys/time_util.h>
 | ||
|  | #include <stdio.h>
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined (SUNOS) || defined (__SUNOS__)
 | ||
|  | #include <stdio.h>
 | ||
|  | #endif
 | ||
|  | #ifdef __APPLE__
 | ||
|  | #include <mach/mach_time.h>
 | ||
|  | #include <TargetConditionals.h>
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(WIN32) || defined(_WIN32)
 | ||
|  | 
 | ||
|  | #define BT_USE_WINDOWS_TIMERS
 | ||
|  | #define WIN32_LEAN_AND_MEAN
 | ||
|  | #define NOWINRES
 | ||
|  | #define NOMCX
 | ||
|  | #define NOIME
 | ||
|  | 
 | ||
|  | #ifdef _XBOX
 | ||
|  | 	#include <Xtl.h>
 | ||
|  | #else //_XBOX
 | ||
|  | 	#include <windows.h>
 | ||
|  | 
 | ||
|  | #if WINVER <0x0602
 | ||
|  | #define GetTickCount64 GetTickCount
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #endif //_XBOX
 | ||
|  | 
 | ||
|  | #include <time.h>
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #else //_WIN32
 | ||
|  | #include <sys/time.h>
 | ||
|  | 
 | ||
|  | #ifdef BT_LINUX_REALTIME
 | ||
|  | //required linking against rt (librt)
 | ||
|  | #include <time.h>
 | ||
|  | #endif //BT_LINUX_REALTIME
 | ||
|  | 
 | ||
|  | #endif //_WIN32
 | ||
|  | 
 | ||
|  | #define mymin(a,b) (a > b ? a : b)
 | ||
|  | 
 | ||
|  | struct btClockData | ||
|  | { | ||
|  | 
 | ||
|  | #ifdef BT_USE_WINDOWS_TIMERS
 | ||
|  | 	LARGE_INTEGER mClockFrequency; | ||
|  | 	LONGLONG mStartTick; | ||
|  | 	LARGE_INTEGER mStartTime; | ||
|  | #else
 | ||
|  | #ifdef __CELLOS_LV2__
 | ||
|  | 	uint64_t	mStartTime; | ||
|  | #else
 | ||
|  | #ifdef __APPLE__
 | ||
|  |     uint64_t mStartTimeNano; | ||
|  | #endif
 | ||
|  | 	struct timeval mStartTime; | ||
|  | #endif
 | ||
|  | #endif //__CELLOS_LV2__
 | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | ///The btClock is a portable basic clock that measures accurate time in seconds, use for profiling.
 | ||
|  | btClock::btClock() | ||
|  | { | ||
|  | 	m_data = new btClockData; | ||
|  | #ifdef BT_USE_WINDOWS_TIMERS
 | ||
|  | 	QueryPerformanceFrequency(&m_data->mClockFrequency); | ||
|  | #endif
 | ||
|  | 	reset(); | ||
|  | } | ||
|  | 
 | ||
|  | btClock::~btClock() | ||
|  | { | ||
|  | 	delete m_data; | ||
|  | } | ||
|  | 
 | ||
|  | btClock::btClock(const btClock& other) | ||
|  | { | ||
|  | 	m_data = new btClockData; | ||
|  | 	*m_data = *other.m_data; | ||
|  | } | ||
|  | 
 | ||
|  | btClock& btClock::operator=(const btClock& other) | ||
|  | { | ||
|  | 	*m_data = *other.m_data; | ||
|  | 	return *this; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 	/// Resets the initial reference time.
 | ||
|  | void btClock::reset() | ||
|  | { | ||
|  | #ifdef BT_USE_WINDOWS_TIMERS
 | ||
|  | 	QueryPerformanceCounter(&m_data->mStartTime); | ||
|  | 	m_data->mStartTick = GetTickCount64(); | ||
|  | #else
 | ||
|  | #ifdef __CELLOS_LV2__
 | ||
|  | 
 | ||
|  | 	typedef uint64_t  ClockSize; | ||
|  | 	ClockSize newTime; | ||
|  | 	//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
 | ||
|  | 	SYS_TIMEBASE_GET( newTime ); | ||
|  | 	m_data->mStartTime = newTime; | ||
|  | #else
 | ||
|  | #ifdef __APPLE__
 | ||
|  |     m_data->mStartTimeNano = mach_absolute_time(); | ||
|  | #endif
 | ||
|  | 	gettimeofday(&m_data->mStartTime, 0); | ||
|  | #endif
 | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | /// Returns the time in ms since the last call to reset or since
 | ||
|  | /// the btClock was created.
 | ||
|  | unsigned long long int btClock::getTimeMilliseconds() | ||
|  | { | ||
|  | #ifdef BT_USE_WINDOWS_TIMERS
 | ||
|  | 	LARGE_INTEGER currentTime; | ||
|  | 	QueryPerformanceCounter(¤tTime); | ||
|  | 	LONGLONG elapsedTime = currentTime.QuadPart - | ||
|  | 		m_data->mStartTime.QuadPart; | ||
|  | 		// Compute the number of millisecond ticks elapsed.
 | ||
|  | 	unsigned long msecTicks = (unsigned long)(1000 * elapsedTime / | ||
|  | 		m_data->mClockFrequency.QuadPart); | ||
|  | 
 | ||
|  | 		return msecTicks; | ||
|  | #else
 | ||
|  | 
 | ||
|  | #ifdef __CELLOS_LV2__
 | ||
|  | 		uint64_t freq=sys_time_get_timebase_frequency(); | ||
|  | 		double dFreq=((double) freq) / 1000.0; | ||
|  | 		typedef uint64_t  ClockSize; | ||
|  | 		ClockSize newTime; | ||
|  | 		SYS_TIMEBASE_GET( newTime ); | ||
|  | 		//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
 | ||
|  | 
 | ||
|  | 		return (unsigned long int)((double(newTime-m_data->mStartTime)) / dFreq); | ||
|  | #else
 | ||
|  | 
 | ||
|  | 		struct timeval currentTime; | ||
|  | 		gettimeofday(¤tTime, 0); | ||
|  | 		return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000 + | ||
|  | 			(currentTime.tv_usec - m_data->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 long int btClock::getTimeMicroseconds() | ||
|  | { | ||
|  | #ifdef BT_USE_WINDOWS_TIMERS
 | ||
|  | 	//see https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx	
 | ||
|  | 		LARGE_INTEGER currentTime, elapsedTime; | ||
|  | 		 | ||
|  | 		QueryPerformanceCounter(¤tTime); | ||
|  | 		elapsedTime.QuadPart = currentTime.QuadPart -  | ||
|  | 			m_data->mStartTime.QuadPart; | ||
|  | 		elapsedTime.QuadPart *= 1000000; | ||
|  | 		elapsedTime.QuadPart /= m_data->mClockFrequency.QuadPart; | ||
|  | 
 | ||
|  | 		return (unsigned long long) elapsedTime.QuadPart; | ||
|  | #else
 | ||
|  | 
 | ||
|  | #ifdef __CELLOS_LV2__
 | ||
|  | 		uint64_t freq=sys_time_get_timebase_frequency(); | ||
|  | 		double dFreq=((double) freq)/ 1000000.0; | ||
|  | 		typedef uint64_t  ClockSize; | ||
|  | 		ClockSize newTime; | ||
|  | 		//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
 | ||
|  | 		SYS_TIMEBASE_GET( newTime ); | ||
|  | 
 | ||
|  | 		return (unsigned long int)((double(newTime-m_data->mStartTime)) / dFreq); | ||
|  | #else
 | ||
|  | 
 | ||
|  | 		struct timeval currentTime; | ||
|  | 		gettimeofday(¤tTime, 0); | ||
|  | 		return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000000 + | ||
|  | 			(currentTime.tv_usec - m_data->mStartTime.tv_usec); | ||
|  | #endif//__CELLOS_LV2__
 | ||
|  | #endif
 | ||
|  | } | ||
|  | 
 | ||
|  | unsigned long long int btClock::getTimeNanoseconds() | ||
|  | { | ||
|  | #ifdef BT_USE_WINDOWS_TIMERS
 | ||
|  | 	//see https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
 | ||
|  | 		LARGE_INTEGER currentTime, elapsedTime; | ||
|  | 		 | ||
|  | 		QueryPerformanceCounter(¤tTime); | ||
|  | 		elapsedTime.QuadPart = currentTime.QuadPart -  | ||
|  | 			m_data->mStartTime.QuadPart; | ||
|  | 		elapsedTime.QuadPart *= 1000000000; | ||
|  | 		elapsedTime.QuadPart /= m_data->mClockFrequency.QuadPart; | ||
|  | 
 | ||
|  | 		return (unsigned long long) elapsedTime.QuadPart; | ||
|  | #else
 | ||
|  | 
 | ||
|  | #ifdef __CELLOS_LV2__
 | ||
|  | 		uint64_t freq=sys_time_get_timebase_frequency(); | ||
|  | 		double dFreq=((double) freq)/ 1e9; | ||
|  | 		typedef uint64_t  ClockSize; | ||
|  | 		ClockSize newTime; | ||
|  | 		//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
 | ||
|  | 		SYS_TIMEBASE_GET( newTime ); | ||
|  | 
 | ||
|  | 		return (unsigned long int)((double(newTime-m_data->mStartTime)) / dFreq); | ||
|  | #else
 | ||
|  | #ifdef __APPLE__
 | ||
|  |     uint64_t ticks = mach_absolute_time() - m_data->mStartTimeNano; | ||
|  |     static long double conversion = 0.0L; | ||
|  |     if( 0.0L == conversion ) | ||
|  |     { | ||
|  |         // attempt to get conversion to nanoseconds
 | ||
|  |         mach_timebase_info_data_t info; | ||
|  |         int err = mach_timebase_info( &info ); | ||
|  |         if( err ) | ||
|  |         { | ||
|  |             btAssert(0); | ||
|  |             conversion = 1.; | ||
|  |         } | ||
|  |         conversion = info.numer / info.denom; | ||
|  |     } | ||
|  |     return (ticks * conversion); | ||
|  | 
 | ||
|  |      | ||
|  | #else//__APPLE__
 | ||
|  |      | ||
|  | #ifdef BT_LINUX_REALTIME
 | ||
|  |     timespec ts; | ||
|  |     clock_gettime(CLOCK_REALTIME,&ts); | ||
|  |     return 1000000000*ts.tv_sec + ts.tv_nsec; | ||
|  | #else
 | ||
|  |     	struct timeval currentTime; | ||
|  | 		gettimeofday(¤tTime, 0); | ||
|  | 		return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1e9 + | ||
|  | 			(currentTime.tv_usec - m_data->mStartTime.tv_usec)*1000; | ||
|  | #endif //BT_LINUX_REALTIME
 | ||
|  | 
 | ||
|  | #endif//__APPLE__
 | ||
|  | #endif//__CELLOS_LV2__
 | ||
|  | #endif 
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /// Returns the time in s since the last call to reset or since 
 | ||
|  | /// the Clock was created.
 | ||
|  | btScalar btClock::getTimeSeconds() | ||
|  | { | ||
|  | 	static const btScalar microseconds_to_seconds = btScalar(0.000001); | ||
|  | 	return btScalar(getTimeMicroseconds()) * microseconds_to_seconds; | ||
|  | } | ||
|  | 
 | ||
|  | #ifndef BT_NO_PROFILE
 | ||
|  | 
 | ||
|  | 
 | ||
|  | static btClock gProfileClock; | ||
|  | 
 | ||
|  | 
 | ||
|  | inline void Profile_Get_Ticks(unsigned long int * ticks) | ||
|  | { | ||
|  | 	*ticks = (unsigned long int)gProfileClock.getTimeMicroseconds(); | ||
|  | } | ||
|  | 
 | ||
|  | inline float Profile_Get_Tick_Rate(void) | ||
|  | { | ||
|  | //	return 1000000.f;
 | ||
|  | 	return 1000.f; | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /***************************************************************************************************
 | ||
|  | ** | ||
|  | ** CProfileNode | ||
|  | ** | ||
|  | ***************************************************************************************************/ | ||
|  | 
 | ||
|  | /***********************************************************************************************
 | ||
|  |  * INPUT:                                                                                      * | ||
|  |  * name - pointer to a static string which is the name of this profile node                    * | ||
|  |  * parent - parent pointer                                                                     * | ||
|  |  *                                                                                             * | ||
|  |  * WARNINGS:                                                                                   * | ||
|  |  * The name is assumed to be a static pointer, only the pointer is stored and compared for     * | ||
|  |  * efficiency reasons.                                                                         * | ||
|  |  *=============================================================================================*/ | ||
|  | CProfileNode::CProfileNode( const char * name, CProfileNode * parent ) : | ||
|  | 	Name( name ), | ||
|  | 	TotalCalls( 0 ), | ||
|  | 	TotalTime( 0 ), | ||
|  | 	StartTime( 0 ), | ||
|  | 	RecursionCounter( 0 ), | ||
|  | 	Parent( parent ), | ||
|  | 	Child( NULL ), | ||
|  | 	Sibling( NULL ), | ||
|  | 	m_userPtr(0) | ||
|  | { | ||
|  | 	Reset(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void	CProfileNode::CleanupMemory() | ||
|  | { | ||
|  | 	delete ( Child); | ||
|  | 	Child = NULL; | ||
|  | 	delete ( Sibling); | ||
|  | 	Sibling = NULL; | ||
|  | } | ||
|  | 
 | ||
|  | CProfileNode::~CProfileNode( void ) | ||
|  | { | ||
|  | 	CleanupMemory(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /***********************************************************************************************
 | ||
|  |  * INPUT:                                                                                      * | ||
|  |  * name - static string pointer to the name of the node we are searching for                   * | ||
|  |  *                                                                                             * | ||
|  |  * WARNINGS:                                                                                   * | ||
|  |  * All profile names are assumed to be static strings so this function uses pointer compares   * | ||
|  |  * to find the named node.                                                                     * | ||
|  |  *=============================================================================================*/ | ||
|  | CProfileNode * CProfileNode::Get_Sub_Node( const char * name ) | ||
|  | { | ||
|  | 	// Try to find this sub node
 | ||
|  | 	CProfileNode * child = Child; | ||
|  | 	while ( child ) { | ||
|  | 		if ( child->Name == name ) { | ||
|  | 			return child; | ||
|  | 		} | ||
|  | 		child = child->Sibling; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// We didn't find it, so add it
 | ||
|  | 
 | ||
|  | 	CProfileNode * node = new CProfileNode( name, this ); | ||
|  | 	node->Sibling = Child; | ||
|  | 	Child = node; | ||
|  | 	return node; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void	CProfileNode::Reset( void ) | ||
|  | { | ||
|  | 	TotalCalls = 0; | ||
|  | 	TotalTime = 0.0f; | ||
|  | 
 | ||
|  | 
 | ||
|  | 	if ( Child ) { | ||
|  | 		Child->Reset(); | ||
|  | 	} | ||
|  | 	if ( Sibling ) { | ||
|  | 		Sibling->Reset(); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void	CProfileNode::Call( void ) | ||
|  | { | ||
|  | 	TotalCalls++; | ||
|  | 	if (RecursionCounter++ == 0) { | ||
|  | 		Profile_Get_Ticks(&StartTime); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | bool	CProfileNode::Return( void ) | ||
|  | { | ||
|  | 	if ( --RecursionCounter == 0 && TotalCalls != 0 ) { | ||
|  | 		unsigned long int time; | ||
|  | 		Profile_Get_Ticks(&time); | ||
|  | 
 | ||
|  | 		time-=StartTime; | ||
|  | 		TotalTime += (float)time / Profile_Get_Tick_Rate(); | ||
|  | 	} | ||
|  | 	return ( RecursionCounter == 0 ); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /***************************************************************************************************
 | ||
|  | ** | ||
|  | ** CProfileIterator | ||
|  | ** | ||
|  | ***************************************************************************************************/ | ||
|  | CProfileIterator::CProfileIterator( CProfileNode * start ) | ||
|  | { | ||
|  | 	CurrentParent = start; | ||
|  | 	CurrentChild = CurrentParent->Get_Child(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void	CProfileIterator::First(void) | ||
|  | { | ||
|  | 	CurrentChild = CurrentParent->Get_Child(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void	CProfileIterator::Next(void) | ||
|  | { | ||
|  | 	CurrentChild = CurrentChild->Get_Sibling(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | bool	CProfileIterator::Is_Done(void) | ||
|  | { | ||
|  | 	return CurrentChild == NULL; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void	CProfileIterator::Enter_Child( int index ) | ||
|  | { | ||
|  | 	CurrentChild = CurrentParent->Get_Child(); | ||
|  | 	while ( (CurrentChild != NULL) && (index != 0) ) { | ||
|  | 		index--; | ||
|  | 		CurrentChild = CurrentChild->Get_Sibling(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if ( CurrentChild != NULL ) { | ||
|  | 		CurrentParent = CurrentChild; | ||
|  | 		CurrentChild = CurrentParent->Get_Child(); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void	CProfileIterator::Enter_Parent( void ) | ||
|  | { | ||
|  | 	if ( CurrentParent->Get_Parent() != NULL ) { | ||
|  | 		CurrentParent = CurrentParent->Get_Parent(); | ||
|  | 	} | ||
|  | 	CurrentChild = CurrentParent->Get_Child(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /***************************************************************************************************
 | ||
|  | ** | ||
|  | ** CProfileManager | ||
|  | ** | ||
|  | ***************************************************************************************************/ | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | CProfileNode	gRoots[BT_QUICKPROF_MAX_THREAD_COUNT]={ | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), | ||
|  | 	CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL) | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | CProfileNode* gCurrentNodes[BT_QUICKPROF_MAX_THREAD_COUNT]= | ||
|  | { | ||
|  | 	&gRoots[ 0],	&gRoots[ 1],	&gRoots[ 2],	&gRoots[ 3], | ||
|  | 	&gRoots[ 4],	&gRoots[ 5],	&gRoots[ 6],	&gRoots[ 7], | ||
|  | 	&gRoots[ 8],	&gRoots[ 9],	&gRoots[10],	&gRoots[11], | ||
|  | 	&gRoots[12],	&gRoots[13],	&gRoots[14],	&gRoots[15], | ||
|  | 	&gRoots[16],	&gRoots[17],	&gRoots[18],	&gRoots[19], | ||
|  | 	&gRoots[20],	&gRoots[21],	&gRoots[22],	&gRoots[23], | ||
|  | 	&gRoots[24],	&gRoots[25],	&gRoots[26],	&gRoots[27], | ||
|  | 	&gRoots[28],	&gRoots[29],	&gRoots[30],	&gRoots[31], | ||
|  | 	&gRoots[32],	&gRoots[33],	&gRoots[34],	&gRoots[35], | ||
|  | 	&gRoots[36],	&gRoots[37],	&gRoots[38],	&gRoots[39], | ||
|  | 	&gRoots[40],	&gRoots[41],	&gRoots[42],	&gRoots[43], | ||
|  | 	&gRoots[44],	&gRoots[45],	&gRoots[46],	&gRoots[47], | ||
|  | 	&gRoots[48],	&gRoots[49],	&gRoots[50],	&gRoots[51], | ||
|  | 	&gRoots[52],	&gRoots[53],	&gRoots[54],	&gRoots[55], | ||
|  | 	&gRoots[56],	&gRoots[57],	&gRoots[58],	&gRoots[59], | ||
|  | 	&gRoots[60],	&gRoots[61],	&gRoots[62],	&gRoots[63], | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | int				CProfileManager::FrameCounter = 0; | ||
|  | unsigned long int			CProfileManager::ResetTime = 0; | ||
|  | 
 | ||
|  | CProfileIterator *	CProfileManager::Get_Iterator( void ) | ||
|  | {  | ||
|  | 
 | ||
|  | 		int threadIndex = btQuickprofGetCurrentThreadIndex2(); | ||
|  | 		if ((threadIndex<0) || threadIndex >= BT_QUICKPROF_MAX_THREAD_COUNT) | ||
|  | 			return 0; | ||
|  | 
 | ||
|  | 		return new CProfileIterator( &gRoots[threadIndex]);  | ||
|  | } | ||
|  | 
 | ||
|  | void						CProfileManager::CleanupMemory(void) | ||
|  | { | ||
|  | 	for (int i=0;i<BT_QUICKPROF_MAX_THREAD_COUNT;i++) | ||
|  | 	{ | ||
|  | 		gRoots[i].CleanupMemory(); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /***********************************************************************************************
 | ||
|  |  * CProfileManager::Start_Profile -- Begin a named profile                                    * | ||
|  |  *                                                                                             * | ||
|  |  * Steps one level deeper into the tree, if a child already exists with the specified name     * | ||
|  |  * then it accumulates the profiling; otherwise a new child node is added to the profile tree. * | ||
|  |  *                                                                                             * | ||
|  |  * INPUT:                                                                                      * | ||
|  |  * name - name of this profiling record                                                        * | ||
|  |  *                                                                                             * | ||
|  |  * WARNINGS:                                                                                   * | ||
|  |  * The string used is assumed to be a static string; pointer compares are used throughout      * | ||
|  |  * the profiling code for efficiency.                                                          * | ||
|  |  *=============================================================================================*/ | ||
|  | void	CProfileManager::Start_Profile( const char * name ) | ||
|  | { | ||
|  | 	int threadIndex = btQuickprofGetCurrentThreadIndex2(); | ||
|  | 	if ((threadIndex<0) || threadIndex >= BT_QUICKPROF_MAX_THREAD_COUNT) | ||
|  | 		return; | ||
|  | 
 | ||
|  | 	if (name != gCurrentNodes[threadIndex]->Get_Name()) { | ||
|  | 		gCurrentNodes[threadIndex] = gCurrentNodes[threadIndex]->Get_Sub_Node( name ); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	gCurrentNodes[threadIndex]->Call(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /***********************************************************************************************
 | ||
|  |  * CProfileManager::Stop_Profile -- Stop timing and record the results.                       * | ||
|  |  *=============================================================================================*/ | ||
|  | void	CProfileManager::Stop_Profile( void ) | ||
|  | { | ||
|  | 	int threadIndex = btQuickprofGetCurrentThreadIndex2(); | ||
|  | 	if ((threadIndex<0) || threadIndex >= BT_QUICKPROF_MAX_THREAD_COUNT) | ||
|  | 		return; | ||
|  | 
 | ||
|  | 	// Return will indicate whether we should back up to our parent (we may
 | ||
|  | 	// be profiling a recursive function)
 | ||
|  | 	if (gCurrentNodes[threadIndex]->Return()) { | ||
|  | 		gCurrentNodes[threadIndex] = gCurrentNodes[threadIndex]->Get_Parent(); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /***********************************************************************************************
 | ||
|  |  * CProfileManager::Reset -- Reset the contents of the profiling system                       * | ||
|  |  *                                                                                             * | ||
|  |  *    This resets everything except for the tree structure.  All of the timing data is reset.  * | ||
|  |  *=============================================================================================*/ | ||
|  | void	CProfileManager::Reset( void ) | ||
|  | { | ||
|  | 	gProfileClock.reset(); | ||
|  | 	int threadIndex = btQuickprofGetCurrentThreadIndex2(); | ||
|  | 	if ((threadIndex<0) || threadIndex >= BT_QUICKPROF_MAX_THREAD_COUNT) | ||
|  | 		return; | ||
|  | 	gRoots[threadIndex].Reset(); | ||
|  | 	gRoots[threadIndex].Call(); | ||
|  | 	FrameCounter = 0; | ||
|  | 	Profile_Get_Ticks(&ResetTime); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /***********************************************************************************************
 | ||
|  |  * CProfileManager::Increment_Frame_Counter -- Increment the frame counter                    * | ||
|  |  *=============================================================================================*/ | ||
|  | void CProfileManager::Increment_Frame_Counter( void ) | ||
|  | { | ||
|  | 	FrameCounter++; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /***********************************************************************************************
 | ||
|  |  * CProfileManager::Get_Time_Since_Reset -- returns the elapsed time since last reset         * | ||
|  |  *=============================================================================================*/ | ||
|  | float CProfileManager::Get_Time_Since_Reset( void ) | ||
|  | { | ||
|  | 	unsigned long int time; | ||
|  | 	Profile_Get_Ticks(&time); | ||
|  | 	time -= ResetTime; | ||
|  | 	return (float)time / Profile_Get_Tick_Rate(); | ||
|  | } | ||
|  | 
 | ||
|  | #include <stdio.h>
 | ||
|  | 
 | ||
|  | void	CProfileManager::dumpRecursive(CProfileIterator* profileIterator, int spacing) | ||
|  | { | ||
|  | 	profileIterator->First(); | ||
|  | 	if (profileIterator->Is_Done()) | ||
|  | 		return; | ||
|  | 
 | ||
|  | 	float accumulated_time=0,parent_time = profileIterator->Is_Root() ? CProfileManager::Get_Time_Since_Reset() : profileIterator->Get_Current_Parent_Total_Time(); | ||
|  | 	int i; | ||
|  | 	int frames_since_reset = CProfileManager::Get_Frame_Count_Since_Reset(); | ||
|  | 	for (i=0;i<spacing;i++)	printf("."); | ||
|  | 	printf("----------------------------------\n"); | ||
|  | 	for (i=0;i<spacing;i++)	printf("."); | ||
|  | 	printf("Profiling: %s (total running time: %.3f ms) ---\n",	profileIterator->Get_Current_Parent_Name(), parent_time ); | ||
|  | 	float totalTime = 0.f; | ||
|  | 
 | ||
|  | 
 | ||
|  | 	int numChildren = 0; | ||
|  | 
 | ||
|  | 	for (i = 0; !profileIterator->Is_Done(); i++,profileIterator->Next()) | ||
|  | 	{ | ||
|  | 		numChildren++; | ||
|  | 		float current_total_time = profileIterator->Get_Current_Total_Time(); | ||
|  | 		accumulated_time += current_total_time; | ||
|  | 		float fraction = parent_time > SIMD_EPSILON ? (current_total_time / parent_time) * 100 : 0.f; | ||
|  | 		{ | ||
|  | 			int i;	for (i=0;i<spacing;i++)	printf("."); | ||
|  | 		} | ||
|  | 		printf("%d -- %s (%.2f %%) :: %.3f ms / frame (%d calls)\n",i, profileIterator->Get_Current_Name(), fraction,(current_total_time / (double)frames_since_reset),profileIterator->Get_Current_Total_Calls()); | ||
|  | 		totalTime += current_total_time; | ||
|  | 		//recurse into children
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (parent_time < accumulated_time) | ||
|  | 	{ | ||
|  | 		//printf("what's wrong\n");
 | ||
|  | 	} | ||
|  | 	for (i=0;i<spacing;i++)	printf("."); | ||
|  | 	printf("%s (%.3f %%) :: %.3f ms\n", "Unaccounted:",parent_time > SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time); | ||
|  | 
 | ||
|  | 	for (i=0;i<numChildren;i++) | ||
|  | 	{ | ||
|  | 		profileIterator->Enter_Child(i); | ||
|  | 		dumpRecursive(profileIterator,spacing+3); | ||
|  | 		profileIterator->Enter_Parent(); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void	CProfileManager::dumpAll() | ||
|  | { | ||
|  | 	CProfileIterator* profileIterator = 0; | ||
|  | 	profileIterator = CProfileManager::Get_Iterator(); | ||
|  | 
 | ||
|  | 	dumpRecursive(profileIterator,0); | ||
|  | 
 | ||
|  | 	CProfileManager::Release_Iterator(profileIterator); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | unsigned int btQuickprofGetCurrentThreadIndex2() | ||
|  | { | ||
|  | #if BT_THREADSAFE
 | ||
|  |     return btGetCurrentThreadIndex(); | ||
|  | #else // #if BT_THREADSAFE
 | ||
|  | 	const unsigned int kNullIndex = ~0U; | ||
|  | #ifdef _WIN32
 | ||
|  |     #if defined(__MINGW32__) || defined(__MINGW64__)
 | ||
|  |         static __thread unsigned int sThreadIndex = kNullIndex; | ||
|  |     #else
 | ||
|  |         __declspec( thread ) static unsigned int sThreadIndex = kNullIndex; | ||
|  |     #endif
 | ||
|  | #else
 | ||
|  | #ifdef __APPLE__
 | ||
|  | 	#if TARGET_OS_IPHONE
 | ||
|  | 		unsigned int sThreadIndex = 0; | ||
|  | 		return -1; | ||
|  | 	#else
 | ||
|  | 		static __thread unsigned int sThreadIndex = kNullIndex; | ||
|  | 	#endif
 | ||
|  | #else//__APPLE__
 | ||
|  | #if __linux__
 | ||
|  | 	static __thread unsigned int sThreadIndex = kNullIndex; | ||
|  | #else
 | ||
|  | 	unsigned int sThreadIndex = 0; | ||
|  | 	return -1; | ||
|  | #endif
 | ||
|  | #endif//__APPLE__
 | ||
|  | 	 | ||
|  | #endif
 | ||
|  | 	static int gThreadCounter=0; | ||
|  | 
 | ||
|  | 	if ( sThreadIndex == kNullIndex ) | ||
|  | 	{ | ||
|  | 		sThreadIndex = gThreadCounter++; | ||
|  | 	} | ||
|  | 	return sThreadIndex; | ||
|  | #endif // #else // #if BT_THREADSAFE
 | ||
|  | } | ||
|  | 
 | ||
|  | void	btEnterProfileZoneDefault(const char* name) | ||
|  | { | ||
|  | 	CProfileManager::Start_Profile( name );  | ||
|  | } | ||
|  | void	btLeaveProfileZoneDefault() | ||
|  | { | ||
|  | 	CProfileManager::Stop_Profile();  | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | #else
 | ||
|  | void	btEnterProfileZoneDefault(const char* name) | ||
|  | { | ||
|  | } | ||
|  | void	btLeaveProfileZoneDefault() | ||
|  | { | ||
|  | } | ||
|  | #endif //BT_NO_PROFILE
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | static btEnterProfileZoneFunc* bts_enterFunc = btEnterProfileZoneDefault; | ||
|  | static btLeaveProfileZoneFunc* bts_leaveFunc = btLeaveProfileZoneDefault; | ||
|  | 
 | ||
|  | void btEnterProfileZone(const char* name) | ||
|  | { | ||
|  | 	(bts_enterFunc)(name); | ||
|  | } | ||
|  | void btLeaveProfileZone() | ||
|  | { | ||
|  | 	(bts_leaveFunc)(); | ||
|  | } | ||
|  | 
 | ||
|  | btEnterProfileZoneFunc* btGetCurrentEnterProfileZoneFunc() | ||
|  | { | ||
|  | 	return bts_enterFunc ; | ||
|  | } | ||
|  | btLeaveProfileZoneFunc* btGetCurrentLeaveProfileZoneFunc() | ||
|  | { | ||
|  | 	return bts_leaveFunc; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void btSetCustomEnterProfileZoneFunc(btEnterProfileZoneFunc* enterFunc) | ||
|  | { | ||
|  | 	bts_enterFunc = enterFunc; | ||
|  | } | ||
|  | void btSetCustomLeaveProfileZoneFunc(btLeaveProfileZoneFunc* leaveFunc) | ||
|  | { | ||
|  | 	bts_leaveFunc = leaveFunc; | ||
|  | } | ||
|  | 
 | ||
|  | CProfileSample::CProfileSample( const char * name ) | ||
|  | {  | ||
|  | 	btEnterProfileZone(name); | ||
|  | } | ||
|  | 
 | ||
|  | CProfileSample::~CProfileSample( void )					 | ||
|  | {  | ||
|  | 	btLeaveProfileZone(); | ||
|  | } | ||
|  | 
 |