Bullet Collision Detection & Physics Library
btQuickprof.cpp
Go to the documentation of this file.
1 /*
2 
3 ***************************************************************************************************
4 **
5 ** profile.cpp
6 **
7 ** Real-Time Hierarchical Profiling for Game Programming Gems 3
8 **
9 ** by Greg Hjelstrom & Byon Garrabrant
10 **
11 ***************************************************************************************************/
12 
13 // Credits: The Clock class was inspired by the Timer classes in
14 // Ogre (www.ogre3d.org).
15 
16 #include "btQuickprof.h"
17 
18 
19 
20 
21 #ifdef __CELLOS_LV2__
22 #include <sys/sys_time.h>
23 #include <sys/time_util.h>
24 #include <stdio.h>
25 #endif
26 
27 #if defined (SUNOS) || defined (__SUNOS__)
28 #include <stdio.h>
29 #endif
30 
31 #if defined(WIN32) || defined(_WIN32)
32 
33 #define BT_USE_WINDOWS_TIMERS
34 #define WIN32_LEAN_AND_MEAN
35 #define NOWINRES
36 #define NOMCX
37 #define NOIME
38 
39 #ifdef _XBOX
40  #include <Xtl.h>
41 #else //_XBOX
42  #include <windows.h>
43 
44 #if WINVER <0x0602
45 #define GetTickCount64 GetTickCount
46 #endif
47 
48 #endif //_XBOX
49 
50 #include <time.h>
51 
52 
53 #else //_WIN32
54 #include <sys/time.h>
55 #endif //_WIN32
56 
57 #define mymin(a,b) (a > b ? a : b)
58 
60 {
61 
62 #ifdef BT_USE_WINDOWS_TIMERS
63  LARGE_INTEGER mClockFrequency;
64  LONGLONG mStartTick;
65  LONGLONG mPrevElapsedTime;
66  LARGE_INTEGER mStartTime;
67 #else
68 #ifdef __CELLOS_LV2__
70 #else
71  struct timeval mStartTime;
72 #endif
73 #endif //__CELLOS_LV2__
74 
75 };
76 
79 {
80  m_data = new btClockData;
81 #ifdef BT_USE_WINDOWS_TIMERS
82  QueryPerformanceFrequency(&m_data->mClockFrequency);
83 #endif
84  reset();
85 }
86 
88 {
89  delete m_data;
90 }
91 
93 {
94  m_data = new btClockData;
95  *m_data = *other.m_data;
96 }
97 
99 {
100  *m_data = *other.m_data;
101  return *this;
102 }
103 
104 
107 {
108 #ifdef BT_USE_WINDOWS_TIMERS
109  QueryPerformanceCounter(&m_data->mStartTime);
110  m_data->mStartTick = GetTickCount64();
111  m_data->mPrevElapsedTime = 0;
112 #else
113 #ifdef __CELLOS_LV2__
114 
115  typedef uint64_t ClockSize;
116  ClockSize newTime;
117  //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
118  SYS_TIMEBASE_GET( newTime );
119  m_data->mStartTime = newTime;
120 #else
121  gettimeofday(&m_data->mStartTime, 0);
122 #endif
123 #endif
124 }
125 
128 unsigned long int btClock::getTimeMilliseconds()
129 {
130 #ifdef BT_USE_WINDOWS_TIMERS
131  LARGE_INTEGER currentTime;
132  QueryPerformanceCounter(&currentTime);
133  LONGLONG elapsedTime = currentTime.QuadPart -
134  m_data->mStartTime.QuadPart;
135  // Compute the number of millisecond ticks elapsed.
136  unsigned long msecTicks = (unsigned long)(1000 * elapsedTime /
137  m_data->mClockFrequency.QuadPart);
138  // Check for unexpected leaps in the Win32 performance counter.
139  // (This is caused by unexpected data across the PCI to ISA
140  // bridge, aka south bridge. See Microsoft KB274323.)
141  unsigned long elapsedTicks = (unsigned long)(GetTickCount64() - m_data->mStartTick);
142  signed long msecOff = (signed long)(msecTicks - elapsedTicks);
143  if (msecOff < -100 || msecOff > 100)
144  {
145  // Adjust the starting time forwards.
146  LONGLONG msecAdjustment = mymin(msecOff *
147  m_data->mClockFrequency.QuadPart / 1000, elapsedTime -
148  m_data->mPrevElapsedTime);
149  m_data->mStartTime.QuadPart += msecAdjustment;
150  elapsedTime -= msecAdjustment;
151 
152  // Recompute the number of millisecond ticks elapsed.
153  msecTicks = (unsigned long)(1000 * elapsedTime /
154  m_data->mClockFrequency.QuadPart);
155  }
156 
157  // Store the current elapsed time for adjustments next time.
158  m_data->mPrevElapsedTime = elapsedTime;
159 
160  return msecTicks;
161 #else
162 
163 #ifdef __CELLOS_LV2__
164  uint64_t freq=sys_time_get_timebase_frequency();
165  double dFreq=((double) freq) / 1000.0;
166  typedef uint64_t ClockSize;
167  ClockSize newTime;
168  SYS_TIMEBASE_GET( newTime );
169  //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
170 
171  return (unsigned long int)((double(newTime-m_data->mStartTime)) / dFreq);
172 #else
173 
174  struct timeval currentTime;
175  gettimeofday(&currentTime, 0);
176  return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000 +
177  (currentTime.tv_usec - m_data->mStartTime.tv_usec) / 1000;
178 #endif //__CELLOS_LV2__
179 #endif
180 }
181 
184 unsigned long int btClock::getTimeMicroseconds()
185 {
186 #ifdef BT_USE_WINDOWS_TIMERS
187  LARGE_INTEGER currentTime;
188  QueryPerformanceCounter(&currentTime);
189  LONGLONG elapsedTime = currentTime.QuadPart -
190  m_data->mStartTime.QuadPart;
191 
192  // Compute the number of millisecond ticks elapsed.
193  unsigned long msecTicks = (unsigned long)(1000 * elapsedTime /
194  m_data->mClockFrequency.QuadPart);
195 
196  // Check for unexpected leaps in the Win32 performance counter.
197  // (This is caused by unexpected data across the PCI to ISA
198  // bridge, aka south bridge. See Microsoft KB274323.)
199  unsigned long elapsedTicks = (unsigned long)(GetTickCount64() - m_data->mStartTick);
200  signed long msecOff = (signed long)(msecTicks - elapsedTicks);
201  if (msecOff < -100 || msecOff > 100)
202  {
203  // Adjust the starting time forwards.
204  LONGLONG msecAdjustment = mymin(msecOff *
205  m_data->mClockFrequency.QuadPart / 1000, elapsedTime -
206  m_data->mPrevElapsedTime);
207  m_data->mStartTime.QuadPart += msecAdjustment;
208  elapsedTime -= msecAdjustment;
209  }
210 
211  // Store the current elapsed time for adjustments next time.
212  m_data->mPrevElapsedTime = elapsedTime;
213 
214  // Convert to microseconds.
215  unsigned long usecTicks = (unsigned long)(1000000 * elapsedTime /
216  m_data->mClockFrequency.QuadPart);
217 
218  return usecTicks;
219 #else
220 
221 #ifdef __CELLOS_LV2__
222  uint64_t freq=sys_time_get_timebase_frequency();
223  double dFreq=((double) freq)/ 1000000.0;
224  typedef uint64_t ClockSize;
225  ClockSize newTime;
226  //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
227  SYS_TIMEBASE_GET( newTime );
228 
229  return (unsigned long int)((double(newTime-m_data->mStartTime)) / dFreq);
230 #else
231 
232  struct timeval currentTime;
233  gettimeofday(&currentTime, 0);
234  return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000000 +
235  (currentTime.tv_usec - m_data->mStartTime.tv_usec);
236 #endif//__CELLOS_LV2__
237 #endif
238 }
239 
240 
241 
245 {
246  static const btScalar microseconds_to_seconds = btScalar(0.000001);
247  return btScalar(getTimeMicroseconds()) * microseconds_to_seconds;
248 }
249 
250 #ifndef BT_NO_PROFILE
251 
252 
253 static btClock gProfileClock;
254 
255 
256 inline void Profile_Get_Ticks(unsigned long int * ticks)
257 {
258  *ticks = gProfileClock.getTimeMicroseconds();
259 }
260 
261 inline float Profile_Get_Tick_Rate(void)
262 {
263 // return 1000000.f;
264  return 1000.f;
265 
266 }
267 
268 
269 /***************************************************************************************************
270 **
271 ** CProfileNode
272 **
273 ***************************************************************************************************/
274 
275 /***********************************************************************************************
276  * INPUT: *
277  * name - pointer to a static string which is the name of this profile node *
278  * parent - parent pointer *
279  * *
280  * WARNINGS: *
281  * The name is assumed to be a static pointer, only the pointer is stored and compared for *
282  * efficiency reasons. *
283  *=============================================================================================*/
284 CProfileNode::CProfileNode( const char * name, CProfileNode * parent ) :
285  Name( name ),
286  TotalCalls( 0 ),
287  TotalTime( 0 ),
288  StartTime( 0 ),
289  RecursionCounter( 0 ),
290  Parent( parent ),
291  Child( NULL ),
292  Sibling( NULL ),
293  m_userPtr(0)
294 {
295  Reset();
296 }
297 
298 
299 void CProfileNode::CleanupMemory()
300 {
301  delete ( Child);
302  Child = NULL;
303  delete ( Sibling);
304  Sibling = NULL;
305 }
306 
307 CProfileNode::~CProfileNode( void )
308 {
309  CleanupMemory();
310 }
311 
312 
313 /***********************************************************************************************
314  * INPUT: *
315  * name - static string pointer to the name of the node we are searching for *
316  * *
317  * WARNINGS: *
318  * All profile names are assumed to be static strings so this function uses pointer compares *
319  * to find the named node. *
320  *=============================================================================================*/
321 CProfileNode * CProfileNode::Get_Sub_Node( const char * name )
322 {
323  // Try to find this sub node
324  CProfileNode * child = Child;
325  while ( child ) {
326  if ( child->Name == name ) {
327  return child;
328  }
329  child = child->Sibling;
330  }
331 
332  // We didn't find it, so add it
333 
334  CProfileNode * node = new CProfileNode( name, this );
335  node->Sibling = Child;
336  Child = node;
337  return node;
338 }
339 
340 
341 void CProfileNode::Reset( void )
342 {
343  TotalCalls = 0;
344  TotalTime = 0.0f;
345 
346 
347  if ( Child ) {
348  Child->Reset();
349  }
350  if ( Sibling ) {
351  Sibling->Reset();
352  }
353 }
354 
355 
356 void CProfileNode::Call( void )
357 {
358  TotalCalls++;
359  if (RecursionCounter++ == 0) {
360  Profile_Get_Ticks(&StartTime);
361  }
362 }
363 
364 
365 bool CProfileNode::Return( void )
366 {
367  if ( --RecursionCounter == 0 && TotalCalls != 0 ) {
368  unsigned long int time;
369  Profile_Get_Ticks(&time);
370  time-=StartTime;
371  TotalTime += (float)time / Profile_Get_Tick_Rate();
372  }
373  return ( RecursionCounter == 0 );
374 }
375 
376 
377 /***************************************************************************************************
378 **
379 ** CProfileIterator
380 **
381 ***************************************************************************************************/
382 CProfileIterator::CProfileIterator( CProfileNode * start )
383 {
384  CurrentParent = start;
385  CurrentChild = CurrentParent->Get_Child();
386 }
387 
388 
389 void CProfileIterator::First(void)
390 {
391  CurrentChild = CurrentParent->Get_Child();
392 }
393 
394 
395 void CProfileIterator::Next(void)
396 {
397  CurrentChild = CurrentChild->Get_Sibling();
398 }
399 
400 
401 bool CProfileIterator::Is_Done(void)
402 {
403  return CurrentChild == NULL;
404 }
405 
406 
407 void CProfileIterator::Enter_Child( int index )
408 {
409  CurrentChild = CurrentParent->Get_Child();
410  while ( (CurrentChild != NULL) && (index != 0) ) {
411  index--;
412  CurrentChild = CurrentChild->Get_Sibling();
413  }
414 
415  if ( CurrentChild != NULL ) {
416  CurrentParent = CurrentChild;
417  CurrentChild = CurrentParent->Get_Child();
418  }
419 }
420 
421 
422 void CProfileIterator::Enter_Parent( void )
423 {
424  if ( CurrentParent->Get_Parent() != NULL ) {
425  CurrentParent = CurrentParent->Get_Parent();
426  }
427  CurrentChild = CurrentParent->Get_Child();
428 }
429 
430 
431 /***************************************************************************************************
432 **
433 ** CProfileManager
434 **
435 ***************************************************************************************************/
436 
437 CProfileNode CProfileManager::Root( "Root", NULL );
438 CProfileNode * CProfileManager::CurrentNode = &CProfileManager::Root;
439 int CProfileManager::FrameCounter = 0;
440 unsigned long int CProfileManager::ResetTime = 0;
441 
442 
443 /***********************************************************************************************
444  * CProfileManager::Start_Profile -- Begin a named profile *
445  * *
446  * Steps one level deeper into the tree, if a child already exists with the specified name *
447  * then it accumulates the profiling; otherwise a new child node is added to the profile tree. *
448  * *
449  * INPUT: *
450  * name - name of this profiling record *
451  * *
452  * WARNINGS: *
453  * The string used is assumed to be a static string; pointer compares are used throughout *
454  * the profiling code for efficiency. *
455  *=============================================================================================*/
456 void CProfileManager::Start_Profile( const char * name )
457 {
458  if (name != CurrentNode->Get_Name()) {
459  CurrentNode = CurrentNode->Get_Sub_Node( name );
460  }
461 
462  CurrentNode->Call();
463 }
464 
465 
466 /***********************************************************************************************
467  * CProfileManager::Stop_Profile -- Stop timing and record the results. *
468  *=============================================================================================*/
469 void CProfileManager::Stop_Profile( void )
470 {
471  // Return will indicate whether we should back up to our parent (we may
472  // be profiling a recursive function)
473  if (CurrentNode->Return()) {
474  CurrentNode = CurrentNode->Get_Parent();
475  }
476 }
477 
478 
479 /***********************************************************************************************
480  * CProfileManager::Reset -- Reset the contents of the profiling system *
481  * *
482  * This resets everything except for the tree structure. All of the timing data is reset. *
483  *=============================================================================================*/
484 void CProfileManager::Reset( void )
485 {
486  gProfileClock.reset();
487  Root.Reset();
488  Root.Call();
489  FrameCounter = 0;
490  Profile_Get_Ticks(&ResetTime);
491 }
492 
493 
494 /***********************************************************************************************
495  * CProfileManager::Increment_Frame_Counter -- Increment the frame counter *
496  *=============================================================================================*/
497 void CProfileManager::Increment_Frame_Counter( void )
498 {
499  FrameCounter++;
500 }
501 
502 
503 /***********************************************************************************************
504  * CProfileManager::Get_Time_Since_Reset -- returns the elapsed time since last reset *
505  *=============================================================================================*/
506 float CProfileManager::Get_Time_Since_Reset( void )
507 {
508  unsigned long int time;
509  Profile_Get_Ticks(&time);
510  time -= ResetTime;
511  return (float)time / Profile_Get_Tick_Rate();
512 }
513 
514 #include <stdio.h>
515 
516 void CProfileManager::dumpRecursive(CProfileIterator* profileIterator, int spacing)
517 {
518  profileIterator->First();
519  if (profileIterator->Is_Done())
520  return;
521 
522  float accumulated_time=0,parent_time = profileIterator->Is_Root() ? CProfileManager::Get_Time_Since_Reset() : profileIterator->Get_Current_Parent_Total_Time();
523  int i;
524  int frames_since_reset = CProfileManager::Get_Frame_Count_Since_Reset();
525  for (i=0;i<spacing;i++) printf(".");
526  printf("----------------------------------\n");
527  for (i=0;i<spacing;i++) printf(".");
528  printf("Profiling: %s (total running time: %.3f ms) ---\n", profileIterator->Get_Current_Parent_Name(), parent_time );
529  float totalTime = 0.f;
530 
531 
532  int numChildren = 0;
533 
534  for (i = 0; !profileIterator->Is_Done(); i++,profileIterator->Next())
535  {
536  numChildren++;
537  float current_total_time = profileIterator->Get_Current_Total_Time();
538  accumulated_time += current_total_time;
539  float fraction = parent_time > SIMD_EPSILON ? (current_total_time / parent_time) * 100 : 0.f;
540  {
541  int i; for (i=0;i<spacing;i++) printf(".");
542  }
543  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());
544  totalTime += current_total_time;
545  //recurse into children
546  }
547 
548  if (parent_time < accumulated_time)
549  {
550  //printf("what's wrong\n");
551  }
552  for (i=0;i<spacing;i++) printf(".");
553  printf("%s (%.3f %%) :: %.3f ms\n", "Unaccounted:",parent_time > SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time);
554 
555  for (i=0;i<numChildren;i++)
556  {
557  profileIterator->Enter_Child(i);
558  dumpRecursive(profileIterator,spacing+3);
559  profileIterator->Enter_Parent();
560  }
561 }
562 
563 
564 
565 void CProfileManager::dumpAll()
566 {
567  CProfileIterator* profileIterator = 0;
568  profileIterator = CProfileManager::Get_Iterator();
569 
570  dumpRecursive(profileIterator,0);
571 
572  CProfileManager::Release_Iterator(profileIterator);
573 }
574 
575 
576 
577 
578 #endif //BT_NO_PROFILE
#define SIMD_EPSILON
Definition: btScalar.h:495
unsigned long long int uint64_t
btScalar getTimeSeconds()
Returns the time in s since the last call to reset or since the Clock was created.
LONGLONG mPrevElapsedTime
Definition: btQuickprof.cpp:65
unsigned long int getTimeMicroseconds()
Returns the time in us since the last call to reset or since the Clock was created.
The btClock is a portable basic clock that measures accurate time in seconds, use for profiling...
Definition: btQuickprof.h:24
LARGE_INTEGER mStartTime
Definition: btQuickprof.cpp:66
void reset()
Resets the initial reference time.
unsigned long int getTimeMilliseconds()
Returns the time in ms since the last call to reset or since the btClock was created.
btClock()
The btClock is a portable basic clock that measures accurate time in seconds, use for profiling...
Definition: btQuickprof.cpp:78
struct btClockData * m_data
Definition: btQuickprof.h:50
#define mymin(a, b)
Definition: btQuickprof.cpp:57
btClock & operator=(const btClock &other)
Definition: btQuickprof.cpp:98
#define GetTickCount64
Definition: btQuickprof.cpp:45
LARGE_INTEGER mClockFrequency
Definition: btQuickprof.cpp:63
LONGLONG mStartTick
Definition: btQuickprof.cpp:64
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:279