|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// MEM_PROFILE.CPP
//
// Memory Profiling Display
//=====================================================================================//
#include "vxconsole.h"
#define PROFILE_MAXSAMPLES 512
#define PROFILE_MEMORYHEIGHT 100
#define PROFILE_NUMMINORTICKS 3
#define PROFILE_LABELWIDTH 50
#define PROFILE_SCALESTEPS 8
#define PROFILE_MINSCALE 0.2f
#define PROFILE_MAXSCALE 3.0f
#define PROFILE_NUMMINORTICKS 3
#define PROFILE_MAJORTICKMB 16
#define PROFILE_WARNINGMB 10
#define PROFILE_SEVEREMB 5
#define ID_MEMPROFILE 1
HWND g_memProfile_hWnd; RECT g_memProfile_WindowRect; int g_memProfile_tickMarks; int g_memProfile_colors; int g_memProfile_scale; UINT_PTR g_memProfile_Timer; int g_memProfile_numSamples; int g_memProfile_samples[PROFILE_MAXSAMPLES];
//-----------------------------------------------------------------------------
// MemProfile_SaveConfig
//
//-----------------------------------------------------------------------------
void MemProfile_SaveConfig() { char buff[256]; WINDOWPLACEMENT wp;
// profile history
if ( g_memProfile_hWnd ) { memset( &wp, 0, sizeof( wp ) ); wp.length = sizeof( WINDOWPLACEMENT ); GetWindowPlacement( g_memProfile_hWnd, &wp ); g_memProfile_WindowRect = wp.rcNormalPosition; sprintf( buff, "%d %d %d %d", wp.rcNormalPosition.left, wp.rcNormalPosition.top, wp.rcNormalPosition.right, wp.rcNormalPosition.bottom ); Sys_SetRegistryString( "MemProfileWindowRect", buff ); }
Sys_SetRegistryInteger( "MemProfileScale", g_memProfile_scale ); Sys_SetRegistryInteger( "MemProfileTickMarks", g_memProfile_tickMarks ); Sys_SetRegistryInteger( "MemProfileColors", g_memProfile_colors ); }
//-----------------------------------------------------------------------------
// MemProfile_LoadConfig
//
//-----------------------------------------------------------------------------
void MemProfile_LoadConfig() { int numArgs; char buff[256];
// profile history
Sys_GetRegistryString( "MemProfileWindowRect", buff, "", sizeof( buff ) ); numArgs = sscanf( buff, "%d %d %d %d", &g_memProfile_WindowRect.left, &g_memProfile_WindowRect.top, &g_memProfile_WindowRect.right, &g_memProfile_WindowRect.bottom ); if ( numArgs != 4 ) { memset( &g_memProfile_WindowRect, 0, sizeof( g_memProfile_WindowRect ) ); }
Sys_GetRegistryInteger( "MemProfileScale", 0, g_memProfile_scale ); if ( g_memProfile_scale < -PROFILE_SCALESTEPS || g_memProfile_scale > PROFILE_SCALESTEPS ) { g_memProfile_scale = 0; }
Sys_GetRegistryInteger( "MemProfileTickMarks", 1, g_memProfile_tickMarks ); Sys_GetRegistryInteger( "MemProfileColors", 1, g_memProfile_colors ); }
//-----------------------------------------------------------------------------
// MemProfile_SetTitle
//
//-----------------------------------------------------------------------------
void MemProfile_SetTitle() { char titleBuff[128];
if ( g_memProfile_hWnd ) { strcpy( titleBuff, "Free Memory Available" ); if ( g_memProfile_Timer ) { strcat( titleBuff, " [ON]" ); }
SetWindowText( g_memProfile_hWnd, titleBuff ); } }
//-----------------------------------------------------------------------------
// MemProfile_EnableProfiling
//
//-----------------------------------------------------------------------------
void MemProfile_EnableProfiling( bool bEnable ) { if ( !g_memProfile_hWnd ) { return; }
UINT_PTR timer = TIMERID_MEMPROFILE; if ( bEnable && !g_memProfile_Timer ) { // run at 10Hz
g_memProfile_Timer = SetTimer( g_memProfile_hWnd, timer, 100, NULL ); } else if ( !bEnable && g_memProfile_Timer ) { KillTimer( g_memProfile_hWnd, timer ); g_memProfile_Timer = NULL; } }
//-----------------------------------------------------------------------------
// MemProfile_UpdateWindow
//
//-----------------------------------------------------------------------------
void MemProfile_UpdateWindow() { if ( g_memProfile_hWnd && !IsIconic( g_memProfile_hWnd ) ) { // visible - force a client repaint
InvalidateRect( g_memProfile_hWnd, NULL, true ); } }
//-----------------------------------------------------------------------------
// rc_FreeMemory
//
//-----------------------------------------------------------------------------
int rc_FreeMemory( char* commandPtr ) { int errCode = -1; int freeMemory;
char *cmdToken = GetToken( &commandPtr ); if ( !cmdToken[0] ) { goto cleanUp; } sscanf( cmdToken, "%x", &freeMemory );
g_memProfile_samples[g_memProfile_numSamples % PROFILE_MAXSAMPLES] = freeMemory; g_memProfile_numSamples++;
DebugCommand( "FreeMemory( 0x%8.8x )\n", freeMemory );
MemProfile_UpdateWindow();
// success
errCode = 0;
cleanUp: return ( errCode ); }
//-----------------------------------------------------------------------------
// MemProfile_ZoomIn
//
//-----------------------------------------------------------------------------
void MemProfile_ZoomIn( int& scale, int numSteps ) { scale++; if ( scale > numSteps ) { scale = numSteps; return; } MemProfile_UpdateWindow(); }
//-----------------------------------------------------------------------------
// MemProfile_ZoomOut
//
//-----------------------------------------------------------------------------
void MemProfile_ZoomOut( int& scale, int numSteps ) { scale--; if ( scale < -numSteps ) { scale = -numSteps; return; } MemProfile_UpdateWindow(); }
//-----------------------------------------------------------------------------
// MemProfile_CalcScale
//
//-----------------------------------------------------------------------------
float MemProfile_CalcScale( int scale, int numSteps, float min, float max ) { float t;
// from integral scale [-numSteps..numSteps] to float scale [min..max]
t = ( float )( scale + numSteps )/( float )( 2*numSteps ); t = min + t*( max-min );
return t; }
//-----------------------------------------------------------------------------
// MemProfile_Draw
//
//-----------------------------------------------------------------------------
void MemProfile_Draw( HDC hdc, RECT* clientRect ) { char labelBuff[128]; HPEN hBlackPen; HPEN hPenOld; HPEN hNullPen; HPEN hGreyPen; HBRUSH hColoredBrush; HBRUSH hBrushOld; HFONT hFontOld; int currentSample; int numTicks; int memoryHeight; int windowWidth; int windowHeight; int x; int y; int y0; int i; int j; int h; int numbars; RECT rect; float t; float scale;
hBlackPen = CreatePen( PS_SOLID, 1, RGB( 0,0,0 ) ); hGreyPen = CreatePen( PS_SOLID, 1, Sys_ColorScale( g_backgroundColor, 0.85f ) ); hNullPen = CreatePen( PS_NULL, 0, RGB( 0,0,0 ) ); hPenOld = ( HPEN )SelectObject( hdc, hBlackPen ); hFontOld = SelectFont( hdc, g_hProportionalFont );
// zoom
scale = MemProfile_CalcScale( g_memProfile_scale, PROFILE_SCALESTEPS, PROFILE_MINSCALE, PROFILE_MAXSCALE ); memoryHeight = ( int )( PROFILE_MEMORYHEIGHT*scale ); windowWidth = clientRect->right-clientRect->left; windowHeight = clientRect->bottom-clientRect->top;
numTicks = windowHeight/memoryHeight + 2; if ( numTicks < 0 ) { numTicks = 1; } else if ( numTicks > 512/PROFILE_MAJORTICKMB + 1 ) { numTicks = 512/PROFILE_MAJORTICKMB + 1; }
SetBkColor( hdc, g_backgroundColor );
x = 0; y = windowHeight; for ( i=0; i<numTicks; i++ ) { // major ticks
SelectObject( hdc, hBlackPen ); MoveToEx( hdc, 0, y, NULL ); LineTo( hdc, windowWidth, y );
if ( g_memProfile_tickMarks ) { // could be very zoomed out, gap must be enough for label, otherwise don't draw
int gapY = memoryHeight/( PROFILE_NUMMINORTICKS+1 ); if ( gapY >= 10 ) { // minor ticks
y0 = y; SelectObject( hdc, hGreyPen ); for ( j=0; j<PROFILE_NUMMINORTICKS; j++ ) { y0 += gapY; MoveToEx( hdc, 0, y0, NULL ); LineTo( hdc, windowWidth, y0 ); } } }
// tick labels
if ( i ) { rect.left = windowWidth - 50; rect.right = windowWidth; rect.top = y - 20; rect.bottom = y; sprintf( labelBuff, "%d MB", i*PROFILE_MAJORTICKMB ); DrawText( hdc, labelBuff, -1, &rect, DT_RIGHT|DT_SINGLELINE|DT_BOTTOM ); }
y -= memoryHeight; }
// vertical bars
if ( g_memProfile_numSamples ) { SelectObject( hdc, hNullPen );
numbars = windowWidth-PROFILE_LABELWIDTH; currentSample = g_memProfile_numSamples-1; for ( x=numbars-1; x>=0; x-=4 ) { float sample = g_memProfile_samples[currentSample % PROFILE_MAXSAMPLES]/( 1024.0f * 1024.0f );
y = windowHeight; t = sample/(float)PROFILE_MAJORTICKMB; h = ( int )( t * ( float )memoryHeight ); if ( h ) { if ( h > windowHeight ) h = windowHeight; COLORREF barColor; if ( sample >= PROFILE_WARNINGMB ) { barColor = RGB( 100, 255, 100 ); } else if ( sample >= PROFILE_SEVEREMB ) { barColor = RGB( 255, 255, 100 ); } else { barColor = RGB( 255, 0, 0 ); }
hColoredBrush = CreateSolidBrush( g_memProfile_colors ? barColor : RGB( 80, 80, 80 ) ); hBrushOld = ( HBRUSH )SelectObject( hdc, hColoredBrush );
Rectangle( hdc, x-4, y-h, x, y+1 ); y -= h;
SelectObject( hdc, hBrushOld ); DeleteObject( hColoredBrush ); }
currentSample--; if ( currentSample < 0 ) { // no data
break; } } }
SelectObject( hdc, hFontOld ); SelectObject( hdc, hPenOld ); DeleteObject( hBlackPen ); DeleteObject( hGreyPen ); }
//-----------------------------------------------------------------------------
// MemProfile_TimerProc
//
//-----------------------------------------------------------------------------
void MemProfile_TimerProc( HWND hwnd, UINT_PTR idEvent ) { static bool busy = false;
if ( busy ) { return; }
busy = true;
if ( g_connectedToApp ) { // send as async
DmAPI_SendCommand( VXCONSOLE_COMMAND_PREFIX "!" "__memory__ quiet", false ); }
busy = false; }
//-----------------------------------------------------------------------------
// MemProfile_WndProc
//
//-----------------------------------------------------------------------------
LRESULT CALLBACK MemProfile_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { WORD wID = LOWORD( wParam ); HDC hdc; PAINTSTRUCT ps; RECT rect; CREATESTRUCT *createStructPtr;
switch ( message ) { case WM_CREATE: // set the window identifier
createStructPtr = ( CREATESTRUCT* )lParam; SetWindowLong( hwnd, GWL_USERDATA+0, ( LONG )createStructPtr->lpCreateParams );
// clear samples
g_memProfile_numSamples = 0; memset( g_memProfile_samples, 0, sizeof( g_memProfile_samples ) ); return 0L;
case WM_DESTROY: MemProfile_SaveConfig(); MemProfile_EnableProfiling( false ); g_memProfile_hWnd = NULL; return 0L;
case WM_INITMENU: CheckMenuItem( ( HMENU )wParam, IDM_MEMPROFILE_TICKMARKS, MF_BYCOMMAND | ( g_memProfile_tickMarks ? MF_CHECKED : MF_UNCHECKED ) ); CheckMenuItem( ( HMENU )wParam, IDM_MEMPROFILE_COLORS, MF_BYCOMMAND | ( g_memProfile_colors ? MF_CHECKED : MF_UNCHECKED ) ); CheckMenuItem( ( HMENU )wParam, IDM_MEMPROFILE_ENABLE, MF_BYCOMMAND | ( g_memProfile_Timer != NULL ? MF_CHECKED : MF_UNCHECKED ) ); return 0L;
case WM_PAINT: GetClientRect( hwnd, &rect ); hdc = BeginPaint( hwnd, &ps ); MemProfile_Draw( hdc, &rect ); EndPaint( hwnd, &ps ); return 0L;
case WM_SIZE: // force a redraw
MemProfile_UpdateWindow(); return 0L;
case WM_TIMER: if ( wID == TIMERID_MEMPROFILE ) { MemProfile_TimerProc( hwnd, TIMERID_MEMPROFILE ); return 0L; } break;
case WM_KEYDOWN: switch ( wParam ) { case VK_INSERT: MemProfile_ZoomIn( g_memProfile_scale, PROFILE_SCALESTEPS ); return 0L;
case VK_DELETE: MemProfile_ZoomOut( g_memProfile_scale, PROFILE_SCALESTEPS ); return 0L; } break;
case WM_COMMAND: switch ( wID ) { case IDM_MEMPROFILE_TICKMARKS: g_memProfile_tickMarks ^= 1; MemProfile_UpdateWindow(); return 0L;
case IDM_MEMPROFILE_COLORS: g_memProfile_colors ^= 1; MemProfile_UpdateWindow(); return 0L;
case IDM_MEMPROFILE_ZOOMIN: MemProfile_ZoomIn( g_memProfile_scale, PROFILE_SCALESTEPS ); return 0L;
case IDM_MEMPROFILE_ZOOMOUT: MemProfile_ZoomOut( g_memProfile_scale, PROFILE_SCALESTEPS ); return 0L;
case IDM_MEMPROFILE_ENABLE: bool bEnable = ( g_memProfile_Timer != NULL ); bEnable ^= 1; MemProfile_EnableProfiling( bEnable ); MemProfile_SetTitle(); return 0L; } break; } return ( DefWindowProc( hwnd, message, wParam, lParam ) ); }
//-----------------------------------------------------------------------------
// MemProfile_Open
//
//-----------------------------------------------------------------------------
void MemProfile_Open() { HWND hWnd; if ( g_memProfile_hWnd ) { // only one profile instance
if ( IsIconic( g_memProfile_hWnd ) ) ShowWindow( g_memProfile_hWnd, SW_RESTORE ); SetForegroundWindow( g_memProfile_hWnd ); return; }
hWnd = CreateWindowEx( WS_EX_CLIENTEDGE, "MEMPROFILECLASS", "", WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, 0, 0, 600, 500, g_hDlgMain, NULL, g_hInstance, ( void* )ID_MEMPROFILE ); g_memProfile_hWnd = hWnd;
MemProfile_EnableProfiling( true ); MemProfile_SetTitle();
if ( g_memProfile_WindowRect.right && g_memProfile_WindowRect.bottom ) 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 ); ShowWindow( g_memProfile_hWnd, SHOW_OPENWINDOW ); }
//-----------------------------------------------------------------------------
// MemProfile_Init
//
//-----------------------------------------------------------------------------
bool MemProfile_Init() { WNDCLASS wndclass;
// set up our window class
memset( &wndclass, 0, sizeof( wndclass ) ); wndclass.style = 0; wndclass.lpfnWndProc = MemProfile_WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = g_hInstance; wndclass.hIcon = g_hIcons[ICON_APPLICATION]; wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); wndclass.hbrBackground = g_hBackgroundBrush; wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_MEMPROFILE ); wndclass.lpszClassName = "MEMPROFILECLASS"; if ( !RegisterClass( &wndclass ) ) return false; MemProfile_LoadConfig();
return true; }
|