diff -r 000000000000 -r a03f92240627 memspy/Engine/Source/Helpers/MemSpyEngineHelperHeap.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/memspy/Engine/Source/Helpers/MemSpyEngineHelperHeap.cpp Tue Feb 02 01:57:15 2010 +0200 @@ -0,0 +1,1197 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +#include + +// System includes +#include + +// Driver includes +#include + +// User includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Constants +const TBool KMemSpyHeapDumpCreateOwnDataStream = ETrue; + +// Literal constants +_LIT( KCellTypeGoodAllocatedCell, "[Allocated Cell] "); +_LIT( KCellTypeGoodFreeCell, "[Free Cell] "); +_LIT( KCellTypeBadAllocatedCellSize, "[Bad Allocated Cell Size] "); +_LIT( KCellTypeBadAllocatedCellAddress, "[Bad Allocated Cell Address]"); +_LIT( KCellTypeBadFreeCellAddress, "[Bad Free Cell Address] "); +_LIT( KCellTypeBadFreeCellSize, "[Bad Free Cell Size] "); +_LIT( KCellTypeUnknown, "[Unknown!] "); +_LIT( KCellListLineFormat, "%S cell: 0x%08x, cellLen: %8d, allocNum: %8d, nestingLev: %8d, cellData: 0x%08x, cellDataAddr: 0x%08x, headerSize: %02d"); +_LIT( KMemSpyMarkerHeapData, "<%SMEMSPY_HEAP_DATA_%03d>" ); +_LIT( KMemSpyMarkerCSV, "<%SMEMSPY_HEAP_CSV>" ); +_LIT( KMemSpyPrefixHeapData, "HeapData - %S - "); +_LIT( KMemSpyPrefixCellList, "CellList - %S - "); +_LIT( KMemSpyPrefixCSV, "CSV - " ); + + +CMemSpyEngineHelperHeap::CMemSpyEngineHelperHeap( CMemSpyEngine& aEngine ) +: iEngine( aEngine ) + { + } + + +CMemSpyEngineHelperHeap::~CMemSpyEngineHelperHeap() + { + } + + +void CMemSpyEngineHelperHeap::ConstructL() + { + } + + +CMemSpyEngineHelperHeap* CMemSpyEngineHelperHeap::NewL( CMemSpyEngine& aEngine ) + { + CMemSpyEngineHelperHeap* self = new(ELeave) CMemSpyEngineHelperHeap( aEngine ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + + + + + + + + + + +EXPORT_C void CMemSpyEngineHelperHeap::OutputCellListingUserL( const CMemSpyThread& aThread ) + { + // Suspend the process + iEngine.ProcessSuspendLC( aThread.Process().Id() ); + + // Free cells + RArray freeCells; + CleanupClosePushL( freeCells ); + + // Info section + TMemSpyHeapInfo heapInfo; + const TInt error = iEngine.Driver().GetHeapInfoUser( heapInfo, aThread.Id(), freeCells ); + if ( error == KErrNone ) + { + UpdateSharedHeapInfoL( aThread.Process().Id(), aThread.Id(), heapInfo ); + } + if ( error == KErrNone && heapInfo.Type() == TMemSpyHeapInfo::ETypeRHeap ) + { + // Get thread name for context + const TFullName pName( aThread.FullName() ); + + // Begin a new data stream + _LIT( KMemSpyFolder, "Heap\\Cell List" ); + _LIT( KMemSpyContext, "Cell List - %S" ); + HBufC* context = HBufC::NewLC( KMaxFileName ); + TPtr pContext( context->Des() ); + pContext.Format( KMemSpyContext, &pName ); + iEngine.Sink().DataStreamBeginL( pContext, KMemSpyFolder ); + CleanupStack::PopAndDestroy( context ); + + // Set prefix for overall listing + iEngine.Sink().OutputPrefixSetFormattedLC( KMemSpyPrefixCellList, &pName ); + + // Start new section + _LIT(KHeader, "CELL LISTING"); + iEngine.Sink().OutputSectionHeadingL( KHeader, '=' ); + + // Prepare temp buffers + TBuf printFormat; + HBufC* tempBuffer = HBufC::NewLC( 2048 ); + TPtr pTempBuffer( tempBuffer->Des() ); + + // Print initial info + OutputHeapInfoL( heapInfo, pName, &freeCells ); + + // Code segments (needed for map file reading...) + _LIT(KCellListCodeSegInfoFormat, "CodeSegs - "); + iEngine.HelperCodeSegment().OutputCodeSegmentsL( aThread.Process().Id(), printFormat, KCellListCodeSegInfoFormat, '-', ETrue ); + + // Now walk the heap! + TInt r = iEngine.Driver().WalkHeapInit( aThread.Id() ); + if ( r == KErrNone ) + { + _LIT(KHeader2, "Cells"); + iEngine.Sink().OutputSectionHeadingL( KHeader2, '-' ); + + TMemSpyDriverCellType cellType; + TAny* cellAddress; + TInt cellLength; + TInt cellNestingLevel; + TInt cellAllocationNumber; + TInt cellHeaderSize; + TAny* cellPayloadAddress; + TBuf8<4> cellData; + // + r = iEngine.Driver().WalkHeapNextCell( aThread.Id(), cellType, cellAddress, cellLength, cellNestingLevel, cellAllocationNumber, cellHeaderSize, cellPayloadAddress ); + while( r == KErrNone ) + { + TUint fourByteCellData = 0; + TPtrC pType(KNullDesC); + // + switch(cellType) + { + case EMemSpyDriverGoodAllocatedCell: + { + r = iEngine.Driver().WalkHeapReadCellData( cellAddress, cellData, 4 ); + if ( r == KErrNone ) + { + fourByteCellData = DescriptorAsDWORD( cellData ); + } + pType.Set(KCellTypeGoodAllocatedCell); + break; + } + case EMemSpyDriverGoodFreeCell: + pType.Set(KCellTypeGoodFreeCell); + break; + case EMemSpyDriverBadAllocatedCellSize: + pType.Set(KCellTypeBadAllocatedCellSize); + break; + case EMemSpyDriverBadAllocatedCellAddress: + pType.Set(KCellTypeBadAllocatedCellAddress); + break; + case EMemSpyDriverBadFreeCellAddress: + pType.Set(KCellTypeBadFreeCellAddress); + break; + case EMemSpyDriverBadFreeCellSize: + pType.Set(KCellTypeBadFreeCellSize); + break; + default: + pType.Set(KCellTypeUnknown); + break; + } + + if ( r == KErrNone ) + { + pTempBuffer.Format( KCellListLineFormat, &pType, cellAddress, cellLength, cellAllocationNumber, cellNestingLevel, fourByteCellData, cellPayloadAddress, cellHeaderSize ); + iEngine.Sink().OutputLineL( pTempBuffer ); + // + r = iEngine.Driver().WalkHeapNextCell( aThread.Id(), cellType, cellAddress, cellLength, cellNestingLevel, cellAllocationNumber, cellHeaderSize, cellPayloadAddress ); + } + } + // + iEngine.Driver().WalkHeapClose(); + } + CleanupStack::PopAndDestroy( tempBuffer ); + CleanupStack::PopAndDestroy(); // clear prefix + + iEngine.Sink().DataStreamEndL(); + } + + CleanupStack::PopAndDestroy( &freeCells ); + CleanupStack::PopAndDestroy(); // resume process + } + + + + + + + + + + + + + + + + + + + +EXPORT_C void CMemSpyEngineHelperHeap::OutputHeapDataUserL( const CMemSpyThread& aThread ) + { + OutputHeapDataUserL( aThread, KMemSpyHeapDumpCreateOwnDataStream ); + } + + +void CMemSpyEngineHelperHeap::OutputHeapDataUserL( const CMemSpyThread& aThread, TBool aCreateDataStream ) + { + // Make sure the process is suspended for the entire time we are manipulating it's heap + iEngine.ProcessSuspendLC( aThread.Process().Id() ); + + // Get the heap info, including free cell information + RArray freeCells; + CleanupClosePushL( freeCells ); + TMemSpyHeapInfo heapInfo; + TRACE( RDebug::Printf( "CMemSpyEngineHelperHeap::OutputHeapDataUserL() - checksum1: 0x%08x", heapInfo.AsRHeap().Statistics().StatsFree().Checksum() ) ); + GetHeapInfoUserL( aThread.Process().Id(), aThread.Id(), heapInfo, &freeCells ); + TRACE( RDebug::Printf( "CMemSpyEngineHelperHeap::OutputHeapDataUserL() - checksum2: 0x%08x", heapInfo.AsRHeap().Statistics().StatsFree().Checksum() ) ); + + // Get the heap data + const TFullName pName( aThread.FullName() ); + OutputHeapDataUserL( aThread.Process().Id(), aThread.Id(), pName, heapInfo, aCreateDataStream, &freeCells ); + CleanupStack::PopAndDestroy( &freeCells ); + + // Resume process + CleanupStack::PopAndDestroy(); + } + + +EXPORT_C void CMemSpyEngineHelperHeap::OutputHeapDataUserL( const TProcessId& aPid, const TThreadId& aTid, const TDesC& aThreadName, const TMemSpyHeapInfo& aInfo, const RArray* aFreeCells ) + { + OutputHeapDataUserL( aPid, aTid, aThreadName, aInfo, ETrue, aFreeCells ); + } + + +void CMemSpyEngineHelperHeap::OutputHeapDataUserL( const TProcessId& aPid, const TThreadId& aTid, const TDesC& aThreadName, const TMemSpyHeapInfo& aInfo, TBool aCreateDataStream, const RArray* aFreeCells ) + { + TBuf printFormat; + + // Begin a new data stream + if ( aCreateDataStream ) + { + _LIT( KMemSpyFolder, "Heap\\Data" ); + _LIT( KMemSpyContext, "Heap Data - %S" ); + HBufC* context = HBufC::NewLC( KMaxFileName ); + TPtr pContext( context->Des() ); + pContext.Format( KMemSpyContext, &aThreadName ); + iEngine.Sink().DataStreamBeginL( pContext, KMemSpyFolder ); + CleanupStack::PopAndDestroy( context ); + } + + // Get the heap info first of all + iEngine.ProcessSuspendLC( aPid ); + + // Start marker + iEngine.Sink().OutputLineFormattedL( KMemSpyMarkerHeapData, &KNullDesC, (TUint) aTid ); + + // Set overall prefix + iEngine.Sink().OutputPrefixSetFormattedLC( KMemSpyPrefixHeapData, &aThreadName ); + + // Info section + OutputHeapInfoL( aInfo, aThreadName, aFreeCells ); + + // Code segments (needed for map file reading...) + _LIT(KCellListCodeSegInfoFormat, "CodeSegs - "); + iEngine.HelperCodeSegment().OutputCodeSegmentsL( aPid, printFormat, KCellListCodeSegInfoFormat, '-', ETrue ); + + // Dump section + _LIT(KHeaderDump, "Heap Data"); + iEngine.Sink().OutputSectionHeadingL( KHeaderDump, '-' ); + + HBufC8* data = HBufC8::NewLC( 4096 * 12 ); + TPtr8 pData(data->Des()); + TUint remaining = 0; + TUint readAddress = 0; + + // When we obtained the heap info, we also obtained a checksum of all the free cells + // within the specified heap. We validate that this hasn't changed at the time we + // request the heap data for paranoia purposes (There have been "Issues" with MemSpy + // not actually suspending a process between fetching heap info & heap data, causing + // a mismatch in free cell information). + const TUint32 checksum = aInfo.AsRHeap().Statistics().StatsFree().Checksum(); + TRACE( RDebug::Printf( "CMemSpyEngineHelperHeap::OutputHeapDataUserL() - checksum: 0x%08x", checksum ) ); + + TInt r = iEngine.Driver().GetHeapData( aTid, checksum, pData, readAddress, remaining ); + if ( r == KErrNone ) + { + while ( r == KErrNone ) + { + _LIT(KHeapDumpDataFormat, "%S"); + iEngine.Sink().OutputBinaryDataL( KHeapDumpDataFormat, pData.Ptr(), (const TUint8*) readAddress, pData.Length() ); + if ( remaining > 0 ) + r = iEngine.Driver().GetHeapDataNext( aTid, pData, readAddress, remaining ); + else + break; + } + } + else + { + _LIT( KHeapFetchError, "Heap error: %d"); + iEngine.Sink().OutputLineFormattedL( KHeapFetchError, r ); + } + + CleanupStack::PopAndDestroy( data ); + + CleanupStack::PopAndDestroy(); // clear prefix + CleanupStack::PopAndDestroy(); // resume process + + // End marker + iEngine.Sink().OutputLineFormattedL( KMemSpyMarkerHeapData, &KMemSpySinkTagClose, (TUint) aTid ); + + if ( aCreateDataStream ) + { + iEngine.Sink().DataStreamEndL(); + } + } + + + + + + + + + + + + + + + + + + + + + +EXPORT_C void CMemSpyEngineHelperHeap::OutputHeapInfoL( const TMemSpyHeapInfo& aInfo, const TDesC& aThreadName, const RArray* aFreeCells ) + { + CMemSpyEngineOutputList* list = NewHeapSummaryExtendedLC( aInfo, aFreeCells ); + + // Format the thread name according to upper/lower case request parameters + _LIT( KOverallCaption1, "HEAP INFO FOR THREAD '%S'"); + list->InsertItemFormatUCL( 0, KOverallCaption1, &aThreadName ); + list->InsertUnderlineForItemAtL( 0 ); + + // Print it + list->PrintL(); + + // Tidy up + CleanupStack::PopAndDestroy( list ); + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +void CMemSpyEngineHelperHeap::OutputCSVEntryL( TInt aIndex, const TMemSpyHeapInfo& aInfo, const TDesC& aThreadName, const TDesC& aProcessName ) + { + const TMemSpyHeapInfoRHeap& rHeapInfo = aInfo.AsRHeap(); + const TMemSpyHeapMetaDataRHeap& rHeapMetaData = rHeapInfo.MetaData(); + const TMemSpyHeapObjectDataRHeap& rHeapObjectData = rHeapInfo.ObjectData(); + const TMemSpyHeapStatisticsRHeap& rHeapStats = rHeapInfo.Statistics(); + + // Example: + // + // + // ESock_IP + // c32exe.exe[101f7989]0001 + // Local-c812ba58 + // 1,0x12400000,0x00c00074,36744,4092,524288,0x00c011a4,0,13,6872,1368,1680,2584,219,40,28996,0 + // + + _LIT( KFmtTagOpenAndClose, "<%S_%04d>%S" ); + + _LIT( KFmtEntryId, "<%SENTRY_%04d>"); + _LIT( KFmtNameThread, "THREAD_NAME"); + _LIT( KFmtNameProcess, "PROCESS_NAME"); + _LIT( KFmtNameChunk, "CHUNK_NAME"); + _LIT( KFmtFields, "FIELDS"); + _LIT( KFmtFieldContent , "<%S_%04d>%06d,0x%08x,0x%08x,%d,%d,%d,0x%08x,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d"); + + // + iEngine.Sink().OutputLineFormattedL( KFmtEntryId, &KNullDesC, aIndex ); + + // ESock_IP + iEngine.Sink().OutputLineFormattedL( KFmtTagOpenAndClose, &KFmtNameThread, aIndex, &aThreadName, &KFmtNameThread, aIndex ); + + // c32exe.exe[101f7989]0001 + iEngine.Sink().OutputLineFormattedL( KFmtTagOpenAndClose, &KFmtNameProcess, aIndex, &aProcessName, &KFmtNameProcess, aIndex ); + + // Local-c812ba58 + const TPtrC pChunkName( rHeapMetaData.ChunkName() ); + iEngine.Sink().OutputLineFormattedL( KFmtTagOpenAndClose, &KFmtNameChunk, aIndex, &pChunkName, &KFmtNameChunk, aIndex ); + + // Fields + iEngine.Sink().OutputLineFormattedL( KFmtFieldContent, + &KFmtFields, + aIndex, + aInfo.Tid(), + rHeapMetaData.ChunkHandle(), + rHeapObjectData.Base(), + rHeapObjectData.Size(), + rHeapObjectData.iMinLength, + rHeapObjectData.iMaxLength, + rHeapObjectData.iFree.next, + rHeapObjectData.iFree.len, + rHeapStats.StatsFree().TypeCount(), + rHeapStats.StatsFree().TypeSize(), + rHeapStats.StatsFree().SlackSpaceCellSize(), + rHeapStats.StatsFree().LargestCellSize(), + rHeapStats.StatsAllocated().LargestCellSize(), + rHeapObjectData.iCellCount, + rHeapObjectData.iMinCell, + rHeapObjectData.iTotalAllocSize, + rHeapMetaData.IsSharedHeap(), + &KFmtFields, + aIndex + ); + + // + iEngine.Sink().OutputLineFormattedL( KFmtEntryId, &KMemSpySinkTagClose, aIndex ); + } + + + +EXPORT_C void CMemSpyEngineHelperHeap::OutputHeapInfoForDeviceL( TBool aIncludeKernel ) + { + // NB: The goal here is to minimise the line length. We already look like we + // could exceed the available RDebug::Print length... + const TInt count = iEngine.Container().Count(); + TInt index = 0; + // + HBufC* buf = HBufC::NewLC( 1024 ); + TPtr pBuf(buf->Des()); + // + _LIT( KMemSpyFolder, "Heap\\Compact" ); + _LIT( KMemSpyContext, "Heap Compact" ); + _LIT( KMemSpyExtension, ".log" ); + iEngine.Sink().DataStreamBeginL( KMemSpyContext, KMemSpyFolder, KMemSpyExtension ); + + // Start marker + iEngine.Sink().OutputLineFormattedL( KMemSpyMarkerCSV, &KNullDesC ); + + // Set overall prefix + iEngine.Sink().OutputPrefixSetLC( KMemSpyPrefixCSV ); + + // Output version info + _LIT( KVersionNumber, "1" ); + iEngine.Sink().OutputLineL( KVersionNumber ); + + // Output time stamp + _LIT( KTimeStamp, "%u" ); + iEngine.Sink().OutputLineFormattedL( KTimeStamp, User::FastCounter() ); + + // Heap info we'll populate by calling the driver + TMemSpyHeapInfo info; + TFullName processName; + + if ( aIncludeKernel ) + { + // Get kernel heap info + GetHeapInfoKernelL( info ); + + if ( info.Type() == TMemSpyHeapInfo::ETypeRHeap ) + { + TName threadName; + MemSpyEngineUtils::GetKernelHeapThreadAndProcessNames( threadName, processName ); + OutputCSVEntryL( index++, info, threadName, processName ); + } + } + + for(TInt ii=0; ii* aFreeCells ) + { + iEngine.ProcessSuspendLC( aProcess ); + TRACE( RDebug::Printf( "CMemSpyEngineHelperHeap::GetHeapInfoUserL() - checksum1: 0x%08x", aInfo.AsRHeap().Statistics().StatsFree().Checksum() ) ); + + TInt r = KErrNone; + // + if ( aFreeCells ) + { + r = iEngine.Driver().GetHeapInfoUser( aInfo, aThread, *aFreeCells ); + } + else + { + r = iEngine.Driver().GetHeapInfoUser( aInfo, aThread ); + } + if ( !r ) + { + UpdateSharedHeapInfoL( aProcess, aThread, aInfo ); + } + + // + TRACE( RDebug::Printf( "CMemSpyEngineHelperHeap::GetHeapInfoUserL() - checksum2: 0x%08x", aInfo.AsRHeap().Statistics().StatsFree().Checksum() ) ); + CleanupStack::PopAndDestroy(); // ProcessSuspendLC + User::LeaveIfError( r ); + } + + +EXPORT_C void CMemSpyEngineHelperHeap::GetHeapInfoUserL( const CMemSpyProcess& aProcess, RArray& aInfos ) + { + aInfos.Reset(); + iEngine.ProcessSuspendLC( aProcess.Id() ); + // + TMemSpyHeapInfo info; + // + const TInt count = aProcess.Count(); + for( TInt i=0; i freeCells; + CleanupClosePushL( freeCells ); + // + TMemSpyHeapInfo info; + GetHeapInfoUserL( aThread.Process().Id(), aThread.Id(), info, &freeCells ); + OutputHeapInfoL( info, *threadName, &freeCells ); + // + CleanupStack::PopAndDestroy( 2, threadName ); // freecells & thread name + } + + + + + + + + + + + + + + + + + +EXPORT_C void CMemSpyEngineHelperHeap::GetHeapInfoKernelL( TMemSpyHeapInfo& aInfo, RArray* aFreeCells ) + { + TInt error = KErrNone; + // + if ( aFreeCells ) + { + error = iEngine.Driver().GetHeapInfoKernel( aInfo, *aFreeCells ); + } + else + { + error = iEngine.Driver().GetHeapInfoKernel( aInfo ); + } + // + User::LeaveIfError( error ); + } + + +EXPORT_C void CMemSpyEngineHelperHeap::OutputHeapInfoKernelL() + { + // Get thread name + TFullName threadName; + MemSpyEngineUtils::GetKernelHeapThreadName( threadName ); + + // Free cells + RArray freeCells; + CleanupClosePushL( freeCells ); + + // Get info + TMemSpyHeapInfo info; + GetHeapInfoKernelL( info, &freeCells ); + + // Ouput + OutputHeapInfoL( info, threadName, &freeCells ); + + CleanupStack::PopAndDestroy( &freeCells ); + } + + +EXPORT_C void CMemSpyEngineHelperHeap::OutputHeapDataKernelL() + { + OutputHeapDataKernelL( KMemSpyHeapDumpCreateOwnDataStream ); + } + + +void CMemSpyEngineHelperHeap::OutputHeapDataKernelL( TBool aCreateDataStream ) + { + // Get thread name + TFullName threadName; + MemSpyEngineUtils::GetKernelHeapThreadName( threadName, EFalse ); + + // Begin a new data stream + if ( aCreateDataStream ) + { + _LIT( KMemSpyFolder, "Heap\\Data" ); + _LIT( KMemSpyContext, "Heap Data - %S" ); + HBufC* context = HBufC::NewLC( KMaxFileName ); + TPtr pContext( context->Des() ); + pContext.Format( KMemSpyContext, &threadName ); + iEngine.Sink().DataStreamBeginL( pContext, KMemSpyFolder ); + CleanupStack::PopAndDestroy( context ); + } + + RArray freeCells; + CleanupClosePushL( freeCells ); + + // Get kernel data and heap info before outputting anything... + TMemSpyHeapInfo info; + HBufC8* data = iEngine.Driver().GetHeapDataKernelLC( info, freeCells ); + + // Start marker + iEngine.Sink().OutputLineFormattedL( KMemSpyMarkerHeapData, &KNullDesC, info.Tid() ); + + // Set overall prefix + iEngine.Sink().OutputPrefixSetFormattedLC( KMemSpyPrefixHeapData, &threadName ); + + // Info section + OutputHeapInfoL( info, threadName, &freeCells ); + + // Dump section + _LIT(KHeaderDump, "Heap Data"); + iEngine.Sink().OutputSectionHeadingL( KHeaderDump, '-' ); + + _LIT(KHeapDumpDataFormat, "%S"); + const TUint8* heapBaseAddress = info.AsRHeap().ObjectData().Base(); + iEngine.Sink().OutputBinaryDataL( KHeapDumpDataFormat, data->Ptr(), heapBaseAddress, data->Length() ); + + CleanupStack::PopAndDestroy(); // clear prefix + CleanupStack::PopAndDestroy( data ); + CleanupStack::PopAndDestroy( &freeCells ); + + // End marker + iEngine.Sink().OutputLineFormattedL( KMemSpyMarkerHeapData, &KMemSpySinkTagClose, info.Tid() ); + + if ( aCreateDataStream ) + { + iEngine.Sink().DataStreamEndL(); + } + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +EXPORT_C CMemSpyEngineOutputList* CMemSpyEngineHelperHeap::NewHeapSummaryShortLC( const TMemSpyHeapInfo& aInfo ) + { + CMemSpyEngineOutputList* list = CMemSpyEngineOutputList::NewLC( iEngine.Sink() ); + + // Heap type + _LIT( KItem0, "Heap type" ); + if ( aInfo.Type() == TMemSpyHeapInfo::ETypeUnknown ) + { + _LIT( KItem0_Type_Unknown, "Unknown" ); + list->AddItemL( KItem0, KItem0_Type_Unknown ); + } + else if ( aInfo.Type() == TMemSpyHeapInfo::ETypeRHeap ) + { + const TMemSpyHeapInfoRHeap& rHeap = aInfo.AsRHeap(); + const TMemSpyHeapMetaDataRHeap& metaData = rHeap.MetaData(); + const TMemSpyHeapObjectDataRHeap& objectData = rHeap.ObjectData(); + const TMemSpyHeapStatisticsRHeap& statistics = rHeap.Statistics(); + + _LIT( KItem0_Type_RHeap, "RHeap" ); + list->AddItemL( KItem0, KItem0_Type_RHeap ); + + // Heap size is the size of the heap minus the size of the embedded (in-place) RHeap. + _LIT( KItem1, "Heap size" ); + list->AddItemL( KItem1, objectData.Size() ); + + _LIT( KItem8b, "Heap base address" ); + list->AddItemHexL( KItem8b, (TUint) objectData.Base() ); + + _LIT( KItem1b, "Shared" ); + list->AddItemYesNoL( KItem1b, metaData.IsSharedHeap() ); + + // This is the size (rounded to the page) of memory associated with + // the underlying heap chunk + _LIT( KItem2, "Chunk size" ); + list->AddItemL( KItem2, metaData.ChunkSize() ); + + _LIT( KItem3, "Alloc. count" ); + list->AddItemL( KItem3, statistics.StatsAllocated().TypeCount() ); + + _LIT( KItem4, "Free. count" ); + list->AddItemL( KItem4, statistics.StatsFree().TypeCount() ); + + _LIT( KItem5, "Biggest alloc." ); + list->AddItemL( KItem5, statistics.StatsAllocated().LargestCellSize() ); + + _LIT( KItem6, "Biggest free" ); + list->AddItemL( KItem6, statistics.StatsFree().LargestCellSize() ); + + _LIT( KItem6a, "Total alloc." ); + list->AddItemL( KItem6a, statistics.StatsAllocated().TypeSize() ); + + _LIT( KItem6b, "Total free" ); + list->AddItemL( KItem6b, statistics.StatsFree().TypeSize() ); + + // Slack is the free space at the end of the heap + _LIT( KItem7, "Slack free space" ); + list->AddItemL( KItem7, statistics.StatsFree().SlackSpaceCellSize() ); + + // Fragmentation is a measurement of free space scattered throughout the heap, but ignoring + // any slack space at the end (which can often be recovered, to the granularity of one page of ram) + _LIT( KItem8a, "Fragmentation" ); + list->AddItemPercentageL( KItem8a, objectData.Size(), ( statistics.StatsFree().TypeSize() - statistics.StatsFree().SlackSpaceCellSize() ) ); + + _LIT( KItem13, "Header size (A)" ); + list->AddItemL( KItem13, metaData.HeaderSizeAllocated() ); + + _LIT( KItem14, "Header size (F)" ); + list->AddItemL( KItem14, metaData.HeaderSizeFree() ); + + _LIT( KItem9a, "Overhead (alloc)" ); + const TInt allocOverhead = metaData.HeaderSizeAllocated() * statistics.StatsAllocated().TypeCount(); + list->AddItemL( KItem9a, allocOverhead ); + + _LIT( KItem9b, "Overhead (free)" ); + const TInt freeOverhead = metaData.HeaderSizeFree() * statistics.StatsFree().TypeCount(); + list->AddItemL( KItem9b, freeOverhead ); + + _LIT( KItem9c, "Overhead (total)" ); + const TInt totalOverhead = freeOverhead + allocOverhead; + list->AddItemL( KItem9c, totalOverhead ); + + _LIT( KItem9d, "Overhead" ); + list->AddItemPercentageL( KItem9d, objectData.Size(), totalOverhead ); + + _LIT( KItem10, "Min. length" ); + list->AddItemL( KItem10, objectData.iMinLength ); + + _LIT( KItem11, "Max. length" ); + list->AddItemL( KItem11, objectData.iMaxLength ); + + _LIT( KItem12, "Debug Allocator Library" ); + list->AddItemYesNoL( KItem12, metaData.IsDebugAllocator() ); + } + + return list; + } + + +EXPORT_C CMemSpyEngineOutputList* CMemSpyEngineHelperHeap::NewHeapSummaryExtendedLC( const TMemSpyHeapInfo& aInfo, const RArray* aFreeCells ) + { + CMemSpyEngineOutputList* list = CMemSpyEngineOutputList::NewLC( iEngine.Sink() ); + // + AppendMetaDataL( aInfo, *list ); + AppendObjectDataL( aInfo, *list ); + AppendStatisticsL( aInfo, *list ); + // + if ( aFreeCells ) + { + AppendFreeCellsL( *aFreeCells, *list ); + } + // + return list; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +TUint CMemSpyEngineHelperHeap::DescriptorAsDWORD( const TDesC8& aItem) + { + __ASSERT_ALWAYS( aItem.Length() >= 4, User::Invariant() ); + const TUint ret = aItem[0] + + (aItem[1] << 8) + + (aItem[2] << 16) + + (aItem[3] << 24); + return ret; + } + + +void CMemSpyEngineHelperHeap::AppendMetaDataL( const TMemSpyHeapInfo& aInfo, CMemSpyEngineOutputList& aList ) + { + const TMemSpyHeapInfoRHeap& rHeap = aInfo.AsRHeap(); + + // Make caption + _LIT( KOverallCaption1, "Meta Data" ); + aList.AddItemL( KOverallCaption1 ); + aList.AddUnderlineForPreviousItemL( '=', 0 ); + + // Type + _LIT( KMetaData_Type, "Type:" ); + if ( aInfo.Type() != TMemSpyHeapInfo::ETypeRHeap ) + { + _LIT( KMetaData_Type_Unknown, "Unknown" ); + aList.AddItemL( KMetaData_Type, KMetaData_Type_Unknown ); + } + else + { + const TMemSpyHeapMetaDataRHeap& metaData = rHeap.MetaData(); + + // Type + _LIT( KMetaData_Type_RHeap, "Symbian OS RHeap" ); + aList.AddItemL( KMetaData_Type, KMetaData_Type_RHeap ); + + // VTable + _LIT( KMetaData_VTable, "VTable:" ); + aList.AddItemHexL( KMetaData_VTable, metaData.VTable() ); + + // Object size + _LIT( KMetaData_ObjectSize, "Object Size:" ); + aList.AddItemL( KMetaData_ObjectSize, metaData.ClassSize() ); + + // Chunk name + _LIT( KMetaData_ChunkName, "Chunk Name:" ); + TPtrC pChunkName( metaData.ChunkName() ); + aList.AddItemL( KMetaData_ChunkName, pChunkName ); + + // Chunk size + _LIT( KMetaData_ChunkSize, "Chunk Size:" ); + aList.AddItemL( KMetaData_ChunkSize, metaData.ChunkSize() ); + + // Chunk base address + _LIT( KMetaData_ChunkBaseAddress, "Chunk Base Address:" ); + aList.AddItemL( KMetaData_ChunkBaseAddress, metaData.ChunkBaseAddress() ); + + // Debug allocator + _LIT( KMetaData_DebugAllocator, "Debug Allocator:" ); + aList.AddItemYesNoL( KMetaData_DebugAllocator, metaData.IsDebugAllocator() ); + + // Cell header overhead (free cells) + _LIT( KMetaData_CellHeaderOverheadFree, "Overhead (Free):" ); + aList.AddItemL( KMetaData_CellHeaderOverheadFree, metaData.HeaderSizeFree() ); + + // Cell header overhead (allocated cells) + _LIT( KMetaData_CellHeaderOverheadAlloc, "Overhead (Alloc):" ); + aList.AddItemL( KMetaData_CellHeaderOverheadAlloc, metaData.HeaderSizeAllocated() ); + + // Shared Heap + _LIT( KMetaData_Shared, "Shared:" ); + aList.AddItemYesNoL( KMetaData_Shared, metaData.IsSharedHeap() ); + + // Add ROM info + iEngine.HelperROM().AddInfoL( aList ); + } + + aList.AddBlankItemL( 1 ); + } + + +void CMemSpyEngineHelperHeap::AppendObjectDataL( const TMemSpyHeapInfo& aInfo, CMemSpyEngineOutputList& aList ) + { + if ( aInfo.Type() == TMemSpyHeapInfo::ETypeRHeap ) + { + const TMemSpyHeapInfoRHeap& rHeap = aInfo.AsRHeap(); + const TMemSpyHeapObjectDataRHeap& objectData = rHeap.ObjectData(); + + // Make caption + _LIT( KOverallCaption1, "RAllocator" ); + aList.AddItemL( KOverallCaption1 ); + aList.AddUnderlineForPreviousItemL( '=', 0 ); + + // RAllocator + _LIT( KObjectData_RAllocator_iAccessCount, "RAllocator::iAccessCount" ); + aList.AddItemL( KObjectData_RAllocator_iAccessCount, objectData.iAccessCount ); + _LIT( KObjectData_RAllocator_iHandleCount, "RAllocator::iHandleCount" ); + aList.AddItemL( KObjectData_RAllocator_iHandleCount, objectData.iHandleCount ); + _LIT( KObjectData_RAllocator_iHandles, "RAllocator::iHandles" ); + aList.AddItemL( KObjectData_RAllocator_iHandles, objectData.iHandles ); + _LIT( KObjectData_RAllocator_iFlags, "RAllocator::iFlags" ); + aList.AddItemHexL( KObjectData_RAllocator_iFlags, objectData.iFlags ); + _LIT( KObjectData_RAllocator_iCellCount, "RAllocator::iCellCount" ); + aList.AddItemL( KObjectData_RAllocator_iCellCount, objectData.iCellCount ); + _LIT( KObjectData_RAllocator_iTotalAllocSize, "RAllocator::iTotalAllocSize" ); + aList.AddItemL( KObjectData_RAllocator_iTotalAllocSize, objectData.iTotalAllocSize ); + + aList.AddBlankItemL( 1 ); + + // Make caption + _LIT( KOverallCaption2, "RHeap" ); + aList.AddItemL( KOverallCaption2 ); + aList.AddUnderlineForPreviousItemL( '=', 0 ); + + // RHeap + _LIT( KObjectData_RHeap_iMinLength, "RHeap::iMinLength" ); + aList.AddItemL( KObjectData_RHeap_iMinLength, objectData.iMinLength ); + _LIT( KObjectData_RHeap_iMaxLength, "RHeap::iMaxLength" ); + aList.AddItemL( KObjectData_RHeap_iMaxLength, objectData.iMaxLength ); + _LIT( KObjectData_RHeap_iOffset, "RHeap::iOffset" ); + aList.AddItemL( KObjectData_RHeap_iOffset, objectData.iOffset ); + _LIT( KObjectData_RHeap_iGrowBy, "RHeap::iGrowBy" ); + aList.AddItemL( KObjectData_RHeap_iGrowBy, objectData.iGrowBy ); + _LIT( KObjectData_RHeap_iChunkHandle, "RHeap::iChunkHandle" ); + aList.AddItemHexL( KObjectData_RHeap_iChunkHandle, objectData.iChunkHandle ); + _LIT( KObjectData_RHeap_iBase, "RHeap::iBase" ); + aList.AddItemL( KObjectData_RHeap_iBase, objectData.iBase ); + _LIT( KObjectData_RHeap_iTop, "RHeap::iTop" ); + aList.AddItemL( KObjectData_RHeap_iTop, objectData.iTop ); + _LIT( KObjectData_RHeap_iAlign, "RHeap::iAlign" ); + aList.AddItemL( KObjectData_RHeap_iAlign, objectData.iAlign ); + _LIT( KObjectData_RHeap_iMinCell, "RHeap::iMinCell" ); + aList.AddItemL( KObjectData_RHeap_iMinCell, objectData.iMinCell ); + _LIT( KObjectData_RHeap_iPageSize, "RHeap::iPageSize" ); + aList.AddItemL( KObjectData_RHeap_iPageSize, objectData.iPageSize ); + _LIT( KObjectData_RHeap_iFree_next, "RHeap::iFree.next" ); + aList.AddItemL( KObjectData_RHeap_iFree_next, objectData.iFree.next ); + _LIT( KObjectData_RHeap_iFree_len, "RHeap::iFree.len" ); + aList.AddItemL( KObjectData_RHeap_iFree_len, objectData.iFree.len ); + _LIT( KObjectData_RHeap_iNestingLevel, "RHeap::iNestingLevel" ); + aList.AddItemL( KObjectData_RHeap_iNestingLevel, objectData.iNestingLevel ); + _LIT( KObjectData_RHeap_iAllocCount, "RHeap::iAllocCount" ); + aList.AddItemL( KObjectData_RHeap_iAllocCount, objectData.iAllocCount ); + _LIT( KObjectData_RHeap_iFailType, "RHeap::iFailType" ); + aList.AddItemL( KObjectData_RHeap_iFailType, (TInt) objectData.iFailType ); + _LIT( KObjectData_RHeap_iFailRate, "RHeap::iFailRate" ); + aList.AddItemL( KObjectData_RHeap_iFailRate, objectData.iFailRate ); + _LIT( KObjectData_RHeap_iFailed, "RHeap::iFailed" ); + aList.AddItemTrueFalseL( KObjectData_RHeap_iFailed, objectData.iFailed ); + _LIT( KObjectData_RHeap_iFailAllocCount, "RHeap::iFailAllocCount" ); + aList.AddItemL( KObjectData_RHeap_iFailAllocCount, objectData.iFailAllocCount ); + _LIT( KObjectData_RHeap_iRand, "RHeap::iRand" ); + aList.AddItemL( KObjectData_RHeap_iRand, objectData.iRand ); + _LIT( KObjectData_RHeap_iTestData, "RHeap::iTestData" ); + aList.AddItemL( KObjectData_RHeap_iTestData, objectData.iTestData ); + + aList.AddBlankItemL( 1 ); + } + } + + +void CMemSpyEngineHelperHeap::AppendStatisticsL( const TMemSpyHeapInfo& aInfo, CMemSpyEngineOutputList& aList ) + { + if ( aInfo.Type() == TMemSpyHeapInfo::ETypeRHeap ) + { + const TMemSpyHeapInfoRHeap& rHeap = aInfo.AsRHeap(); + const TMemSpyHeapStatisticsRHeap& rHeapStats = rHeap.Statistics(); + + // Shared captions + _LIT( KStatsData_CellCount, "Number of cells:" ); + _LIT( KStatsData_CellSize, "Size of cells:" ); + _LIT( KStatsData_LargestCellAddress, "Largest cell:" ); + _LIT( KStatsData_LargestCellSize, "Largest cell size:" ); + + // Free space + _LIT( KOverallCaption1, "Free Cell Statistics" ); + aList.AddItemL( KOverallCaption1 ); + aList.AddUnderlineForPreviousItemL( '=', 0 ); + + aList.AddItemL( KStatsData_CellCount, rHeapStats.StatsFree().TypeCount() ); + aList.AddItemL( KStatsData_CellSize, rHeapStats.StatsFree().TypeSize() ); + aList.AddItemL( KStatsData_LargestCellAddress, rHeapStats.StatsFree().LargestCellAddress() ); + aList.AddItemL( KStatsData_LargestCellSize, rHeapStats.StatsFree().LargestCellSize() ); + _LIT( KStatsData_Free_SlackCellAddress, "Slack:" ); + aList.AddItemL( KStatsData_Free_SlackCellAddress, rHeapStats.StatsFree().SlackSpaceCellAddress() ); + _LIT( KStatsData_Free_SlackCellSize, "Slack size:" ); + aList.AddItemL( KStatsData_Free_SlackCellSize, rHeapStats.StatsFree().SlackSpaceCellSize() ); + _LIT( KStatsData_Free_Checksum, "Checksum:" ); + aList.AddItemHexL( KStatsData_Free_Checksum, rHeapStats.StatsFree().Checksum() ); + + aList.AddBlankItemL( 1 ); + + // Allocated space + _LIT( KOverallCaption2, "Allocated Cell Statistics" ); + aList.AddItemL( KOverallCaption2 ); + aList.AddUnderlineForPreviousItemL( '=', 0 ); + + aList.AddItemL( KStatsData_CellCount, rHeapStats.StatsAllocated().TypeCount() ); + aList.AddItemL( KStatsData_CellSize, rHeapStats.StatsAllocated().TypeSize() ); + aList.AddItemL( KStatsData_LargestCellAddress, rHeapStats.StatsAllocated().LargestCellAddress() ); + aList.AddItemL( KStatsData_LargestCellSize, rHeapStats.StatsAllocated().LargestCellSize() ); + + aList.AddBlankItemL( 1 ); + + // Common + _LIT( KOverallCaption3, "Common Statistics" ); + aList.AddItemL( KOverallCaption3 ); + aList.AddUnderlineForPreviousItemL( '=', 0 ); + + _LIT( KStatsData_Common_TotalCellCount, "Total cell count:" ); + aList.AddItemL( KStatsData_Common_TotalCellCount, rHeapStats.StatsCommon().TotalCellCount() ); + + _LIT( KStatsData_Common_TotalSize, "Total cell size:" ); + aList.AddItemL( KStatsData_Common_TotalSize, rHeapStats.StatsAllocated().TypeSize() + rHeapStats.StatsFree().TypeSize() ); + + aList.AddBlankItemL( 1 ); + } + } + + +void CMemSpyEngineHelperHeap::AppendFreeCellsL( const RArray& aFreeCells, CMemSpyEngineOutputList& aList ) + { + // Free space + _LIT( KOverallCaption1, "Free Cell List" ); + aList.AddItemL( KOverallCaption1 ); + aList.AddUnderlineForPreviousItemL( '=', 0 ); + + TBuf<128> caption; + _LIT( KCaptionFormat, "FC %04d" ); + _LIT( KValueFormat, "0x%08x %8d %1d" ); + + const TInt count = aFreeCells.Count(); + for( TInt i=0; i threads; + CleanupClosePushL( threads ); + iEngine.Driver().GetThreadsL( aProcess, threads ); + TMemSpyHeapInfo otherHeap; + TThreadId otherThreadId; + TInt r( KErrNone ); + for ( TInt i = 0; i < threads.Count(); i++ ) + { + otherThreadId = threads[i]; + if ( aThread != otherThreadId ) // skip current thread + { + r = iEngine.Driver().GetHeapInfoUser( otherHeap, otherThreadId ); + if ( !r && otherHeap.AsRHeap().MetaData().ChunkHandle() == aInfo.AsRHeap().MetaData().ChunkHandle() ) + { + TRACE( RDebug::Printf( "CMemSpyEngineHelperHeap::UpdateSharedHeapInfoL - shared heap detected chunkhandle: 0x%08x", aInfo.AsRHeap().MetaData().ChunkHandle() ) ); + aInfo.AsRHeap().MetaData().SetSharedHeap( ETrue ); + break; + } + } + } + CleanupStack::PopAndDestroy( &threads ); + } +