//========= Copyright Valve Corporation, All rights reserved. ============// // // SHOW_MEMDUMP.CPP // // Show Mem Dump Display. //=====================================================================================// #include "vxconsole.h" #define ID_SHOWMEMDUMP_LISTVIEW 100 // column id, pool mode #define ID_DUMPPOOL_POOL 0 #define ID_DUMPPOOL_SIZE 1 #define ID_DUMPPOOL_ALLOCATED 2 #define ID_DUMPPOOL_FREE 3 #define ID_DUMPPOOL_COMMITTED 4 #define ID_DUMPPOOL_COMMITTEDSIZE 5 // column id, detailed mode #define ID_DUMPDETAIL_ALLOCATION 0 #define ID_DUMPDETAIL_CURRENTSIZE 1 #define ID_DUMPDETAIL_PEAKSIZE 2 #define ID_DUMPDETAIL_TOTALSIZE 3 #define ID_DUMPDETAIL_OVERHEAD 4 #define ID_DUMPDETAIL_PEAKOVERHEAD 5 #define ID_DUMPDETAIL_TIME 6 #define ID_DUMPDETAIL_CURRENTCOUNT 7 #define ID_DUMPDETAIL_PEAKCOUNT 8 #define ID_DUMPDETAIL_TOTALCOUNT 9 #define ID_DUMPDETAIL_LTE16 10 #define ID_DUMPDETAIL_LTE32 11 #define ID_DUMPDETAIL_LTE128 12 #define ID_DUMPDETAIL_LTE1024 13 #define ID_DUMPDETAIL_GT1024 14 #define SHOW_BYTES 0 #define SHOW_KILOBYTES 1 #define SHOW_MEGABYTES 2 #define FORMAT_POOLS 0 #define FORMAT_DETAILS 1 struct MemoryPool_t { int pool; char poolBuff[32]; int size; char sizeBuff[32]; int allocated; char allocatedBuff[32]; int free; char freeBuff[32]; int committed; char committedBuff[32]; int committedSize; char committedSizeBuff[32]; }; struct MemoryDetail_t { char *pAllocationName; int currentSize; char currentSizeBuff[32]; int peakSize; char peakSizeBuff[32]; int totalSize; char totalSizeBuff[32]; int overheadSize; char overheadSizeBuff[32]; int peakOverheadSize; char peakOverheadSizeBuff[32]; int time; char timeBuff[32]; int currentCount; char currentCountBuff[32]; int peakCount; char peakCountBuff[32]; int totalCount; char totalCountBuff[32]; int lte16; char lte16Buff[32]; int lte32; char lte32Buff[32]; int lte128; char lte128Buff[32]; int lte1024; char lte1024Buff[32]; int gt1024; char gt1024Buff[32]; }; struct memory_t { int listIndex; MemoryPool_t pool; MemoryDetail_t detail; }; struct label_t { const CHAR* name; int width; int subItemIndex; CHAR nameBuff[64]; }; HWND g_showMemDump_hWnd; HWND g_showMemDump_hWndListView; RECT g_showMemDump_windowRect; int g_showMemDump_sortColumn; int g_showMemDump_sortDescending; memory_t *g_showMemDump_pMemory; int g_showMemDump_numMemory; int g_showMemDump_showBytes; bool g_showMemDump_bCollapseOutput; char g_showMemDump_currentFilename[MAX_PATH]; int g_showMemDump_format; void ShowMemDump_Parse( const char *pBuffer, int fileSize ); label_t g_showMemDump_PoolLabels[] = { {"Pool", 120, ID_DUMPPOOL_POOL}, {"Size", 120, ID_DUMPPOOL_SIZE}, {"Allocated Count", 120, ID_DUMPPOOL_ALLOCATED}, {"Free Count", 120, ID_DUMPPOOL_FREE}, {"Committed Count", 120, ID_DUMPPOOL_COMMITTED}, {"Committed Size", 120, ID_DUMPPOOL_COMMITTEDSIZE}, }; label_t g_showMemDump_DetailLabels[] = { {"Allocation", 200, ID_DUMPDETAIL_ALLOCATION}, {"Current Size", 120, ID_DUMPDETAIL_CURRENTSIZE}, {"Peak Size", 120, ID_DUMPDETAIL_PEAKSIZE}, {"Total Allocations", 120, ID_DUMPDETAIL_TOTALSIZE}, {"Overhead Size", 120, ID_DUMPDETAIL_OVERHEAD}, {"Peak Overhead Size", 120, ID_DUMPDETAIL_PEAKOVERHEAD}, {"Time (ms)", 120, ID_DUMPDETAIL_TIME}, {"Current Count", 120, ID_DUMPDETAIL_CURRENTCOUNT}, {"Peak Count", 120, ID_DUMPDETAIL_PEAKCOUNT}, {"Total Count", 120, ID_DUMPDETAIL_TOTALCOUNT}, {"<=16 bytes", 100, ID_DUMPDETAIL_LTE16}, {"17-32 bytes", 100, ID_DUMPDETAIL_LTE32}, {"33-128 bytes", 100, ID_DUMPDETAIL_LTE128}, {"129-1024 bytes", 100, ID_DUMPDETAIL_LTE1024}, {"> 1024 bytes", 100, ID_DUMPDETAIL_GT1024}, }; //----------------------------------------------------------------------------- // ShowMemDump_FormatSize // //----------------------------------------------------------------------------- char *ShowMemDump_FormatSize( int size, char *pBuff, bool bUnits ) { switch ( g_showMemDump_showBytes ) { case SHOW_BYTES: sprintf( pBuff, "%d", size ); break; case SHOW_KILOBYTES: sprintf( pBuff, "%.2f", (float)size/1024.0f ); if ( bUnits ) strcat( pBuff, " K"); break; case SHOW_MEGABYTES: sprintf( pBuff, "%.2f", (float)size/(1024.0f*1024.0f) ); if ( bUnits ) strcat( pBuff, " MB"); break; } return pBuff; } //----------------------------------------------------------------------------- // ShowMemDump_SaveConfig // //----------------------------------------------------------------------------- void ShowMemDump_SaveConfig() { char buff[256]; Sys_SetRegistryInteger( "showMemDumpSortColumn", g_showMemDump_sortColumn ); Sys_SetRegistryInteger( "showMemDumpSortDescending", g_showMemDump_sortDescending ); Sys_SetRegistryInteger( "showMemDumpShowBytes", g_showMemDump_showBytes ); WINDOWPLACEMENT wp; memset( &wp, 0, sizeof( wp ) ); wp.length = sizeof( WINDOWPLACEMENT ); GetWindowPlacement( g_showMemDump_hWnd, &wp ); g_showMemDump_windowRect = wp.rcNormalPosition; sprintf( buff, "%d %d %d %d", g_showMemDump_windowRect.left, g_showMemDump_windowRect.top, g_showMemDump_windowRect.right, g_showMemDump_windowRect.bottom ); Sys_SetRegistryString( "showMemDumpWindowRect", buff ); } //----------------------------------------------------------------------------- // ShowMemDump_LoadConfig // //----------------------------------------------------------------------------- void ShowMemDump_LoadConfig() { int numArgs; char buff[256]; Sys_GetRegistryInteger( "showMemDumpSortColumn", 0, g_showMemDump_sortColumn ); Sys_GetRegistryInteger( "showMemDumpSortDescending", false, g_showMemDump_sortDescending ); Sys_GetRegistryInteger( "showMemDumpShowBytes", SHOW_KILOBYTES, g_showMemDump_showBytes ); Sys_GetRegistryString( "showMemDumpWindowRect", buff, "", sizeof( buff ) ); numArgs = sscanf( buff, "%d %d %d %d", &g_showMemDump_windowRect.left, &g_showMemDump_windowRect.top, &g_showMemDump_windowRect.right, &g_showMemDump_windowRect.bottom ); if ( numArgs != 4 || g_showMemDump_windowRect.left < 0 || g_showMemDump_windowRect.top < 0 || g_showMemDump_windowRect.right < 0 || g_showMemDump_windowRect.bottom < 0 ) memset( &g_showMemDump_windowRect, 0, sizeof( g_showMemDump_windowRect ) ); } //----------------------------------------------------------------------------- // ShowMemDump_Clear // //----------------------------------------------------------------------------- void ShowMemDump_Clear() { // delete all the list view entries if ( g_showMemDump_hWnd ) { ListView_DeleteAllItems( g_showMemDump_hWndListView ); } if ( !g_showMemDump_pMemory ) return; for ( int i=0; i1024 Byte Allocations" ); fprintf( fp, "\n" ); // dump to the log for ( i=0; i 1024:\t\t\t%d\n", g_showMemDump_numMemory, (float)currentSize/( 1024.0F*1024.0F ), (float)peakSize/( 1024.0F*1024.0F ), (float)totalSize/( 1024.0F*1024.0F ), overheadSize, peakOverheadSize, time, currentCount, peakCount, totalCount, lte16, lte32, lte128, lte1024, gt1024 ); MessageBox( g_showMemDump_hWnd, buff, "Memory Dump Summary", MB_OK|MB_APPLMODAL ); } //----------------------------------------------------------------------------- // ShowMemDump_SetTitle // //----------------------------------------------------------------------------- void ShowMemDump_SetTitle() { if ( g_showMemDump_hWnd ) { SetWindowText( g_showMemDump_hWnd, "Memory Dump" ); } } //----------------------------------------------------------------------------- // ShowMemDump_CompareFunc // //----------------------------------------------------------------------------- int CALLBACK ShowMemDump_CompareFunc( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort ) { memory_t* pMemoryA = (memory_t*)lParam1; memory_t* pMemoryB = (memory_t*)lParam2; int sort = 0; if ( g_showMemDump_format == FORMAT_POOLS ) { switch ( g_showMemDump_sortColumn ) { case ID_DUMPPOOL_POOL: sort = pMemoryA->pool.pool - pMemoryB->pool.pool; break; case ID_DUMPPOOL_SIZE: sort = pMemoryA->pool.size - pMemoryB->pool.size; break; case ID_DUMPPOOL_ALLOCATED: sort = pMemoryA->pool.allocated - pMemoryB->pool.allocated; break; case ID_DUMPPOOL_FREE: sort = pMemoryA->pool.free - pMemoryB->pool.free; break; case ID_DUMPPOOL_COMMITTED: sort = pMemoryA->pool.committed - pMemoryB->pool.committed; break; case ID_DUMPPOOL_COMMITTEDSIZE: sort = pMemoryA->pool.committedSize - pMemoryB->pool.committedSize; break; } } else { switch ( g_showMemDump_sortColumn ) { case ID_DUMPDETAIL_ALLOCATION: sort = stricmp( pMemoryA->detail.pAllocationName, pMemoryB->detail.pAllocationName ); break; case ID_DUMPDETAIL_CURRENTSIZE: sort = pMemoryA->detail.currentSize - pMemoryB->detail.currentSize; break; case ID_DUMPDETAIL_PEAKSIZE: sort = pMemoryA->detail.peakSize - pMemoryB->detail.peakSize; break; case ID_DUMPDETAIL_TOTALSIZE: sort = pMemoryA->detail.totalSize - pMemoryB->detail.totalSize; break; case ID_DUMPDETAIL_OVERHEAD: sort = pMemoryA->detail.overheadSize - pMemoryB->detail.overheadSize; break; case ID_DUMPDETAIL_PEAKOVERHEAD: sort = pMemoryA->detail.peakOverheadSize - pMemoryB->detail.peakOverheadSize; break; case ID_DUMPDETAIL_TIME: sort = pMemoryA->detail.time - pMemoryB->detail.time; break; case ID_DUMPDETAIL_CURRENTCOUNT: sort = pMemoryA->detail.currentCount - pMemoryB->detail.currentCount; break; case ID_DUMPDETAIL_PEAKCOUNT: sort = pMemoryA->detail.peakCount - pMemoryB->detail.peakCount; break; case ID_DUMPDETAIL_TOTALCOUNT: sort = pMemoryA->detail.totalCount - pMemoryB->detail.totalCount; break; case ID_DUMPDETAIL_LTE16: sort = pMemoryA->detail.lte16 - pMemoryB->detail.lte16; break; case ID_DUMPDETAIL_LTE32: sort = pMemoryA->detail.lte32 - pMemoryB->detail.lte32; break; case ID_DUMPDETAIL_LTE128: sort = pMemoryA->detail.lte128 - pMemoryB->detail.lte128; break; case ID_DUMPDETAIL_LTE1024: sort = pMemoryA->detail.lte1024 - pMemoryB->detail.lte1024; break; case ID_DUMPDETAIL_GT1024: sort = pMemoryA->detail.gt1024 - pMemoryB->detail.gt1024; break; } } // flip the sort order if ( g_showMemDump_sortDescending ) { sort *= -1; } return ( sort ); } //----------------------------------------------------------------------------- // ShowMemDump_SortItems // //----------------------------------------------------------------------------- void ShowMemDump_SortItems() { LVITEM lvitem; memory_t *pMemory; int i; if ( !g_showMemDump_hWnd ) { // only sort if window is visible return; } ListView_SortItems( g_showMemDump_hWndListView, ShowMemDump_CompareFunc, 0 ); memset( &lvitem, 0, sizeof( lvitem ) ); lvitem.mask = LVIF_PARAM; // get each item and reset its list index int itemCount = ListView_GetItemCount( g_showMemDump_hWndListView ); for ( i=0; ilistIndex = i; } int count; label_t* pLabels; if ( g_showMemDump_format == FORMAT_POOLS ) { count = sizeof( g_showMemDump_PoolLabels )/sizeof( g_showMemDump_PoolLabels[0] ); pLabels = g_showMemDump_PoolLabels; } else { count = sizeof( g_showMemDump_DetailLabels )/sizeof( g_showMemDump_DetailLabels[0] ); pLabels = g_showMemDump_DetailLabels; } // update list view columns with sort key for ( i = 0; i < count; i++ ) { char symbol; LVCOLUMN lvc; if ( i == g_showMemDump_sortColumn ) symbol = g_showMemDump_sortDescending ? '<' : '>'; else symbol = ' '; sprintf( pLabels[i].nameBuff, "%s %c", pLabels[i].name, symbol ); memset( &lvc, 0, sizeof( lvc ) ); lvc.mask = LVCF_TEXT; lvc.pszText = (LPSTR)pLabels[i].nameBuff; ListView_SetColumn( g_showMemDump_hWndListView, i, &lvc ); } } //----------------------------------------------------------------------------- // ShowMemDump_FormatItems // //----------------------------------------------------------------------------- void ShowMemDump_FormatItems() { if ( g_showMemDump_format == FORMAT_POOLS ) { for ( int i = 0; i < g_showMemDump_numMemory; i++ ) { sprintf( g_showMemDump_pMemory[i].pool.sizeBuff, "%d", g_showMemDump_pMemory[i].pool.size ); ShowMemDump_FormatSize( g_showMemDump_pMemory[i].pool.committedSize, g_showMemDump_pMemory[i].pool.committedSizeBuff, true ); } } else { for ( int i = 0; i < g_showMemDump_numMemory; i++ ) { ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.currentSize, g_showMemDump_pMemory[i].detail.currentSizeBuff, true ); ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.peakSize, g_showMemDump_pMemory[i].detail.peakSizeBuff, true ); ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.totalSize, g_showMemDump_pMemory[i].detail.totalSizeBuff, true ); ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.overheadSize, g_showMemDump_pMemory[i].detail.overheadSizeBuff, true ); ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.peakOverheadSize, g_showMemDump_pMemory[i].detail.peakOverheadSizeBuff, true ); } } ShowMemDump_SortItems(); } //----------------------------------------------------------------------------- // ShowMemDump_AddViewItem // //----------------------------------------------------------------------------- void ShowMemDump_AddViewItem( memory_t* pMemory ) { LVITEM lvi; if ( !g_showMemDump_hWnd ) { // only valid if log window is visible return; } // update the text callback buffers if ( g_showMemDump_format == FORMAT_POOLS ) { sprintf( pMemory->pool.sizeBuff, "%d", pMemory->pool.size ); sprintf( pMemory->pool.poolBuff, "%d", pMemory->pool.pool ); sprintf( pMemory->pool.allocatedBuff, "%d", pMemory->pool.allocated ); sprintf( pMemory->pool.freeBuff, "%d", pMemory->pool.free ); sprintf( pMemory->pool.committedBuff, "%d", pMemory->pool.committed ); ShowMemDump_FormatSize( pMemory->pool.committedSize, pMemory->pool.committedSizeBuff, true ); } else { ShowMemDump_FormatSize( pMemory->detail.currentSize, pMemory->detail.currentSizeBuff, true ); ShowMemDump_FormatSize( pMemory->detail.peakSize, pMemory->detail.peakSizeBuff, true ); ShowMemDump_FormatSize( pMemory->detail.totalSize, pMemory->detail.totalSizeBuff, true ); ShowMemDump_FormatSize( pMemory->detail.overheadSize, pMemory->detail.overheadSizeBuff, true ); ShowMemDump_FormatSize( pMemory->detail.peakOverheadSize, pMemory->detail.peakOverheadSizeBuff, true ); sprintf( pMemory->detail.timeBuff, "%d", pMemory->detail.time ); sprintf( pMemory->detail.currentCountBuff, "%d", pMemory->detail.currentCount ); sprintf( pMemory->detail.peakCountBuff, "%d", pMemory->detail.peakCount ); sprintf( pMemory->detail.totalCountBuff, "%d", pMemory->detail.totalCount ); sprintf( pMemory->detail.lte16Buff, "%d", pMemory->detail.lte16 ); sprintf( pMemory->detail.lte32Buff, "%d", pMemory->detail.lte32 ); sprintf( pMemory->detail.lte128Buff, "%d", pMemory->detail.lte128 ); sprintf( pMemory->detail.lte1024Buff, "%d", pMemory->detail.lte1024 ); sprintf( pMemory->detail.gt1024Buff, "%d", pMemory->detail.gt1024 ); } int itemCount = ListView_GetItemCount( g_showMemDump_hWndListView ); // setup and insert at end of list memset( &lvi, 0, sizeof( lvi ) ); lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; lvi.iItem = itemCount; lvi.iSubItem = 0; lvi.state = 0; lvi.stateMask = 0; lvi.pszText = LPSTR_TEXTCALLBACK; lvi.lParam = (LPARAM)pMemory; // insert and set the real index pMemory->listIndex = ListView_InsertItem( g_showMemDump_hWndListView, &lvi ); } //----------------------------------------------------------------------------- // ShowMemDump_Refresh // //----------------------------------------------------------------------------- void ShowMemDump_Refresh() { // send the command to application which replies with list data if ( g_connectedToApp ) { ProcessCommand( "mem_dump" ); } } //----------------------------------------------------------------------------- // ShowMemDump_RefreshView // //----------------------------------------------------------------------------- void ShowMemDump_RefreshView() { if ( strlen( g_showMemDump_currentFilename ) == 0 ) { // first time ShowMemDump_Refresh(); return; } // get current file int fileSize; char *pBuffer; bool bSuccess = LoadTargetFile( g_showMemDump_currentFilename, &fileSize, (void **)&pBuffer ); if ( !bSuccess ) { // stale, try again ShowMemDump_Refresh(); return; } // parse and update view ShowMemDump_Parse( pBuffer, fileSize ); Sys_Free( pBuffer ); } //----------------------------------------------------------------------------- // ShowMemDump_PopulateList // //----------------------------------------------------------------------------- void ShowMemDump_PopulateList() { // delete previous labels while ( 1 ) { if ( !ListView_DeleteColumn( g_showMemDump_hWndListView, 0 ) ) { break; } } int count; label_t* pLabels; if ( g_showMemDump_format == FORMAT_POOLS ) { count = sizeof( g_showMemDump_PoolLabels )/sizeof( g_showMemDump_PoolLabels[0] ); pLabels = g_showMemDump_PoolLabels; } else { count = sizeof( g_showMemDump_DetailLabels )/sizeof( g_showMemDump_DetailLabels[0] ); pLabels = g_showMemDump_DetailLabels; } // init list view columns for ( int i = 0; i < count; i++ ) { LVCOLUMN lvc; memset( &lvc, 0, sizeof( lvc ) ); lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM; lvc.iSubItem = 0; lvc.cx = pLabels[i].width; lvc.fmt = LVCFMT_LEFT; lvc.pszText = ( LPSTR )pLabels[i].name; ListView_InsertColumn( g_showMemDump_hWndListView, i, &lvc ); } // populate list view for ( int i = 0; i < g_showMemDump_numMemory; i++ ) { ShowMemDump_AddViewItem( &g_showMemDump_pMemory[i] ); } ShowMemDump_SortItems(); } //----------------------------------------------------------------------------- // ShowMemDump_SizeWindow // //----------------------------------------------------------------------------- void ShowMemDump_SizeWindow( HWND hwnd, int cx, int cy ) { if ( cx==0 || cy==0 ) { RECT rcClient; GetClientRect( hwnd, &rcClient ); cx = rcClient.right; cy = rcClient.bottom; } // position the ListView SetWindowPos( g_showMemDump_hWndListView, NULL, 0, 0, cx, cy, SWP_NOZORDER ); } //----------------------------------------------------------------------------- // ShowMemDump_WndProc // //----------------------------------------------------------------------------- LRESULT CALLBACK ShowMemDump_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { WORD wID = LOWORD( wParam ); memory_t* pMemory; switch ( message ) { case WM_CREATE: return 0L; case WM_DESTROY: ShowMemDump_SaveConfig(); g_showMemDump_hWnd = NULL; return 0L; case WM_INITMENU: CheckMenuItem( (HMENU)wParam, IDM_OPTIONS_BYTES, MF_BYCOMMAND | ( g_showMemDump_showBytes == SHOW_BYTES ? MF_CHECKED : MF_UNCHECKED ) ); CheckMenuItem( (HMENU)wParam, IDM_OPTIONS_KILOBYTES, MF_BYCOMMAND | ( g_showMemDump_showBytes == SHOW_KILOBYTES ? MF_CHECKED : MF_UNCHECKED ) ); CheckMenuItem( (HMENU)wParam, IDM_OPTIONS_MEGABYTES, MF_BYCOMMAND | ( g_showMemDump_showBytes == SHOW_MEGABYTES ? MF_CHECKED : MF_UNCHECKED ) ); CheckMenuItem( (HMENU)wParam, IDM_OPTIONS_COLLAPSEOUTPUT, MF_BYCOMMAND | ( g_showMemDump_bCollapseOutput ? MF_CHECKED : MF_UNCHECKED ) ); return 0L; case WM_SIZE: ShowMemDump_SizeWindow( hwnd, LOWORD( lParam ), HIWORD( lParam ) ); return 0L; case WM_NOTIFY: switch ( ( ( LPNMHDR )lParam )->code ) { case LVN_COLUMNCLICK: NMLISTVIEW* pnmlv; pnmlv = ( NMLISTVIEW* )lParam; if ( g_showMemDump_sortColumn == pnmlv->iSubItem ) { // user has clicked on same column - flip the sort g_showMemDump_sortDescending ^= 1; } else { // sort by new column g_showMemDump_sortColumn = pnmlv->iSubItem; } ShowMemDump_SortItems(); return 0L; case LVN_GETDISPINFO: NMLVDISPINFO* plvdi; plvdi = (NMLVDISPINFO*)lParam; pMemory = (memory_t*)plvdi->item.lParam; if ( g_showMemDump_format == FORMAT_POOLS ) { switch ( plvdi->item.iSubItem ) { case ID_DUMPPOOL_POOL: plvdi->item.pszText = pMemory->pool.poolBuff; return 0L; case ID_DUMPPOOL_SIZE: plvdi->item.pszText = pMemory->pool.sizeBuff; return 0L; case ID_DUMPPOOL_ALLOCATED: plvdi->item.pszText = pMemory->pool.allocatedBuff; return 0L; case ID_DUMPPOOL_FREE: plvdi->item.pszText = pMemory->pool.freeBuff; return 0L; case ID_DUMPPOOL_COMMITTED: plvdi->item.pszText = pMemory->pool.committedBuff; return 0L; case ID_DUMPPOOL_COMMITTEDSIZE: plvdi->item.pszText = pMemory->pool.committedSizeBuff; return 0L; } } else { switch ( plvdi->item.iSubItem ) { case ID_DUMPDETAIL_ALLOCATION: plvdi->item.pszText = pMemory->detail.pAllocationName; return 0L; case ID_DUMPDETAIL_CURRENTSIZE: plvdi->item.pszText = pMemory->detail.currentSizeBuff; return 0L; case ID_DUMPDETAIL_PEAKSIZE: plvdi->item.pszText = pMemory->detail.peakSizeBuff; return 0L; case ID_DUMPDETAIL_TOTALSIZE: plvdi->item.pszText = pMemory->detail.totalSizeBuff; return 0L; case ID_DUMPDETAIL_OVERHEAD: plvdi->item.pszText = pMemory->detail.overheadSizeBuff; return 0L; case ID_DUMPDETAIL_PEAKOVERHEAD: plvdi->item.pszText = pMemory->detail.peakOverheadSizeBuff; return 0L; case ID_DUMPDETAIL_TIME: plvdi->item.pszText = pMemory->detail.timeBuff; return 0L; case ID_DUMPDETAIL_CURRENTCOUNT: plvdi->item.pszText = pMemory->detail.currentCountBuff; return 0L; case ID_DUMPDETAIL_PEAKCOUNT: plvdi->item.pszText = pMemory->detail.peakCountBuff; return 0L; case ID_DUMPDETAIL_TOTALCOUNT: plvdi->item.pszText = pMemory->detail.totalCountBuff; return 0L; case ID_DUMPDETAIL_LTE16: plvdi->item.pszText = pMemory->detail.lte16Buff; return 0L; case ID_DUMPDETAIL_LTE32: plvdi->item.pszText = pMemory->detail.lte32Buff; return 0L; case ID_DUMPDETAIL_LTE128: plvdi->item.pszText = pMemory->detail.lte128Buff; return 0L; case ID_DUMPDETAIL_LTE1024: plvdi->item.pszText = pMemory->detail.lte1024Buff; return 0L; case ID_DUMPDETAIL_GT1024: plvdi->item.pszText = pMemory->detail.gt1024Buff; return 0L; default: break; } } break; } break; case WM_COMMAND: switch ( wID ) { case IDM_OPTIONS_REFRESH: ShowMemDump_Refresh(); return 0L; case IDM_OPTIONS_EXPORT: ShowMemDump_Export(); return 0L; case IDM_OPTIONS_SUMMARY: ShowMemDump_Summary(); return 0L; case IDM_OPTIONS_BYTES: g_showMemDump_showBytes = SHOW_BYTES; ShowMemDump_FormatItems(); return 0L; case IDM_OPTIONS_KILOBYTES: g_showMemDump_showBytes = SHOW_KILOBYTES; ShowMemDump_FormatItems(); return 0L; case IDM_OPTIONS_MEGABYTES: g_showMemDump_showBytes = SHOW_MEGABYTES; ShowMemDump_FormatItems(); return 0L; case IDM_OPTIONS_COLLAPSEOUTPUT: g_showMemDump_bCollapseOutput = !g_showMemDump_bCollapseOutput; ShowMemDump_RefreshView(); return 0L; } break; } return ( DefWindowProc( hwnd, message, wParam, lParam ) ); } //----------------------------------------------------------------------------- // ShowMemDump_Init // //----------------------------------------------------------------------------- bool ShowMemDump_Init() { // set up our window class WNDCLASS wndclass; memset( &wndclass, 0, sizeof( wndclass ) ); wndclass.style = 0; wndclass.lpfnWndProc = ShowMemDump_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_SHOWMEMORYDUMP ); wndclass.lpszClassName = "SHOWMEMDUMPCLASS"; if ( !RegisterClass( &wndclass ) ) return false; ShowMemDump_LoadConfig(); return true; } //----------------------------------------------------------------------------- // ShowMemDump_Open // //----------------------------------------------------------------------------- void ShowMemDump_Open() { RECT clientRect; HWND hWnd; if ( g_showMemDump_hWnd ) { // only one instance if ( IsIconic( g_showMemDump_hWnd ) ) ShowWindow( g_showMemDump_hWnd, SW_RESTORE ); SetForegroundWindow( g_showMemDump_hWnd ); return; } hWnd = CreateWindowEx( WS_EX_CLIENTEDGE, "SHOWMEMDUMPCLASS", "", WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, 0, 0, 700, 400, g_hDlgMain, NULL, g_hInstance, NULL ); g_showMemDump_hWnd = hWnd; GetClientRect( g_showMemDump_hWnd, &clientRect ); hWnd = CreateWindow( WC_LISTVIEW, "", WS_VISIBLE|WS_CHILD|LVS_REPORT, 0, 0, clientRect.right-clientRect.left, clientRect.bottom-clientRect.top, g_showMemDump_hWnd, ( HMENU )ID_SHOWMEMDUMP_LISTVIEW, g_hInstance, NULL ); g_showMemDump_hWndListView = hWnd; ListView_SetBkColor( g_showMemDump_hWndListView, g_backgroundColor ); ListView_SetTextBkColor( g_showMemDump_hWndListView, g_backgroundColor ); DWORD style = LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP; ListView_SetExtendedListViewStyleEx( g_showMemDump_hWndListView, style, style ); ShowMemDump_PopulateList(); ShowMemDump_SetTitle(); if ( g_showMemDump_windowRect.right && g_showMemDump_windowRect.bottom ) MoveWindow( g_showMemDump_hWnd, g_showMemDump_windowRect.left, g_showMemDump_windowRect.top, g_showMemDump_windowRect.right-g_showMemDump_windowRect.left, g_showMemDump_windowRect.bottom-g_showMemDump_windowRect.top, FALSE ); ShowWindow( g_showMemDump_hWnd, SHOW_OPENWINDOW ); // get data from application ShowMemDump_Refresh(); } //----------------------------------------------------------------------------- // MatchAllocationName // //----------------------------------------------------------------------------- void MatchAllocationName( memory_t *&pMemory ) { memory_t *curEntry = g_showMemDump_pMemory; for ( int i=0; idetail.pAllocationName, pMemory->detail.pAllocationName ) ) { pMemory = curEntry; return; } ++curEntry; } } //----------------------------------------------------------------------------- // ShowMemDump_Parse // //----------------------------------------------------------------------------- void ShowMemDump_Parse( const char *pBuffer, int fileSize ) { char *ptr; char *pToken; char *pLineStart; int numLines; int size; memory_t *pMemory; // remove old entries ShowMemDump_Clear(); if ( !pBuffer || !fileSize ) { // no valid data return; } Sys_SetScriptData( pBuffer, fileSize ); // skip first line, column headers Sys_SkipRestOfLine(); Sys_SaveParser(); // count lines numLines = 0; while ( 1 ) { pToken = Sys_GetToken( true ); if ( !pToken || !pToken[0] ) break; numLines++; Sys_SkipRestOfLine(); } // each line represents one complete entry g_showMemDump_pMemory = (memory_t *)Sys_Alloc( numLines * sizeof( memory_t ) ); Sys_RestoreParser(); pMemory = g_showMemDump_pMemory; int format = 0; if ( !V_strnicmp( g_sys_scriptptr, "pool ", 5 ) ) { // parse as pool stats format = FORMAT_POOLS; while ( 1 ) { // find start of relevant data bool bFound = false; while ( 1 ) { pToken = Sys_GetToken( true ); if ( !pToken || !pToken[0] ) break; if ( !V_stricmp( pToken, "size:" ) ) { bFound = true; break; } } if ( !bFound ) { break; } memset( pMemory, 0, sizeof( memory_t ) ); pMemory->pool.pool = g_showMemDump_numMemory; pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->pool.size = atoi( pToken ); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; if ( !V_stricmp( pToken, "allocated:" ) ) { pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->pool.allocated = atoi( pToken ); } else { break; } pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; if ( !V_stricmp( pToken, "free:" ) ) { pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->pool.free = atoi( pToken ); } else { break; } pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; if ( !V_stricmp( pToken, "committed:" ) ) { pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->pool.committed = atoi( pToken ); } else { break; } pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; if ( !V_stricmp( pToken, "committedsize:" ) ) { pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->pool.committedSize = atoi( pToken ); } else { break; } pMemory++; g_showMemDump_numMemory++; if ( g_showMemDump_numMemory >= numLines ) break; } } else { // parse as detail stats format = FORMAT_DETAILS; while ( 1 ) { pLineStart = g_sys_scriptptr; // can't tokenize, find start of parsable data ptr = V_stristr( g_sys_scriptptr, ", line " ); if ( !ptr ) break; g_sys_scriptptr = ptr + strlen( ", line " ); // advance past the expected line number pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; if ( !g_showMemDump_bCollapseOutput ) { size = g_sys_scriptptr-pLineStart; } else { size = ptr-pLineStart; } memset( pMemory, 0, sizeof(memory_t) ); memory_t *pCurRecordStart = pMemory; pMemory->detail.pAllocationName = new char[size+1]; memcpy( pMemory->detail.pAllocationName, pLineStart, size ); pMemory->detail.pAllocationName[size] = '\0'; Sys_NormalizePath( pMemory->detail.pAllocationName, false ); if ( g_showMemDump_bCollapseOutput ) { MatchAllocationName( pMemory ); } pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.currentSize += (int)(1024.0f*atof( pToken )); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.peakSize += (int)(1024.0f*atof( pToken )); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.totalSize += (int)(1024.0f*atof( pToken )); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.overheadSize += (int)(1024.0f*atof( pToken )); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.peakOverheadSize += (int)(1024.0f*atof( pToken )); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.time += atoi( pToken ); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.currentCount += atoi( pToken ); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.peakCount += atoi( pToken ); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.totalCount += atoi( pToken ); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.lte16 += atoi( pToken ); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.lte32 += atoi( pToken ); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.lte128 += atoi( pToken ); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.lte1024 += atoi( pToken ); pToken = Sys_GetToken( false ); if ( !pToken || !pToken[0] ) break; pMemory->detail.gt1024 += atoi( pToken ); Sys_SkipRestOfLine(); if( pMemory == pCurRecordStart ) { pMemory++; g_showMemDump_numMemory++; } else { pMemory = pCurRecordStart; } if ( g_showMemDump_numMemory >= numLines ) break; } } if ( g_showMemDump_format != format ) { // format change will cause list view change g_showMemDump_format = format; g_showMemDump_sortColumn = 0; g_showMemDump_sortDescending = 0; } ShowMemDump_PopulateList(); } //----------------------------------------------------------------------------- // rc_MemDump // // Sent from application with memory dump file //----------------------------------------------------------------------------- int rc_MemDump( char *pCommand ) { char* pToken; int retVal; int errCode = -1; int fileSize; char *pBuffer; // get name of file pToken = GetToken( &pCommand ); if ( !pToken[0] ) goto cleanUp; // get file strcpy( g_showMemDump_currentFilename, pToken ); retVal = LoadTargetFile( g_showMemDump_currentFilename, &fileSize, (void **)&pBuffer ); DebugCommand( "0x%8.8x = MemDump( %s )\n", retVal, g_showMemDump_currentFilename ); // parse and update view ShowMemDump_Parse( pBuffer, fileSize ); Sys_Free( pBuffer ); // success errCode = 0; cleanUp: return ( errCode ); }