3 /***************************************************************************************************
7 ** Real-Time Hierarchical Profiling for Game Programming Gems 3
9 ** by Greg Hjelstrom & Byon Garrabrant
11 ***************************************************************************************************/
13 // Credits: The Clock class was inspired by the Timer classes in
14 // Ogre (www.ogre3d.org).
16 #include "LinearMath/btQuickprof.h"
21 static btClock gProfileClock;
23 inline void Profile_Get_Ticks(unsigned long int * ticks)
25 *ticks = gProfileClock.getTimeMicroseconds();
28 inline float Profile_Get_Tick_Rate(void)
37 /***************************************************************************************************
41 ***************************************************************************************************/
43 /***********************************************************************************************
45 * name - pointer to a static string which is the name of this profile node *
46 * parent - parent pointer *
49 * The name is assumed to be a static pointer, only the pointer is stored and compared for *
50 * efficiency reasons. *
51 *=============================================================================================*/
52 CProfileNode::CProfileNode( const char * name, CProfileNode * parent ) :
57 RecursionCounter( 0 ),
66 void CProfileNode::CleanupMemory()
74 CProfileNode::~CProfileNode( void )
81 /***********************************************************************************************
83 * name - static string pointer to the name of the node we are searching for *
86 * All profile names are assumed to be static strings so this function uses pointer compares *
87 * to find the named node. *
88 *=============================================================================================*/
89 CProfileNode * CProfileNode::Get_Sub_Node( const char * name )
91 // Try to find this sub node
92 CProfileNode * child = Child;
94 if ( child->Name == name ) {
97 child = child->Sibling;
100 // We didn't find it, so add it
102 CProfileNode * node = new CProfileNode( name, this );
103 node->Sibling = Child;
109 void CProfileNode::Reset( void )
124 void CProfileNode::Call( void )
127 if (RecursionCounter++ == 0) {
128 Profile_Get_Ticks(&StartTime);
133 bool CProfileNode::Return( void )
135 if ( --RecursionCounter == 0 && TotalCalls != 0 ) {
136 unsigned long int time;
137 Profile_Get_Ticks(&time);
139 TotalTime += (float)time / Profile_Get_Tick_Rate();
141 return ( RecursionCounter == 0 );
145 /***************************************************************************************************
149 ***************************************************************************************************/
150 CProfileIterator::CProfileIterator( CProfileNode * start )
152 CurrentParent = start;
153 CurrentChild = CurrentParent->Get_Child();
157 void CProfileIterator::First(void)
159 CurrentChild = CurrentParent->Get_Child();
163 void CProfileIterator::Next(void)
165 CurrentChild = CurrentChild->Get_Sibling();
169 bool CProfileIterator::Is_Done(void)
171 return CurrentChild == NULL;
175 void CProfileIterator::Enter_Child( int index )
177 CurrentChild = CurrentParent->Get_Child();
178 while ( (CurrentChild != NULL) && (index != 0) ) {
180 CurrentChild = CurrentChild->Get_Sibling();
183 if ( CurrentChild != NULL ) {
184 CurrentParent = CurrentChild;
185 CurrentChild = CurrentParent->Get_Child();
190 void CProfileIterator::Enter_Parent( void )
192 if ( CurrentParent->Get_Parent() != NULL ) {
193 CurrentParent = CurrentParent->Get_Parent();
195 CurrentChild = CurrentParent->Get_Child();
199 /***************************************************************************************************
203 ***************************************************************************************************/
205 CProfileNode CProfileManager::Root( "Root", NULL );
206 CProfileNode * CProfileManager::CurrentNode = &CProfileManager::Root;
207 int CProfileManager::FrameCounter = 0;
208 unsigned long int CProfileManager::ResetTime = 0;
211 /***********************************************************************************************
212 * CProfileManager::Start_Profile -- Begin a named profile *
214 * Steps one level deeper into the tree, if a child already exists with the specified name *
215 * then it accumulates the profiling; otherwise a new child node is added to the profile tree. *
218 * name - name of this profiling record *
221 * The string used is assumed to be a static string; pointer compares are used throughout *
222 * the profiling code for efficiency. *
223 *=============================================================================================*/
224 void CProfileManager::Start_Profile( const char * name )
226 if (name != CurrentNode->Get_Name()) {
227 CurrentNode = CurrentNode->Get_Sub_Node( name );
234 /***********************************************************************************************
235 * CProfileManager::Stop_Profile -- Stop timing and record the results. *
236 *=============================================================================================*/
237 void CProfileManager::Stop_Profile( void )
239 // Return will indicate whether we should back up to our parent (we may
240 // be profiling a recursive function)
241 if (CurrentNode->Return()) {
242 CurrentNode = CurrentNode->Get_Parent();
247 /***********************************************************************************************
248 * CProfileManager::Reset -- Reset the contents of the profiling system *
250 * This resets everything except for the tree structure. All of the timing data is reset. *
251 *=============================================================================================*/
252 void CProfileManager::Reset( void )
254 gProfileClock.reset();
258 Profile_Get_Ticks(&ResetTime);
262 /***********************************************************************************************
263 * CProfileManager::Increment_Frame_Counter -- Increment the frame counter *
264 *=============================================================================================*/
265 void CProfileManager::Increment_Frame_Counter( void )
271 /***********************************************************************************************
272 * CProfileManager::Get_Time_Since_Reset -- returns the elapsed time since last reset *
273 *=============================================================================================*/
274 float CProfileManager::Get_Time_Since_Reset( void )
276 unsigned long int time;
277 Profile_Get_Ticks(&time);
279 return (float)time / Profile_Get_Tick_Rate();
284 void CProfileManager::dumpRecursive(CProfileIterator* profileIterator, int spacing)
286 profileIterator->First();
287 if (profileIterator->Is_Done())
290 float accumulated_time=0,parent_time = profileIterator->Is_Root() ? CProfileManager::Get_Time_Since_Reset() : profileIterator->Get_Current_Parent_Total_Time();
292 int frames_since_reset = CProfileManager::Get_Frame_Count_Since_Reset();
293 for (i=0;i<spacing;i++) printf(".");
294 printf("----------------------------------\n");
295 for (i=0;i<spacing;i++) printf(".");
296 printf("Profiling: %s (total running time: %.3f ms) ---\n", profileIterator->Get_Current_Parent_Name(), parent_time );
297 float totalTime = 0.f;
302 for (i = 0; !profileIterator->Is_Done(); i++,profileIterator->Next())
305 float current_total_time = profileIterator->Get_Current_Total_Time();
306 accumulated_time += current_total_time;
307 float fraction = parent_time > SIMD_EPSILON ? (current_total_time / parent_time) * 100 : 0.f;
309 int i; for (i=0;i<spacing;i++) printf(".");
311 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());
312 totalTime += current_total_time;
313 //recurse into children
316 if (parent_time < accumulated_time)
318 printf("what's wrong\n");
320 for (i=0;i<spacing;i++) printf(".");
321 printf("%s (%.3f %%) :: %.3f ms\n", "Unaccounted:",parent_time > SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time);
323 for (i=0;i<numChildren;i++)
325 profileIterator->Enter_Child(i);
326 dumpRecursive(profileIterator,spacing+3);
327 profileIterator->Enter_Parent();
333 void CProfileManager::dumpAll()
335 CProfileIterator* profileIterator = 0;
336 profileIterator = CProfileManager::Get_Iterator();
338 dumpRecursive(profileIterator,0);
340 CProfileManager::Release_Iterator(profileIterator);
345 #endif //USE_BT_CLOCK