b3Quickprof.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. /*
  2. Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org
  3. This software is provided 'as-is', without any express or implied warranty.
  4. In no event will the authors be held liable for any damages arising from the use of this software.
  5. Permission is granted to anyone to use this software for any purpose,
  6. including commercial applications, and to alter it and redistribute it freely,
  7. subject to the following restrictions:
  8. 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  9. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  10. 3. This notice may not be removed or altered from any source distribution.
  11. */
  12. /*
  13. ***************************************************************************************************
  14. **
  15. ** profile.cpp
  16. **
  17. ** Real-Time Hierarchical Profiling for Game Programming Gems 3
  18. **
  19. ** by Greg Hjelstrom & Byon Garrabrant
  20. **
  21. ***************************************************************************************************/
  22. // Credits: The Clock class was inspired by the Timer classes in
  23. // Ogre (www.ogre3d.org).
  24. #include "Bullet3Common/b3MinMax.h"
  25. #include "b3Quickprof.h"
  26. #ifndef B3_NO_PROFILE
  27. static b3Clock b3s_profileClock;
  28. inline void b3Profile_Get_Ticks(unsigned long int * ticks)
  29. {
  30. *ticks = b3s_profileClock.getTimeMicroseconds();
  31. }
  32. inline float b3Profile_Get_Tick_Rate(void)
  33. {
  34. // return 1000000.f;
  35. return 1000.f;
  36. }
  37. /***************************************************************************************************
  38. **
  39. ** b3ProfileNode
  40. **
  41. ***************************************************************************************************/
  42. /***********************************************************************************************
  43. * INPUT: *
  44. * name - pointer to a static string which is the name of this profile node *
  45. * parent - parent pointer *
  46. * *
  47. * WARNINGS: *
  48. * The name is assumed to be a static pointer, only the pointer is stored and compared for *
  49. * efficiency reasons. *
  50. *=============================================================================================*/
  51. b3ProfileNode::b3ProfileNode( const char * name, b3ProfileNode * parent ) :
  52. Name( name ),
  53. TotalCalls( 0 ),
  54. TotalTime( 0 ),
  55. StartTime( 0 ),
  56. RecursionCounter( 0 ),
  57. Parent( parent ),
  58. Child( NULL ),
  59. Sibling( NULL ),
  60. m_userPtr(0)
  61. {
  62. Reset();
  63. }
  64. void b3ProfileNode::CleanupMemory()
  65. {
  66. delete ( Child);
  67. Child = NULL;
  68. delete ( Sibling);
  69. Sibling = NULL;
  70. }
  71. b3ProfileNode::~b3ProfileNode( void )
  72. {
  73. delete ( Child);
  74. delete ( Sibling);
  75. }
  76. /***********************************************************************************************
  77. * INPUT: *
  78. * name - static string pointer to the name of the node we are searching for *
  79. * *
  80. * WARNINGS: *
  81. * All profile names are assumed to be static strings so this function uses pointer compares *
  82. * to find the named node. *
  83. *=============================================================================================*/
  84. b3ProfileNode * b3ProfileNode::Get_Sub_Node( const char * name )
  85. {
  86. // Try to find this sub node
  87. b3ProfileNode * child = Child;
  88. while ( child ) {
  89. if ( child->Name == name ) {
  90. return child;
  91. }
  92. child = child->Sibling;
  93. }
  94. // We didn't find it, so add it
  95. b3ProfileNode * node = new b3ProfileNode( name, this );
  96. node->Sibling = Child;
  97. Child = node;
  98. return node;
  99. }
  100. void b3ProfileNode::Reset( void )
  101. {
  102. TotalCalls = 0;
  103. TotalTime = 0.0f;
  104. if ( Child ) {
  105. Child->Reset();
  106. }
  107. if ( Sibling ) {
  108. Sibling->Reset();
  109. }
  110. }
  111. void b3ProfileNode::Call( void )
  112. {
  113. TotalCalls++;
  114. if (RecursionCounter++ == 0) {
  115. b3Profile_Get_Ticks(&StartTime);
  116. }
  117. }
  118. bool b3ProfileNode::Return( void )
  119. {
  120. if ( --RecursionCounter == 0 && TotalCalls != 0 ) {
  121. unsigned long int time;
  122. b3Profile_Get_Ticks(&time);
  123. time-=StartTime;
  124. TotalTime += (float)time / b3Profile_Get_Tick_Rate();
  125. }
  126. return ( RecursionCounter == 0 );
  127. }
  128. /***************************************************************************************************
  129. **
  130. ** b3ProfileIterator
  131. **
  132. ***************************************************************************************************/
  133. b3ProfileIterator::b3ProfileIterator( b3ProfileNode * start )
  134. {
  135. CurrentParent = start;
  136. CurrentChild = CurrentParent->Get_Child();
  137. }
  138. void b3ProfileIterator::First(void)
  139. {
  140. CurrentChild = CurrentParent->Get_Child();
  141. }
  142. void b3ProfileIterator::Next(void)
  143. {
  144. CurrentChild = CurrentChild->Get_Sibling();
  145. }
  146. bool b3ProfileIterator::Is_Done(void)
  147. {
  148. return CurrentChild == NULL;
  149. }
  150. void b3ProfileIterator::Enter_Child( int index )
  151. {
  152. CurrentChild = CurrentParent->Get_Child();
  153. while ( (CurrentChild != NULL) && (index != 0) ) {
  154. index--;
  155. CurrentChild = CurrentChild->Get_Sibling();
  156. }
  157. if ( CurrentChild != NULL ) {
  158. CurrentParent = CurrentChild;
  159. CurrentChild = CurrentParent->Get_Child();
  160. }
  161. }
  162. void b3ProfileIterator::Enter_Parent( void )
  163. {
  164. if ( CurrentParent->Get_Parent() != NULL ) {
  165. CurrentParent = CurrentParent->Get_Parent();
  166. }
  167. CurrentChild = CurrentParent->Get_Child();
  168. }
  169. /***************************************************************************************************
  170. **
  171. ** b3ProfileManager
  172. **
  173. ***************************************************************************************************/
  174. b3ProfileNode b3ProfileManager::Root( "Root", NULL );
  175. b3ProfileNode * b3ProfileManager::CurrentNode = &b3ProfileManager::Root;
  176. int b3ProfileManager::FrameCounter = 0;
  177. unsigned long int b3ProfileManager::ResetTime = 0;
  178. /***********************************************************************************************
  179. * b3ProfileManager::Start_Profile -- Begin a named profile *
  180. * *
  181. * Steps one level deeper into the tree, if a child already exists with the specified name *
  182. * then it accumulates the profiling; otherwise a new child node is added to the profile tree. *
  183. * *
  184. * INPUT: *
  185. * name - name of this profiling record *
  186. * *
  187. * WARNINGS: *
  188. * The string used is assumed to be a static string; pointer compares are used throughout *
  189. * the profiling code for efficiency. *
  190. *=============================================================================================*/
  191. void b3ProfileManager::Start_Profile( const char * name )
  192. {
  193. if (name != CurrentNode->Get_Name()) {
  194. CurrentNode = CurrentNode->Get_Sub_Node( name );
  195. }
  196. CurrentNode->Call();
  197. }
  198. /***********************************************************************************************
  199. * b3ProfileManager::Stop_Profile -- Stop timing and record the results. *
  200. *=============================================================================================*/
  201. void b3ProfileManager::Stop_Profile( void )
  202. {
  203. // Return will indicate whether we should back up to our parent (we may
  204. // be profiling a recursive function)
  205. if (CurrentNode->Return()) {
  206. CurrentNode = CurrentNode->Get_Parent();
  207. }
  208. }
  209. /***********************************************************************************************
  210. * b3ProfileManager::Reset -- Reset the contents of the profiling system *
  211. * *
  212. * This resets everything except for the tree structure. All of the timing data is reset. *
  213. *=============================================================================================*/
  214. void b3ProfileManager::Reset( void )
  215. {
  216. b3s_profileClock.reset();
  217. Root.Reset();
  218. Root.Call();
  219. FrameCounter = 0;
  220. b3Profile_Get_Ticks(&ResetTime);
  221. }
  222. /***********************************************************************************************
  223. * b3ProfileManager::Increment_Frame_Counter -- Increment the frame counter *
  224. *=============================================================================================*/
  225. void b3ProfileManager::Increment_Frame_Counter( void )
  226. {
  227. FrameCounter++;
  228. }
  229. /***********************************************************************************************
  230. * b3ProfileManager::Get_Time_Since_Reset -- returns the elapsed time since last reset *
  231. *=============================================================================================*/
  232. float b3ProfileManager::Get_Time_Since_Reset( void )
  233. {
  234. unsigned long int time;
  235. b3Profile_Get_Ticks(&time);
  236. time -= ResetTime;
  237. return (float)time / b3Profile_Get_Tick_Rate();
  238. }
  239. #include <stdio.h>
  240. void b3ProfileManager::dumpRecursive(b3ProfileIterator* profileIterator, int spacing)
  241. {
  242. profileIterator->First();
  243. if (profileIterator->Is_Done())
  244. return;
  245. float accumulated_time=0,parent_time = profileIterator->Is_Root() ? b3ProfileManager::Get_Time_Since_Reset() : profileIterator->Get_Current_Parent_Total_Time();
  246. int i;
  247. int frames_since_reset = b3ProfileManager::Get_Frame_Count_Since_Reset();
  248. for (i=0;i<spacing;i++) b3Printf(".");
  249. b3Printf("----------------------------------\n");
  250. for (i=0;i<spacing;i++) b3Printf(".");
  251. b3Printf("Profiling: %s (total running time: %.3f ms) ---\n", profileIterator->Get_Current_Parent_Name(), parent_time );
  252. float totalTime = 0.f;
  253. int numChildren = 0;
  254. for (i = 0; !profileIterator->Is_Done(); i++,profileIterator->Next())
  255. {
  256. numChildren++;
  257. float current_total_time = profileIterator->Get_Current_Total_Time();
  258. accumulated_time += current_total_time;
  259. float fraction = parent_time > B3_EPSILON ? (current_total_time / parent_time) * 100 : 0.f;
  260. {
  261. int i; for (i=0;i<spacing;i++) b3Printf(".");
  262. }
  263. b3Printf("%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());
  264. totalTime += current_total_time;
  265. //recurse into children
  266. }
  267. if (parent_time < accumulated_time)
  268. {
  269. b3Printf("what's wrong\n");
  270. }
  271. for (i=0;i<spacing;i++) b3Printf(".");
  272. b3Printf("%s (%.3f %%) :: %.3f ms\n", "Unaccounted:",parent_time > B3_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time);
  273. for (i=0;i<numChildren;i++)
  274. {
  275. profileIterator->Enter_Child(i);
  276. dumpRecursive(profileIterator,spacing+3);
  277. profileIterator->Enter_Parent();
  278. }
  279. }
  280. void b3ProfileManager::dumpAll()
  281. {
  282. b3ProfileIterator* profileIterator = 0;
  283. profileIterator = b3ProfileManager::Get_Iterator();
  284. dumpRecursive(profileIterator,0);
  285. b3ProfileManager::Release_Iterator(profileIterator);
  286. }
  287. void b3ProfileManager::dumpRecursive(FILE* f, b3ProfileIterator* profileIterator, int spacing)
  288. {
  289. profileIterator->First();
  290. if (profileIterator->Is_Done())
  291. return;
  292. float accumulated_time=0,parent_time = profileIterator->Is_Root() ? b3ProfileManager::Get_Time_Since_Reset() : profileIterator->Get_Current_Parent_Total_Time();
  293. int i;
  294. int frames_since_reset = b3ProfileManager::Get_Frame_Count_Since_Reset();
  295. for (i=0;i<spacing;i++) fprintf(f,".");
  296. fprintf(f,"----------------------------------\n");
  297. for (i=0;i<spacing;i++) fprintf(f,".");
  298. fprintf(f,"Profiling: %s (total running time: %.3f ms) ---\n", profileIterator->Get_Current_Parent_Name(), parent_time );
  299. float totalTime = 0.f;
  300. int numChildren = 0;
  301. for (i = 0; !profileIterator->Is_Done(); i++,profileIterator->Next())
  302. {
  303. numChildren++;
  304. float current_total_time = profileIterator->Get_Current_Total_Time();
  305. accumulated_time += current_total_time;
  306. float fraction = parent_time > B3_EPSILON ? (current_total_time / parent_time) * 100 : 0.f;
  307. {
  308. int i; for (i=0;i<spacing;i++) fprintf(f,".");
  309. }
  310. fprintf(f,"%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());
  311. totalTime += current_total_time;
  312. //recurse into children
  313. }
  314. if (parent_time < accumulated_time)
  315. {
  316. fprintf(f,"what's wrong\n");
  317. }
  318. for (i=0;i<spacing;i++)
  319. fprintf(f,".");
  320. fprintf(f,"%s (%.3f %%) :: %.3f ms\n", "Unaccounted:",parent_time > B3_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time);
  321. for (i=0;i<numChildren;i++)
  322. {
  323. profileIterator->Enter_Child(i);
  324. dumpRecursive(f,profileIterator,spacing+3);
  325. profileIterator->Enter_Parent();
  326. }
  327. }
  328. void b3ProfileManager::dumpAll(FILE* f)
  329. {
  330. b3ProfileIterator* profileIterator = 0;
  331. profileIterator = b3ProfileManager::Get_Iterator();
  332. dumpRecursive(f, profileIterator,0);
  333. b3ProfileManager::Release_Iterator(profileIterator);
  334. }
  335. #endif //B3_NO_PROFILE