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