piprofiler/plugins/DebugOutputWriterPlugin/src/DebOutWriterPlugin.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 25 May 2010 14:22:58 +0300
branchRCL_3
changeset 13 da2cedce4920
permissions -rw-r--r--
Revision: 201019 Kit: 2010121

/*
* 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 Files  

#include "DebOutWriterPlugin.h"	
#include <e32base.h>
//#include <piprofiler/EngineUIDs.h>
#include <piprofiler/ProfilerTraces.h>
#ifdef OST_TRACE_COMPILER_IN_USE
#include <OpenSystemTrace.h>
#include "DebOutWriterPluginTraces.h"
#endif

// engine properties
const TUid KEngineStatusPropertyCat={0x2001E5AD};
enum TEnginePropertyKeys
    {
    EProfilerEngineStatus = 8,
    EProfilerErrorStatus
    };

// CONSTANTS
// own UID
const TUid KDebOutWriterPluginUid = { 0x2001E5BA };

//  Member Functions
/*
 *
 *	Class CDebOutWriterPlugin implementation
 *
 */

CDebOutWriterPlugin* CDebOutWriterPlugin::NewL(const TUid /*aImplementationUid*/, TAny* /*aInitParams*/)
{
	LOGTEXT(_L("CDebOutWriterPlugin::NewL() - entry"));
	CDebOutWriterPlugin* self = new (ELeave) CDebOutWriterPlugin(KDebOutWriterPluginUid);
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();
	LOGTEXT(_L("CDebOutWriterPlugin::NewL() - exit"));
    return self;
}

CDebOutWriterPlugin::CDebOutWriterPlugin(const TUid aImplementationUid) :
	iWriterType(aImplementationUid.iUid)
    {
    LOGTEXT(_L("CDebOutWriterPlugin::CDebOutWriterPlugin - entry"));
    isEnabled = EFalse;
    iWriterId = Id().iUid;
    LOGTEXT(_L("CDebOutWriterPlugin::CDebOutWriterPlugin - exit"));
    }

CDebOutWriterPlugin::~CDebOutWriterPlugin()
    {
    LOGTEXT(_L("CDebOutWriterPlugin::~CDebOutWriterPlugin - entry"));

    iErrorStatus.Close();
    
    if(iWriterHandler)
        {
        iWriterHandler->Cancel();
        delete iWriterHandler;
        }
    LOGTEXT(_L("CDebOutWriterPlugin::~CDebOutWriterPlugin - exit"));
    }    
    
void CDebOutWriterPlugin::ConstructL()
	{
	// second phase constructor, anything that may leave must be constructed here

	LOGTEXT(_L("CDebOutWriterPlugin::ConstructL() - entry"));
	iWriterHandler = CDebOutWriterHandler::NewL(this);
    User::LeaveIfError(iErrorStatus.Attach(KEngineStatusPropertyCat, EProfilerErrorStatus));
    
	LOGTEXT(_L("CDebOutWriterPlugin::ConstructL() - exit"));
	}

TInt CDebOutWriterPlugin::Start()
	{
	LOGTEXT(_L("CDebOutWriterPlugin::Start() - entry"));
	
#ifdef OST_TRACE_COMPILER_IN_USE
    TInt err(KErrNone);
	// activate traces on TraceCore
    RTcDriverParameters tcdp_ThreadIdentification;
    tcdp_ThreadIdentification.iComponentId = KOstTraceComponentID;
    tcdp_ThreadIdentification.iGroupId = CDEBOUTWRITERPLUGIN_PRINTDESCRIPTORASBASE64START;
    err = tcldd.ActivateTrace(tcdp_ThreadIdentification);

    tcdp_ThreadIdentification.iGroupId = CDEBOUTWRITERPLUGIN_PRINTDESCRIPTORASBASE64LINE;
    err = tcldd.ActivateTrace(tcdp_ThreadIdentification);

    tcdp_ThreadIdentification.iGroupId = CDEBOUTWRITERPLUGIN_PRINTDESCRIPTORASBASE64FIN;
    err = tcldd.ActivateTrace(tcdp_ThreadIdentification);

    tcdp_ThreadIdentification.iGroupId = CDEBOUTWRITERPLUGIN_PRINTDESCRIPTORASBASE64END;
    err = tcldd.ActivateTrace(tcdp_ThreadIdentification);

    RDebug::Print(_L("Debug output activated"));
    if(err != KErrNone)
        RDebug::Print(_L("TraceCore LDD API responded: %d"), err);
#endif

	LOGTEXT(_L("CDebOutWriterPlugin::Start() - exit"));
	return KErrNone;
	}

void CDebOutWriterPlugin::Stop()
	{
	LOGTEXT(_L("CDebOutWriterPlugin::Stop() - entry"));
	iWriterHandler->Stop();
#ifdef OST_TRACE_COMPILER_IN_USE
	TInt err(KErrNone);
    // activate traces on TraceCore
    RTcDriverParameters tcdp_ThreadIdentification;
    tcdp_ThreadIdentification.iComponentId = KOstTraceComponentID;
    tcdp_ThreadIdentification.iGroupId = CDEBOUTWRITERPLUGIN_PRINTDESCRIPTORASBASE64START;
    err = tcldd.DeactivateTrace(tcdp_ThreadIdentification);

    tcdp_ThreadIdentification.iGroupId = CDEBOUTWRITERPLUGIN_PRINTDESCRIPTORASBASE64LINE;
    err = tcldd.DeactivateTrace(tcdp_ThreadIdentification);

    tcdp_ThreadIdentification.iGroupId = CDEBOUTWRITERPLUGIN_PRINTDESCRIPTORASBASE64FIN;
    err = tcldd.DeactivateTrace(tcdp_ThreadIdentification);

    tcdp_ThreadIdentification.iGroupId = CDEBOUTWRITERPLUGIN_PRINTDESCRIPTORASBASE64END;
    err = tcldd.DeactivateTrace(tcdp_ThreadIdentification);

    RDebug::Print(_L("Debug output deactivated"));
    if(err != KErrNone)
        RDebug::Print(_L("TraceCore LDD API responded: %d"), err);
#endif
	LOGTEXT(_L("CDebOutWriterPlugin::Stop() - exit"));
	}

TUid CDebOutWriterPlugin::Id() const
	{
    LOGSTRING2("CDebOutWriterPlugin::Id(): 0x%X", KDebOutWriterPluginUid.iUid );
    return KDebOutWriterPluginUid;
	//return iDtor_ID_Key;
	}

TBool CDebOutWriterPlugin::GetEnabled()
	{
	return isEnabled;
	}

void CDebOutWriterPlugin::SetValue( const TWriterPluginValueKeys aKey,
                                    TDes& aValue )
    {
    TRAP_IGNORE( SetValueL( aKey, aValue ) );
    }


void CDebOutWriterPlugin::GetValue( const TWriterPluginValueKeys aKey,
                                    TDes& aValue )
    {
    TRAP_IGNORE( GetValueL( aKey, aValue ) );
    }



void CDebOutWriterPlugin::SetValueL( const TWriterPluginValueKeys aKey, TDes& /*aValue*/ )
{
	LOGTEXT(_L("CDebOutWriterPlugin::SetValueL - entry"));	
	
    switch( aKey )
        {
        case EWriterPluginEnabled:
            isEnabled = ETrue;
        	LOGTEXT(_L("CDebOutWriterPlugin::SetValueL - plugin enabled"));
        	break;
        case EWriterPluginDisabled:
            isEnabled = EFalse;
        	LOGTEXT(_L("CDebOutWriterPlugin::SetValueL - plugin disabled"));	
            break;
        case EWriterPluginSettings:
        	//result = StringLoader::LoadL(PROFILER_KERNEL_MODE_SAMPLER);
        	LOGTEXT(_L("CDebOutWriterPlugin::SetValueL - setting plugin settings"));	
        	break;
        default:
        	break;
        }
	LOGTEXT(_L("CDebOutWriterPlugin::SetValueL - exit"));	

}

TUint32 CDebOutWriterPlugin::GetWriterType()
	{
	return iWriterType;
	}


void CDebOutWriterPlugin::GetValueL( const TWriterPluginValueKeys aKey, TDes& aValue )
    {
    switch( aKey )
        {
        case EWriterPluginVersion:

        	GetWriterVersion(&aValue);
        	break;
        case EWriterPluginType:
        	break;
           default:
                break;
        }
    }

void CDebOutWriterPlugin::GetWriterVersion(TDes* aDes)
	{
	_LIT(KDebugOutputWriterVersion, "1.0.0");
	aDes->Append(KDebugOutputWriterVersion);
	}

void CDebOutWriterPlugin::DoCancel()
{
	LOGTEXT(_L("CDebOutWriterPlugin::DoCancel - entry"));
}

void CDebOutWriterPlugin::WriteData()
    {
    // Activate handler to write data from buffer to output
    LOGTEXT(_L("CDiskWriterPlugin::WriteData() - entry"));
    TRAP_IGNORE(iWriterHandler->StartL());
    LOGTEXT(_L("CDiskWriterPlugin::WriteData() - exit"));
    }

void CDebOutWriterPlugin::HandleError(TInt aError)
    {
    TInt err(KErrNone);
    err = iErrorStatus.Set(aError);
    if(err != KErrNone)
        {
        RDebug::Print(_L("CDiskWriterPlugin::HandleError() - error: %d"), err);
        }
    }

void CDebOutWriterPlugin::PrintDescriptorAsBase64(	TDesC8& aDes,
                                                    TRequestStatus* aStatus,
													TUint32 sampleTime,
													TBool aEmptying)
{
	LOGTEXT(_L("CDebOutWriterPlugin::PrintDescriptorAsBase64() - entry"));
	TUint len = aDes.Length();

	// we must wait for the sample tick to be printed, in case
	// prints are performed at user side, otherwise the kernel
	// prints will corrupt the data
	if(sampleTime != 0xffffffff)
	{
		TUint32 remains = sampleTime%1000;
	
		if(remains > 800) 
		{
			TTimeIntervalMicroSeconds32 timeToWait = ((1050-remains)*1000);
			User::After(timeToWait);
		}
	}
	
	TBuf16<75> buf;

	// Header
#ifdef OST_TRACE_COMPILER_IN_USE
    OstTrace0( PIPROFILER_TRACE_OUT, CDEBOUTWRITERPLUGIN_PRINTDESCRIPTORASBASE64START, 
            "<PIPROF>=================================================================" );
#else
	RDebug::Print(_L("<PIPROF>================================================================="));
#endif
	buf.Zero();

	// base64 encoding table
	const char uu_base64[64] =
	{
		'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
		'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
		'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
		'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
		'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
		'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
		'w', 'x', 'y', 'z', '0', '1', '2', '3',
		'4', '5', '6', '7', '8', '9', '+', '/'
	};

	TChar byte1, byte2, byte3, byte4;
	TUint8 count = 0x30;
	// base64 encoding 
	for(TUint i = 0, j = 0; i < len; i += 3, j = (j + 1) % 18) 
	{
    // byte 1
		byte1 = uu_base64[(aDes[i] >> 2) & 0x3F];
		
		// byte 2
		if(i+1 < len)
			byte2 = uu_base64[(aDes[i] << 4) & 0x3f | (aDes[i+1] >> 4)];
		else
			byte2 = uu_base64[(aDes[i] << 4) & 0x3f];

		// byte 3
		if(i+1 < len && i+2 < len)
			byte3 = uu_base64[(aDes[i+1] << 2) & 0x3f | (aDes[i+2] >> 6)];
		else if(i+1 < len)
			byte3 = uu_base64[(aDes[i+1] << 2) & 0x3f];
		else
			byte3 = '=';

		// byte 4
		if(i+2 < len) 
			byte4 = uu_base64[aDes[i+2] & 0x3f];
		else
			byte4 = '=';
	
		// append to buffer
		buf.Append(byte1);
		buf.Append(byte2);
		buf.Append(byte3);
		buf.Append(byte4);

		// output 72 chars / line
		if(j == 17) 
		{		
			// add check number at the end of line
			buf.Append(count);
#ifdef OST_TRACE_COMPILER_IN_USE
			OstTraceExt1( PIPROFILER_TRACE_OUT, CDEBOUTWRITERPLUGIN_PRINTDESCRIPTORASBASE64LINE, "<PIPROF>%S", &buf );
#else
			RDebug::Print(_L("<PIPROF>%S"),&buf);
#endif
			count++;
			if(count > 0x39)
				count = 0x30;
			buf.Zero();
		}
	}
	
#ifdef OST_TRACE_COMPILER_IN_USE
	OstTraceExt1( PIPROFILER_TRACE_OUT, CDEBOUTWRITERPLUGIN_PRINTDESCRIPTORASBASE64FIN, "<PIPROF>%S", &buf );
#else
	RDebug::Print(_L("<PIPROF>%S"),&buf);
#endif
	buf.Zero();

	// footer
#ifdef OST_TRACE_COMPILER_IN_USE
	OstTrace0( PIPROFILER_TRACE_OUT, CDEBOUTWRITERPLUGIN_PRINTDESCRIPTORASBASE64END, 
	        "<PIPROF>=================================================================" );
#else
	RDebug::Print(_L("<PIPROF>================================================================="));
#endif

	if(!aEmptying)
	    {
        if(aStatus != 0) 
            User::RequestComplete(aStatus,0);
	    }
	
	LOGTEXT(_L("CDebOutWriterPlugin::PrintDescriptorAsBase64() - exit"));
}



/*
 * 
 * Implementation of class CDebOutWriterHandler
 * 
 */
CDebOutWriterHandler::CDebOutWriterHandler(CDebOutWriterPlugin* aWriter) :
    CActive(EPriorityStandard)
    {
    LOGTEXT(_L("CDebOutWriterHandler::CDebOutWriterHandler - entry"));
    iWriter = aWriter;
    
    // set initial mode to non-stopping
    iStopping = EFalse;
    
    // add the handler to the active scheduler
    CActiveScheduler::Add(this);
    LOGTEXT(_L("CDebOutWriterHandler::CDebOutWriterHandler - exit"));
    }

CDebOutWriterHandler* CDebOutWriterHandler::NewL(CDebOutWriterPlugin* aWriter)
{
	LOGTEXT(_L("CDebOutWriterHandler::NewL() - entry"));
	CDebOutWriterHandler* self = new (ELeave) CDebOutWriterHandler(aWriter);
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();
	LOGTEXT(_L("CDebOutWriterHandler::NewL() - exit"));
    return self;
}

CDebOutWriterHandler::~CDebOutWriterHandler()
    {
	LOGTEXT(_L("CDebOutWriterHandler::~CDebOutWriterHandler - entry"));
    
    LOGTEXT(_L("CDebOutWriterHandler::~CDebOutWriterHandler - exit"));
    }    
    
void CDebOutWriterHandler::ConstructL()
	{

	}

void CDebOutWriterHandler::StartL()
	{
	LOGTEXT(_L("CDebOutWriterHandler::StartL - entry"));
    if(!IsActive())
        {
        LOGTEXT(_L("CDiskWriterHandler::StartL - is not active"));
    
        TBapBuf* nextBuf = iWriter->iStream->GetNextFilledBuffer();
        LOGSTRING2("CDiskWriterHandler::StartL - got next filled 0x%x",nextBuf);
    
        if(nextBuf != 0)
            {
            LOGTEXT(_L("CDiskWriterHandler::StartL - writing to file"));
            WriteBufferToOutput(nextBuf);
            }
        }
	LOGTEXT(_L("CDebOutWriterHandler::StartL - entry"));
	}

void CDebOutWriterHandler::Stop()
	{
	LOGTEXT(_L("CDebOutWriterHandler::Stop - entry"));
   
	// do write once more to write the logged data to output
    // set to stopping mode, needed for emptying the remaining full buffers
    iStopping = ETrue;

    // stop the timer
    Reset();

    // set mode back to non-stopping
    iStopping = EFalse;
	LOGTEXT(_L("CDebOutWriterHandler::Stop - exit"));
	}

void CDebOutWriterHandler::Reset()
    {
  
    // start writing new buffer if there is one available
    TBapBuf* nextBuf = iWriter->iStream->GetNextFilledBuffer();
    
    // empty the rest of the buffers synchronously
    while(nextBuf != 0)
        {
        if(nextBuf->iDataSize != 0)
            {
            LOGTEXT(_L("CDiskWriterHandler::Reset - writing to file"));
            iWriter->PrintDescriptorAsBase64(*(nextBuf->iBufDes),&iStatus,0xffffffff, iStopping);
            }
        
        // empty buffers when profiling stopped
        iWriter->iStream->AddToFreeBuffers(nextBuf);

        LOGTEXT(_L("CDiskWriterHandler::Reset - get next full buffer"));
        // start writing new buffer if there is one available
        nextBuf = iWriter->iStream->GetNextFilledBuffer();
        LOGSTRING2("CDiskWriterHandler::Reset - got next filled 0x%x",nextBuf);
        }
    }

void CDebOutWriterHandler::HandleFullBuffers()
    {
    LOGTEXT(_L("CDiskWriterHandler::HandleFullBuffers - entry"));
    // previous write operation has finished
    // release the previous buffer 
    iWriter->iStream->AddToFreeBuffers(iBufferBeingWritten);

    LOGTEXT(_L("CDiskWriterHandler::HandleFullBuffers - get next full buffer"));
    // start writing new buffer if there is one available
    TBapBuf* nextBuf = iWriter->iStream->GetNextFilledBuffer();

    if(nextBuf != 0)
        {
        LOGTEXT(_L("CDiskWriterHandler::HandleFullBuffers - writing to file"));
        if(nextBuf->iDataSize != 0)
            {
            WriteBufferToOutput(nextBuf);
            }
        } 
    LOGTEXT(_L("CDiskWriterHandler::HandleFullBuffers - exit"));
    }

void CDebOutWriterHandler::RunL()
    {
    // call function to complete full buffer handling
    HandleFullBuffers();
    }

void CDebOutWriterHandler::DoCancel()
    {
    
    }

void CDebOutWriterHandler::WriteBufferToOutput(TBapBuf* aBuf)
    {
    LOGTEXT(_L("CDebOutWriterHandler::WriteBufferToOutput - entry"));
    iBufferBeingWritten = aBuf;

    // set the data length just to be sure
    iBufferBeingWritten->iBufDes->SetLength(aBuf->iDataSize);

    LOGTEXT(_L("CDiskWriterPlugin::WriteBufferToOutput - writing to file"));
//    PrintBufferToOutput(iBufferBeingWritten, iStatus);
    iWriter->PrintDescriptorAsBase64(*(iBufferBeingWritten->iBufDes),&iStatus,0xffffffff, iStopping);
    // set AO back to active, until filled buffers are emptied 
    SetActive();
    
    LOGTEXT(_L("CDebOutWriterHandler::WriteBufferToOutput - exit"));
    }

// private
void CDebOutWriterHandler::PrintBufferToOutput(TBapBuf* aBuffer, TRequestStatus& aStatus)
    {
    LOGTEXT(_L("CDebOutWriterHandler::WriteBufferToOutput() - debug out writer tick activated"));

    TPtrC8& aDes = (TPtrC8&)*(aBuffer->iBufDes);
#ifdef BAPPEA_SAMPLE_MARKS
    TUint32 time = iSampler->GetSampleTime();
#else
    TUint32 time = 0xffffffff;
#endif
    iWriter->PrintDescriptorAsBase64(aDes,&aStatus,time, iStopping);
    }