AUD_Profiler.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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. ** **
  20. ** Westwood Studios Pacific. **
  21. ** **
  22. ** Confidential Information **
  23. ** Copyright (C) 2000 - All Rights Reserved **
  24. ** **
  25. ******************************************************************************
  26. ** **
  27. ** Project: Dune Emperor **
  28. ** **
  29. ** Module: <module> (<prefix>_) **
  30. ** **
  31. ** Version: $ID$ **
  32. ** **
  33. ** File name: audprof.cpp **
  34. ** **
  35. ** Created by: mm/dd/yy <author> **
  36. ** **
  37. ** Description: <description> **
  38. ** **
  39. *****************************************************************************/
  40. /*****************************************************************************
  41. ** Includes **
  42. *****************************************************************************/
  43. #define WIN32_LEAN_AND_MEAN
  44. #include <windows.h>
  45. #include <stdio.h>
  46. #include <wpaudio/profiler.h>
  47. /*****************************************************************************
  48. ** Externals **
  49. *****************************************************************************/
  50. /*****************************************************************************
  51. ** Defines **
  52. *****************************************************************************/
  53. /*****************************************************************************
  54. ** Private Types **
  55. *****************************************************************************/
  56. /*****************************************************************************
  57. ** Private Data **
  58. *****************************************************************************/
  59. /*****************************************************************************
  60. ** Public Data **
  61. *****************************************************************************/
  62. /*****************************************************************************
  63. ** Private Prototypes **
  64. *****************************************************************************/
  65. /*****************************************************************************
  66. ** Private Functions **
  67. *****************************************************************************/
  68. /*****************************************************************************
  69. ** Public Functions **
  70. *****************************************************************************/
  71. #ifndef IG_FINAL_RELEASE
  72. /******************************************************************/
  73. /* */
  74. /* */
  75. /******************************************************************/
  76. void ProfCacheInit ( ProfileData *prof, int pages, int pageSize )
  77. {
  78. memset ( prof, 0, sizeof ( ProfileData ));
  79. if ( !QueryPerformanceFrequency( (LARGE_INTEGER*) &prof->freq ))
  80. {
  81. prof->freq = 0;
  82. }
  83. prof->update = prof->freq;
  84. prof->cacheSize = pages*pageSize;
  85. prof->numPages = pages;
  86. prof->pageSize = pageSize;
  87. }
  88. /******************************************************************/
  89. /* */
  90. /* */
  91. /******************************************************************/
  92. void ProfCacheDeinit ( ProfileData * )
  93. {
  94. }
  95. /******************************************************************/
  96. /* */
  97. /* */
  98. /******************************************************************/
  99. void ProfCacheNewFrame ( ProfileData *prof )
  100. {
  101. int total;
  102. prof->frames++;
  103. if ( prof->totalTime > prof->longestFrame )
  104. {
  105. prof->nextLongestFrame = prof->longestFrame;
  106. prof->nextLongestFramePages = prof->longestFramePages;
  107. prof->nextLongestFrameBytes = prof->longestFrameBytes;
  108. prof->longestFrame = prof->totalTime ;
  109. prof->longestFrameBytes = prof->totalDataBytes;
  110. prof->longestFramePages = prof->pageCount;
  111. }
  112. else if ( prof->totalTime > prof->nextLongestFrame )
  113. {
  114. prof->nextLongestFrame = prof->totalTime ;
  115. prof->nextLongestFrameBytes = prof->totalDataBytes;
  116. prof->nextLongestFramePages = prof->pageCount;
  117. }
  118. prof->pageCount = 0;
  119. if ( (total = prof->hits + prof->misses ))
  120. {
  121. prof->HitPercent = (prof->hits *100) / total;
  122. }
  123. prof->BytesPerFrame = prof->totalFrameBytes / prof->frames;
  124. if ( prof->frames > 3*30 )
  125. {
  126. prof->totalFrameBytes = 0;
  127. prof->frames = 0;
  128. }
  129. if ( ! (prof->frames % 30) )
  130. {
  131. prof->hits = 0;
  132. prof->misses = 0;
  133. }
  134. if ( prof->totalTime > prof->update )
  135. {
  136. int ms;
  137. ms = (int) ( (prof->totalTime *1000 )/prof->freq);
  138. prof->TotalBytesPerSecond = (int) (((unsigned __int64) prof->totalDataBytes *1000)/ ms);
  139. prof->totalDataBytes = 0;
  140. prof->totalTime = 0;
  141. ms = (int) ((prof->totalDecompTime *1000 )/prof->freq) ;
  142. if ( ms )
  143. {
  144. prof->DecompBytesPerSecond = (int) (((unsigned __int64) prof->totalDecompBytes *1000)/ ms);
  145. }
  146. else
  147. {
  148. prof->DecompBytesPerSecond = 0;
  149. }
  150. prof->totalDecompBytes = 0;
  151. prof->totalDecompTime = 0;
  152. ms = (int) ((prof->totalLoadTime *1000 )/prof->freq );
  153. if ( ms )
  154. {
  155. prof->LoadBytesPerSecond = (int) (((unsigned __int64)prof->totalLoadBytes *1000)/ ms);
  156. }
  157. else
  158. {
  159. prof->LoadBytesPerSecond = 0;
  160. }
  161. prof->totalLoadBytes = 0;
  162. prof->totalLoadTime = 0;
  163. }
  164. }
  165. /******************************************************************/
  166. /* */
  167. /* */
  168. /******************************************************************/
  169. void ProfCacheLoadStart ( ProfileData *prof, int bytes )
  170. {
  171. QueryPerformanceCounter( (LARGE_INTEGER*)&prof->start );
  172. prof->dbytes = bytes;
  173. prof->start_decomp = 0;
  174. prof->pageCount++;
  175. }
  176. /******************************************************************/
  177. /* */
  178. /* */
  179. /******************************************************************/
  180. void ProfCacheAddLoadBytes ( ProfileData *prof, int bytes )
  181. {
  182. prof->dbytes += bytes;
  183. }
  184. /******************************************************************/
  185. /* */
  186. /* */
  187. /******************************************************************/
  188. void ProfCacheDecompress ( ProfileData *prof, int bytes )
  189. {
  190. QueryPerformanceCounter( (LARGE_INTEGER*)&prof->start_decomp );
  191. prof->lbytes = bytes;
  192. }
  193. /******************************************************************/
  194. /* */
  195. /* */
  196. /******************************************************************/
  197. void ProfCacheLoadEnd ( ProfileData *prof )
  198. {
  199. QueryPerformanceCounter( (LARGE_INTEGER*)&prof->end );
  200. prof->totalTime += prof->end - prof->start;
  201. prof->totalDataBytes += prof->dbytes;
  202. prof->totalFrameBytes += prof->dbytes;
  203. if ( prof->start_decomp )
  204. {
  205. prof->totalLoadTime += prof->start_decomp - prof->start;
  206. prof->totalDecompTime += prof->end - prof->start_decomp;
  207. prof->totalLoadBytes += prof->lbytes;
  208. prof->totalDecompBytes += prof->dbytes;
  209. }
  210. else
  211. {
  212. prof->totalLoadTime += prof->end - prof->start;
  213. prof->totalLoadBytes += prof->dbytes;
  214. }
  215. }
  216. /******************************************************************/
  217. /* */
  218. /* */
  219. /******************************************************************/
  220. void ProfCacheMiss ( ProfileData *prof )
  221. {
  222. prof->misses++;
  223. }
  224. /******************************************************************/
  225. /* */
  226. /* */
  227. /******************************************************************/
  228. void ProfCacheHit ( ProfileData *prof )
  229. {
  230. prof->hits++;
  231. }
  232. /******************************************************************/
  233. /* */
  234. /* */
  235. /******************************************************************/
  236. void ProfCacheAddPage ( ProfileData *prof )
  237. {
  238. prof->pagesUsed++;
  239. }
  240. /******************************************************************/
  241. /* */
  242. /* */
  243. /******************************************************************/
  244. void ProfCacheRemovePage ( ProfileData *prof )
  245. {
  246. prof->pagesUsed--;
  247. }
  248. /******************************************************************/
  249. /* */
  250. /* */
  251. /******************************************************************/
  252. void ProfCacheFill ( ProfileData *prof, int bytes )
  253. {
  254. prof->cacheUsed += bytes;
  255. }
  256. /******************************************************************/
  257. /* */
  258. /* */
  259. /******************************************************************/
  260. void ProfCacheRemove ( ProfileData *prof, int bytes )
  261. {
  262. prof->cacheUsed -= bytes;
  263. }
  264. /******************************************************************/
  265. /* */
  266. /* */
  267. /******************************************************************/
  268. void ProfCacheText ( ProfileData *prof, void ( *print) ( char *text ) )
  269. {
  270. char buf[1024];
  271. int used;
  272. int filled;
  273. print ("Audio Cache Stats\n");
  274. sprintf( buf, "Hits: %d%%\n", prof->HitPercent );
  275. print ( buf );
  276. if ( prof->numPages )
  277. {
  278. used = (prof->pagesUsed *100)/prof->numPages;
  279. }
  280. else
  281. {
  282. used = 0;
  283. }
  284. if ( prof->pagesUsed * prof->pageSize )
  285. {
  286. filled = (prof->cacheUsed *100)/ (prof->pagesUsed * prof->pageSize );
  287. }
  288. else
  289. {
  290. filled = 0;
  291. }
  292. sprintf( buf, "Used: %d%% (%d%%)\n", used, filled );
  293. print ( buf );
  294. sprintf( buf, "KbPS: %d.%02d (%d.%02d,%d.%02d)\n",
  295. prof->TotalBytesPerSecond/1024, ((prof->TotalBytesPerSecond%1024)*100)/1024,
  296. prof->LoadBytesPerSecond/1024, ((prof->LoadBytesPerSecond%1024)*100)/1024,
  297. prof->DecompBytesPerSecond/1024, ((prof->DecompBytesPerSecond%1024)*100)/1024);
  298. print ( buf );
  299. sprintf( buf, "KPF: %d.%02d\n",
  300. prof->BytesPerFrame/1024, ((prof->BytesPerFrame%1024)*100)/1024 );
  301. print ( buf );
  302. sprintf( buf, " LF: %d.%02ds; %d pages; %d Kb\n",
  303. (int) (prof->longestFrame/prof->freq), (int)(((prof->longestFrame % prof->freq)*100)/prof->freq),
  304. prof->longestFramePages, prof->longestFrameBytes/1024 );
  305. print ( buf );
  306. sprintf( buf, "NLF: %d.%02ds; %d pages; %d Kb\n",
  307. (int) (prof->nextLongestFrame/prof->freq), (int) (((prof->nextLongestFrame % prof->freq)*100)/prof->freq),
  308. prof->nextLongestFramePages, prof->nextLongestFrameBytes/1024 );
  309. print ( buf );
  310. }
  311. /******************************************************************/
  312. /* */
  313. /* */
  314. /******************************************************************/
  315. void ProfCacheUpdateInterval ( ProfileData *prof, int mseconds )
  316. {
  317. prof->update = (prof->freq * mseconds )/ 1000;
  318. }
  319. /******************************************************************/
  320. /* */
  321. /* */
  322. /******************************************************************/
  323. static ProfStamp calc_ticks ( ProfStamp start, ProfStamp end )
  324. {
  325. if ( start < end )
  326. {
  327. return end - start;
  328. }
  329. return ((ProfStamp)0xffffffffffffffff) - start + end ;
  330. }
  331. /******************************************************************/
  332. /* */
  333. /* */
  334. /******************************************************************/
  335. static void calc_stats ( ProfileCPU &prof )
  336. {
  337. if ( prof.lastCPU )
  338. {
  339. prof.cpuUsage = (int) ((prof.lastTicks*((ProfStamp)1000))/prof.lastCPU);
  340. }
  341. else
  342. {
  343. prof.cpuUsage = 0;
  344. }
  345. }
  346. /******************************************************************/
  347. /* */
  348. /* */
  349. /******************************************************************/
  350. void ProfileCPUInit ( ProfileCPU &prof )
  351. {
  352. memset ( &prof, 0, sizeof ( ProfileCPU ));
  353. if ( !QueryPerformanceFrequency( (LARGE_INTEGER*) &prof.freq ))
  354. {
  355. prof.freq = 0;
  356. }
  357. prof.updateInterval = SECONDS(1);
  358. if ( prof.freq )
  359. {
  360. prof.overflowInterval = SECONDS ( (((ProfStamp) 0xffffffffffffffff) / prof.freq) );
  361. if ( prof.overflowInterval < prof.updateInterval )
  362. {
  363. prof.updateInterval = prof.overflowInterval;
  364. }
  365. }
  366. }
  367. /******************************************************************/
  368. /* */
  369. /* */
  370. /******************************************************************/
  371. void ProfileCPUDeinit ( ProfileCPU &prof )
  372. {
  373. prof;
  374. }
  375. /******************************************************************/
  376. /* */
  377. /* */
  378. /******************************************************************/
  379. void ProfileCPUStart ( ProfileCPU &prof )
  380. {
  381. if ( prof.state == PROF_STATE_IDLE )
  382. {
  383. QueryPerformanceCounter( (LARGE_INTEGER*)&prof.start );
  384. if ( prof.lastStart )
  385. {
  386. prof.totalCPUTicks += calc_ticks ( prof.lastStart, prof.start );
  387. }
  388. prof.lastStart = prof.start;
  389. prof.state = PROF_STATE_PROFILING;
  390. }
  391. }
  392. /******************************************************************/
  393. /* */
  394. /* */
  395. /******************************************************************/
  396. void ProfileCPUPause ( ProfileCPU &prof )
  397. {
  398. if ( prof.state == PROF_STATE_PROFILING )
  399. {
  400. ProfStamp end;
  401. QueryPerformanceCounter( (LARGE_INTEGER*) &end );
  402. prof.totalTicks += calc_ticks ( prof.start, end );
  403. prof.state = PROF_STATE_PAUSED;
  404. }
  405. }
  406. /******************************************************************/
  407. /* */
  408. /* */
  409. /******************************************************************/
  410. void ProfileCPUResume ( ProfileCPU &prof )
  411. {
  412. if ( prof.state == PROF_STATE_PAUSED )
  413. {
  414. QueryPerformanceCounter( (LARGE_INTEGER*) &prof.start );
  415. prof.state = PROF_STATE_PROFILING;
  416. }
  417. }
  418. /******************************************************************/
  419. /* */
  420. /* */
  421. /******************************************************************/
  422. void ProfileCPUEnd ( ProfileCPU &prof )
  423. {
  424. ProfStamp end;
  425. QueryPerformanceCounter( (LARGE_INTEGER*) &end );
  426. if ( prof.state != PROF_STATE_IDLE )
  427. {
  428. if ( prof.start && prof.totalCPUTicks )
  429. {
  430. prof.totalTicks += calc_ticks ( prof.start, end );
  431. }
  432. prof.state = PROF_STATE_IDLE;
  433. }
  434. TimeStamp now = AudioGetTime();
  435. TimeStamp lastUpdate = now - prof.lastUpdate;
  436. if ( lastUpdate > prof.updateInterval )
  437. {
  438. prof.lastUpdate = now;
  439. if ( lastUpdate < prof.overflowInterval )
  440. {
  441. // we can use the data
  442. prof.lastTicks = prof.totalTicks;
  443. prof.lastCPU = prof.totalCPUTicks;
  444. calc_stats ( prof );
  445. }
  446. prof.totalTicks = 0;
  447. prof.totalCPUTicks = 0;
  448. }
  449. }
  450. /******************************************************************/
  451. /* */
  452. /* */
  453. /******************************************************************/
  454. int ProfileCPUUsage ( ProfileCPU &prof )
  455. {
  456. return prof.cpuUsage;
  457. }
  458. /******************************************************************/
  459. /* */
  460. /* */
  461. /******************************************************************/
  462. int ProfileCPUTicks ( ProfileCPU &prof )
  463. {
  464. prof;
  465. return 0;
  466. }
  467. /******************************************************************/
  468. /* */
  469. /* */
  470. /******************************************************************/
  471. void ProfileCPUSetName ( ProfileCPU &prof, const char *name )
  472. {
  473. strncpy ( prof.name, name, MAX_PROF_NAME );
  474. }
  475. /******************************************************************/
  476. /* */
  477. /* */
  478. /******************************************************************/
  479. void ProfileCPUPrint ( ProfileCPU &prof, void ( *print) ( char *text ) )
  480. {
  481. char buffer[200];
  482. if ( prof.freq )
  483. {
  484. sprintf ( buffer, "%s : CPU %3d.%1d / %I64d", prof.name, prof.cpuUsage/10, prof.cpuUsage%10, prof.lastTicks );
  485. }
  486. else
  487. {
  488. sprintf ( buffer, "%s : CPU (no timer)" );
  489. }
  490. print ( buffer );
  491. }
  492. /******************************************************************/
  493. /* */
  494. /* */
  495. /******************************************************************/
  496. #endif