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#include "btThreads.h"
18
19
20
21
22#ifdef __CELLOS_LV2__
23#include <sys/sys_time.h>
24#include <sys/time_util.h>
25#include <stdio.h>
26#endif
27
28#if defined (SUNOS) || defined (__SUNOS__)
29#include <stdio.h>
30#endif
31#ifdef __APPLE__
32#include <mach/mach_time.h>
33#include <TargetConditionals.h>
34#endif
35
36#if defined(WIN32) || defined(_WIN32)
37
38#define BT_USE_WINDOWS_TIMERS
39#define WIN32_LEAN_AND_MEAN
40#define NOWINRES
41#define NOMCX
42#define NOIME
43
44#ifdef _XBOX
45 #include <Xtl.h>
46#else //_XBOX
47 #include <windows.h>
48
49#if WINVER <0x0602
50#define GetTickCount64 GetTickCount
51#endif
52
53#endif //_XBOX
54
55#include <time.h>
56
57
58#else //_WIN32
59#include <sys/time.h>
60
61#ifdef BT_LINUX_REALTIME
62//required linking against rt (librt)
63#include <time.h>
64#endif //BT_LINUX_REALTIME
65
66#endif //_WIN32
67
68#define mymin(a,b) (a > b ? a : b)
69
71{
72
73#ifdef BT_USE_WINDOWS_TIMERS
77#else
78#ifdef __CELLOS_LV2__
80#else
81#ifdef __APPLE__
83#endif
84 struct timeval mStartTime;
85#endif
86#endif //__CELLOS_LV2__
87
88};
89
92{
93 m_data = new btClockData;
94#ifdef BT_USE_WINDOWS_TIMERS
96#endif
97 reset();
98}
99
101{
102 delete m_data;
103}
104
106{
107 m_data = new btClockData;
108 *m_data = *other.m_data;
109}
110
112{
113 *m_data = *other.m_data;
114 return *this;
115}
116
117
120{
121#ifdef BT_USE_WINDOWS_TIMERS
124#else
125#ifdef __CELLOS_LV2__
126
127 typedef uint64_t ClockSize;
129 //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
132#else
133#ifdef __APPLE__
134 m_data->mStartTimeNano = mach_absolute_time();
135#endif
137#endif
138#endif
139}
140
143unsigned long long int btClock::getTimeMilliseconds()
144{
145#ifdef BT_USE_WINDOWS_TIMERS
148 LONGLONG elapsedTime = currentTime.QuadPart -
149 m_data->mStartTime.QuadPart;
150 // Compute the number of millisecond ticks elapsed.
151 unsigned long msecTicks = (unsigned long)(1000 * elapsedTime /
152 m_data->mClockFrequency.QuadPart);
153
154 return msecTicks;
155#else
156
157#ifdef __CELLOS_LV2__
159 double dFreq=((double) freq) / 1000.0;
160 typedef uint64_t ClockSize;
163 //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
164
165 return (unsigned long int)((double(newTime-m_data->mStartTime)) / dFreq);
166#else
167
168 struct timeval currentTime;
170 return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000 +
171 (currentTime.tv_usec - m_data->mStartTime.tv_usec) / 1000;
172#endif //__CELLOS_LV2__
173#endif
174}
175
178unsigned long long int btClock::getTimeMicroseconds()
179{
180#ifdef BT_USE_WINDOWS_TIMERS
181 //see https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
183
185 elapsedTime.QuadPart = currentTime.QuadPart -
186 m_data->mStartTime.QuadPart;
187 elapsedTime.QuadPart *= 1000000;
188 elapsedTime.QuadPart /= m_data->mClockFrequency.QuadPart;
189
190 return (unsigned long long) elapsedTime.QuadPart;
191#else
192
193#ifdef __CELLOS_LV2__
195 double dFreq=((double) freq)/ 1000000.0;
196 typedef uint64_t ClockSize;
198 //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
200
201 return (unsigned long int)((double(newTime-m_data->mStartTime)) / dFreq);
202#else
203
204 struct timeval currentTime;
206 return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000000 +
207 (currentTime.tv_usec - m_data->mStartTime.tv_usec);
208#endif//__CELLOS_LV2__
209#endif
210}
211
212unsigned long long int btClock::getTimeNanoseconds()
213{
214#ifdef BT_USE_WINDOWS_TIMERS
215 //see https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
217
219 elapsedTime.QuadPart = currentTime.QuadPart -
220 m_data->mStartTime.QuadPart;
221 elapsedTime.QuadPart *= 1000000000;
222 elapsedTime.QuadPart /= m_data->mClockFrequency.QuadPart;
223
224 return (unsigned long long) elapsedTime.QuadPart;
225#else
226
227#ifdef __CELLOS_LV2__
229 double dFreq=((double) freq)/ 1e9;
230 typedef uint64_t ClockSize;
232 //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
234
235 return (unsigned long int)((double(newTime-m_data->mStartTime)) / dFreq);
236#else
237#ifdef __APPLE__
238 uint64_t ticks = mach_absolute_time() - m_data->mStartTimeNano;
239 static long double conversion = 0.0L;
240 if( 0.0L == conversion )
241 {
242 // attempt to get conversion to nanoseconds
244 int err = mach_timebase_info( &info );
245 if( err )
246 {
247 btAssert(0);
248 conversion = 1.;
249 }
250 conversion = info.numer / info.denom;
251 }
252 return (ticks * conversion);
253
254
255#else//__APPLE__
256
257#ifdef BT_LINUX_REALTIME
258 timespec ts;
260 return 1000000000*ts.tv_sec + ts.tv_nsec;
261#else
262 struct timeval currentTime;
264 return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1e9 +
265 (currentTime.tv_usec - m_data->mStartTime.tv_usec)*1000;
266#endif //BT_LINUX_REALTIME
267
268#endif//__APPLE__
269#endif//__CELLOS_LV2__
270#endif
271}
272
273
277{
278 static const btScalar microseconds_to_seconds = btScalar(0.000001);
280}
281
282#ifndef BT_NO_PROFILE
283
284
286
287
288inline void Profile_Get_Ticks(unsigned long int * ticks)
289{
290 *ticks = (unsigned long int)gProfileClock.getTimeMicroseconds();
291}
292
293inline float Profile_Get_Tick_Rate(void)
294{
295// return 1000000.f;
296 return 1000.f;
297
298}
299
300
301/***************************************************************************************************
302**
303** CProfileNode
304**
305***************************************************************************************************/
306
307/***********************************************************************************************
308 * INPUT: *
309 * name - pointer to a static string which is the name of this profile node *
310 * parent - parent pointer *
311 * *
312 * WARNINGS: *
313 * The name is assumed to be a static pointer, only the pointer is stored and compared for *
314 * efficiency reasons. *
315 *=============================================================================================*/
317 Name( name ),
318 TotalCalls( 0 ),
319 TotalTime( 0 ),
320 StartTime( 0 ),
321 RecursionCounter( 0 ),
322 Parent( parent ),
323 Child( NULL ),
324 Sibling( NULL ),
325 m_userPtr(0)
326{
327 Reset();
328}
329
330
332{
333 delete ( Child);
334 Child = NULL;
335 delete ( Sibling);
336 Sibling = NULL;
337}
338
340{
342}
343
344
345/***********************************************************************************************
346 * INPUT: *
347 * name - static string pointer to the name of the node we are searching for *
348 * *
349 * WARNINGS: *
350 * All profile names are assumed to be static strings so this function uses pointer compares *
351 * to find the named node. *
352 *=============================================================================================*/
354{
355 // Try to find this sub node
357 while ( child ) {
358 if ( child->Name == name ) {
359 return child;
360 }
362 }
363
364 // We didn't find it, so add it
365
366 CProfileNode * node = new CProfileNode( name, this );
367 node->Sibling = Child;
368 Child = node;
369 return node;
370}
371
372
374{
375 TotalCalls = 0;
376 TotalTime = 0.0f;
377
378
379 if ( Child ) {
380 Child->Reset();
381 }
382 if ( Sibling ) {
383 Sibling->Reset();
384 }
385}
386
387
389{
390 TotalCalls++;
391 if (RecursionCounter++ == 0) {
393 }
394}
395
396
398{
399 if ( --RecursionCounter == 0 && TotalCalls != 0 ) {
400 unsigned long int time;
402
405 }
406 return ( RecursionCounter == 0 );
407}
408
409
410/***************************************************************************************************
411**
412** CProfileIterator
413**
414***************************************************************************************************/
416{
419}
420
421
423{
425}
426
427
429{
431}
432
433
435{
436 return CurrentChild == NULL;
437}
438
439
441{
443 while ( (CurrentChild != NULL) && (index != 0) ) {
444 index--;
446 }
447
448 if ( CurrentChild != NULL ) {
451 }
452}
453
454
456{
457 if ( CurrentParent->Get_Parent() != NULL ) {
459 }
461}
462
463
464/***************************************************************************************************
465**
466** CProfileManager
467**
468***************************************************************************************************/
469
470
471
472
474 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
475 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
476 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
477 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
478 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
479 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
480 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
481 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
482 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
483 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
484 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
485 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
486 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
487 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
488 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),
489 CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL)
490};
491
492
494{
495 &gRoots[ 0], &gRoots[ 1], &gRoots[ 2], &gRoots[ 3],
496 &gRoots[ 4], &gRoots[ 5], &gRoots[ 6], &gRoots[ 7],
497 &gRoots[ 8], &gRoots[ 9], &gRoots[10], &gRoots[11],
498 &gRoots[12], &gRoots[13], &gRoots[14], &gRoots[15],
499 &gRoots[16], &gRoots[17], &gRoots[18], &gRoots[19],
500 &gRoots[20], &gRoots[21], &gRoots[22], &gRoots[23],
501 &gRoots[24], &gRoots[25], &gRoots[26], &gRoots[27],
502 &gRoots[28], &gRoots[29], &gRoots[30], &gRoots[31],
503 &gRoots[32], &gRoots[33], &gRoots[34], &gRoots[35],
504 &gRoots[36], &gRoots[37], &gRoots[38], &gRoots[39],
505 &gRoots[40], &gRoots[41], &gRoots[42], &gRoots[43],
506 &gRoots[44], &gRoots[45], &gRoots[46], &gRoots[47],
507 &gRoots[48], &gRoots[49], &gRoots[50], &gRoots[51],
508 &gRoots[52], &gRoots[53], &gRoots[54], &gRoots[55],
509 &gRoots[56], &gRoots[57], &gRoots[58], &gRoots[59],
510 &gRoots[60], &gRoots[61], &gRoots[62], &gRoots[63],
511};
512
513
515unsigned long int CProfileManager::ResetTime = 0;
516
518{
519
522 return 0;
523
524 return new CProfileIterator( &gRoots[threadIndex]);
525}
526
528{
529 for (int i=0;i<BT_QUICKPROF_MAX_THREAD_COUNT;i++)
530 {
532 }
533}
534
535
536/***********************************************************************************************
537 * CProfileManager::Start_Profile -- Begin a named profile *
538 * *
539 * Steps one level deeper into the tree, if a child already exists with the specified name *
540 * then it accumulates the profiling; otherwise a new child node is added to the profile tree. *
541 * *
542 * INPUT: *
543 * name - name of this profiling record *
544 * *
545 * WARNINGS: *
546 * The string used is assumed to be a static string; pointer compares are used throughout *
547 * the profiling code for efficiency. *
548 *=============================================================================================*/
550{
553 return;
554
555 if (name != gCurrentNodes[threadIndex]->Get_Name()) {
557 }
558
560}
561
562
563/***********************************************************************************************
564 * CProfileManager::Stop_Profile -- Stop timing and record the results. *
565 *=============================================================================================*/
567{
570 return;
571
572 // Return will indicate whether we should back up to our parent (we may
573 // be profiling a recursive function)
574 if (gCurrentNodes[threadIndex]->Return()) {
576 }
577}
578
579
580
581
582
583
584/***********************************************************************************************
585 * CProfileManager::Reset -- Reset the contents of the profiling system *
586 * *
587 * This resets everything except for the tree structure. All of the timing data is reset. *
588 *=============================================================================================*/
590{
594 return;
597 FrameCounter = 0;
599}
600
601
602/***********************************************************************************************
603 * CProfileManager::Increment_Frame_Counter -- Increment the frame counter *
604 *=============================================================================================*/
606{
607 FrameCounter++;
608}
609
610
611/***********************************************************************************************
612 * CProfileManager::Get_Time_Since_Reset -- returns the elapsed time since last reset *
613 *=============================================================================================*/
615{
616 unsigned long int time;
618 time -= ResetTime;
619 return (float)time / Profile_Get_Tick_Rate();
620}
621
622#include <stdio.h>
623
625{
626 profileIterator->First();
627 if (profileIterator->Is_Done())
628 return;
629
630 float accumulated_time=0,parent_time = profileIterator->Is_Root() ? CProfileManager::Get_Time_Since_Reset() : profileIterator->Get_Current_Parent_Total_Time();
631 int i;
633 for (i=0;i<spacing;i++) printf(".");
634 printf("----------------------------------\n");
635 for (i=0;i<spacing;i++) printf(".");
636 printf("Profiling: %s (total running time: %.3f ms) ---\n", profileIterator->Get_Current_Parent_Name(), parent_time );
637 float totalTime = 0.f;
638
639
640 int numChildren = 0;
641
642 for (i = 0; !profileIterator->Is_Done(); i++,profileIterator->Next())
643 {
644 numChildren++;
645 float current_total_time = profileIterator->Get_Current_Total_Time();
647 float fraction = parent_time > SIMD_EPSILON ? (current_total_time / parent_time) * 100 : 0.f;
648 {
649 int i; for (i=0;i<spacing;i++) printf(".");
650 }
651 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());
653 //recurse into children
654 }
655
657 {
658 //printf("what's wrong\n");
659 }
660 for (i=0;i<spacing;i++) printf(".");
661 printf("%s (%.3f %%) :: %.3f ms\n", "Unaccounted:",parent_time > SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time);
662
663 for (i=0;i<numChildren;i++)
664 {
665 profileIterator->Enter_Child(i);
667 profileIterator->Enter_Parent();
668 }
669}
670
671
672
674{
677
679
681}
682
683
684
685
687{
688#if BT_THREADSAFE
690#else // #if BT_THREADSAFE
691 const unsigned int kNullIndex = ~0U;
692#ifdef _WIN32
693 #if defined(__MINGW32__) || defined(__MINGW64__)
694 static __thread unsigned int sThreadIndex = kNullIndex;
695 #else
696 __declspec( thread ) static unsigned int sThreadIndex = kNullIndex;
697 #endif
698#else
699#ifdef __APPLE__
700 #if TARGET_OS_IPHONE
701 unsigned int sThreadIndex = 0;
702 return -1;
703 #else
704 static __thread unsigned int sThreadIndex = kNullIndex;
705 #endif
706#else//__APPLE__
707#if __linux__
708 static __thread unsigned int sThreadIndex = kNullIndex;
709#else
710 unsigned int sThreadIndex = 0;
711 return -1;
712#endif
713#endif//__APPLE__
714
715#endif
716 static int gThreadCounter=0;
717
718 if ( sThreadIndex == kNullIndex )
719 {
721 }
722 return sThreadIndex;
723#endif // #else // #if BT_THREADSAFE
724}
725
727{
729}
731{
733}
734
735
736#else
737void btEnterProfileZoneDefault(const char* name)
738{
739}
741{
742}
743#endif //BT_NO_PROFILE
744
745
746
747
748
751
752void btEnterProfileZone(const char* name)
753{
755}
757{
758 (bts_leaveFunc)();
759}
760
762{
763 return bts_enterFunc ;
764}
766{
767 return bts_leaveFunc;
768}
769
770
772{
774}
776{
778}
779
781{
783}
784
786{
788}
789
unsigned long long int uint64_t
unsigned int U
Definition btGjkEpa3.h:87
const T & btMax(const T &a, const T &b)
Definition btMinMax.h:29
btEnterProfileZoneFunc * btGetCurrentEnterProfileZoneFunc()
void btSetCustomEnterProfileZoneFunc(btEnterProfileZoneFunc *enterFunc)
static btEnterProfileZoneFunc * bts_enterFunc
static btClock gProfileClock
float Profile_Get_Tick_Rate(void)
void btLeaveProfileZone()
void btLeaveProfileZoneDefault()
void btSetCustomLeaveProfileZoneFunc(btLeaveProfileZoneFunc *leaveFunc)
void btEnterProfileZoneDefault(const char *name)
void btEnterProfileZone(const char *name)
unsigned int btQuickprofGetCurrentThreadIndex2()
void Profile_Get_Ticks(unsigned long int *ticks)
CProfileNode gRoots[BT_QUICKPROF_MAX_THREAD_COUNT]
static btLeaveProfileZoneFunc * bts_leaveFunc
CProfileNode * gCurrentNodes[BT_QUICKPROF_MAX_THREAD_COUNT]
#define GetTickCount64
btLeaveProfileZoneFunc * btGetCurrentLeaveProfileZoneFunc()
const unsigned int BT_QUICKPROF_MAX_THREAD_COUNT
Definition btQuickprof.h:77
unsigned int btQuickprofGetCurrentThreadIndex2()
void btLeaveProfileZoneFunc()
Definition btQuickprof.h:58
void btEnterProfileZoneFunc(const char *msg)
Definition btQuickprof.h:57
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition btScalar.h:292
#define SIMD_EPSILON
Definition btScalar.h:521
#define btAssert(x)
Definition btScalar.h:131
unsigned int btGetCurrentThreadIndex()
static ThreadsafeCounter gThreadCounter
An iterator to navigate through the tree.
void Enter_Child(int index)
CProfileNode * CurrentChild
void Enter_Parent(void)
CProfileNode * CurrentParent
CProfileIterator(CProfileNode *start)
static int FrameCounter
static void dumpAll()
static void Increment_Frame_Counter(void)
static void Release_Iterator(CProfileIterator *iterator)
static float Get_Time_Since_Reset(void)
static CProfileIterator * Get_Iterator(void)
static int Get_Frame_Count_Since_Reset(void)
static void Reset(void)
static void CleanupMemory(void)
static void dumpRecursive(CProfileIterator *profileIterator, int spacing)
static void Start_Profile(const char *name)
static void Stop_Profile(void)
static unsigned long int ResetTime
A node in the Profile Hierarchy Tree.
Definition btQuickprof.h:93
CProfileNode * Child
void Reset(void)
CProfileNode * Sibling
CProfileNode * Get_Sub_Node(const char *name)
CProfileNode * Get_Parent(void)
void Call(void)
unsigned long int StartTime
CProfileNode(const char *name, CProfileNode *parent)
bool Return(void)
void CleanupMemory()
CProfileNode * Get_Child(void)
CProfileNode * Get_Sibling(void)
CProfileSample(const char *name)
The btClock is a portable basic clock that measures accurate time in seconds, use for profiling.
Definition btQuickprof.h:25
btScalar getTimeSeconds()
Returns the time in s since the last call to reset or since the Clock was created.
unsigned long long int getTimeNanoseconds()
void reset()
Resets the initial reference time.
struct btClockData * m_data
Definition btQuickprof.h:52
unsigned long long int getTimeMilliseconds()
Returns the time in ms since the last call to reset or since the btClock was created.
unsigned long long int getTimeMicroseconds()
Returns the time in us since the last call to reset or since the Clock was created.
btClock()
The btClock is a portable basic clock that measures accurate time in seconds, use for profiling.
btClock & operator=(const btClock &other)
LARGE_INTEGER mStartTime
LARGE_INTEGER mClockFrequency
LONGLONG mStartTick