Bullet Collision Detection & Physics Library: btQuickprof.cpp Source File

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
59 struct btClockData
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__
69 uint64_t mStartTime;
70 #else
71 struct timeval mStartTime;
72 #endif
73 #endif //__CELLOS_LV2__
74
75 };
76
78 btClock::btClock()
79 {
80 m_data = new btClockData;
81 #ifdef BT_USE_WINDOWS_TIMERS
82 QueryPerformanceFrequency(&m_data->mClockFrequency);
83 #endif
84 reset();
85 }
86
87 btClock::~btClock()
88 {
89 delete m_data;
90 }
91
92 btClock::btClock(const btClock& other)
93 {
94 m_data = new btClockData;
95 *m_data = *other.m_data;
96 }
97
98 btClock& btClock::operator=(const btClock& other)
99 {
100 *m_data = *other.m_data;
101 return *this;
102 }
103
104
106 void btClock::reset()
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
244 btScalar btClock::getTimeSeconds()
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
SIMD_EPSILON
#define SIMD_EPSILON
Definition: btScalar.h:495
uint64_t
unsigned long long int uint64_t
Definition: btConvexHullComputer.cpp:33
btClock::getTimeSeconds
btScalar getTimeSeconds()
Returns the time in s since the last call to reset or since the Clock was created.
Definition: btQuickprof.cpp:244
btClockData::mPrevElapsedTime
LONGLONG mPrevElapsedTime
Definition: btQuickprof.cpp:65
btClock::getTimeMicroseconds
unsigned long int getTimeMicroseconds()
Returns the time in us since the last call to reset or since the Clock was created.
Definition: btQuickprof.cpp:184
btClock
The btClock is a portable basic clock that measures accurate time in seconds, use for profiling...
Definition: btQuickprof.h:24
btClockData::mStartTime
LARGE_INTEGER mStartTime
Definition: btQuickprof.cpp:66
btClock::reset
void reset()
Resets the initial reference time.
Definition: btQuickprof.cpp:106
btClock::getTimeMilliseconds
unsigned long int getTimeMilliseconds()
Returns the time in ms since the last call to reset or since the btClock was created.
Definition: btQuickprof.cpp:128
btClock::btClock
btClock()
The btClock is a portable basic clock that measures accurate time in seconds, use for profiling...
Definition: btQuickprof.cpp:78
btClock::m_data
struct btClockData * m_data
Definition: btQuickprof.h:50
btClock::~btClock
~btClock()
Definition: btQuickprof.cpp:87
mymin
#define mymin(a, b)
Definition: btQuickprof.cpp:57
btClock::operator=
btClock & operator=(const btClock &other)
Definition: btQuickprof.cpp:98
btQuickprof.h
btClockData
Definition: btQuickprof.cpp:59
GetTickCount64
#define GetTickCount64
Definition: btQuickprof.cpp:45
btClockData::mClockFrequency
LARGE_INTEGER mClockFrequency
Definition: btQuickprof.cpp:63
btClockData::mStartTick
LONGLONG mStartTick
Definition: btQuickprof.cpp:64
btScalar
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition: btScalar.h:279