memspy/Engine/Source/Helpers/MemSpyEngineHelperStack.cpp
changeset 0 a03f92240627
child 39 3406c99bc375
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/memspy/Engine/Source/Helpers/MemSpyEngineHelperStack.cpp	Tue Feb 02 01:57:15 2010 +0200
@@ -0,0 +1,407 @@
+/*
+* 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 )
+            {
+            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;
+                    }
+                }
+            }
+
+        }
+    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;
+    }
+
+
+