memspy/Engine/Source/DeviceWideOps/MemSpyDeviceWideOperations.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 15 Sep 2010 13:53:27 +0300
branchRCL_3
changeset 49 7fdc9a71d314
parent 44 52e343bb8f80
child 59 8ad140f3dd41
permissions -rw-r--r--
Revision: 201035 Kit: 201036

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

// Engine includes
#include <memspy/engine/memspyengine.h>
#include <memspy/engine/memspyengineoutputsink.h>
#include <memspy/engine/memspyengineobjectthread.h>
#include <memspy/engine/memspyengineobjectthread.h>
#include <memspy/engine/memspyengineobjectprocess.h>
#include <memspy/engine/memspyengineobjectcontainer.h>
#include <memspy/engine/memspyengineobjectthreadinfocontainer.h>
#include <memspy/engine/memspyenginehelperchunk.h>
#include <memspy/engine/memspyenginehelpercodesegment.h>
#include <memspy/engine/memspyenginehelperheap.h>
#include <memspy/engine/memspyenginehelperstack.h>
#include <memspy/engine/memspyenginehelperthread.h>
#include <memspy/engine/memspyenginehelperprocess.h>

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

// Literal constants
_LIT( KMemSpyUiThreadNameKernel, "Kernel" );
_LIT( KMemSpyUiCompactHeap, "Compact Heap" );
_LIT( KMemSpyUiCompactStack, "Compact Stack" );



CMemSpyDeviceWideOperations::CMemSpyDeviceWideOperations( CMemSpyEngine& aEngine, MMemSpyDeviceWideOperationsObserver& aObserver, TOperation aOperation )
:   CActive( EPriorityIdle ), iEngine( aEngine ), iObserver( aObserver ), iOperation( aOperation )
    {
    CActiveScheduler::Add( this );
    }


EXPORT_C CMemSpyDeviceWideOperations::~CMemSpyDeviceWideOperations()
    {
#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::~CMemSpyDeviceWideOperations() - START - iOperationCancelled: %d", iOperationCancelled );
#endif

    Cancel();

#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::~CMemSpyDeviceWideOperations() - END" );
#endif
    }


void CMemSpyDeviceWideOperations::ConstructL()
    {
#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::ConstructL() - START" );
#endif

    // Set engine sink time stamp, which will cause the data to be written to a 
    // uniquely named folder (if we're using a file sink)
    TTime now;
    now.HomeTime();
    iEngine.Sink().DataStreamTimeStampBeginL( now );

    const TInt processCountUser = iEngine.Container().Count();
    const TInt threadCountUser = TotalNumberOfThreads();
    const TInt threadCountIncludingKernelSupervisor = threadCountUser + 1; // includes kernel supervisor thread

    // Decide what the maximum progress bar value is...
    // If we're performing a detailed operation, then skip straight to the end because
    // the entire operation is performed in one go.
    iTotalOperationSize = 0;
    switch( iOperation )
        {
    // Only applicable to user-threads
    default:
    case EPerEntityGeneralSummary:
    case EPerEntityGeneralDetailed:
    case EPerEntityGeneralHandles:
    case EPerEntityHeapCellListing:
    case EPerEntityStackInfo:
    case EPerEntityStackDataUser:
    case EPerEntityStackDataKernel:
        iTotalOperationSize = threadCountUser;
        break;
    // Applies to user and kernel threads
    case EPerEntityHeapInfo:
        iTotalOperationSize = threadCountIncludingKernelSupervisor;
        break;
    // Operation is performed in one go
    case EEntireDeviceHeapInfoCompact:
    case EEntireDeviceStackInfoCompact:
        iProcessIndex = processCountUser;
        iTotalOperationSize = 1;
        break;
        }

#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::ConstructL() - op. count: %d", iTotalOperationSize );
#endif

    // Report total amount of work to observer
    iObserver.HandleDeviceWideOperationEvent( MMemSpyDeviceWideOperationsObserver::EOperationSized, iTotalOperationSize, KNullDesC );

    // Start the process rolling...
    CompleteSelf( KErrNone );

    // Indicate that we're now starting the operation
    iObserver.HandleDeviceWideOperationEvent( MMemSpyDeviceWideOperationsObserver::EOperationStarting, 0, KNullDesC );

#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::ConstructL() - END" );
#endif
    }


EXPORT_C CMemSpyDeviceWideOperations* CMemSpyDeviceWideOperations::NewL( CMemSpyEngine& aEngine, MMemSpyDeviceWideOperationsObserver& aObserver, TOperation aOperation )
    {
    CMemSpyDeviceWideOperations* self = new(ELeave) CMemSpyDeviceWideOperations( aEngine, aObserver, aOperation );
    CleanupStack::PushL( self );
    self->ConstructL();
#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::NewL() - about to pop..." );
#endif
    CleanupStack::Pop( self );
#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::NewL() - popped" );
#endif
    return self;
    }


EXPORT_C void CMemSpyDeviceWideOperations::Cancel()
    {
#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::Cancel() - START - IsActive: %d", IsActive() );
#endif

    if  ( IsActive() )
        {
        CActive::Cancel();
        iObserver.HandleDeviceWideOperationEvent( MMemSpyDeviceWideOperationsObserver::EOperationCancelled, 0, KNullDesC );
        }

#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::Cancel() - END" );
#endif
    }


EXPORT_C TInt CMemSpyDeviceWideOperations::TotalOperationSize() const
    {
#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::TotalOperationSize::Cancel() - ret: %d", iTotalOperationSize );
#endif
    return iTotalOperationSize;
    }


void CMemSpyDeviceWideOperations::RunL()
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyDeviceWideOperations::RunL() - START - iStatus: %d, iOperationCancelled: %d, iThreadIndex: %03d, iOperation: %d", iStatus.Int(), iOperationCancelled, iThreadIndex, iOperation );
#endif

    User::LeaveIfError( iStatus.Int() );
    User::ResetInactivityTime();
 
    if  ( iOperationCancelled )
        {
#ifdef _DEBUG
        RDebug::Printf( "CMemSpyDeviceWideOperations::RunL() - operation was cancelled whilst running... => Finished" );
#endif
        SetFinished();
        }
    else
        {
        // Get the current process
        CMemSpyEngineObjectContainer& container = iEngine.Container();
        const TInt processCount = container.Count();
        //
        if  ( iProcessIndex < processCount ) 
            {
            PerformNextStepL();
            }
        else
            {
            // We're done - RunL will not be called again
            TRAP_IGNORE( PerformFinalOperationL() );
            SetFinished();
            }
        }

#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::RunL() - END" );
#endif
    }


void CMemSpyDeviceWideOperations::DoCancel()
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyDeviceWideOperations::DoCancel() - START" );
#endif

    // Nothing to do here
    iOperationCancelled = ETrue;

#ifdef _DEBUG
    RDebug::Printf( "CMemSpyDeviceWideOperations::DoCancel() - END" );
#endif
    }


TInt CMemSpyDeviceWideOperations::RunError( TInt aError )
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyDeviceWideOperations::RunError() - START - iOperationCancelled: %d, aError: %d", iOperationCancelled, aError );
#endif

    // KErrNotFound can come when trying to suspend a process or thread that no longer exists.
    if  ( !( aError == KErrDied || aError == KErrNotFound ) )
        {
#ifdef _DEBUG
        RDebug::Printf( "CMemSpyDeviceWideOperations::RunError() - fatal error - cancelling..." );
#endif       
        Cancel();
        }
    //
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyDeviceWideOperations::RunError() - END - iOperationCancelled: %d, aError: %d", iOperationCancelled, aError );
#endif
    return KErrNone;
    }


void CMemSpyDeviceWideOperations::CompleteSelf( TInt aError )
    {
    TRequestStatus* status = &iStatus;
    User::RequestComplete( status, aError );
    SetActive();
    }


void CMemSpyDeviceWideOperations::PerformFinalOperationL()
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyDeviceWideOperations::PerformFinalOperationL() - START" );
#endif

    iObserver.HandleDeviceWideOperationEvent( MMemSpyDeviceWideOperationsObserver::EOperationCompleting, 0, KNullDesC );
 
    // Carry out any remaining final one-shot operation
    TPtrC pType( KNullDesC );
    switch( iOperation )
        {
    case EEntireDeviceHeapInfoCompact:
        // Entire operation is performed here
        pType.Set( KMemSpyUiCompactHeap );
        iObserver.HandleDeviceWideOperationEvent( MMemSpyDeviceWideOperationsObserver::EOperationProgressStart, 0, pType );
        iEngine.HelperHeap().OutputHeapInfoForDeviceL();
        break;
    case EEntireDeviceStackInfoCompact:
        // Entire operation is performed here
        pType.Set( KMemSpyUiCompactStack );
        iObserver.HandleDeviceWideOperationEvent( MMemSpyDeviceWideOperationsObserver::EOperationProgressStart, 0, pType );
        iEngine.HelperStack().OutputStackInfoForDeviceL();
        break;
    case EPerEntityHeapInfo:
        // Complete op by outputting kernel heap summary
        pType.Set( KMemSpyUiThreadNameKernel );
        iObserver.HandleDeviceWideOperationEvent( MMemSpyDeviceWideOperationsObserver::EOperationProgressStart, 0, pType );
        iEngine.HelperHeap().OutputHeapInfoKernelL();
        break;
    case EPerEntityHeapData:
        // Complete op by outputting kernel heap data
        // TODO: Uncomment after kernel heap dump is fixed
//        pType.Set( KMemSpyUiThreadNameKernel );
//        iObserver.HandleDeviceWideOperationEvent( MMemSpyDeviceWideOperationsObserver::EOperationProgressStart, 0, pType );
//        iEngine.HelperHeap().OutputHeapDataKernelL();
        break;
    default:
        break;
        }

    // Report progress
    iObserver.HandleDeviceWideOperationEvent( MMemSpyDeviceWideOperationsObserver::EOperationProgressEnd, 1, pType );

#ifdef _DEBUG
    RDebug::Print( _L("CMemSpyDeviceWideOperations::PerformFinalOperationL() - END - pType: %S"), &pType );
#endif
    }


void CMemSpyDeviceWideOperations::PerformNextStepL()
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyDeviceWideOperations::PerformNextStepL() - START - iProcessIndex: %d, iThreadIndex: %d", iProcessIndex, iThreadIndex );
#endif

    // Get the current process
    CMemSpyEngineObjectContainer& container = iEngine.Container();
    const TInt processCount = container.Count();
    CMemSpyProcess& process = container.At( iProcessIndex );
    const TInt threadCount = process.Count();
    
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyDeviceWideOperations::PerformNextStepL() - threadCount: %d, processCount: %d", threadCount, processCount );
#endif

    // Get current thread
    if  ( iThreadIndex < threadCount )
        {
        CMemSpyThread& thread = process.At( iThreadIndex++ );
        const TPtrC pName( thread.Name() );
    
#ifdef _DEBUG
        RDebug::Print( _L("CMemSpyDeviceWideOperations::PerformNextStepL() - thread: %S"), &pName );
#endif

        // Report progress
        iObserver.HandleDeviceWideOperationEvent( MMemSpyDeviceWideOperationsObserver::EOperationProgressStart, 0, pName );

        TInt progressAmount = 1;
        TRAP_IGNORE(

            switch(iOperation)
                {
            case EPerEntityGeneralSummary:
            case EPerEntityGeneralDetailed:
                if  ( iOperation == EPerEntityGeneralSummary )
                    {
                    iEngine.HelperProcess().OutputProcessInfoL( process );
                    }
                else
                    {
                    iEngine.HelperProcess().OutputProcessInfoDetailedL( process );
                    }

                // Process specific item, so do this only once per perocess
                progressAmount = threadCount; 
                iThreadIndex = threadCount;
                break;
            case EPerEntityGeneralHandles:
                thread.InfoContainerForceSyncronousConstructionL().PrintL();
                break;
            case EPerEntityHeapInfo:
                // Output user thread summary here, kernel thread summary will be
                // handled when dialog dismissed
                iEngine.HelperHeap().OutputHeapInfoUserL( thread );
                break;
            case EPerEntityHeapCellListing:
                iEngine.HelperHeap().OutputCellListingUserL( thread );
                break;
            case EPerEntityHeapData:
                iEngine.HelperHeap().OutputHeapDataUserL( thread );
                break;
            case EPerEntityStackInfo:
                iEngine.HelperStack().OutputStackInfoL( thread );
                break;
            case EPerEntityStackDataUser:
                iEngine.HelperStack().OutputStackDataL( thread, EMemSpyDriverDomainUser );
                break;
            case EPerEntityStackDataKernel:
                iEngine.HelperStack().OutputStackDataL( thread, EMemSpyDriverDomainKernel );
                break;
            default:
                break;
                }
            );

        // Report progress
        iObserver.HandleDeviceWideOperationEvent( MMemSpyDeviceWideOperationsObserver::EOperationProgressEnd, progressAmount, pName );
        }
    else
        {
        // This process is exhausted - move on to the next
        ++iProcessIndex;
        iThreadIndex = 0;
 
#ifdef _DEBUG
        RDebug::Printf( "CMemSpyDeviceWideOperations::PerformNextStepL() - move to next process..." );
#endif
        }

    // Request RunL be called again...
    CompleteSelf( KErrNone );

#ifdef _DEBUG
    RDebug::Printf( "CMemSpyDeviceWideOperations::PerformNextStepL() - END" );
#endif
    }


void CMemSpyDeviceWideOperations::SetFinished()
    {
#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::SetFinished() - START" );
#endif

    // Cancel sink time stamp
    iEngine.Sink().DataStreamTimeStampEnd();

    iObserver.HandleDeviceWideOperationEvent( MMemSpyDeviceWideOperationsObserver::EOperationCompleted, 0, KNullDesC );

#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::SetFinished() - END" );
#endif
    }


TInt CMemSpyDeviceWideOperations::TotalNumberOfThreads() const
    {
    TInt count = 0;
    //
    const CMemSpyEngineObjectContainer& container = iEngine.Container();
    const TInt processCount = container.Count();
    //
    for(TInt i=0; i<processCount; i++)
        {
        const CMemSpyProcess& process = container.At( i );
        count += process.Count();
        }
    //
#ifdef _DEBUG
    RDebug::Printf("CMemSpyDeviceWideOperations::TotalNumberOfThreads() - count: %d", count );
#endif
    return count;
    }