//========= 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= 10 ) { // minor ticks y0 = y; SelectObject( hdc, hGreyPen ); for ( j=0; j=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; }