memspy/Engine/Source/Helpers/MemSpyEngineHelperChunk.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 16:45:49 +0300
branchRCL_3
changeset 20 ca8a1b6995f6
parent 0 a03f92240627
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* 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 <memspy/engine/memspyenginehelperchunk.h>

// Driver includes
#include <memspy/driver/memspydriverclient.h>

// User includes
#include <memspy/engine/memspyengine.h>
#include <memspy/engine/memspyengineutils.h>
#include <memspy/engine/memspyengineoutputsink.h>
#include <memspy/engine/memspyengineoutputlist.h>
#include <memspy/engine/memspyengineobjectthread.h>
#include <memspy/engine/memspyengineobjectprocess.h>

// Constants
const TInt KMemSpyEngineMaxChunkCount = 768;

// Literal constants
_LIT( KMemSpyEngineChunkListOutputComma, ", " );



CMemSpyEngineHelperChunk::CMemSpyEngineHelperChunk( CMemSpyEngine& aEngine )
:   iEngine( aEngine )
    {
    }

    
CMemSpyEngineHelperChunk::~CMemSpyEngineHelperChunk()
    {
    }


void CMemSpyEngineHelperChunk::ConstructL()
    {
    }


CMemSpyEngineHelperChunk* CMemSpyEngineHelperChunk::NewL( CMemSpyEngine& aEngine )
    {
    CMemSpyEngineHelperChunk* self = new(ELeave) CMemSpyEngineHelperChunk( aEngine );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }


EXPORT_C void CMemSpyEngineHelperChunk::OutputChunkInfoForThreadL( const CMemSpyThread& aThread )
    {
    OutputChunkInfoForThreadL( aThread.Id() );
    }


EXPORT_C void CMemSpyEngineHelperChunk::OutputChunkInfoForThreadL( TThreadId aTid )
    {
    TBuf<512> lineBuffer;
    OutputChunkInfoForThreadL( aTid, lineBuffer );
    }


EXPORT_C void CMemSpyEngineHelperChunk::OutputChunkInfoForThreadL( TThreadId aTid, TDes& aLineBuffer )
    {
    DoOutputChunkInfoForObjectL( aTid, aLineBuffer, EThread );
    }


EXPORT_C void CMemSpyEngineHelperChunk::OutputChunkInfoForProcessL( const CMemSpyProcess& aProcess )
    {
    OutputChunkInfoForProcessL( aProcess.Id() );
    }


EXPORT_C void CMemSpyEngineHelperChunk::OutputChunkInfoForProcessL( TProcessId aPid )
    {
    TBuf<512> lineBuffer;
    OutputChunkInfoForProcessL( aPid, lineBuffer );
    }


EXPORT_C void CMemSpyEngineHelperChunk::OutputChunkInfoForProcessL( TProcessId aPid, TDes& aLineBuffer )
    {
    DoOutputChunkInfoForObjectL( aPid, aLineBuffer, EProcess );
    }


EXPORT_C CMemSpyEngineChunkList* CMemSpyEngineHelperChunk::ListL()
    {
    RArray<TAny*> handles( 128 );
    CleanupClosePushL( handles );
    //
    GetChunkHandlesL( handles, EAll );
    CMemSpyEngineChunkList* list = CreateListFromHandlesL( handles );
    //
    CleanupStack::PopAndDestroy( &handles );
    return list;
    }


EXPORT_C CMemSpyEngineChunkList* CMemSpyEngineHelperChunk::ListForThreadL( TThreadId aTid )
    {
    RArray<TAny*> handles( 128 );
    CleanupClosePushL( handles );
    //
    GetChunkHandlesL( handles, EThread, aTid );
    CMemSpyEngineChunkList* list = CreateListFromHandlesL( handles );
    //
    CleanupStack::PopAndDestroy( &handles );
    return list;
    }


EXPORT_C CMemSpyEngineChunkList* CMemSpyEngineHelperChunk::ListForProcessL( TProcessId aPid )
    {
    RArray<TAny*> handles( 128 );
    CleanupClosePushL( handles );
    //
    GetChunkHandlesL( handles, EProcess, aPid );
    CMemSpyEngineChunkList* list = CreateListFromHandlesL( handles );
    //
    CleanupStack::PopAndDestroy( &handles );
    return list;
    }


void CMemSpyEngineHelperChunk::DoOutputChunkInfoForObjectL( TUint aId, TDes& aLineBuffer, TType aType )
    {
    TFullName ownerName;
	//
    RArray<TAny*> handles( 128 );
    CleanupClosePushL( handles );
    //
    GetChunkHandlesL( handles, aType, aId );
    CMemSpyEngineChunkList* list = CreateListFromHandlesL( handles );
    //
    CleanupStack::PopAndDestroy( &handles );
    CleanupStack::PushL( list );
    //
    const TInt count = list->Count();
    for (TInt i=0; i<count; i++)
    	{
        const CMemSpyEngineChunkEntry& entry = list->At( i );
        //
        _LIT(KLine1, "Name");
        iEngine.Sink().OutputItemAndValueL( KLine1, entry.Name() );
        //
        _LIT(KLine2, "Owner");
        entry.OwnerName( ownerName );
        iEngine.Sink().OutputItemAndValueL( KLine2, ownerName );
        //
        _LIT(KLine3, "Address");
        _LIT(KLine3Format, "0x%08x - 0x%08x");
        aLineBuffer.Format(KLine3Format, entry.BaseAddress(), entry.UpperAddress() );
        iEngine.Sink().OutputItemAndValueL( KLine3, aLineBuffer );
        //
        _LIT(KLine4, "Size (max)");
        _LIT(KLine4Format, "%d (%d)");
        aLineBuffer.Format(KLine4Format, entry.Size(), entry.MaxSize());
        iEngine.Sink().OutputItemAndValueL( KLine4, aLineBuffer );
        //
        if  ( i < count - 1 )
            {
            iEngine.Sink().OutputBlankLineL();
    		}
        }
    //
    CleanupStack::PopAndDestroy( list );
    }


void CMemSpyEngineHelperChunk::GetChunkHandlesL( RArray<TAny*>& aHandles, TType aType, TUint aId )
    {
	TAny* handles[ KMemSpyEngineMaxChunkCount ];
	TInt count = KMemSpyEngineMaxChunkCount;

    TInt r = 0;
    //
    switch( aType )
        {
    case EThread:
        r = iEngine.Driver().GetChunkHandlesForThread( aId, handles, count );
        break;
    case EProcess:
        r = iEngine.Driver().GetChunkHandlesForProcess( aId, handles, count );
        break;
    default:
    case EAll:
        r = iEngine.Driver().GetChunkHandles( handles, count );
        break;
        }
    //
    if  ( r == KErrNone )
    	{
        count = Min( count, KMemSpyEngineMaxChunkCount );
        for( TInt index = 0; index < count; index++ )
            {
            TAny* handle = handles[ index ];

            if  ( aHandles.Find( handle ) == KErrNotFound )
                {
                aHandles.AppendL( handle );
                }
            }
        }
    }


CMemSpyEngineChunkList* CMemSpyEngineHelperChunk::CreateListFromHandlesL( const RArray<TAny*>& aHandles )
    {
    CMemSpyEngineChunkList* list = CMemSpyEngineChunkList::NewLC( iEngine );
    //
    TMemSpyDriverChunkInfo info;
    const TInt count = aHandles.Count();
    //
    for( TInt i=0; i<count; i++ )
        {
        TAny* handle = aHandles[ i ];
        //
    	const TInt error = iEngine.Driver().GetChunkInfo( handle, info );
        if  ( error == KErrNone )
            {
            CMemSpyEngineChunkEntry* entry = CMemSpyEngineChunkEntry::NewLC( iEngine, info );
            list->AddItemL( entry );
            CleanupStack::Pop( entry );
            }
        }
    //
    list->SortBySizeL();
    //
    CleanupStack::Pop( list );
    return list;
    }













































CMemSpyEngineChunkList::CMemSpyEngineChunkList( CMemSpyEngine& aEngine )
:   iEngine( aEngine )
    {
    }


EXPORT_C CMemSpyEngineChunkList::~CMemSpyEngineChunkList()
    {
    iItems.ResetAndDestroy();
    iItems.Close();
    }


void CMemSpyEngineChunkList::ConstructL()
    {
    }


CMemSpyEngineChunkList* CMemSpyEngineChunkList::NewLC( CMemSpyEngine& aEngine )
    {
    CMemSpyEngineChunkList* self = new(ELeave) CMemSpyEngineChunkList( aEngine );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }


EXPORT_C TInt CMemSpyEngineChunkList::Count() const
    {
    return iItems.Count();
    }


EXPORT_C CMemSpyEngineChunkEntry& CMemSpyEngineChunkList::At( TInt aIndex )
    {
    return *iItems[ aIndex ];
    }


EXPORT_C const CMemSpyEngineChunkEntry& CMemSpyEngineChunkList::At( TInt aIndex ) const
    {
    return *iItems[ aIndex ];
    }


EXPORT_C void CMemSpyEngineChunkList::SortByNameL()
    {
    TLinearOrder< CMemSpyEngineChunkEntry > comparer( CompareByName );
    iItems.Sort( comparer );
    }


EXPORT_C void CMemSpyEngineChunkList::SortBySizeL()
    {
    TLinearOrder< CMemSpyEngineChunkEntry > comparer( CompareBySize );
    iItems.Sort( comparer );
    }


EXPORT_C TInt CMemSpyEngineChunkList::ItemIndex( const CMemSpyEngineChunkEntry& aEntry ) const
    {
    TInt ret = KErrNotFound;
    //
    const TInt count = Count();
    for( TInt i=0; i<count; i++ )
        {
        const CMemSpyEngineChunkEntry* item = iItems[ i ];
        //
        if  ( item == &aEntry )
            {
            ret = i;
            break;
            }
        }
    //
    return ret;
    }


EXPORT_C void CMemSpyEngineChunkList::OutputDataColumnsL( CMemSpyEngine& aEngine )
    {
    HBufC* columns = HBufC::NewLC( 1024 );
    TPtr pColumns( columns->Des() );

    //
    _LIT(KCol1, "Name");
    pColumns.Append( KCol1 );
    pColumns.Append( KMemSpyEngineChunkListOutputComma );

    //
    _LIT(KCol2, "Owning Process");
    pColumns.Append( KCol2 );
    pColumns.Append( KMemSpyEngineChunkListOutputComma );

    //
    _LIT(KCol3, "Size");
    pColumns.Append( KCol3 );
    pColumns.Append( KMemSpyEngineChunkListOutputComma );

    //
    _LIT(KCol4, "Max. Size");
    pColumns.Append( KCol4 );
    pColumns.Append( KMemSpyEngineChunkListOutputComma );

    //
    _LIT(KCol5, "Address");
    pColumns.Append( KCol5 );

    //
    aEngine.Sink().OutputLineL( pColumns );
    CleanupStack::PopAndDestroy( columns );
    }


EXPORT_C TBool CMemSpyEngineChunkList::EntryExists( TAny* aHandle ) const
    {
    TBool ret = EFalse;
    //
    const TInt count = Count();
    for( TInt i=0; i<count && !ret; i++ )
        {
        const CMemSpyEngineChunkEntry* item = iItems[ i ];
        ret = ( item->Handle() == aHandle );
        }
    //
    return ret;
    }


void CMemSpyEngineChunkList::AddItemL( CMemSpyEngineChunkEntry* aItem )
    {
    iItems.AppendL( aItem );
    }


void CMemSpyEngineChunkList::Remove( TInt aIndex )
    {
    CMemSpyEngineChunkEntry* item = iItems[ aIndex ];
    delete item;
    iItems.Remove( aIndex );
    }


void CMemSpyEngineChunkList::RemoveByHandle( TAny* aChunkHandle )
    {
    const TInt index = ItemIndexByChunkHandle( aChunkHandle );
    if  ( index >= 0 )
        {
        Remove( index );
        }
    }


TInt CMemSpyEngineChunkList::ItemIndexByProcessId( TUint aPid ) const
    {
    const TInt ret = ItemIndexByProcessId( aPid, 0 );
    return ret;
    }


TInt CMemSpyEngineChunkList::ItemIndexByProcessId( TUint aPid, TInt aStartIndex ) const
    {
    TInt ret = KErrNotFound;
    //
    const TInt count = Count();
    for( TInt i=aStartIndex; i<count; i++ )
        {
        const CMemSpyEngineChunkEntry* item = iItems[ i ];
        //
        if  ( item->OwnerId() == aPid )
            {
            ret = i;
            break;
            }
        }
    //
    return ret;
    }


TInt CMemSpyEngineChunkList::ItemIndexByProcessId( TUint aPid, TMemSpyDriverChunkType aType ) const
    {
    TInt ret = KErrNotFound;
    //
    const TInt count = Count();
    for( TInt i=0; i<count; i++ )
        {
        const CMemSpyEngineChunkEntry* item = iItems[ i ];
        //
        if  ( item->OwnerId() == aPid && item->Info().iType == aType )
            {
            ret = i;
            break;
            }
        }
    //
    return ret;
    }


TInt CMemSpyEngineChunkList::ItemIndexByChunkHandle( TAny* aHandle ) const
    {
    TInt ret = KErrNotFound;
    //
    const TInt count = Count();
    for( TInt i=0; i<count; i++ )
        {
        const CMemSpyEngineChunkEntry* item = iItems[ i ];
        //
        if  ( item->Handle() == aHandle )
            {
            ret = i;
            break;
            }
        }
    //
    return ret;
    }


EXPORT_C TInt CMemSpyEngineChunkList::MdcaCount() const
    {
    return Count();
    }


EXPORT_C TPtrC CMemSpyEngineChunkList::MdcaPoint( TInt aIndex ) const
    {
    const CMemSpyEngineChunkEntry& item = At( aIndex );
    return TPtrC( item.Caption() );
    }


TInt CMemSpyEngineChunkList::CompareByName( const CMemSpyEngineChunkEntry& aLeft, const CMemSpyEngineChunkEntry& aRight )
    {
    const TInt ret = aLeft.Name().CompareF( aRight.Name() );
    return ret;
    }


TInt CMemSpyEngineChunkList::CompareBySize( const CMemSpyEngineChunkEntry& aLeft, const CMemSpyEngineChunkEntry& aRight )
    {
    TInt ret = -1;
    //
    if  ( aLeft.Size() < aRight.Size() )
        {
        ret = 1;
        }
    else if ( aLeft.Size() == aRight.Size() )
        {
        ret = 0;
        }
    //
    return ret;
    }


















CMemSpyEngineChunkEntry::CMemSpyEngineChunkEntry( CMemSpyEngine& aEngine )
:   iEngine( aEngine )
    {
    }


CMemSpyEngineChunkEntry::~CMemSpyEngineChunkEntry()
    {
    delete iCaption;
    delete iInfo;
    delete iList;
    }


void CMemSpyEngineChunkEntry::ConstructL( const TMemSpyDriverChunkInfo& aInfo )
    {
    // Copy info
    iInfo = new(ELeave) TMemSpyDriverChunkInfo();
    *iInfo = aInfo;

    // Make caption
    TBuf<KMaxFullName+128> item;
    _LIT(KCaptionFormat, "\t%S\t\t%d");
    item.Format( KCaptionFormat, &Name(), Size() );
    iCaption = item.AllocL();

    // Make other items
    iList = CMemSpyEngineOutputList::NewL();

    _LIT( KEntry0, "Name");
    iList->AddItemL( KEntry0, Name() );

    _LIT( KEntryType, "Type" );
    switch( aInfo.iType )
        {
    default:
    case EMemSpyDriverChunkTypeUnknown:
        iList->AddItemL( KEntryType, _L("Unknown") );
        break;
    case EMemSpyDriverChunkTypeHeap:
        iList->AddItemL( KEntryType, _L("Heap") );
        break;
    case EMemSpyDriverChunkTypeHeapKernel:
        iList->AddItemL( KEntryType, _L("Kernel Heap") );
        break;
    case EMemSpyDriverChunkTypeStackAndProcessGlobalData:
        iList->AddItemL( KEntryType, _L("Stack and Process Global Data") );
        break;
    case EMemSpyDriverChunkTypeStackKernel:
        iList->AddItemL( KEntryType, _L("Kernel Stack") );
        break;
    case EMemSpyDriverChunkTypeGlobalData:
        iList->AddItemL( KEntryType, _L("Global Data") );
        break;
    case EMemSpyDriverChunkTypeCode:
        iList->AddItemL( KEntryType, _L("Code") );
        break;
    case EMemSpyDriverChunkTypeCodeGlobal:
        iList->AddItemL( KEntryType, _L("Global Code") );
        break;
    case EMemSpyDriverChunkTypeCodeSelfModifiable:
        iList->AddItemL( KEntryType, _L("Self Modifiable Code") );
        break;
    case EMemSpyDriverChunkTypeLocal:
        iList->AddItemL( KEntryType, _L("Local") );
        break;
    case EMemSpyDriverChunkTypeGlobal:
        iList->AddItemL( KEntryType, _L("Global") );
        break;
    case EMemSpyDriverChunkTypeRamDrive:
        iList->AddItemL( KEntryType, _L("RAM Drive") );
        break;
        }

    _LIT( KEntry1, "Owning Process");
    OwnerName( item );
    iList->AddItemL( KEntry1, item );

    _LIT( KEntry2, "Address" );
    _LIT( KEntry2Format, "0x%08x - 0x%08x" );
    item.Format( KEntry2Format, BaseAddress(), UpperAddress() );
    iList->AddItemL( KEntry2, item );

    _LIT( KEntry3, "Size");
    iList->AddItemL( KEntry3, Size() );

    _LIT( KEntry4, "Max. Size");
    iList->AddItemL( KEntry4, MaxSize() );

    _LIT( KEntryAttributeFormat, "Attribute %d");
    TInt attribNum = 0;
    //
    if  ( aInfo.iAttributes & ENormal )
        {
        item.Format( KEntryAttributeFormat, ++attribNum );
        iList->AddItemL( item, _L("Normal") );
        }
    if  ( aInfo.iAttributes & EDoubleEnded )
        {
        item.Format( KEntryAttributeFormat, ++attribNum );
        iList->AddItemL( item, _L("Double Ended") );
        }
    if  ( aInfo.iAttributes & EDisconnected )
        {
        item.Format( KEntryAttributeFormat, ++attribNum );
        iList->AddItemL( item, _L("Disconnected") );
        }
    if  ( aInfo.iAttributes & EConstructed )
        {
        item.Format( KEntryAttributeFormat, ++attribNum );
        iList->AddItemL( item, _L("Constructed") );
        }
    if  ( aInfo.iAttributes & EMemoryNotOwned )
        {
        item.Format( KEntryAttributeFormat, ++attribNum );
        iList->AddItemL( item, _L("Memory Not Owned") );
        }
    }


CMemSpyEngineChunkEntry* CMemSpyEngineChunkEntry::NewLC( CMemSpyEngine& aEngine, const TMemSpyDriverChunkInfo& aInfo )
    {
    CMemSpyEngineChunkEntry* self = new(ELeave) CMemSpyEngineChunkEntry( aEngine );
    CleanupStack::PushL( self );
    self->ConstructL( aInfo );
    return self;
    }


const TDesC& CMemSpyEngineChunkEntry::Name() const
    {
    return iInfo->iName;
    }


TAny* CMemSpyEngineChunkEntry::Handle() const 
    {
    return iInfo->iHandle;
    }


TInt CMemSpyEngineChunkEntry::Size() const
    {
    return iInfo->iSize;
    }


TInt CMemSpyEngineChunkEntry::MaxSize() const
    {
    return iInfo->iMaxSize;
    }


TAny* CMemSpyEngineChunkEntry::BaseAddress() const
    { 
    return iInfo->iBaseAddress;
    }


TAny* CMemSpyEngineChunkEntry::UpperAddress() const
    {
    return (TAny*) (TUint(BaseAddress()) + TUint(Size()));
    }


TUint CMemSpyEngineChunkEntry::OwnerId() const
    {
    return iInfo->iOwnerId;
    }


EXPORT_C void CMemSpyEngineChunkEntry::OwnerName( TDes& aDes ) const
    {
    aDes.Zero();
    AppendOwnerName( aDes );
    }


EXPORT_C void CMemSpyEngineChunkEntry::AppendOwnerName( TDes& aDes ) const
    {
    RProcess owner;
    const TInt error = owner.Open( (TProcessId) OwnerId() );
    if  ( error == KErrNone )
        {
        aDes.Append( owner.FullName() );
        owner.Close();
        }
    }


EXPORT_C void CMemSpyEngineChunkEntry::OutputDataL( CMemSpyEngineHelperChunk& aHelper ) const
    {
    HBufC* columns = HBufC::NewLC( 1024 );
    TPtr pColumns( columns->Des() );

    // Name
    pColumns.Copy( Name() );
    MemSpyEngineUtils::TextAfterDoubleColon( pColumns );
    pColumns.Append( KMemSpyEngineChunkListOutputComma );

    // Owning Process
    AppendOwnerName( pColumns );
    pColumns.Append( KMemSpyEngineChunkListOutputComma );

    // Size
    pColumns.AppendNum( Size(), EDecimal ); 
    pColumns.Append( KMemSpyEngineChunkListOutputComma );

    // Max. Size
    pColumns.AppendNum( MaxSize(), EDecimal ); 
    pColumns.Append( KMemSpyEngineChunkListOutputComma );

    // Address
    _LIT( KAddressFormat, "0x%08x - 0x%08x");
    pColumns.AppendFormat( KAddressFormat, BaseAddress(), UpperAddress() );

    //
    aHelper.Engine().Sink().OutputLineL( pColumns );
    CleanupStack::PopAndDestroy( columns );
    }


EXPORT_C TInt CMemSpyEngineChunkEntry::MdcaCount() const
    {
    return iList->MdcaCount();
    }


EXPORT_C TPtrC CMemSpyEngineChunkEntry::MdcaPoint( TInt aIndex ) const
    {
    return iList->MdcaPoint( aIndex );
    }


TMemSpyDriverChunkInfo& CMemSpyEngineChunkEntry::Info()
    {
    return *iInfo;
    }


const TMemSpyDriverChunkInfo& CMemSpyEngineChunkEntry::Info() const
    {
    return *iInfo;
    }