wwprofile.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWDebug *
  23. * *
  24. * $Archive:: /Commando/Code/wwdebug/wwprofile.cpp $*
  25. * *
  26. * $Author:: Tom_s $*
  27. * *
  28. * $Modtime:: 6/29/01 3:10p $*
  29. * *
  30. * $Revision:: 14 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * WWProfile_Get_Ticks -- Retrieves the cpu performance counter *
  34. * WWProfile_Get_Tick_Rate -- returns the clock frequency of the cpu *
  35. * WWProfileHierachyNodeClass::WWProfileHierachyNodeClass -- Constructor *
  36. * WWProfileHierachyNodeClass::~WWProfileHierachyNodeClass -- Destructor *
  37. * WWProfileHierachyNodeClass::Get_Sub_Node -- Searches for a child node by name (pointer) *
  38. * WWProfileHierachyNodeClass::Reset -- Reset all profiling data in the tree *
  39. * WWProfileHierachyNodeClass::Call -- Start timing *
  40. * WWProfileHierachyNodeClass::Return -- Stop timing, record results *
  41. * WWProfileManager::Start_Profile -- Begin a named profile *
  42. * WWProfileManager::Stop_Profile -- Stop timing and record the results. *
  43. * WWProfileManager::Reset -- Reset the contents of the profiling system *
  44. * WWProfileManager::Increment_Frame_Counter -- Increment the frame counter *
  45. * WWProfileManager::Get_Time_Since_Reset -- returns the elapsed time since last reset *
  46. * WWProfileManager::Get_Iterator -- Creates an iterator for the profile tree *
  47. * WWProfileManager::Release_Iterator -- Return an iterator for the profile tree *
  48. * WWProfileManager::Get_In_Order_Iterator -- Creates an "in-order" iterator for the profile *
  49. * WWProfileManager::Release_In_Order_Iterator -- Return an "in-order" iterator *
  50. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  51. #include "always.h"
  52. #include "wwprofile.h"
  53. #include "wwdebug.h"
  54. #include <windows.h>
  55. /***********************************************************************************************
  56. * WWProfile_Get_Ticks -- Retrieves the cpu performance counter *
  57. * *
  58. * INPUT: *
  59. * *
  60. * OUTPUT: *
  61. * *
  62. * WARNINGS: *
  63. * *
  64. * HISTORY: *
  65. * 9/24/2000 gth : Created. *
  66. *=============================================================================================*/
  67. inline void WWProfile_Get_Ticks(_int64 * ticks)
  68. {
  69. #ifdef _UNIX
  70. *ticks = 0;
  71. #else
  72. __asm
  73. {
  74. push edx;
  75. push ecx;
  76. mov ecx,ticks;
  77. _emit 0Fh
  78. _emit 31h
  79. mov [ecx],eax;
  80. mov [ecx+4],edx;
  81. pop ecx;
  82. pop edx;
  83. }
  84. #endif
  85. }
  86. /***********************************************************************************************
  87. * WWProfile_Get_Tick_Rate -- returns the clock frequency of the cpu *
  88. * *
  89. * INPUT: *
  90. * *
  91. * OUTPUT: *
  92. * *
  93. * WARNINGS: *
  94. * *
  95. * HISTORY: *
  96. * 9/24/2000 gth : Created. *
  97. *=============================================================================================*/
  98. inline float WWProfile_Get_Tick_Rate(void)
  99. {
  100. #ifdef _UNIX
  101. return(0);
  102. #else
  103. static float _CPUFrequency = -1.0f;
  104. if (_CPUFrequency == -1.0f) {
  105. __int64 curr_rate = 0;
  106. ::QueryPerformanceFrequency ((LARGE_INTEGER *)&curr_rate);
  107. _CPUFrequency = (float)curr_rate;
  108. }
  109. return _CPUFrequency;
  110. #endif
  111. }
  112. /***********************************************************************************************
  113. * WWProfileHierachyNodeClass::WWProfileHierachyNodeClass -- Constructor *
  114. * *
  115. * *
  116. * INPUT: *
  117. * name - pointer to a static string which is the name of this profile node *
  118. * parent - parent pointer *
  119. * *
  120. * OUTPUT: *
  121. * *
  122. * WARNINGS: *
  123. * The name is assumed to be a static pointer, only the pointer is stored and compared for *
  124. * efficiency reasons. *
  125. * *
  126. * HISTORY: *
  127. * 9/24/2000 gth : Created. *
  128. *=============================================================================================*/
  129. WWProfileHierachyNodeClass::WWProfileHierachyNodeClass( const char * name, WWProfileHierachyNodeClass * parent ) :
  130. Name( name ),
  131. TotalCalls( 0 ),
  132. TotalTime( 0 ),
  133. StartTime( 0 ),
  134. RecursionCounter( 0 ),
  135. Parent( parent ),
  136. Child( NULL ),
  137. Sibling( NULL )
  138. {
  139. Reset();
  140. }
  141. /***********************************************************************************************
  142. * WWProfileHierachyNodeClass::~WWProfileHierachyNodeClass -- Destructor *
  143. * *
  144. * INPUT: *
  145. * *
  146. * OUTPUT: *
  147. * *
  148. * WARNINGS: *
  149. * *
  150. * HISTORY: *
  151. * 9/24/2000 gth : Created. *
  152. *=============================================================================================*/
  153. WWProfileHierachyNodeClass::~WWProfileHierachyNodeClass( void )
  154. {
  155. delete Child;
  156. delete Sibling;
  157. }
  158. /***********************************************************************************************
  159. * WWProfileHierachyNodeClass::Get_Sub_Node -- Searches for a child node by name (pointer) *
  160. * *
  161. * INPUT: *
  162. * name - static string pointer to the name of the node we are searching for *
  163. * *
  164. * OUTPUT: *
  165. * *
  166. * WARNINGS: *
  167. * All profile names are assumed to be static strings so this function uses pointer compares *
  168. * to find the named node. *
  169. * *
  170. * HISTORY: *
  171. * 9/24/2000 gth : Created. *
  172. *=============================================================================================*/
  173. WWProfileHierachyNodeClass * WWProfileHierachyNodeClass::Get_Sub_Node( const char * name )
  174. {
  175. // Try to find this sub node
  176. WWProfileHierachyNodeClass * child = Child;
  177. while ( child ) {
  178. if ( child->Name == name ) {
  179. return child;
  180. }
  181. child = child->Sibling;
  182. }
  183. // We didn't find it, so add it
  184. WWProfileHierachyNodeClass * node = W3DNEW WWProfileHierachyNodeClass( name, this );
  185. node->Sibling = Child;
  186. Child = node;
  187. return node;
  188. }
  189. /***********************************************************************************************
  190. * WWProfileHierachyNodeClass::Reset -- Reset all profiling data in the tree *
  191. * *
  192. * INPUT: *
  193. * *
  194. * OUTPUT: *
  195. * *
  196. * WARNINGS: *
  197. * *
  198. * HISTORY: *
  199. * 9/24/2000 gth : Created. *
  200. *=============================================================================================*/
  201. void WWProfileHierachyNodeClass::Reset( void )
  202. {
  203. TotalCalls = 0;
  204. TotalTime = 0.0f;
  205. if ( Child ) {
  206. Child->Reset();
  207. }
  208. if ( Sibling ) {
  209. Sibling->Reset();
  210. }
  211. }
  212. /***********************************************************************************************
  213. * WWProfileHierachyNodeClass::Call -- Start timing *
  214. * *
  215. * INPUT: *
  216. * *
  217. * OUTPUT: *
  218. * *
  219. * WARNINGS: *
  220. * *
  221. * HISTORY: *
  222. * 9/24/2000 gth : Created. *
  223. *=============================================================================================*/
  224. void WWProfileHierachyNodeClass::Call( void )
  225. {
  226. TotalCalls++;
  227. if (RecursionCounter++ == 0) {
  228. WWProfile_Get_Ticks(&StartTime);
  229. }
  230. }
  231. /***********************************************************************************************
  232. * WWProfileHierachyNodeClass::Return -- Stop timing, record results *
  233. * *
  234. * INPUT: *
  235. * *
  236. * OUTPUT: *
  237. * *
  238. * WARNINGS: *
  239. * *
  240. * HISTORY: *
  241. * 9/24/2000 gth : Created. *
  242. *=============================================================================================*/
  243. bool WWProfileHierachyNodeClass::Return( void )
  244. {
  245. if (--RecursionCounter == 0) {
  246. if ( TotalCalls != 0 ) {
  247. __int64 time;
  248. WWProfile_Get_Ticks(&time);
  249. time-=StartTime;
  250. float sec = (float)time / WWProfile_Get_Tick_Rate();
  251. // if ( sec > 1 ) {
  252. // WWDEBUG_SAY(( "WWProfile of %s took %f seconds\n", Name, sec ));
  253. // }
  254. TotalTime += sec;
  255. }
  256. }
  257. return RecursionCounter == 0;
  258. }
  259. /***************************************************************************************************
  260. **
  261. ** WWProfileManager Implementation
  262. **
  263. ***************************************************************************************************/
  264. WWProfileHierachyNodeClass WWProfileManager::Root( "Root", NULL );
  265. WWProfileHierachyNodeClass * WWProfileManager::CurrentNode = &WWProfileManager::Root;
  266. int WWProfileManager::FrameCounter = 0;
  267. __int64 WWProfileManager::ResetTime = 0;
  268. static unsigned int ThreadID = static_cast<unsigned int>(-1);
  269. /***********************************************************************************************
  270. * WWProfileManager::Start_Profile -- Begin a named profile *
  271. * *
  272. * Steps one level deeper into the tree, if a child already exists with the specified name *
  273. * then it accumulates the profiling; otherwise a new child node is added to the profile tree. *
  274. * *
  275. * INPUT: *
  276. * name - name of this profiling record *
  277. * *
  278. * OUTPUT: *
  279. * *
  280. * WARNINGS: *
  281. * The string used is assumed to be a static string; pointer compares are used throughout *
  282. * the profiling code for efficiency. *
  283. * *
  284. * HISTORY: *
  285. * 9/24/2000 gth : Created. *
  286. *=============================================================================================*/
  287. void WWProfileManager::Start_Profile( const char * name )
  288. {
  289. if (::GetCurrentThreadId() != ThreadID) {
  290. return;
  291. }
  292. // int current_thread = ::GetCurrentThreadId();
  293. if (name != CurrentNode->Get_Name()) {
  294. CurrentNode = CurrentNode->Get_Sub_Node( name );
  295. }
  296. CurrentNode->Call();
  297. }
  298. /***********************************************************************************************
  299. * WWProfileManager::Stop_Profile -- Stop timing and record the results. *
  300. * *
  301. * INPUT: *
  302. * *
  303. * OUTPUT: *
  304. * *
  305. * WARNINGS: *
  306. * *
  307. * HISTORY: *
  308. * 9/24/2000 gth : Created. *
  309. *=============================================================================================*/
  310. void WWProfileManager::Stop_Profile( void )
  311. {
  312. if (::GetCurrentThreadId() != ThreadID) {
  313. return;
  314. }
  315. // Return will indicate whether we should back up to our parent (we may
  316. // be profiling a recursive function)
  317. if (CurrentNode->Return()) {
  318. CurrentNode = CurrentNode->Get_Parent();
  319. }
  320. }
  321. /***********************************************************************************************
  322. * WWProfileManager::Reset -- Reset the contents of the profiling system *
  323. * *
  324. * This resets everything except for the tree structure. All of the timing data is reset. *
  325. * *
  326. * *
  327. * INPUT: *
  328. * *
  329. * OUTPUT: *
  330. * *
  331. * WARNINGS: *
  332. * *
  333. * HISTORY: *
  334. * 9/24/2000 gth : Created. *
  335. *=============================================================================================*/
  336. void WWProfileManager::Reset( void )
  337. {
  338. ThreadID = ::GetCurrentThreadId();
  339. Root.Reset();
  340. FrameCounter = 0;
  341. WWProfile_Get_Ticks(&ResetTime);
  342. }
  343. /***********************************************************************************************
  344. * WWProfileManager::Increment_Frame_Counter -- Increment the frame counter *
  345. * *
  346. * INPUT: *
  347. * *
  348. * OUTPUT: *
  349. * *
  350. * WARNINGS: *
  351. * *
  352. * HISTORY: *
  353. * 9/24/2000 gth : Created. *
  354. *=============================================================================================*/
  355. void WWProfileManager::Increment_Frame_Counter( void )
  356. {
  357. FrameCounter++;
  358. }
  359. /***********************************************************************************************
  360. * WWProfileManager::Get_Time_Since_Reset -- returns the elapsed time since last reset *
  361. * *
  362. * INPUT: *
  363. * *
  364. * OUTPUT: *
  365. * *
  366. * WARNINGS: *
  367. * *
  368. * HISTORY: *
  369. * 9/24/2000 gth : Created. *
  370. *=============================================================================================*/
  371. float WWProfileManager::Get_Time_Since_Reset( void )
  372. {
  373. __int64 time;
  374. WWProfile_Get_Ticks(&time);
  375. time -= ResetTime;
  376. return (float)time / WWProfile_Get_Tick_Rate();
  377. }
  378. /***********************************************************************************************
  379. * WWProfileManager::Get_Iterator -- Creates an iterator for the profile tree *
  380. * *
  381. * INPUT: *
  382. * *
  383. * OUTPUT: *
  384. * *
  385. * WARNINGS: *
  386. * *
  387. * HISTORY: *
  388. * 9/24/2000 gth : Created. *
  389. *=============================================================================================*/
  390. WWProfileIterator * WWProfileManager::Get_Iterator( void )
  391. {
  392. return W3DNEW WWProfileIterator( &Root );
  393. }
  394. /***********************************************************************************************
  395. * WWProfileManager::Release_Iterator -- Return an iterator for the profile tree *
  396. * *
  397. * INPUT: *
  398. * *
  399. * OUTPUT: *
  400. * *
  401. * WARNINGS: *
  402. * *
  403. * HISTORY: *
  404. * 9/24/2000 gth : Created. *
  405. *=============================================================================================*/
  406. void WWProfileManager::Release_Iterator( WWProfileIterator * iterator )
  407. {
  408. delete iterator;
  409. }
  410. /***********************************************************************************************
  411. * WWProfileManager::Get_In_Order_Iterator -- Creates an "in-order" iterator for the profile t *
  412. * *
  413. * INPUT: *
  414. * *
  415. * OUTPUT: *
  416. * *
  417. * WARNINGS: *
  418. * *
  419. * HISTORY: *
  420. * 9/24/2000 gth : Created. *
  421. *=============================================================================================*/
  422. WWProfileInOrderIterator * WWProfileManager::Get_In_Order_Iterator( void )
  423. {
  424. return W3DNEW WWProfileInOrderIterator;
  425. }
  426. /***********************************************************************************************
  427. * WWProfileManager::Release_In_Order_Iterator -- Return an "in-order" iterator *
  428. * *
  429. * INPUT: *
  430. * *
  431. * OUTPUT: *
  432. * *
  433. * WARNINGS: *
  434. * *
  435. * HISTORY: *
  436. * 9/24/2000 gth : Created. *
  437. *=============================================================================================*/
  438. void WWProfileManager::Release_In_Order_Iterator( WWProfileInOrderIterator * iterator )
  439. {
  440. delete iterator;
  441. }
  442. /***************************************************************************************************
  443. **
  444. ** WWProfileIterator Implementation
  445. **
  446. ***************************************************************************************************/
  447. WWProfileIterator::WWProfileIterator( WWProfileHierachyNodeClass * start )
  448. {
  449. CurrentParent = start;
  450. CurrentChild = CurrentParent->Get_Child();
  451. }
  452. void WWProfileIterator::First(void)
  453. {
  454. CurrentChild = CurrentParent->Get_Child();
  455. }
  456. void WWProfileIterator::Next(void)
  457. {
  458. CurrentChild = CurrentChild->Get_Sibling();
  459. }
  460. bool WWProfileIterator::Is_Done(void)
  461. {
  462. return CurrentChild == NULL;
  463. }
  464. void WWProfileIterator::Enter_Child( void )
  465. {
  466. CurrentParent = CurrentChild;
  467. CurrentChild = CurrentParent->Get_Child();
  468. }
  469. void WWProfileIterator::Enter_Child( int index )
  470. {
  471. CurrentChild = CurrentParent->Get_Child();
  472. while ( (CurrentChild != NULL) && (index != 0) ) {
  473. index--;
  474. CurrentChild = CurrentChild->Get_Sibling();
  475. }
  476. if ( CurrentChild != NULL ) {
  477. CurrentParent = CurrentChild;
  478. CurrentChild = CurrentParent->Get_Child();
  479. }
  480. }
  481. void WWProfileIterator::Enter_Parent( void )
  482. {
  483. if ( CurrentParent->Get_Parent() != NULL ) {
  484. CurrentParent = CurrentParent->Get_Parent();
  485. }
  486. CurrentChild = CurrentParent->Get_Child();
  487. }
  488. /***************************************************************************************************
  489. **
  490. ** WWProfileInOrderIterator Implementation
  491. **
  492. ***************************************************************************************************/
  493. WWProfileInOrderIterator::WWProfileInOrderIterator( void )
  494. {
  495. CurrentNode = &WWProfileManager::Root;
  496. }
  497. void WWProfileInOrderIterator::First(void)
  498. {
  499. CurrentNode = &WWProfileManager::Root;
  500. }
  501. void WWProfileInOrderIterator::Next(void)
  502. {
  503. if ( CurrentNode->Get_Child() ) { // If I have a child, go to child
  504. CurrentNode = CurrentNode->Get_Child();
  505. } else if ( CurrentNode->Get_Sibling() ) { // If I have a sibling, go to sibling
  506. CurrentNode = CurrentNode->Get_Sibling();
  507. } else { // if not, go to my parent's sibling, or his.......
  508. // Find a parent with a sibling....
  509. bool done = false;
  510. while ( CurrentNode != NULL && !done ) {
  511. // go to my parent
  512. CurrentNode = CurrentNode->Get_Parent();
  513. // If I have a sibling, go there
  514. if ( CurrentNode != NULL && CurrentNode->Get_Sibling() != NULL ) {
  515. CurrentNode = CurrentNode->Get_Sibling();
  516. done = true;
  517. }
  518. }
  519. }
  520. }
  521. bool WWProfileInOrderIterator::Is_Done(void)
  522. {
  523. return CurrentNode == NULL;
  524. }
  525. /*
  526. **
  527. */
  528. WWTimeItClass::WWTimeItClass( const char * name )
  529. {
  530. Name = name;
  531. WWProfile_Get_Ticks( &Time );
  532. }
  533. WWTimeItClass::~WWTimeItClass( void )
  534. {
  535. __int64 End;
  536. WWProfile_Get_Ticks( &End );
  537. End -= Time;
  538. #ifdef WWDEBUG
  539. float time = End / WWProfile_Get_Tick_Rate();
  540. WWDEBUG_SAY(( "*** WWTIMEIT *** %s took %1.9f\n", Name, time ));
  541. #endif
  542. }
  543. /*
  544. **
  545. */
  546. WWMeasureItClass::WWMeasureItClass( float * p_result )
  547. {
  548. WWASSERT(p_result != NULL);
  549. PResult = p_result;
  550. WWProfile_Get_Ticks( &Time );
  551. }
  552. WWMeasureItClass::~WWMeasureItClass( void )
  553. {
  554. __int64 End;
  555. WWProfile_Get_Ticks( &End );
  556. End -= Time;
  557. WWASSERT(PResult != NULL);
  558. *PResult = End / WWProfile_Get_Tick_Rate();
  559. }