memspy/Engine/Source/MemSpyEngineProcessMemoryTracker.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 06 Jul 2010 16:05:13 +0300
changeset 34 7259cf1302ad
parent 0 a03f92240627
permissions -rw-r--r--
Revision: 201027 Kit: 2010127

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

// System includes
#include <e32debug.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>

// Constants
const TInt KMemSpyNumberOfChangesReceivedProcessNotYetOpen = -1;
const TInt KMemSpyNumberOfChangesReceivedProcessNowOpen = 0;


CMemSpyEngineProcessMemoryTracker::CMemSpyEngineProcessMemoryTracker( CMemSpyEngine& aEngine, const TProcessId& aProcessId )
:   CActive( EPriorityStandard ), iEngine( aEngine ), iProcessId( aProcessId ), iNumberOfChangesReceived( KMemSpyNumberOfChangesReceivedProcessNotYetOpen )
    {
    CActiveScheduler::Add( this );
    }


CMemSpyEngineProcessMemoryTracker::~CMemSpyEngineProcessMemoryTracker()
    {
    Cancel();
    
    // Don't close the process if we didn't successfully open it...
    if  ( iNumberOfChangesReceived != KMemSpyNumberOfChangesReceivedProcessNotYetOpen )
        {
        iEngine.Driver().ProcessInspectionClose( iProcessId );
        }

    iObservers.Close();
    delete iProcessName;
    }


void CMemSpyEngineProcessMemoryTracker::ConstructL()
    {
    // Cache name    
    RProcess process;
    User::LeaveIfError( iEngine.Driver().OpenProcess( iProcessId, process ) );
    CleanupClosePushL( process );
    iProcessName = process.FullName().AllocL();
    iSID = process.SecureId();
    CleanupStack::PopAndDestroy( &process );

    // Indicate that we've opened the process
    iNumberOfChangesReceived = KMemSpyNumberOfChangesReceivedProcessNowOpen;

    // Open driver session
    const TInt error = iEngine.Driver().ProcessInspectionOpen( iProcessId );
    User::LeaveIfError( error );

    // Pull out the first change which the driver always prepares for us when
    // we open an initial connection.
    TRequestStatus status = KRequestPending;
    iEngine.Driver().ProcessInspectionRequestChanges( iProcessId, status, iInfoCurrent );
    User::WaitForRequest( status );
    
    // And update our HWM value based upon this initial seed...
    UpdatePeaks( iInfoCurrent );
    UpdateHWMIncShared( iInfoCurrent );
    UpdateHWMExcShared( iInfoCurrent );
    }


CMemSpyEngineProcessMemoryTracker* CMemSpyEngineProcessMemoryTracker::NewLC( CMemSpyEngine& aEngine, const TProcessId& aProcessId )
    {
    CMemSpyEngineProcessMemoryTracker* self = new(ELeave) CMemSpyEngineProcessMemoryTracker( aEngine, aProcessId );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }


EXPORT_C TBool CMemSpyEngineProcessMemoryTracker::AmTracking() const
    {
    return iAmTracking;
    }


EXPORT_C void CMemSpyEngineProcessMemoryTracker::StartL()
    {
    Cancel();
    iNumberOfChangesReceived = 0;
    //
    iEngine.Driver().ProcessInspectionRequestChanges( iProcessId, iStatus, iInfoCurrent );
    SetActive();
    iAmTracking = ETrue;
    //
    const TInt count = iObservers.Count();
    for( TInt i=0; i<count; i++ )
        {
        MMemSpyEngineProcessMemoryTrackerObserver* obs = iObservers[ i ];
        TRAP_IGNORE( obs->HandleMemoryTrackingStartedL() );
        }
    }


EXPORT_C void CMemSpyEngineProcessMemoryTracker::Stop()
    {
    Cancel();
    //
    iAmTracking = EFalse;
    //
    const TInt count = iObservers.Count();
    for( TInt i=0; i<count; i++ )
        {
        MMemSpyEngineProcessMemoryTrackerObserver* obs = iObservers[ i ];
        TRAP_IGNORE( obs->HandleMemoryTrackingStoppedL() );
        }
    }


EXPORT_C void CMemSpyEngineProcessMemoryTracker::AddObserverL( MMemSpyEngineProcessMemoryTrackerObserver& aObserver )
    {
    RemoveObserver( aObserver );
    User::LeaveIfError( iObservers.Append( &aObserver ) );
    }
 

EXPORT_C void CMemSpyEngineProcessMemoryTracker::RemoveObserver( MMemSpyEngineProcessMemoryTrackerObserver& aObserver )
    {
    TInt pos = iObservers.Find( &aObserver );
    while( pos >= 0 )
        {
        iObservers.Remove( pos );
        pos = iObservers.Find( &aObserver );
        }
    }


EXPORT_C void CMemSpyEngineProcessMemoryTracker::ResetHWML()
    {
    iInfoHWMIncShared.iMemoryStack = 0;
    iInfoHWMIncShared.iMemoryHeap = 0;
    iInfoHWMIncShared.iMemoryChunkLocal = 0;
    iInfoHWMIncShared.iMemoryChunkShared = 0;
    iInfoHWMIncShared.iMemoryGlobalData = 0;
    //
    iInfoHWMExcShared.iMemoryStack = 0;
    iInfoHWMExcShared.iMemoryHeap = 0;
    iInfoHWMExcShared.iMemoryChunkLocal = 0;
    iInfoHWMExcShared.iMemoryChunkShared = 0;
    iInfoHWMExcShared.iMemoryGlobalData = 0;
    //
    const TInt count = iObservers.Count();
    for( TInt i=0; i<count; i++ )
        {
        MMemSpyEngineProcessMemoryTrackerObserver* obs = iObservers[ i ];
        TRAP_IGNORE( obs->HandleMemoryChangedL( iProcessId, InfoCurrent(), InfoHWMIncShared(), InfoHWMExcShared() ) );
        }
    }


void CMemSpyEngineProcessMemoryTracker::RunL()
    {
    //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::RunL() - START" );
    ++iNumberOfChangesReceived;
    
    // Copy current results and request next event providing the driver didn't
    // indicate an error (e.g. KErrDied in the case of process termination)
    TMemSpyDriverProcessInspectionInfo info( iInfoCurrent );
    if  ( iStatus.Int() >= KErrNone )
        {
        iEngine.Driver().ProcessInspectionRequestChanges( iProcessId, iStatus, iInfoCurrent );
        SetActive();
        }
    else
        {
        //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::RunL() - iStatus: %d, not requesting further changes...", iStatus.Int() );
        }

    // Update stats
    UpdatePeaks( info );
    UpdateHWMIncShared( info );
    UpdateHWMExcShared( info );

    // Print out change to file/trace
    //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::RunL() - printing info..." );
    PrintInfoL( info );
    //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::RunL() - done printing info" );

    // Reset peak flags for next cycle
    iInfoPeaks.ResetPeakFlags();

    // Notify observers
    const TInt count = iObservers.Count();
    for( TInt i=0; i<count; i++ )
        {
        MMemSpyEngineProcessMemoryTrackerObserver* obs = iObservers[ i ];
        TRAP_IGNORE( obs->HandleMemoryChangedL( iProcessId, info, InfoHWMIncShared(), InfoHWMExcShared() ) );
        }

    //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::RunL() - END" );
    }


void CMemSpyEngineProcessMemoryTracker::DoCancel()
    {
    ////RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::DoCancel() - START - iStatus: %d", iStatus.Int() );
    iEngine.Driver().ProcessInspectionRequestChangesCancel( iProcessId );
    ////RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::DoCancel() - END - iStatus: %d", iStatus.Int() );
    }


void CMemSpyEngineProcessMemoryTracker::UpdatePeaks( const TMemSpyDriverProcessInspectionInfo& aLatestInfo )
    {
    if  ( aLatestInfo.iMemoryStack > iInfoPeaks.iMemoryStack )
        {
        iInfoPeaks.iPeakStack = ETrue;
        iInfoPeaks.iMemoryStack = aLatestInfo.iMemoryStack;
        }
    if  ( aLatestInfo.iMemoryHeap > iInfoPeaks.iMemoryHeap )
        {
        iInfoPeaks.iPeakHeap = ETrue;
        iInfoPeaks.iMemoryHeap = aLatestInfo.iMemoryHeap;
        }
    if  ( aLatestInfo.iMemoryChunkLocal > iInfoPeaks.iMemoryChunkLocal )
        {
        iInfoPeaks.iPeakChunkLocal = ETrue;
        iInfoPeaks.iMemoryChunkLocal = aLatestInfo.iMemoryChunkLocal;
        }
    if  ( aLatestInfo.iMemoryChunkShared > iInfoPeaks.iMemoryChunkShared )
        {
        iInfoPeaks.iPeakChunkShared = ETrue;
        iInfoPeaks.iMemoryChunkShared = aLatestInfo.iMemoryChunkShared;
        }
    if  ( aLatestInfo.iMemoryGlobalData > iInfoPeaks.iMemoryGlobalData )
        {
        iInfoPeaks.iPeakGlobalData = ETrue;
        iInfoPeaks.iMemoryGlobalData = aLatestInfo.iMemoryGlobalData;
        }
    }


void CMemSpyEngineProcessMemoryTracker::UpdateHWMIncShared( const TMemSpyDriverProcessInspectionInfo& aLatestInfo )
    {
    const TUint32 totalCurrent = aLatestInfo.TotalIncShared();
    const TUint32 totalHWM = iInfoHWMIncShared.TotalIncShared();
    //
    if  ( totalCurrent > totalHWM )
        {
        // Got new HWM
        iInfoHWMIncShared = aLatestInfo;
        }
    }


void CMemSpyEngineProcessMemoryTracker::UpdateHWMExcShared( const TMemSpyDriverProcessInspectionInfo& aLatestInfo )
    {
    const TUint32 totalCurrent = aLatestInfo.TotalExcShared();
    const TUint32 totalHWM = iInfoHWMExcShared.TotalExcShared();
    //
    if  ( totalCurrent > totalHWM )
        {
        // Got new HWM
        iInfoHWMExcShared = aLatestInfo;
        }
    }


void CMemSpyEngineProcessMemoryTracker::PrintInfoL( const TMemSpyDriverProcessInspectionInfo& aInfo )
    {
    //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::PrintInfoL() - START" );
    TBuf<128> timeBuf;
    TTime time( aInfo.iTime );
    MemSpyEngineUtils::FormatTimeSimple( timeBuf, time );
    //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::PrintInfoL() - got time..." );

    // Output changes
    const TBool noOverwrite = EFalse;
    const TBool noTimeStamp = EFalse;

    // Prepare prefix
    _LIT( KMemSpyProcessMemoryTrackerPrefix, "[Change %05d] " );
    TBuf<25> prefixBuf;
    prefixBuf.Format( KMemSpyProcessMemoryTrackerPrefix, iNumberOfChangesReceived );
    iEngine.Sink().OutputPrefixSetLC( prefixBuf );
    //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::PrintInfoL() - set prefix" );

    // Resume (or create) a data stream
    _LIT( KMemSpyFolder, "Process Memory Tracking" );
    _LIT( KMemSpyContext, "Process [0x%08x]" );
    HBufC* context = HBufC::NewLC( KMaxFileName );
    TPtr pContext( context->Des() );
    pContext.Format( KMemSpyContext, (TUint) iSID );
    iEngine.Sink().DataStreamBeginL( pContext, KMemSpyFolder, KNullDesC, noOverwrite, noTimeStamp );
    CleanupStack::PopAndDestroy( context );
    //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::PrintInfoL() - set context" );

    // Preapre peak characters
    const TText KItemPeaked     = '*';
    const TText KItemDidNotPeak = ' ';
    const TText peakStack       = ( iInfoPeaks.iPeakStack       ? KItemPeaked : KItemDidNotPeak );
    const TText peakHeap        = ( iInfoPeaks.iPeakHeap        ? KItemPeaked : KItemDidNotPeak );
    const TText peakChunkLocal  = ( iInfoPeaks.iPeakChunkLocal  ? KItemPeaked : KItemDidNotPeak );
    const TText peakChunkShared = ( iInfoPeaks.iPeakChunkShared ? KItemPeaked : KItemDidNotPeak );
    const TText peakGlobalData  = ( iInfoPeaks.iPeakGlobalData  ? KItemPeaked : KItemDidNotPeak );

    // Write data
    _LIT( KMemSpyMemChangeFormat, "%S - pID: 0x%04x, stack[%c]: %6d, heap[%c]: %10d, local[%c]: %10d, shared[%c]: %10d, globalD[%c]: %10d, totalC: [%10d/%10d], totalHWM: [%10d/%10d] %S" );
    HBufC* buf = HBufC::NewLC( 1024 );

    //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::PrintInfoL() - formatting buffer..." );
    buf->Des().Format( KMemSpyMemChangeFormat, &timeBuf, (TUint) iProcessId, 
                                               peakStack, aInfo.iMemoryStack,
                                               peakHeap, aInfo.iMemoryHeap,
                                               peakChunkLocal, aInfo.iMemoryChunkLocal,
                                               peakChunkShared, aInfo.iMemoryChunkShared, 
                                               peakGlobalData, aInfo.iMemoryGlobalData, 
                                               aInfo.TotalIncShared(), aInfo.TotalExcShared(), 
                                               InfoHWMIncShared().TotalIncShared(), InfoHWMExcShared().TotalExcShared(), 
                                               iProcessName );
    //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::PrintInfoL() - outputting - 1, sinkType: %d", iEngine.Sink().Type() );
    //RDebug::Print( _L("%S"), buf );
    //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::PrintInfoL() - outputting - 2" );
    iEngine.Sink().OutputLineL( *buf, ETrue );
    CleanupStack::PopAndDestroy( buf );

    // End stream
    //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::PrintInfoL() - ending stream" );
    iEngine.Sink().DataStreamEndL();

    // Remove prefix
    CleanupStack::PopAndDestroy();
    //RDebug::Printf( "CMemSpyEngineProcessMemoryTracker::PrintInfoL() - END" );
    }