btQuickprof.h 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /***************************************************************************************************
  2. **
  3. ** Real-Time Hierarchical Profiling for Game Programming Gems 3
  4. **
  5. ** by Greg Hjelstrom & Byon Garrabrant
  6. **
  7. ***************************************************************************************************/
  8. // Credits: The Clock class was inspired by the Timer classes in
  9. // Ogre (www.ogre3d.org).
  10. #ifndef QUICK_PROF_H
  11. #define QUICK_PROF_H
  12. //To disable built-in profiling, please comment out next line
  13. //#define BT_NO_PROFILE 1
  14. #ifndef BT_NO_PROFILE
  15. #include "btScalar.h"
  16. #include "btAlignedAllocator.h"
  17. #include <new>
  18. //if you don't need btClock, you can comment next line
  19. #define USE_BT_CLOCK 1
  20. #ifdef USE_BT_CLOCK
  21. #ifdef __CELLOS_LV2__
  22. #include <sys/sys_time.h>
  23. #include <sys/time_util.h>
  24. #include <stdio.h>
  25. #endif
  26. #if defined (SUNOS) || defined (__SUNOS__)
  27. #include <stdio.h>
  28. #endif
  29. #if defined(WIN32) || defined(_WIN32)
  30. #define USE_WINDOWS_TIMERS
  31. #define WIN32_LEAN_AND_MEAN
  32. #define NOWINRES
  33. #define NOMCX
  34. #define NOIME
  35. #ifdef _XBOX
  36. #include <Xtl.h>
  37. #else
  38. #include <windows.h>
  39. #endif
  40. #include <time.h>
  41. #else
  42. #include <sys/time.h>
  43. #endif
  44. #define mymin(a,b) (a > b ? a : b)
  45. ///The btClock is a portable basic clock that measures accurate time in seconds, use for profiling.
  46. class btClock
  47. {
  48. public:
  49. btClock()
  50. {
  51. #ifdef USE_WINDOWS_TIMERS
  52. QueryPerformanceFrequency(&mClockFrequency);
  53. #endif
  54. reset();
  55. }
  56. ~btClock()
  57. {
  58. }
  59. /// Resets the initial reference time.
  60. void reset()
  61. {
  62. #ifdef USE_WINDOWS_TIMERS
  63. QueryPerformanceCounter(&mStartTime);
  64. mStartTick = GetTickCount();
  65. mPrevElapsedTime = 0;
  66. #else
  67. #ifdef __CELLOS_LV2__
  68. typedef uint64_t ClockSize;
  69. ClockSize newTime;
  70. //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
  71. SYS_TIMEBASE_GET( newTime );
  72. mStartTime = newTime;
  73. #else
  74. gettimeofday(&mStartTime, 0);
  75. #endif
  76. #endif
  77. }
  78. /// Returns the time in ms since the last call to reset or since
  79. /// the btClock was created.
  80. unsigned long int getTimeMilliseconds()
  81. {
  82. #ifdef USE_WINDOWS_TIMERS
  83. LARGE_INTEGER currentTime;
  84. QueryPerformanceCounter(&currentTime);
  85. LONGLONG elapsedTime = currentTime.QuadPart -
  86. mStartTime.QuadPart;
  87. // Compute the number of millisecond ticks elapsed.
  88. unsigned long msecTicks = (unsigned long)(1000 * elapsedTime /
  89. mClockFrequency.QuadPart);
  90. // Check for unexpected leaps in the Win32 performance counter.
  91. // (This is caused by unexpected data across the PCI to ISA
  92. // bridge, aka south bridge. See Microsoft KB274323.)
  93. unsigned long elapsedTicks = GetTickCount() - mStartTick;
  94. signed long msecOff = (signed long)(msecTicks - elapsedTicks);
  95. if (msecOff < -100 || msecOff > 100)
  96. {
  97. // Adjust the starting time forwards.
  98. LONGLONG msecAdjustment = mymin(msecOff *
  99. mClockFrequency.QuadPart / 1000, elapsedTime -
  100. mPrevElapsedTime);
  101. mStartTime.QuadPart += msecAdjustment;
  102. elapsedTime -= msecAdjustment;
  103. // Recompute the number of millisecond ticks elapsed.
  104. msecTicks = (unsigned long)(1000 * elapsedTime /
  105. mClockFrequency.QuadPart);
  106. }
  107. // Store the current elapsed time for adjustments next time.
  108. mPrevElapsedTime = elapsedTime;
  109. return msecTicks;
  110. #else
  111. #ifdef __CELLOS_LV2__
  112. uint64_t freq=sys_time_get_timebase_frequency();
  113. double dFreq=((double) freq) / 1000.0;
  114. typedef uint64_t ClockSize;
  115. ClockSize newTime;
  116. SYS_TIMEBASE_GET( newTime );
  117. //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
  118. return (unsigned long int)((double(newTime-mStartTime)) / dFreq);
  119. #else
  120. struct timeval currentTime;
  121. gettimeofday(&currentTime, 0);
  122. return (currentTime.tv_sec - mStartTime.tv_sec) * 1000 +
  123. (currentTime.tv_usec - mStartTime.tv_usec) / 1000;
  124. #endif //__CELLOS_LV2__
  125. #endif
  126. }
  127. /// Returns the time in us since the last call to reset or since
  128. /// the Clock was created.
  129. unsigned long int getTimeMicroseconds()
  130. {
  131. #ifdef USE_WINDOWS_TIMERS
  132. LARGE_INTEGER currentTime;
  133. QueryPerformanceCounter(&currentTime);
  134. LONGLONG elapsedTime = currentTime.QuadPart -
  135. mStartTime.QuadPart;
  136. // Compute the number of millisecond ticks elapsed.
  137. unsigned long msecTicks = (unsigned long)(1000 * elapsedTime /
  138. mClockFrequency.QuadPart);
  139. // Check for unexpected leaps in the Win32 performance counter.
  140. // (This is caused by unexpected data across the PCI to ISA
  141. // bridge, aka south bridge. See Microsoft KB274323.)
  142. unsigned long elapsedTicks = GetTickCount() - mStartTick;
  143. signed long msecOff = (signed long)(msecTicks - elapsedTicks);
  144. if (msecOff < -100 || msecOff > 100)
  145. {
  146. // Adjust the starting time forwards.
  147. LONGLONG msecAdjustment = mymin(msecOff *
  148. mClockFrequency.QuadPart / 1000, elapsedTime -
  149. mPrevElapsedTime);
  150. mStartTime.QuadPart += msecAdjustment;
  151. elapsedTime -= msecAdjustment;
  152. }
  153. // Store the current elapsed time for adjustments next time.
  154. mPrevElapsedTime = elapsedTime;
  155. // Convert to microseconds.
  156. unsigned long usecTicks = (unsigned long)(1000000 * elapsedTime /
  157. mClockFrequency.QuadPart);
  158. return usecTicks;
  159. #else
  160. #ifdef __CELLOS_LV2__
  161. uint64_t freq=sys_time_get_timebase_frequency();
  162. double dFreq=((double) freq)/ 1000000.0;
  163. typedef uint64_t ClockSize;
  164. ClockSize newTime;
  165. //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
  166. SYS_TIMEBASE_GET( newTime );
  167. return (unsigned long int)((double(newTime-mStartTime)) / dFreq);
  168. #else
  169. struct timeval currentTime;
  170. gettimeofday(&currentTime, 0);
  171. return (currentTime.tv_sec - mStartTime.tv_sec) * 1000000 +
  172. (currentTime.tv_usec - mStartTime.tv_usec);
  173. #endif//__CELLOS_LV2__
  174. #endif
  175. }
  176. private:
  177. #ifdef USE_WINDOWS_TIMERS
  178. LARGE_INTEGER mClockFrequency;
  179. DWORD mStartTick;
  180. LONGLONG mPrevElapsedTime;
  181. LARGE_INTEGER mStartTime;
  182. #else
  183. #ifdef __CELLOS_LV2__
  184. uint64_t mStartTime;
  185. #else
  186. struct timeval mStartTime;
  187. #endif
  188. #endif //__CELLOS_LV2__
  189. };
  190. #endif //USE_BT_CLOCK
  191. ///A node in the Profile Hierarchy Tree
  192. class CProfileNode {
  193. public:
  194. CProfileNode( const char * name, CProfileNode * parent );
  195. ~CProfileNode( void );
  196. CProfileNode * Get_Sub_Node( const char * name );
  197. CProfileNode * Get_Parent( void ) { return Parent; }
  198. CProfileNode * Get_Sibling( void ) { return Sibling; }
  199. CProfileNode * Get_Child( void ) { return Child; }
  200. void CleanupMemory();
  201. void Reset( void );
  202. void Call( void );
  203. bool Return( void );
  204. const char * Get_Name( void ) { return Name; }
  205. int Get_Total_Calls( void ) { return TotalCalls; }
  206. float Get_Total_Time( void ) { return TotalTime; }
  207. protected:
  208. const char * Name;
  209. int TotalCalls;
  210. float TotalTime;
  211. unsigned long int StartTime;
  212. int RecursionCounter;
  213. CProfileNode * Parent;
  214. CProfileNode * Child;
  215. CProfileNode * Sibling;
  216. };
  217. ///An iterator to navigate through the tree
  218. class CProfileIterator
  219. {
  220. public:
  221. // Access all the children of the current parent
  222. void First(void);
  223. void Next(void);
  224. bool Is_Done(void);
  225. bool Is_Root(void) { return (CurrentParent->Get_Parent() == 0); }
  226. void Enter_Child( int index ); // Make the given child the new parent
  227. void Enter_Largest_Child( void ); // Make the largest child the new parent
  228. void Enter_Parent( void ); // Make the current parent's parent the new parent
  229. // Access the current child
  230. const char * Get_Current_Name( void ) { return CurrentChild->Get_Name(); }
  231. int Get_Current_Total_Calls( void ) { return CurrentChild->Get_Total_Calls(); }
  232. float Get_Current_Total_Time( void ) { return CurrentChild->Get_Total_Time(); }
  233. // Access the current parent
  234. const char * Get_Current_Parent_Name( void ) { return CurrentParent->Get_Name(); }
  235. int Get_Current_Parent_Total_Calls( void ) { return CurrentParent->Get_Total_Calls(); }
  236. float Get_Current_Parent_Total_Time( void ) { return CurrentParent->Get_Total_Time(); }
  237. protected:
  238. CProfileNode * CurrentParent;
  239. CProfileNode * CurrentChild;
  240. CProfileIterator( CProfileNode * start );
  241. friend class CProfileManager;
  242. };
  243. ///The Manager for the Profile system
  244. class CProfileManager {
  245. public:
  246. static void Start_Profile( const char * name );
  247. static void Stop_Profile( void );
  248. static void CleanupMemory(void)
  249. {
  250. Root.CleanupMemory();
  251. }
  252. static void Reset( void );
  253. static void Increment_Frame_Counter( void );
  254. static int Get_Frame_Count_Since_Reset( void ) { return FrameCounter; }
  255. static float Get_Time_Since_Reset( void );
  256. static CProfileIterator * Get_Iterator( void )
  257. {
  258. return new CProfileIterator( &Root );
  259. }
  260. static void Release_Iterator( CProfileIterator * iterator ) { delete ( iterator); }
  261. static void dumpRecursive(CProfileIterator* profileIterator, int spacing);
  262. static void dumpAll();
  263. private:
  264. static CProfileNode Root;
  265. static CProfileNode * CurrentNode;
  266. static int FrameCounter;
  267. static unsigned long int ResetTime;
  268. };
  269. ///ProfileSampleClass is a simple way to profile a function's scope
  270. ///Use the BT_PROFILE macro at the start of scope to time
  271. class CProfileSample {
  272. public:
  273. CProfileSample( const char * name )
  274. {
  275. CProfileManager::Start_Profile( name );
  276. }
  277. ~CProfileSample( void )
  278. {
  279. CProfileManager::Stop_Profile();
  280. }
  281. };
  282. #define BT_PROFILE( name ) CProfileSample __profile( name )
  283. #else
  284. #define BT_PROFILE( name )
  285. #endif //#ifndef BT_NO_PROFILE
  286. #endif //QUICK_PROF_H