www.pudn.com > imageFeatures_Ver3_0_source.zip > profile.cpp


/*************************************************************************************************** 
** 
** profile.cpp 
** 
** Real-Time Hierarchical Profiling for Game Programming Gems 3 
** 
** by Greg Hjelstrom & Byon Garrabrant 
** 
***************************************************************************************************/ 
 
#include "stdafx.h" 
#include  
#include  
 
#include "profile.h"

inline void Profile_Get_Ticks(_int64 * ticks)
{
	__asm
	{
		push edx;
		push ecx;
		mov ecx,ticks;
		_emit 0Fh
		_emit 31h
		mov [ecx],eax;
		mov [ecx+4],edx;
		pop ecx;
		pop edx;
	}
}

inline float Profile_Get_Tick_Rate(void)
{
	static float _CPUFrequency = -1.0f;
	
	if (_CPUFrequency == -1.0f) {
		__int64 curr_rate = 0;
		::QueryPerformanceFrequency ((LARGE_INTEGER *)&curr_rate);
		_CPUFrequency = (float)curr_rate;
	} 
	
	return _CPUFrequency;
}

/*************************************************************************************************** 
** 
** 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 )
{ 
	Reset();
}


CProfileNode::~CProfileNode( void )
{
	delete Child;
	delete Sibling;
}


/***********************************************************************************************
 * 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 ) {  
		__int64 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(); 
	} 
} 
 
// Changed from void to bool    6/02/03  TCF 
bool	CProfileIterator::Enter_Parent( void ) 
{ 
	bool moved = false; 
	if ( CurrentParent->Get_Parent() != NULL ) { 
		CurrentParent = CurrentParent->Get_Parent(); 
		moved = true; 
	} 
	CurrentChild = CurrentParent->Get_Child(); 
	return moved; 
} 
 
 
/***************************************************************************************************
**
** CProfileManager
** 
***************************************************************************************************/ 

CProfileNode	CProfileManager::Root( "Root", NULL );
CProfileNode *	CProfileManager::CurrentNode = &CProfileManager::Root;
int				CProfileManager::FrameCounter = 0;
__int64			CProfileManager::ResetTime = 0;
 

/***********************************************************************************************
 * 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 )
{
	if (name != CurrentNode->Get_Name()) {
		CurrentNode = CurrentNode->Get_Sub_Node( name );
	} 
	
	CurrentNode->Call();
}


/***********************************************************************************************
 * CProfileManager::Stop_Profile -- Stop timing and record the results.                       *
 *=============================================================================================*/
void	CProfileManager::Stop_Profile( void )
{
	// Return will indicate whether we should back up to our parent (we may
	// be profiling a recursive function)
	if (CurrentNode->Return()) {
		CurrentNode = CurrentNode->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 )
{ 
	Root.Reset(); 
	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 )
{
	__int64 time;
	Profile_Get_Ticks(&time);
	time -= ResetTime;
	return (float)time / Profile_Get_Tick_Rate();
}
 
/*********************************************************************************************** 
 * CProfileManager::Write -- write the results to a file                                       * 
 *                  Tyler C. Folsom   6/02/03                                                  * 
 *=============================================================================================*/ 
void CProfileManager::Write( void ) 
{ 
	float time = Get_Time_Since_Reset(); 
	ofstream proFile( "Profile.txt", ios::out ); 
	CProfileIterator *iter = Get_Iterator(); 
 
	proFile << "Elapsed time: " << time << endl; 
	time = iter->Get_Current_Parent_Total_Time(); 
	proFile << iter->Get_Current_Parent_Total_Calls() << '\t' 
			<< time  << '\t' 
			<< iter->Get_Current_Parent_Name()        << endl; 
	proFile.close(); 
 
	Search( *iter ); 
 
 
	Release_Iterator( iter ); 
	proFile.close(); 
 
} 

/*********************************************************************************************** 
 * CProfileManager::Search -- recursive search of a node.                                       * 
 *                  Tyler C. Folsom   6/02/03                                                  * 
 *=============================================================================================*/ 
void CProfileManager::Search( CProfileIterator iter) 
{ 
	ofstream proFile( "Profile.txt", ios::app ); 
	proFile << iter.Get_Current_Parent_Total_Calls() << '\t' 
			<< iter.Get_Current_Parent_Total_Time()  << '\t' 
			<< iter.Get_Current_Parent_Name()        << endl; 
 
	if (iter.Is_Done())   
	{   // no children 
		proFile.close(); 
		return; 
	} 
	proFile << iter.Get_Current_Total_Calls() << '\t' 
			<< iter.Get_Current_Total_Time()  << '\t' 
			<< iter.Get_Current_Name()        << '\t' 
			<< iter.Get_Current_Parent_Name() << '\t'; 
	if( iter.Get_Current_Parent_Total_Time() > 0) 
		proFile	<< iter.Get_Current_Total_Time() / iter.Get_Current_Parent_Total_Time(); 
	proFile << endl; 
	proFile.close(); 
	int i = 0; 
	for( ; !iter.Is_Done(); iter.Next() ) 
	{	// siblings 
		iter.Enter_Child(i++); 
		Search( iter ); 
		iter.Enter_Parent(); 
	} 
//	iter.Enter_Parent(); 
 
}