btQuickprof.cpp 23 KB

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