/// /// Copyright © 2003-2008 JetBrains s.r.o. /// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder). /// #include #include #include "HeapWalker.h" #include "BTreePage.h" using namespace System::Runtime::InteropServices; namespace DBIndex { void Win32Heaps::Dump( String* filename ) { if( _walker == 0 ) { _walker = new Win32HeapWalker(); } IntPtr ptr = Marshal::StringToHGlobalAnsi( filename ); _walker->Dump( (const char*) ptr.ToPointer() ); Marshal::FreeCoTaskMem( ptr ); } #pragma unmanaged #define OM_MAX_HEAPS 256 static HANDLE heaps[ OM_MAX_HEAPS ]; static DWORD heapCount = OM_MAX_HEAPS; Win32HeapWalker::Win32HeapWalker() { if( heapCount == OM_MAX_HEAPS ) { heapCount = ::GetProcessHeaps( heapCount, heaps ); char msg[ 100 ]; sprintf_s( msg, 100, "Number of Win32 heaps: %u", heapCount ); ::OutputDebugString( msg ); if( heapCount > OM_MAX_HEAPS ) { ::DebugBreak(); } } } unsigned Win32HeapWalker::HeapCount() const { return heapCount; } unsigned Win32HeapWalker::HeapTotalSize() const { unsigned size = 0; for( DWORD i = 0; i < heapCount; ++i ) { HANDLE heap = heaps[ i ]; if( ::HeapValidate( heap, 0, NULL ) ) { ::HeapLock( heap ); PROCESS_HEAP_ENTRY heapEntry; heapEntry.lpData = NULL; while( ::HeapWalk( heap, &heapEntry ) ) { if( heapEntry.wFlags & PROCESS_HEAP_ENTRY_BUSY ) { size += heapEntry.cbData; size += heapEntry.cbOverhead; } } ::HeapUnlock( heap ); } } return size; } unsigned Win32HeapWalker::DBIndexMemUsage() const { unsigned result = 0; for( DWORD i = 0; i < heapCount; ++i ) { HANDLE heap = heaps[ i ]; if( !::HeapValidate( heap, 0, NULL ) ) { char errorMsg[ 100 ]; sprintf_s( errorMsg, 100, "Heap(%08x) is invalid!", heap ); ::OutputDebugString( errorMsg ); } else { ::HeapLock( heap ); PROCESS_HEAP_ENTRY heapEntry; heapEntry.lpData = NULL; while( ::HeapWalk( heap, &heapEntry ) ) { // check whether heap entry is OmniaMeaBTree page if( ( heapEntry.wFlags & PROCESS_HEAP_ENTRY_BUSY ) && ( heapEntry.cbData > 12 * 1024 ) ) { unsigned* ptr = (unsigned*) heapEntry.lpData; // skip pointer to vtbl if( ptr[ 1 ] == BTREE_PAGE_MAGIC_NUMBER ) { result += heapEntry.cbData; } } } ::HeapUnlock( heap ); } } return result; } static unsigned size_counts[ 200000 ]; void Win32HeapWalker::Dump( const char* filename ) const { FILE* dump = fopen( filename, "wb" ); for( DWORD i = 0; i < heapCount; ++i ) { HANDLE heap = heaps[ i ]; if( !::HeapValidate( heap, 0, NULL ) ) { fprintf( dump, "Heap(%08x) is invalid!\n", heap ); } else { memset( size_counts, 0, sizeof( size_counts ) ); unsigned size = 0; fprintf( dump, "\t size overhead\n" ); ::HeapLock( heap ); PROCESS_HEAP_ENTRY heapEntry; heapEntry.lpData = NULL; while( ::HeapWalk( heap, &heapEntry ) ) { if( heapEntry.wFlags & PROCESS_HEAP_ENTRY_BUSY ) { size += heapEntry.cbData; size += heapEntry.cbOverhead; char str[ 129 ]; DWORD i = 0; for( ; i < heapEntry.cbData && i < 64; ++i ) { sprintf_s( &str[ i << 1 ], 129, "%02x", ((byte*)heapEntry.lpData)[ i ] ); } str[ i << 1 ] = '\0'; fprintf( dump, "\t%10d%10d %s\n", heapEntry.cbData, heapEntry.cbOverhead, str ); if( heapEntry.cbData < 200000 ) { ++size_counts[ heapEntry.cbData ]; } } } ::HeapUnlock( heap ); fprintf( dump, "Total size of memory allocated in heap(%08x): %d\n", heap, size ); fprintf( dump, "Dump counts of blocks by size (less than 200000)\n" ); fprintf( dump, " size count\n"); for( int i = 0; i < 200000; ++i ) { if( size_counts[ i ] ) { fprintf( dump, "%10d%10d\n", i, size_counts[ i ] ); } } } fprintf( dump, "\n" ); } fclose( dump ); } }