memspy/Engine/Source/Helpers/MemSpyEngineHelperStack.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 13 Oct 2010 16:17:58 +0300
branchRCL_3
changeset 59 8ad140f3dd41
parent 49 7fdc9a71d314
permissions -rw-r--r--
Revision: 201039 Kit: 201041

/*
* 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/memspyenginehelperstack.h>

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

// User includes
#include <memspy/engine/memspyengine.h>
#include <memspy/engine/memspyengineoutputsink.h>
#include <memspy/engine/memspyengineoutputlist.h>
#include <memspy/engine/memspyengineobjectthread.h>
#include <memspy/engine/memspyengineobjectprocess.h>
#include "MemSpyEngineOutputListItem.h"
#include <memspy/engine/memspyengineobjectcontainer.h>
#include <memspy/engine/memspyenginehelpercodesegment.h>

// Literal constants
_LIT( KMemSpyPrefixStackData, "StackData - %S - " );
_LIT( KMemSpyMarkerStackData, "<%SMEMSPY_STACK_DATA_%03d>" );


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

    
CMemSpyEngineHelperStack::~CMemSpyEngineHelperStack()
    {
    }


void CMemSpyEngineHelperStack::ConstructL()
    {
    }


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


EXPORT_C void CMemSpyEngineHelperStack::OutputStackInfoL( const CMemSpyThread& aThread )
    {
    const TFullName pName( aThread.FullName() );
    //
    _LIT(KHeader, "STACK INFO FOR THREAD '%S'");
    TBuf<KMaxFullName + 100> printFormat;
    printFormat.Format( KHeader, &pName );
    iEngine.Sink().OutputSectionHeadingL( printFormat, '=' );

    OutputStackInfoL( aThread.Process().Id(), aThread.Id(), printFormat );
    }


EXPORT_C void CMemSpyEngineHelperStack::OutputStackInfoL( TProcessId aPid, TThreadId aTid, TDes& aLineBuffer )
    {
    TMemSpyDriverStackInfo info;
    //
    iEngine.ProcessSuspendLC( aPid );
    const TInt r = iEngine.Driver().GetStackInfo( aTid, info );
    CleanupStack::PopAndDestroy(); // ProcessSuspendLC
    //
    if  ( r == KErrNone )
        {
        CMemSpyEngineOutputList* list = CMemSpyEngineOutputList::NewLC( iEngine.Sink() );

        {
        // Header - user stack
        list->AddItemL( _L("USER STACK") );
        list->AddUnderlineForPreviousItemL();

        // Summary
        list->AddItemFormatL( _L("Address range"), _L("0x%08x - 0x%08x (%8d)"), info.iUserStackBase, info.iUserStackBase + info.iUserStackSize, info.iUserStackSize );
        list->AddItemHexL( _L("Current stack pointer"), info.iUserStackPointer );

        // Calculate usage
        const TInt usedUserStack = (TInt) ( info.iUserStackBase + info.iUserStackSize ) - info.iUserStackPointer;
        const TInt userStackUsagePct = (TInt) (( (TReal) usedUserStack / (TReal) info.iUserStackSize) * 100.0);
        aLineBuffer.Format(_L("%d (%3d"), usedUserStack, userStackUsagePct);
        aLineBuffer.Append(_L(" pct)"));
        list->AddItemL( _L("Stack usage"), aLineBuffer );

        // High watermark
        list->AddItemHexL( _L("High watermark"), info.iUserStackHighWatermark );
        const TInt userHighWaterMarkUsage = (TInt) ( info.iUserStackBase + info.iUserStackSize ) - info.iUserStackHighWatermark;
        const TInt userStackHighWaterMarkUsagePct = (TInt) (( (TReal) userHighWaterMarkUsage / (TReal) info.iUserStackSize) * 100.0);
        aLineBuffer.Format(_L("%d (%3d"), userHighWaterMarkUsage, userStackHighWaterMarkUsagePct);
        aLineBuffer.Append(_L(" pct)"));
        list->AddItemL( _L("High watermark usage"), aLineBuffer );
        }


        {
        // Header - supervisor stack
        list->AddItemL( _L("SUPERVISOR STACK") );
        list->AddUnderlineForPreviousItemL();

        // Summary
        list->AddItemFormatL( _L("Address range"), _L("0x%08x - 0x%08x (%8d)"), info.iSupervisorStackBase, info.iSupervisorStackBase + info.iSupervisorStackSize, info.iSupervisorStackSize );
        list->AddItemHexL( _L("Current stack pointer"), info.iSupervisorStackPointer );

        // Calculate usage
        const TInt usedSupervisorStack = (TInt) ( info.iSupervisorStackBase + info.iSupervisorStackSize ) - info.iSupervisorStackPointer;
        const TInt supervisorStackUsagePct = (TInt) (( (TReal) usedSupervisorStack / (TReal) info.iSupervisorStackSize) * 100.0);
        aLineBuffer.Format(_L("%d (%3d"), usedSupervisorStack, supervisorStackUsagePct );
        aLineBuffer.Append(_L(" pct)"));
        list->AddItemL( _L("Stack usage"), aLineBuffer );

        // High watermark
        list->AddItemHexL( _L("High watermark"), info.iSupervisorStackHighWatermark );
        const TInt supervisorStackHighWaterMarkUsage = (TInt) ( info.iSupervisorStackBase + info.iSupervisorStackSize ) - info.iSupervisorStackHighWatermark;
        const TInt supervisorStackHighWaterMarkUsagePct = (TInt) (( (TReal) supervisorStackHighWaterMarkUsage / (TReal) info.iSupervisorStackSize) * 100.0);
        aLineBuffer.Format(_L("%d (%3d"), supervisorStackHighWaterMarkUsage, supervisorStackHighWaterMarkUsagePct );
        aLineBuffer.Append(_L(" pct)"));
        list->AddItemL( _L("High watermark usage"), aLineBuffer );
        }

        list->PrintL();
        CleanupStack::PopAndDestroy( list );
        }

    }


EXPORT_C void CMemSpyEngineHelperStack::OutputStackDataL( const CMemSpyThread& aThread, TMemSpyDriverDomainType aType )
    {
    OutputStackDataL( aThread, aType, ETrue );
    }


EXPORT_C void CMemSpyEngineHelperStack::OutputStackDataL( const CMemSpyThread& aThread, TMemSpyDriverDomainType aType, TBool aEntireStack )
    {
    TBuf<KMaxFullName + 100> printFormat;
    printFormat = aThread.FullName();

    // Begin a new data stream
    _LIT( KMemSpyFolder, "Stack" );
    HBufC* context = HBufC::NewLC( KMaxFileName );
    TPtr pContext( context->Des() );
    if  ( aType == EMemSpyDriverDomainUser )
        {
        _LIT(KMemSpyContext, "Data (User) - %S");
        pContext.Format( KMemSpyContext, &printFormat );
        }
    else if ( aType == EMemSpyDriverDomainKernel )
        {
        _LIT(KMemSpyContext, "Data (Supervisor) - %S");
        pContext.Format( KMemSpyContext, &printFormat );
        }
    iEngine.Sink().DataStreamBeginL( pContext, KMemSpyFolder );
    CleanupStack::PopAndDestroy( context );

    // Suspend all threads in the process
    iEngine.ProcessSuspendLC( aThread.Process().Id() );

    // Start marker
    iEngine.Sink().OutputLineFormattedL( KMemSpyMarkerStackData, &KNullDesC, (TUint) aThread.Id() );

    // Set overall prefix
    iEngine.Sink().OutputPrefixSetFormattedLC( KMemSpyPrefixStackData, &printFormat );

    // Prepare data buffer
    HBufC8* data = HBufC8::NewLC( 4096 * 4 );
    TPtr8 pData(data->Des());
    TUint remaining = 0;

    TMemSpyDriverStackInfo info;
    TInt r = iEngine.Driver().GetStackInfo( aThread.Id(), info );
    if  ( r == KErrNone )
        {
        TUint spAddress = 0;
        if  ( aType == EMemSpyDriverDomainUser )
            {
            _LIT(KHeaderUser, "USER STACK DATA");
            iEngine.Sink().OutputSectionHeadingL(KHeaderUser, '-');
            spAddress = info.iUserStackPointer;
            }
        else if ( aType == EMemSpyDriverDomainKernel )
            {
            _LIT(KHeaderKernel, "SUPERVISOR STACK DATA");
            iEngine.Sink().OutputSectionHeadingL(KHeaderKernel, '-');
            spAddress = info.iSupervisorStackPointer;
            }

        // Print header information
        // ========================
        TBuf<240> buf;

        // Stack pointer
        _LIT( KLine1, "Current stack pointer: 0x%08x");
        buf.Format( KLine1, spAddress );
        iEngine.Sink().OutputLineL( buf );

        // Stack address range
        _LIT( KLine2, "Stack address range:   0x%08x - 0x%08x");
        if  ( aType == EMemSpyDriverDomainUser )
            {
            buf.Format( KLine2, info.iUserStackBase, info.iUserStackBase + info.iUserStackSize );
            }
        else
            {
            buf.Format( KLine2, info.iSupervisorStackBase, info.iSupervisorStackBase + info.iSupervisorStackSize );
            }
        iEngine.Sink().OutputLineL( buf );

        // Stack size
        _LIT( KLine3, "Stack size:              %d");
        buf.Format( KLine3, ( aType == EMemSpyDriverDomainUser ) ? info.iUserStackSize : info.iSupervisorStackSize );
        iEngine.Sink().OutputLineL( buf );
        iEngine.Sink().OutputBlankLineL();

        // If we are only fetching the 'current' part of the stack, then we need to maniuplate the
        // printing address used to display the stack content
        if  ( !aEntireStack )
            {
            // We start at the stack pointer address and work towards the end of the stack.
            info.iUserStackBase = spAddress;
            }

        // Code segments (needed for map file reading...)
        _LIT(KCodeSegInfoPrefix, "CodeSeg - ");
        iEngine.HelperCodeSegment().OutputCodeSegmentsL( aThread.Process().Id(), printFormat, KCodeSegInfoPrefix );
        
        // Get the stack data
        // ==================
        _LIT(KStackDataPrefix, "%S");
        r = iEngine.Driver().GetStackData( aThread.Id(), pData, remaining, aType, aEntireStack );

        if  ( r == KErrNone )
            {
            if ( aType == EMemSpyDriverDomainUser ) {
                while ( r == KErrNone )
                    {
                    iEngine.Sink().OutputBinaryDataL( KStackDataPrefix, pData.Ptr(), (const TUint8*) info.iUserStackBase, pData.Length() );
                    //
                    if  ( remaining > 0 )
                        {
                        info.iUserStackBase += pData.Length();
                        r = iEngine.Driver().GetStackDataNext( aThread.Id(), pData, remaining, aType, aEntireStack );
                        }
                    else
                        {
                        break;
                        }
                    }
            }
            else if ( aType == EMemSpyDriverDomainKernel ) {
                while ( r == KErrNone ) {
                
                    iEngine.Sink().OutputBinaryDataL( KStackDataPrefix, pData.Ptr(), (const TUint8*) info.iSupervisorStackBase, pData.Length() );
                    //
                    if  ( remaining > 0 ) {
                        info.iSupervisorStackBase += pData.Length();
                        r = iEngine.Driver().GetStackDataNext( aThread.Id(), pData, remaining, aType, aEntireStack );
                    }
                    else {
                         break;
                    }
               }
            }
        }
    CleanupStack::PopAndDestroy( data );

    CleanupStack::PopAndDestroy(); // clear prefix
    CleanupStack::PopAndDestroy(); // resume process

    // End marker
    iEngine.Sink().OutputLineFormattedL( KMemSpyMarkerStackData, &KMemSpySinkTagClose, (TUint) aThread.Id() );
    iEngine.Sink().DataStreamEndL();
    }
}    


EXPORT_C void CMemSpyEngineHelperStack::OutputStackInfoForDeviceL()
    {
    const TInt count = iEngine.Container().Count();
    //
    HBufC* buf = HBufC::NewLC( 1024 );
    TPtr pBuf(buf->Des());
    //
    _LIT( KMemSpyContext, "Stack" );
    _LIT( KMemSpyFolder, "Device-Wide" );
    _LIT( KMemSpyExtension, ".csv" );
    iEngine.Sink().DataStreamBeginL( KMemSpyContext, KMemSpyFolder, KMemSpyExtension );

    // Set overall prefix
    _LIT(KOverallPrefix, "[Stack Summary]");
    iEngine.Sink().OutputPrefixSetLC( KOverallPrefix );

    _LIT(KListingHeader, "Thread, US. Base Address, US. Size, US. Addr, US. Usage, US. Usage Pct, US. HWM Addr, US. HWM Usage, US. HWM Usage Pct, SS. Base Address, SS. Size, SS. Addr, SS. Usage, SS. Usage Pct., SS. HWM Addr, SS. HWM Usage, SS. HWM Usage Pct");
    iEngine.Sink().OutputBlankLineL();
    iEngine.Sink().OutputLineL(KListingHeader);
    
    for(TInt ii=0; ii<count; ii++)
        {
        const CMemSpyProcess& process = iEngine.Container().At( ii );
        const TPtrC procName( process.Name() );
        //
        if  ( iEngine.ProcessSuspendAndGetErrorLC( process.Id() ) == KErrNone )
            {
            TMemSpyDriverStackInfo info;
            const TInt threadCount = process.Count();
            //
            for(TInt j=0; j<threadCount; j++)
                {
                const CMemSpyThread& thread = process.At( j );
                const TPtrC threadName(thread.Name());

                const TInt error = iEngine.Driver().GetStackInfo( thread.Id(), info );
                if  ( error == KErrNone )
                    {
                    const TInt userStackUsage = (TInt) ( info.iUserStackBase + info.iUserStackSize ) - info.iUserStackPointer;
                    const TInt userStackUsagePct = (TInt) (( (TReal) userStackUsage / (TReal) info.iUserStackSize) * 100.0);
                    const TInt userStackHighWaterMarkUsage = (TInt) ( info.iUserStackBase + info.iUserStackSize ) - info.iUserStackHighWatermark;
                    const TInt userStackHighWaterMarkUsagePct = (TInt) (( (TReal) userStackHighWaterMarkUsage / (TReal) info.iUserStackSize) * 100.0);
                    const TInt supervisorStackUsage = (TInt) ( info.iSupervisorStackBase + info.iSupervisorStackSize ) - info.iSupervisorStackPointer;
                    const TInt supervisorStackUsagePct = (TInt) (( (TReal) supervisorStackUsage / (TReal) info.iSupervisorStackSize) * 100.0);
                    const TInt supervisorStackHighWaterMarkUsage = (TInt) ( info.iSupervisorStackBase + info.iSupervisorStackSize ) - info.iSupervisorStackHighWatermark;
                    const TInt supervisorStackHighWaterMarkUsagePct = (TInt) (( (TReal) supervisorStackHighWaterMarkUsage / (TReal) info.iSupervisorStackSize) * 100.0);

                    _LIT(KFormat, "%S::%S, 0x%08x, %8d, 0x%08x, %8d, %8d, 0x%08x, %8d, %8d, 0x%08x, %8d, 0x%08x, %8d, %8d, 0x%08x, %8d, %8d");
                    pBuf.Format(  KFormat, &procName, &threadName, 
                                 info.iUserStackBase, 
                                 info.iUserStackSize, 
                                 info.iUserStackPointer, 
                                 userStackUsage,
                                 userStackUsagePct,
                                 info.iUserStackHighWatermark,
                                 userStackHighWaterMarkUsage,
                                 userStackHighWaterMarkUsagePct,
                                 info.iSupervisorStackBase,
                                 info.iSupervisorStackSize,
                                 info.iSupervisorStackPointer,
                                 supervisorStackUsage,
                                 supervisorStackUsagePct,
                                 info.iSupervisorStackHighWatermark,
                                 supervisorStackHighWaterMarkUsage,
                                 supervisorStackHighWaterMarkUsagePct
                                 );
                    iEngine.Sink().OutputLineL( pBuf );
                    }
                }
            }
        
        CleanupStack::PopAndDestroy(); // ProcessSuspendLC
        }

    CleanupStack::PopAndDestroy(); // clear prefix

    CleanupStack::PopAndDestroy( buf );

    _LIT(KEndOfHeapListing, "<= End Stack Summary =>");
    iEngine.Sink().OutputLineL( KEndOfHeapListing );

    iEngine.Sink().DataStreamEndL();
    }


EXPORT_C TInt CMemSpyEngineHelperStack::CalculateStackSizes( const CMemSpyProcess& aProcess )
    {
    TInt ret = 0;
    //
    TRAPD( error, ret = CalculateStackSizesL( aProcess ) );
    //
    if ( error != KErrNone )
        {
        ret = error;
        }
    //
    return ret;
    }


TInt CMemSpyEngineHelperStack::CalculateStackSizesL( const CMemSpyProcess& aProcess )
    {
	TInt ret = 0;
	//
    iEngine.ProcessSuspendLC( aProcess.Id() );

    TMemSpyDriverStackInfo info;
    //
    const TInt threadCount = aProcess.Count();
    for( TInt i=0; i<threadCount; i++ )
        {
        const CMemSpyThread& thread = aProcess.At( i );
        //
        TInt r = iEngine.Driver().GetStackInfo( thread.Id(), info );
        if  ( r == KErrNone )
            {
            ret += info.iUserStackSize;
            ret += info.iSupervisorStackSize;
            }
        }
    //
    CleanupStack::PopAndDestroy(); // ProcessSuspendLC
	return ret;
    }