Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

561 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // MEM_PROFILE.CPP
  4. //
  5. // Memory Profiling Display
  6. //=====================================================================================//
  7. #include "vxconsole.h"
  8. #define PROFILE_MAXSAMPLES 512
  9. #define PROFILE_MEMORYHEIGHT 100
  10. #define PROFILE_NUMMINORTICKS 3
  11. #define PROFILE_LABELWIDTH 50
  12. #define PROFILE_SCALESTEPS 8
  13. #define PROFILE_MINSCALE 0.2f
  14. #define PROFILE_MAXSCALE 3.0f
  15. #define PROFILE_NUMMINORTICKS 3
  16. #define PROFILE_MAJORTICKMB 16
  17. #define PROFILE_WARNINGMB 10
  18. #define PROFILE_SEVEREMB 5
  19. #define ID_MEMPROFILE 1
  20. HWND g_memProfile_hWnd;
  21. RECT g_memProfile_WindowRect;
  22. int g_memProfile_tickMarks;
  23. int g_memProfile_colors;
  24. int g_memProfile_scale;
  25. UINT_PTR g_memProfile_Timer;
  26. int g_memProfile_numSamples;
  27. int g_memProfile_samples[PROFILE_MAXSAMPLES];
  28. //-----------------------------------------------------------------------------
  29. // MemProfile_SaveConfig
  30. //
  31. //-----------------------------------------------------------------------------
  32. void MemProfile_SaveConfig()
  33. {
  34. char buff[256];
  35. WINDOWPLACEMENT wp;
  36. // profile history
  37. if ( g_memProfile_hWnd )
  38. {
  39. memset( &wp, 0, sizeof( wp ) );
  40. wp.length = sizeof( WINDOWPLACEMENT );
  41. GetWindowPlacement( g_memProfile_hWnd, &wp );
  42. g_memProfile_WindowRect = wp.rcNormalPosition;
  43. sprintf( buff, "%d %d %d %d", wp.rcNormalPosition.left, wp.rcNormalPosition.top, wp.rcNormalPosition.right, wp.rcNormalPosition.bottom );
  44. Sys_SetRegistryString( "MemProfileWindowRect", buff );
  45. }
  46. Sys_SetRegistryInteger( "MemProfileScale", g_memProfile_scale );
  47. Sys_SetRegistryInteger( "MemProfileTickMarks", g_memProfile_tickMarks );
  48. Sys_SetRegistryInteger( "MemProfileColors", g_memProfile_colors );
  49. }
  50. //-----------------------------------------------------------------------------
  51. // MemProfile_LoadConfig
  52. //
  53. //-----------------------------------------------------------------------------
  54. void MemProfile_LoadConfig()
  55. {
  56. int numArgs;
  57. char buff[256];
  58. // profile history
  59. Sys_GetRegistryString( "MemProfileWindowRect", buff, "", sizeof( buff ) );
  60. numArgs = sscanf( buff, "%d %d %d %d", &g_memProfile_WindowRect.left, &g_memProfile_WindowRect.top, &g_memProfile_WindowRect.right, &g_memProfile_WindowRect.bottom );
  61. if ( numArgs != 4 )
  62. {
  63. memset( &g_memProfile_WindowRect, 0, sizeof( g_memProfile_WindowRect ) );
  64. }
  65. Sys_GetRegistryInteger( "MemProfileScale", 0, g_memProfile_scale );
  66. if ( g_memProfile_scale < -PROFILE_SCALESTEPS || g_memProfile_scale > PROFILE_SCALESTEPS )
  67. {
  68. g_memProfile_scale = 0;
  69. }
  70. Sys_GetRegistryInteger( "MemProfileTickMarks", 1, g_memProfile_tickMarks );
  71. Sys_GetRegistryInteger( "MemProfileColors", 1, g_memProfile_colors );
  72. }
  73. //-----------------------------------------------------------------------------
  74. // MemProfile_SetTitle
  75. //
  76. //-----------------------------------------------------------------------------
  77. void MemProfile_SetTitle()
  78. {
  79. char titleBuff[128];
  80. if ( g_memProfile_hWnd )
  81. {
  82. strcpy( titleBuff, "Free Memory Available" );
  83. if ( g_memProfile_Timer )
  84. {
  85. strcat( titleBuff, " [ON]" );
  86. }
  87. SetWindowText( g_memProfile_hWnd, titleBuff );
  88. }
  89. }
  90. //-----------------------------------------------------------------------------
  91. // MemProfile_EnableProfiling
  92. //
  93. //-----------------------------------------------------------------------------
  94. void MemProfile_EnableProfiling( bool bEnable )
  95. {
  96. if ( !g_memProfile_hWnd )
  97. {
  98. return;
  99. }
  100. UINT_PTR timer = TIMERID_MEMPROFILE;
  101. if ( bEnable && !g_memProfile_Timer )
  102. {
  103. // run at 10Hz
  104. g_memProfile_Timer = SetTimer( g_memProfile_hWnd, timer, 100, NULL );
  105. }
  106. else if ( !bEnable && g_memProfile_Timer )
  107. {
  108. KillTimer( g_memProfile_hWnd, timer );
  109. g_memProfile_Timer = NULL;
  110. }
  111. }
  112. //-----------------------------------------------------------------------------
  113. // MemProfile_UpdateWindow
  114. //
  115. //-----------------------------------------------------------------------------
  116. void MemProfile_UpdateWindow()
  117. {
  118. if ( g_memProfile_hWnd && !IsIconic( g_memProfile_hWnd ) )
  119. {
  120. // visible - force a client repaint
  121. InvalidateRect( g_memProfile_hWnd, NULL, true );
  122. }
  123. }
  124. //-----------------------------------------------------------------------------
  125. // rc_FreeMemory
  126. //
  127. //-----------------------------------------------------------------------------
  128. int rc_FreeMemory( char* commandPtr )
  129. {
  130. int errCode = -1;
  131. int freeMemory;
  132. char *cmdToken = GetToken( &commandPtr );
  133. if ( !cmdToken[0] )
  134. {
  135. goto cleanUp;
  136. }
  137. sscanf( cmdToken, "%x", &freeMemory );
  138. g_memProfile_samples[g_memProfile_numSamples % PROFILE_MAXSAMPLES] = freeMemory;
  139. g_memProfile_numSamples++;
  140. DebugCommand( "FreeMemory( 0x%8.8x )\n", freeMemory );
  141. MemProfile_UpdateWindow();
  142. // success
  143. errCode = 0;
  144. cleanUp:
  145. return ( errCode );
  146. }
  147. //-----------------------------------------------------------------------------
  148. // MemProfile_ZoomIn
  149. //
  150. //-----------------------------------------------------------------------------
  151. void MemProfile_ZoomIn( int& scale, int numSteps )
  152. {
  153. scale++;
  154. if ( scale > numSteps )
  155. {
  156. scale = numSteps;
  157. return;
  158. }
  159. MemProfile_UpdateWindow();
  160. }
  161. //-----------------------------------------------------------------------------
  162. // MemProfile_ZoomOut
  163. //
  164. //-----------------------------------------------------------------------------
  165. void MemProfile_ZoomOut( int& scale, int numSteps )
  166. {
  167. scale--;
  168. if ( scale < -numSteps )
  169. {
  170. scale = -numSteps;
  171. return;
  172. }
  173. MemProfile_UpdateWindow();
  174. }
  175. //-----------------------------------------------------------------------------
  176. // MemProfile_CalcScale
  177. //
  178. //-----------------------------------------------------------------------------
  179. float MemProfile_CalcScale( int scale, int numSteps, float min, float max )
  180. {
  181. float t;
  182. // from integral scale [-numSteps..numSteps] to float scale [min..max]
  183. t = ( float )( scale + numSteps )/( float )( 2*numSteps );
  184. t = min + t*( max-min );
  185. return t;
  186. }
  187. //-----------------------------------------------------------------------------
  188. // MemProfile_Draw
  189. //
  190. //-----------------------------------------------------------------------------
  191. void MemProfile_Draw( HDC hdc, RECT* clientRect )
  192. {
  193. char labelBuff[128];
  194. HPEN hBlackPen;
  195. HPEN hPenOld;
  196. HPEN hNullPen;
  197. HPEN hGreyPen;
  198. HBRUSH hColoredBrush;
  199. HBRUSH hBrushOld;
  200. HFONT hFontOld;
  201. int currentSample;
  202. int numTicks;
  203. int memoryHeight;
  204. int windowWidth;
  205. int windowHeight;
  206. int x;
  207. int y;
  208. int y0;
  209. int i;
  210. int j;
  211. int h;
  212. int numbars;
  213. RECT rect;
  214. float t;
  215. float scale;
  216. hBlackPen = CreatePen( PS_SOLID, 1, RGB( 0,0,0 ) );
  217. hGreyPen = CreatePen( PS_SOLID, 1, Sys_ColorScale( g_backgroundColor, 0.85f ) );
  218. hNullPen = CreatePen( PS_NULL, 0, RGB( 0,0,0 ) );
  219. hPenOld = ( HPEN )SelectObject( hdc, hBlackPen );
  220. hFontOld = SelectFont( hdc, g_hProportionalFont );
  221. // zoom
  222. scale = MemProfile_CalcScale( g_memProfile_scale, PROFILE_SCALESTEPS, PROFILE_MINSCALE, PROFILE_MAXSCALE );
  223. memoryHeight = ( int )( PROFILE_MEMORYHEIGHT*scale );
  224. windowWidth = clientRect->right-clientRect->left;
  225. windowHeight = clientRect->bottom-clientRect->top;
  226. numTicks = windowHeight/memoryHeight + 2;
  227. if ( numTicks < 0 )
  228. {
  229. numTicks = 1;
  230. }
  231. else if ( numTicks > 512/PROFILE_MAJORTICKMB + 1 )
  232. {
  233. numTicks = 512/PROFILE_MAJORTICKMB + 1;
  234. }
  235. SetBkColor( hdc, g_backgroundColor );
  236. x = 0;
  237. y = windowHeight;
  238. for ( i=0; i<numTicks; i++ )
  239. {
  240. // major ticks
  241. SelectObject( hdc, hBlackPen );
  242. MoveToEx( hdc, 0, y, NULL );
  243. LineTo( hdc, windowWidth, y );
  244. if ( g_memProfile_tickMarks )
  245. {
  246. // could be very zoomed out, gap must be enough for label, otherwise don't draw
  247. int gapY = memoryHeight/( PROFILE_NUMMINORTICKS+1 );
  248. if ( gapY >= 10 )
  249. {
  250. // minor ticks
  251. y0 = y;
  252. SelectObject( hdc, hGreyPen );
  253. for ( j=0; j<PROFILE_NUMMINORTICKS; j++ )
  254. {
  255. y0 += gapY;
  256. MoveToEx( hdc, 0, y0, NULL );
  257. LineTo( hdc, windowWidth, y0 );
  258. }
  259. }
  260. }
  261. // tick labels
  262. if ( i )
  263. {
  264. rect.left = windowWidth - 50;
  265. rect.right = windowWidth;
  266. rect.top = y - 20;
  267. rect.bottom = y;
  268. sprintf( labelBuff, "%d MB", i*PROFILE_MAJORTICKMB );
  269. DrawText( hdc, labelBuff, -1, &rect, DT_RIGHT|DT_SINGLELINE|DT_BOTTOM );
  270. }
  271. y -= memoryHeight;
  272. }
  273. // vertical bars
  274. if ( g_memProfile_numSamples )
  275. {
  276. SelectObject( hdc, hNullPen );
  277. numbars = windowWidth-PROFILE_LABELWIDTH;
  278. currentSample = g_memProfile_numSamples-1;
  279. for ( x=numbars-1; x>=0; x-=4 )
  280. {
  281. float sample = g_memProfile_samples[currentSample % PROFILE_MAXSAMPLES]/( 1024.0f * 1024.0f );
  282. y = windowHeight;
  283. t = sample/(float)PROFILE_MAJORTICKMB;
  284. h = ( int )( t * ( float )memoryHeight );
  285. if ( h )
  286. {
  287. if ( h > windowHeight )
  288. h = windowHeight;
  289. COLORREF barColor;
  290. if ( sample >= PROFILE_WARNINGMB )
  291. {
  292. barColor = RGB( 100, 255, 100 );
  293. }
  294. else if ( sample >= PROFILE_SEVEREMB )
  295. {
  296. barColor = RGB( 255, 255, 100 );
  297. }
  298. else
  299. {
  300. barColor = RGB( 255, 0, 0 );
  301. }
  302. hColoredBrush = CreateSolidBrush( g_memProfile_colors ? barColor : RGB( 80, 80, 80 ) );
  303. hBrushOld = ( HBRUSH )SelectObject( hdc, hColoredBrush );
  304. Rectangle( hdc, x-4, y-h, x, y+1 );
  305. y -= h;
  306. SelectObject( hdc, hBrushOld );
  307. DeleteObject( hColoredBrush );
  308. }
  309. currentSample--;
  310. if ( currentSample < 0 )
  311. {
  312. // no data
  313. break;
  314. }
  315. }
  316. }
  317. SelectObject( hdc, hFontOld );
  318. SelectObject( hdc, hPenOld );
  319. DeleteObject( hBlackPen );
  320. DeleteObject( hGreyPen );
  321. }
  322. //-----------------------------------------------------------------------------
  323. // MemProfile_TimerProc
  324. //
  325. //-----------------------------------------------------------------------------
  326. void MemProfile_TimerProc( HWND hwnd, UINT_PTR idEvent )
  327. {
  328. static bool busy = false;
  329. if ( busy )
  330. {
  331. return;
  332. }
  333. busy = true;
  334. if ( g_connectedToApp )
  335. {
  336. // send as async
  337. DmAPI_SendCommand( VXCONSOLE_COMMAND_PREFIX "!" "__memory__ quiet", false );
  338. }
  339. busy = false;
  340. }
  341. //-----------------------------------------------------------------------------
  342. // MemProfile_WndProc
  343. //
  344. //-----------------------------------------------------------------------------
  345. LRESULT CALLBACK MemProfile_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
  346. {
  347. WORD wID = LOWORD( wParam );
  348. HDC hdc;
  349. PAINTSTRUCT ps;
  350. RECT rect;
  351. CREATESTRUCT *createStructPtr;
  352. switch ( message )
  353. {
  354. case WM_CREATE:
  355. // set the window identifier
  356. createStructPtr = ( CREATESTRUCT* )lParam;
  357. SetWindowLong( hwnd, GWL_USERDATA+0, ( LONG )createStructPtr->lpCreateParams );
  358. // clear samples
  359. g_memProfile_numSamples = 0;
  360. memset( g_memProfile_samples, 0, sizeof( g_memProfile_samples ) );
  361. return 0L;
  362. case WM_DESTROY:
  363. MemProfile_SaveConfig();
  364. MemProfile_EnableProfiling( false );
  365. g_memProfile_hWnd = NULL;
  366. return 0L;
  367. case WM_INITMENU:
  368. CheckMenuItem( ( HMENU )wParam, IDM_MEMPROFILE_TICKMARKS, MF_BYCOMMAND | ( g_memProfile_tickMarks ? MF_CHECKED : MF_UNCHECKED ) );
  369. CheckMenuItem( ( HMENU )wParam, IDM_MEMPROFILE_COLORS, MF_BYCOMMAND | ( g_memProfile_colors ? MF_CHECKED : MF_UNCHECKED ) );
  370. CheckMenuItem( ( HMENU )wParam, IDM_MEMPROFILE_ENABLE, MF_BYCOMMAND | ( g_memProfile_Timer != NULL ? MF_CHECKED : MF_UNCHECKED ) );
  371. return 0L;
  372. case WM_PAINT:
  373. GetClientRect( hwnd, &rect );
  374. hdc = BeginPaint( hwnd, &ps );
  375. MemProfile_Draw( hdc, &rect );
  376. EndPaint( hwnd, &ps );
  377. return 0L;
  378. case WM_SIZE:
  379. // force a redraw
  380. MemProfile_UpdateWindow();
  381. return 0L;
  382. case WM_TIMER:
  383. if ( wID == TIMERID_MEMPROFILE )
  384. {
  385. MemProfile_TimerProc( hwnd, TIMERID_MEMPROFILE );
  386. return 0L;
  387. }
  388. break;
  389. case WM_KEYDOWN:
  390. switch ( wParam )
  391. {
  392. case VK_INSERT:
  393. MemProfile_ZoomIn( g_memProfile_scale, PROFILE_SCALESTEPS );
  394. return 0L;
  395. case VK_DELETE:
  396. MemProfile_ZoomOut( g_memProfile_scale, PROFILE_SCALESTEPS );
  397. return 0L;
  398. }
  399. break;
  400. case WM_COMMAND:
  401. switch ( wID )
  402. {
  403. case IDM_MEMPROFILE_TICKMARKS:
  404. g_memProfile_tickMarks ^= 1;
  405. MemProfile_UpdateWindow();
  406. return 0L;
  407. case IDM_MEMPROFILE_COLORS:
  408. g_memProfile_colors ^= 1;
  409. MemProfile_UpdateWindow();
  410. return 0L;
  411. case IDM_MEMPROFILE_ZOOMIN:
  412. MemProfile_ZoomIn( g_memProfile_scale, PROFILE_SCALESTEPS );
  413. return 0L;
  414. case IDM_MEMPROFILE_ZOOMOUT:
  415. MemProfile_ZoomOut( g_memProfile_scale, PROFILE_SCALESTEPS );
  416. return 0L;
  417. case IDM_MEMPROFILE_ENABLE:
  418. bool bEnable = ( g_memProfile_Timer != NULL );
  419. bEnable ^= 1;
  420. MemProfile_EnableProfiling( bEnable );
  421. MemProfile_SetTitle();
  422. return 0L;
  423. }
  424. break;
  425. }
  426. return ( DefWindowProc( hwnd, message, wParam, lParam ) );
  427. }
  428. //-----------------------------------------------------------------------------
  429. // MemProfile_Open
  430. //
  431. //-----------------------------------------------------------------------------
  432. void MemProfile_Open()
  433. {
  434. HWND hWnd;
  435. if ( g_memProfile_hWnd )
  436. {
  437. // only one profile instance
  438. if ( IsIconic( g_memProfile_hWnd ) )
  439. ShowWindow( g_memProfile_hWnd, SW_RESTORE );
  440. SetForegroundWindow( g_memProfile_hWnd );
  441. return;
  442. }
  443. hWnd = CreateWindowEx(
  444. WS_EX_CLIENTEDGE,
  445. "MEMPROFILECLASS",
  446. "",
  447. WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,
  448. 0,
  449. 0,
  450. 600,
  451. 500,
  452. g_hDlgMain,
  453. NULL,
  454. g_hInstance,
  455. ( void* )ID_MEMPROFILE );
  456. g_memProfile_hWnd = hWnd;
  457. MemProfile_EnableProfiling( true );
  458. MemProfile_SetTitle();
  459. if ( g_memProfile_WindowRect.right && g_memProfile_WindowRect.bottom )
  460. MoveWindow( g_memProfile_hWnd, g_memProfile_WindowRect.left, g_memProfile_WindowRect.top, g_memProfile_WindowRect.right-g_memProfile_WindowRect.left, g_memProfile_WindowRect.bottom-g_memProfile_WindowRect.top, FALSE );
  461. ShowWindow( g_memProfile_hWnd, SHOW_OPENWINDOW );
  462. }
  463. //-----------------------------------------------------------------------------
  464. // MemProfile_Init
  465. //
  466. //-----------------------------------------------------------------------------
  467. bool MemProfile_Init()
  468. {
  469. WNDCLASS wndclass;
  470. // set up our window class
  471. memset( &wndclass, 0, sizeof( wndclass ) );
  472. wndclass.style = 0;
  473. wndclass.lpfnWndProc = MemProfile_WndProc;
  474. wndclass.cbClsExtra = 0;
  475. wndclass.cbWndExtra = 0;
  476. wndclass.hInstance = g_hInstance;
  477. wndclass.hIcon = g_hIcons[ICON_APPLICATION];
  478. wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
  479. wndclass.hbrBackground = g_hBackgroundBrush;
  480. wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_MEMPROFILE );
  481. wndclass.lpszClassName = "MEMPROFILECLASS";
  482. if ( !RegisterClass( &wndclass ) )
  483. return false;
  484. MemProfile_LoadConfig();
  485. return true;
  486. }