perfsrv/piprofiler/plugins/GeneralsPlugin/src/GeneralsDriver.cpp
author hgs
Tue, 26 Oct 2010 16:20:32 +0300
changeset 62 1c2bb2fc7c87
parent 51 98307c651589
permissions -rw-r--r--
201043

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


//
// LDD for thread time profiling
//

#include <kern_priv.h>
#include <platform.h>
#include <arm.h>
#include <kernel/kpower.h>

#ifdef __SMP__
#include <assp/naviengine/naviengine.h> 
#include <nkernsmp/arm/arm_gic.h>
#include <nkernsmp/arm/arm_tmr.h>
#endif

#include "GeneralsDriver.h"
#include <piprofiler/PluginDriver.h>
#include <piprofiler/PluginSampler.h>
#include <piprofiler/ProfilerTraces.h>

#include "GppSamplerImpl.h"
#include "GfcSamplerImpl.h"
#include "IttSamplerImpl.h"
#include "MemSamplerImpl.h"
#include "PriSamplerImpl.h"


#ifndef __SMP__
extern TUint* IntStackPtr();
extern void UsrModLr(TUint32*);
#endif
// for security check
#define KProfilerExeSecurUid 0x2001E5AD
static _LIT_SECURITY_POLICY_PASS(KAllowAllPolicy);
static _LIT_SECURITY_POLICY_FAIL( KDenyAllPolicy );

// CONSTANTS
//_LIT(DProfilerThread,"DProfilerThread");
const TInt KDSamplerThreadPriority = 27;

const TInt KGeneralsDriverThreadPriority = 24;
_LIT(KGeneralsDriverThread, "PIGeneralsDriver");

// global Dfc Que
TDynamicDfcQue* gDfcQ;

#ifdef __SMP__
static TSpinLock PiSpinLock = TSpinLock(TSpinLock::EOrderGenericIrqLow2);
#endif

/*
 *
 *
 *	Class DGeneralsProfilerFactory definition
 *
 *
 */

class DGeneralsProfilerFactory : public DLogicalDevice
{
	public:
		DGeneralsProfilerFactory();
		~DGeneralsProfilerFactory();

	public:
		virtual TInt Install();
		virtual void GetCaps(TDes8& aDes) const;
		virtual TInt Create(DLogicalChannelBase*& aChannel);
};

/*
 *
 *
 *	Class DGeneralsDriver definition
 *
 *
 */
class DPluginDriver;
class DSamplerPowerHandler;

class DGeneralsDriver : public DPluginDriver
{

public:
	DGeneralsDriver();
	~DGeneralsDriver();
    TInt                    StartSampling(TInt aRate, TInt aInterruptNumber);
    TInt                    StopSampling();
private:
    TInt                    isExecuted;
    TInt                    NewStart(TInt aRate);
    void                    IncrementSampleNeededState(TInt aId);
    void                    DecrementSampleNeededState();
	static void				NewDoProfilerProfile(TAny*);
	static void				NewDoDfc(TAny*);
	
	// called by each core
	static void				Sample(TAny* aPtr);

	TInt					GetSampleTime(TUint32* time);
	//TInt					Test(TUint32 testCase); 


	void					InitialiseSamplerList(); 

	DProfilerSamplerBase*	GetSamplerForId(TInt samplerId);
	TInt					GetSamplerVersion(TDes* aDes);
	
#ifdef __SMP__
	void                    UnbindInterrupts();
#endif
	TInt					ProcessStreamReadRequest(TBapBuf* aBuf,TRequestStatus* aStatus);

	TInt					MarkTraceActive(TInt samplerIdToActivate);
	TInt					MarkTraceInactive(TInt samplerIdToDisable);
	TInt					OutputSettingsForTrace(TInt samplerId,TInt settings);
	TInt					AdditionalTraceSettings(TInt samplerId,TInt settings);
	TInt					AdditionalTraceSettings2(TInt samplerId,TInt settings);
	TInt					SetSamplingPeriod(TInt /*samplerId*/,TInt settings);
private:
	// create the driver in EKA-2 version
	TInt			        DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);

	// receive commands and control in EKA-2 version
	void					HandleMsg(TMessageBase* aMsg);
private:
	// timer mechanism in EKA-2 version
	NTimer						iTimer;
	TDfc						iNewDfc;
	TInt						iCount;
	TInt						iLastPcVal;					
	TInt						iPeriod;
	
	// sync sample number property for synchronizing other samplers
	RPropertyRef 				iSampleStartTimeProp;
	TInt						iSampleStartTime;
	
	DProfilerGppSampler<10000> 	gppSampler;
#ifdef __SMP__
	DProfilerGppSampler<10000>  gppSampler2;
    DProfilerGppSampler<10000>  gppSampler3;
    DProfilerGppSampler<10000>  gppSampler4;
#endif
	DProfilerGfcSampler<10000> 	gfcSampler;
	DProfilerIttSampler<10000> 	ittSampler;
	DProfilerMemSampler<10000> 	memSampler;
	DProfilerPriSampler<10000> 	priSampler;
#ifdef __SMP__
//    DProfilerPriSampler<10000>  priSampler2;
//    DProfilerPriSampler<10000>  priSampler3;
//    DProfilerPriSampler<10000>  priSampler4;
#endif
	
#ifndef __SMP__
	static const TInt			KSamplerAmount = 5;
#else
    static const TInt           KSamplerAmount = 8;
#endif
	DProfilerSamplerBase*		iSamplers[KSamplerAmount];
    TUint                       iInterruptCounter[KMaxCpus];
    TInt                        iMaxCpus;
    TUint32                     iStartTime; 
    TInt8                       postSampleNeeded;
    DSamplerPowerHandler*       iPowerHandler;
    
    /* using the HAL machine UID we determine the platform Bridge/Naviengine */
      enum TPlatform
          {
          /* Bridge Platform STE500*/
          EBridge,
          /* Naviengine Platform NE1_TB */
          ENaviengine,
          /* Not recognised platform */
          ENotRecognised,
          /* Spare */
          ESpare
          };
      TPlatform iPlatform;

public:
    TUint8 iStarted;
    TUint8 iOff;
    TInt iRate;
    TInt iIntNo; // Interrupt Number
};
/*
 * PowerHandler
 */
class DSamplerPowerHandler : public DPowerHandler
    {
public: // from DPowerHandler
    void PowerUp();
    void PowerDown(TPowerState);
public:
    DSamplerPowerHandler(DGeneralsDriver* aChannel);
public:
    DGeneralsDriver* iChannel;
    };


/*
 *
 *
 *	Class DGeneralsProfilerFactory implementation
 *
 *
 */

DECLARE_STANDARD_LDD()
    {
	return new DGeneralsProfilerFactory();
    }

TInt DGeneralsProfilerFactory::Create(DLogicalChannelBase*& aChannel)
    {
	aChannel = new DGeneralsDriver;
	return aChannel?KErrNone:KErrNoMemory;
    }


DGeneralsProfilerFactory::DGeneralsProfilerFactory()
    {
	// major, minor, and build version number
    iVersion=TVersion(1,0,1);
    }

DGeneralsProfilerFactory::~DGeneralsProfilerFactory()
    {
    if (gDfcQ)
        {
        gDfcQ->Destroy();
        }
    }

TInt DGeneralsProfilerFactory::Install()
    {
    // Allocate a kernel thread to run the DFC 
    TInt r = Kern::DynamicDfcQCreate(gDfcQ, KDSamplerThreadPriority, KGeneralsDriverThread);
    if (r != KErrNone)
        {
        return r;
        }

    return(SetName(&KPluginSamplerName));
    }

void DGeneralsProfilerFactory::GetCaps(TDes8& aDes) const
    {
    TCapsSamplerV01 b;
    
    b.iVersion=TVersion(1,0,1);
    
    aDes.FillZ(aDes.MaxLength());
    aDes.Copy((TUint8*)&b,Min(aDes.MaxLength(),sizeof(b)));
    }

/*
 *
 *
 *	Class DGeneralsDriver implementation
 *
 *
 */
 
DGeneralsDriver::DGeneralsDriver() :
	iTimer(NewDoProfilerProfile,this),
	iNewDfc(NewDoDfc,this,NULL,7),
#ifdef __SMP__
	gppSampler(0),
	gppSampler2(1),
    gppSampler3(2),
    gppSampler4(3),
#endif
	gfcSampler(gppSampler.GetExportData()),
	ittSampler(gppSampler.GetExportData()),
	memSampler(gppSampler.GetExportData(), PROFILER_MEM_SAMPLER_ID),
	priSampler(gppSampler.GetExportData(), PROFILER_PRI_SAMPLER_ID)
#ifdef __SMP__
//    ,priSampler2(gppSampler.GetExportData(), PROFILER_PRI_SAMPLER_ID),
//    priSampler3(gppSampler.GetExportData(), PROFILER_PRI_SAMPLER_ID),
//    priSampler4(gppSampler.GetExportData(), PROFILER_PRI_SAMPLER_ID)
#endif
    {
	LOGSTRING("DGeneralsDriver::DGeneralsDriver()");

	iState = EStopped;
	iEndRequestStatus = 0;
	doingDfc = 0;
	sampleRunning = 0;
	iSyncOffset = 0;
	iStartTime = 0;
	postSampleNeeded = 0;
	InitialiseSamplerList();
    }

/*
 *
 *	This method has to be changed for each new sampler
 *
 */ 
void DGeneralsDriver::InitialiseSamplerList()
	{
	// initialize all samplers to zero
	for(TInt i(0);i<KSamplerAmount;i++)
		{
		iSamplers[i] = 0;
		}

	TInt i(0);
	iSamplers[i] = &gppSampler;i++;
#ifdef __SMP__
	iSamplers[i] = &gppSampler2;i++;
    iSamplers[i] = &gppSampler3;i++;
    iSamplers[i] = &gppSampler4;i++;
#endif
	iSamplers[i] = &gfcSampler;i++;
	iSamplers[i] = &ittSampler;i++;
	iSamplers[i] = &memSampler;i++;
	iSamplers[i] = &priSampler;i++;
	
#ifdef __SMP__
    // get the number of cpus
    iMaxCpus = NKern::NumberOfCpus();
    for(TInt nCpu(0); nCpu < iMaxCpus; nCpu++)
        {
        iInterruptCounter[nCpu] = 0;
        }

#else
    iMaxCpus = 0;
#endif
    
	// initialize synchronizing property
	LOGSTRING("DGeneralsDriver::InitialiseSamplerList() - initializing property");
	TInt r(iSampleStartTimeProp.Attach(KGppPropertyCat, EGppPropertySyncSampleNumber));
    if (r!=KErrNone)
        {
        Kern::Printf("DGeneralsDriver::InitialiseSamplerList() - error in attaching counter property, error %d", r);
        }
    LOGSTRING("DGeneralsDriver::InitialiseSamplerList() - defining properties");
    r = iSampleStartTimeProp.Define(RProperty::EInt, KAllowAllPolicy, KDenyAllPolicy, 0, NULL);
    if (r!=KErrNone)
        {
        Kern::Printf("DGeneralsDriver::InitialiseSamplerList() - error in defining counter property, error %d", r);
        }
	}


DProfilerSamplerBase* DGeneralsDriver::GetSamplerForId(TInt samplerIdToGet)
    {
	for(TInt i(0);i<KSamplerAmount;i++)
	    {
		if(iSamplers[i]->iSamplerId == samplerIdToGet)
		    {
			return iSamplers[i];
		    }
	    }
	return (DProfilerSamplerBase*)0;
    }

TInt DGeneralsDriver::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer)
    {
    TUint8 err(KErrNone);
    LOGSTRING("DGeneralsDriver::DoCreate()");
    if (!Kern::QueryVersionSupported(TVersion(1,0,1),aVer))
	   	return KErrNotSupported;
    
    // just for testing 
#ifndef __SMP__
    LOGTEXT("Initializing the stack pointer");
    stackTop=(TUint32*)IntStackPtr();
    LOGSTRING2("Got stack pointer 0x%x",(TUint32)stackTop);
#endif

    iClient = &Kern::CurrentThread();
    err = iClient->Open();
	
    DProcess* clientProcess(iClient->iOwningProcess);
    if (clientProcess)
        {
        //Require Power Management and All Files to use this driver
        // Not ideal, but better than nothing
        if(!Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,__PLATSEC_DIAGNOSTIC_STRING("Checked by GeneralsDriver.ldd")))
            {
            Kern::Printf("DGeneralsDriver::CurrentThreadHasCapability - denied");
            return KErrPermissionDenied;
            }
        if(!Kern::CurrentThreadHasCapability(ECapabilityAllFiles,__PLATSEC_DIAGNOSTIC_STRING("Checked by GeneralsDriver.ldd")))
            {
                Kern::Printf("DGeneralsDriver::CurrentThreadHasCapability - denied");
                return KErrPermissionDenied;
            }
        
        SSecurityInfo secureInfo = clientProcess->iS;
        if (secureInfo.iSecureId != KProfilerExeSecurUid)
            {
            Kern::Printf("DGeneralsDriver::security - denied");
            return KErrPermissionDenied;
            }
        }
    
    // initiate sample stream ready for collecting the trace data
	iSampleStream.InsertCurrentClient(iClient);
	
	iTimer.Cancel();
	iNewDfc.Cancel();

	Kern::SetThreadPriority(KGeneralsDriverThreadPriority);

    SetDfcQ(gDfcQ);
    iNewDfc.SetDfcQ(iDfcQ);
    iMsgQ.Receive();
	
	// create the power handler
    iPowerHandler = new DSamplerPowerHandler(this);
    if (!iPowerHandler)
        {
        Kern::Printf("DGeneralsDriver::DoCreate() : new DSamplerPowerHandler(this) failed");
        return KErrNoMemory;
        }
    iPowerHandler->Add();
	return err;
    }

DGeneralsDriver::~DGeneralsDriver()
    {
	if (iState!=EStopped)
	    iTimer.Cancel();
	iNewDfc.Cancel();
	
	iSampleStartTimeProp.Close();
	Kern::SafeClose((DObject*&)iClient,NULL);
    }


TInt DGeneralsDriver::GetSampleTime(TUint32* time)
    {
	LOGSTRING("DGeneralsDriver::GetSampleTime - entry");

	Kern::ThreadRawWrite(	iClient,(TAny*)time, 
							(TAny*)&gppSampler.GetExportData()->sampleNumber, 
							4, iClient);

	LOGSTRING("DGeneralsDriver::GetSampleTime - exit");

	return KErrNone;
    }


TInt DGeneralsDriver::GetSamplerVersion(TDes* aDes)
    {
	LOGSTRING2("DGeneralsDriver::GetSamplerVersion - 0x%x",aDes);
	
	TBuf8<16> aBuf;
	aBuf.Append(PROFILER_SAMPLER_VERSION);
	Kern::ThreadDesWrite(iClient,aDes,aBuf,0,KChunkShiftBy0,iClient);
	LOGSTRING("DGeneralsDriver::GetSamplerVersion - written client descriptor");
	return KErrNone;
    }

TInt DGeneralsDriver::NewStart(TInt aDelay)
    {	
	LOGSTRING("DGeneralsDriver::NewStart");
	iEndRequestStatus = 0;
	
	aDelay = Min(KMaxDelay, Max(KMinDelay, aDelay));

	// always use this rate
	iPeriod = aDelay;
	
#ifdef __SMP__
    /*
     * Bind and enable the sampling interrupts 
     */
    TInt err(0);
    TUint32 flags(NKern::EIrqBind_Count);
    TInt noofCpu(NKern::NumberOfCpus());

    //Binding to the interrupt(s)
    for( TInt nCpu(0); nCpu < noofCpu; nCpu++ )
        {
        LOGSTRING3(" > Interrupt::InterruptBind %d + %d - 32", iIntNo, nCpu );
        err = NKern::InterruptBind( (iIntNo + nCpu - 32) , DGeneralsDriver::Sample, this, flags, 0);
        if(err < 0)
            {
            Kern::Printf(" InterruptBind %d + %d - 32 Error = 0x%x", iIntNo, nCpu, err );
            return err;
            }
        }
     
    //Enabling Interrupt(s)
    for( TInt nCpu(0); nCpu < noofCpu; nCpu++ )
        {
        LOGSTRING3(" > NKern::InterruptEnable %d + %d - 32", iIntNo, nCpu );
        err = NKern::InterruptEnable(iIntNo + nCpu - 32);
        if(err < 0)
            {
            Kern::Printf(" InterruptEnable %d + %d - 32 ret = 0x%x", iIntNo, nCpu, err );
            return err;
            }
        
        /* For Bridge we enable one single interrupt for CPU 1 */
       if(iPlatform == EBridge)
           break;
        }
        
#endif
	
	iTimer.OneShot(aDelay);
	
	iState = ERunning;

	return KErrNone;
    }

void DGeneralsDriver::IncrementSampleNeededState(TInt aId)
    {
    LOGSTRING2("DGeneralsDriver::IncrementSampleNeededState() - incrementing sample needed state, caller id: %d", (aId+1));
#ifdef __SMP__
    TInt intState(0);
    intState = __SPIN_LOCK_IRQSAVE(PiSpinLock);
#endif
    postSampleNeeded++;
#ifdef __SMP__
    __SPIN_UNLOCK_IRQRESTORE(PiSpinLock, intState);
#endif
    }

void DGeneralsDriver::DecrementSampleNeededState()
    {
    LOGSTRING("DGeneralsDriver::DecrementSampleNeededState() - decrementing sample needed state");
#ifdef __SMP__
    TInt intState(0);
    intState = __SPIN_LOCK_IRQSAVE(PiSpinLock);
#endif
    postSampleNeeded--;
#ifdef __SMP__
    __SPIN_UNLOCK_IRQRESTORE(PiSpinLock, intState);
#endif
    }


/*
 *	This function is run in each interrupt
 */
// EKA-2 implementation of the sampler method

void DGeneralsDriver::NewDoProfilerProfile(TAny* aPtr)
    {
    LOGSTRING("DGeneralsDriver::NewDoProfilerProfile - entry");
    DGeneralsDriver& d=*(DGeneralsDriver*)aPtr;
#ifdef __SMP__      
    TInt currCpu(NKern::CurrentCpu());
#endif

    if(!d.iOff)
        {
        if (d.iState == ERunning && d.sampleRunning == 0)
            {
            // start timer again
            d.iTimer.Again(d.iPeriod);
            d.sampleRunning++;

#ifdef __SMP__      
            // print out the sample tick
            if(d.gppSampler.GetExportData()->sampleNumber% 1000 == 0) 
                {
                Kern::Printf(("PIPROF SAMPLE TICK, #%d"), d.gppSampler.GetExportData()->sampleNumber);
                }
            
            // call the actual CPU sampling function for CPU 0 (in NaviEngine), later may be on any of the CPUs
            Sample(aPtr);
            
            /* 
            This is the master sampler from the watchdog timer, so 
            send interrupts to the other CPU(s)
            */
            TScheduler *theSched = TScheduler::Ptr();
//            GicDistributor* gicDist = (GicDistributor* )theSched->i_GicDistAddr;
            GicDistributor* gicDist = (GicDistributor* )(theSched->iSX.iGicDistAddr);
            
            // post-sampling for NTimer interrupted CPU
            //d.postSampleNeeded += d.iSamplers[currCpu]->PostSampleNeeded();
            
            if (d.iPlatform == EBridge)
                {
                /* The Interrupt ID is hardcoded for Bridge to be 108/117, using SPI on ARM GIC
                 * Programming the GIC Distributor Set-Pending Register to raise an interrupt
                 * Programming the GIC Distributor Target Register to set an interrupt in CPU 1
                 */
            
                /* Interrupt Processor Targets Registers (ICDIPTRn)
                 * target register  ICDIPTR number, M, is given by M = N DIV 4
                 * so M is 27 for N = 108/117
                 * NTimer interrupt is always defaulted to CPU 0 so we have to interrupt CPU 1
                 * setting 0bxxxxxx1x CPU interface 1
                 */
//                gicDist->iTarget[27] |= 0x00000002; 
//                gicDist->iTarget[27] &= 0xFE;
                gicDist->iTarget[29] |= 0x00000200; 
                gicDist->iTarget[29] &= 0xFFFFFEFF;

                /* Interrupt Set-Pending Registers (ICDISPRn) 
                 * the corresponding ICDISPR number, M, is given by M = N DIV 32
                 * M = 3 for N being 108/117
                 * the bit number of the required Set-pending bit in this register is N MOD 32
                 * which in this case is 12
                 */ 
//                gicDist->iPendingSet[3] = 1<<((12));  // N = 108
                gicDist->iPendingSet[3] = 1<<((21));    // N = 117

                arm_dsb();
                
                }
            else if (d.iPlatform == ENaviengine) //naviengine platform
                {
                for( TInt nCpu(0); nCpu < NKern::NumberOfCpus(); nCpu++ )
                    {
                    if( nCpu != currCpu )
                        {
                        //Kern::Printf(("DProfile::TimerSampleIsr() > iSoftIrq: to cpu%d, 0x%08X"), nCpu, ( 0x10000 << nCpu ) | (d.iIntNo + nCpu));
                        gicDist->iSoftIrq = ( 0x10000 << nCpu ) | (d.iIntNo + nCpu);
                        }
                    // post-sampling for CPUs with specifically generated interrupts
                    //d.postSampleNeeded += d.iSamplers[nCpu]->PostSampleNeeded();
                    }
                arm_dsb();
               
                }
            else
                {
                Kern::Printf("DGeneralsDriver::NewDoProfilerProfile - SMP Platform not recognised " ); 
                }

#endif  
            // then sample the rest of non-cpu samplers
            for(TInt i(0);i<KSamplerAmount;i++)
                {
                if(d.iSamplers[i]->iEnabled)
                    {
                    d.iSamplers[i]->Sample(aPtr);
                    if(d.iSamplers[i]->PostSampleNeeded())
                        {
                        d.IncrementSampleNeededState(i);
                        }
                    }
                }

//            // check if post sampling is needed for samplers
//            for(TInt i(0);i<KSamplerAmount;i++)
//                {
//                if(d.iSamplers[i]->iEnabled)
//                    {
//                    if(d.iSamplers[i]->PostSampleNeeded())
//                        {
//                        d.IncrementSampleNeededState(i);
//                        }
//                    }
//                }

            if(d.postSampleNeeded > 0 && d.doingDfc == 0)
            //if(d.postSampleNeeded > 0)
                {
                LOGSTRING2("DGeneralsDriver::NewDoProfilerProfile - postSampleNeeded count %d ", d.postSampleNeeded );
                d.doingDfc++;
                d.iNewDfc.Add();
        
                d.sampleRunning--;
        
                return;
                }
            d.sampleRunning--;
            }   // if (d.iState == ERunning && d.sampleRunning == 0)
        else if (d.iState == EStopping && d.sampleRunning == 0)
            {
            // add a dfc for this final time
            d.iNewDfc.Add();
            LOGSTRING("DGeneralsDriver::NewDoProfilerProfile - sampling added to dfc queue");
            }
        else
            {
            // the previous sample has not finished,
            Kern::Printf("DGeneralsDriver::NewDoProfilerProfile - Profiler Sampler Error - interrupted before finished sampling!!");
            }
        LOGSTRING("DGeneralsDriver::NewDoProfilerProfile - exit");
        } // iOff
    else
        {
        Kern::Printf("DGeneralsDriver::iOff");
        }
}


void DGeneralsDriver::Sample(TAny* aPtr)
    {
    LOGSTRING("DGeneralsDriver::Sample - entry");

#ifdef __SMP__
    DGeneralsDriver& d=*(DGeneralsDriver*)aPtr;

    TInt currCpu(NKern::CurrentCpu());
    ++d.iInterruptCounter[currCpu];

    d.iSamplers[currCpu]->Sample(aPtr);
#endif
    LOGSTRING("DGeneralsDriver::Sample - exit");
    }

/*
 *	This function is run when any of the samplers
 *	requires post sampling
 */
void DGeneralsDriver::NewDoDfc(TAny* pointer)
    {
	DGeneralsDriver& d(*((DGeneralsDriver*)pointer));
	
	if(d.iState == ERunning)
	    {
		// for all enabled samplers, perform
		// post sample if needed
		for(TInt i(0);i<KSamplerAmount;i++)
		    {
			if(d.iSamplers[i]->iEnabled)
			    {
				if(d.iSamplers[i]->PostSampleNeeded())
				    {
                    LOGSTRING3("DGeneralsDriver::NewDoDfc iSamplers[%d] PostSampleNeeded count %d", i, d.postSampleNeeded);
                    d.iSamplers[i]->PostSample();
                    d.DecrementSampleNeededState();
                    LOGSTRING3("DGeneralsDriver::NewDoDfc iSamplers[%d] PostSampleNeeded count %d", i, d.postSampleNeeded);
                    }
                }
            }
		d.doingDfc--;
        }

	else if(d.iState == EStopping)
	    {
        LOGSTRING("DGeneralsDriver::NewDoDfc state Stopping()");
		// for all enabled samplers,
		// perform end sampling
		TBool releaseBuffer(false);
		for(TInt i(0);i<KSamplerAmount;i++)
		    {
			if(d.iSamplers[i]->iEnabled)
			    {
                LOGSTRING("DGeneralsDriver::NewDoDfc() - ending");
                if(d.iSamplers[i]->PostSampleNeeded())
                    {
                    LOGSTRING2("DGeneralsDriver::NewDoDfc iSamplers[%d] PostSampleNeeded still", i);
                    d.iSamplers[i]->PostSample();
                    }
				// perform end sampling for all samplers
				// stream mode samplers may be pending, if they
				// are still waiting for another client buffer
				if(d.iSamplers[i]->EndSampling() == KErrNotReady) 
				    {
                    LOGSTRING("DGeneralsDriver::NewDoDfc() - stream data pending");
					releaseBuffer = true;
                    }
				else 
				    {
                    LOGSTRING("DGeneralsDriver::NewDoDfc() - no data pending");
					releaseBuffer = true;
                    }		
                }
            }

		// At the end, once all the samplers are gone through, the buffer should be released
		if (true == releaseBuffer) 
		    {
            LOGSTRING("DGeneralsDriver::NewDoDfc() - release the buffer");
			d.iSampleStream.ReleaseIfPending();	
            }
		
		d.iState = EStopped;
		if(d.iEndRequestStatus != 0 && d.iClient != 0)
		    {
			// sampling has ended
			Kern::RequestComplete(d.iClient,d.iEndRequestStatus,KErrNone);
			LOGSTRING("DGeneralsDriver::NewDoDfc() - request complete, stopped");
            }
        }
    }


/*
 *	All controls are handled here
 */
 
void DGeneralsDriver::HandleMsg(TMessageBase* aMsg)
    {
	TInt r(KErrNone);
	TThreadMessage& m(*(TThreadMessage*)aMsg);

	LOGSTRING5("DGeneralsDriver::HandleMsg 0x%x 0x%x 0x%x 0x%x",m.Int0(),m.Int1(),m.Int2(),m.Int3());
	
	if(m.iValue == (TInt)ECloseMsg)
	    {
		LOGSTRING("DGeneralsDriver::HandleMsg - received close message");
		iTimer.Cancel();
		iNewDfc.Cancel();

		m.Complete(KErrNone,EFalse);
		iMsgQ.CompleteAll(KErrServerTerminated);
		LOGSTRING("DGeneralsDriver::HandleMsg - cleaned up the driver!");
		return;
        }

	if (m.Client()!=iClient)
	    {
		LOGSTRING("DGeneralsDriver::HandleMsg - ERROR, wrong client");
		m.PanicClient(_L("GENERALSSAMPLER"),EAccessDenied);
		return;
        }

	TInt id(m.iValue);
	switch(id)
	    {
		 //Controls are handled here
		case RPluginSampler::EMarkTraceActive:
			LOGSTRING("DGeneralsDriver::HandleMsg - EMarkTraceActive");
			r = MarkTraceActive((TInt)m.Int0());
			break;

		case RPluginSampler::EOutputSettingsForTrace:
			LOGSTRING("DGeneralsDriver::HandleMsg - EOutputSettingsForTrace");
			r = OutputSettingsForTrace((TInt)m.Int0(),(TInt)m.Int1());
			break;

		case RPluginSampler::EAdditionalTraceSettings:
			LOGSTRING("DGeneralsDriver::HandleMsg - EAdditionalTraceSettings");
			r = AdditionalTraceSettings((TInt)m.Int0(),(TInt)m.Int1());
			break;

		case RPluginSampler::EAdditionalTraceSettings2:
			LOGSTRING("DGeneralsDriver::HandleMsg - EAdditionalTraceSettings2");
			r = AdditionalTraceSettings2((TInt)m.Int0(),(TInt)m.Int1());
			break;
			
		case RPluginSampler::ESetSamplingPeriod:
		    LOGSTRING2("DGeneralsDriver::HandleMsg - ESetSamplingPeriod %d", (TInt)m.Int1());
			r = SetSamplingPeriod((TInt)m.Int0(),(TInt)m.Int1());
			break;
			
		case RPluginSampler::EMarkTraceInactive:
			LOGSTRING("DGeneralsDriver::HandleMsg - EMarkTraceInactive");
			r = MarkTraceInactive((TInt)m.Int0());
			break;

		case RPluginSampler::ESample:
			LOGSTRING("DGeneralsDriver::HandleMsg - ESample");
			//r = Sample();  // hack. Original implementation of sample just returned 0
			r = 0;
			break;

		case RPluginSampler::EStartSampling:
		    LOGSTRING("DGeneralsDriver::HandleMsg - EStartSampling");
			iStarted = (TUint8)ETrue;
			r=StartSampling(m.Int0(),m.Int1());
			//r = StartSampling();
			break;

		case RPluginSampler::EGetSampleTime:
			LOGSTRING("DGeneralsDriver::HandleMsg - EGetSampleTime");
			r = GetSampleTime(reinterpret_cast<TUint32*>(m.Ptr0()));
			break;

		case RPluginSampler::EGetSamplerVersion:
			LOGSTRING("DGeneralsDriver::HandleMsg - EGetSamplerVersion");
			r = GetSamplerVersion(reinterpret_cast<TDes*>(m.Ptr0()));
			break;
		
		case RPluginSampler::ECancelStreamRead:
			LOGSTRING("DGeneralsDriver::HandleMsg - ECancelStreamRead");
			iStreamReadCancelStatus = reinterpret_cast<TRequestStatus*>(m.Ptr0());
			r = ProcessStreamReadCancel();
			break;


		 //	Requests are handled here

		case ~RPluginSampler::EStopAndWaitForEnd:
            LOGSTRING("DGeneralsDriver::HandleMsg - EStopAndWaitForEnd");
			iEndRequestStatus = reinterpret_cast<TRequestStatus*>(m.Ptr0());
			r = StopSampling();
#ifdef __SMP__
			UnbindInterrupts();
#endif
			break;

		case ~RPluginSampler::ERequestFillThisStreamBuffer:
			LOGSTRING("DGeneralsDriver::HandleMsg - ERequestFillThisStreamBuffer");			
			r = ProcessStreamReadRequest(	reinterpret_cast<TBapBuf*>(m.Ptr1()),
											reinterpret_cast<TRequestStatus*>(m.Ptr0()));
			break;

		default:
			Kern::Printf("DGeneralsDriver::HandleMsg - ERROR, unknown command %d",id);
			r = KErrNotSupported;
			break;
        }

	LOGSTRING("DGeneralsDriver::HandleMsg - Completed");
	m.Complete(r,ETrue);
    }

#ifdef __SMP__
inline void DGeneralsDriver::UnbindInterrupts()
    {
    TInt err(0);
        /*
         * Disable and unbind the sampling interrupts associated with each core. 
         */
        TInt noofCpu(NKern::NumberOfCpus());
        //Disabling Interrupt(s)
        for( TInt nCpu(0); nCpu < noofCpu; nCpu++ )
            {
            err = NKern::InterruptDisable(iIntNo + nCpu - 32);
            if(err < 0)
                {
                Kern::Printf(" Interrupt Disable iIntNo + %d - 32 ret = %d", nCpu, err );
                }
            }
        
        //UnBinding to the interrupt(s)
        for( TInt nCpu(0); nCpu < noofCpu; nCpu++ )
            {
            LOGSTRING3(" > Interrupt::InterruptUnBind + %d -32 =%d", nCpu, iIntNo + nCpu -32 );
            err = NKern::InterruptUnbind( (iIntNo + nCpu - 32) );
            if(err < 0)
                {
                Kern::Printf(" InterruptUnBind iIntNo + %d - 32 Error = %d", nCpu, err );
                }
            }
    }
#endif

inline TInt DGeneralsDriver::ProcessStreamReadRequest(TBapBuf* aBuf,TRequestStatus* aStatus)
	{
	LOGSTRING("DGeneralsDriver::ProcessStreamReadRequest - entry");
	
	// a new sample buffer has been received from the client
	iSampleStream.AddSampleBuffer(aBuf,aStatus);
	
	// check if we are waiting for the last data to be written to the client
	if(iState == EStopped)
	    {
		LOGSTRING("DGeneralsDriver::ProcessStreamReadRequest state = EStopped");
	
		// sampling has stopped and stream read cancel is pending
		// try to perform the end sampling procedure again
		TBool releaseBuffer(false);
		for(TInt i(0);i<KSamplerAmount;i++)
		    {
			// only for all enabled samplers that have stream output mode
			if(iSamplers[i]->iEnabled /*&& samplers[i]->outputMode == 2*/)
			    {
				//TInt pending = 0;
				// stream mode samplers may be pending, if they
				// are still waiting for another client buffer,
				// in that case, the request should be completed already
				if(iSamplers[i]->EndSampling() == KErrNotReady) 
				    {
                    LOGSTRING("DGeneralsDriver::ProcessStreamReadRequest - still data pending");
					releaseBuffer = false;
                    }
				else 
				    {
                    LOGSTRING("DGeneralsDriver::ProcessStreamReadRequest - no data pending");
					releaseBuffer = true;
                    }
                }
            }
		// At the end, once all the samplers are gone through, the buffer should be released
		if (true == releaseBuffer) 
		    {
            LOGSTRING("DGeneralsDriver::ProcessStreamReadRequest - all data copied, release the buffer");
			iSampleStream.ReleaseIfPending();
		    }
        }
	LOGSTRING("DGeneralsDriver::ProcessStreamReadRequest - exit");
	
	return KErrNone;
	}


/*
 *	Mark traces active or inactive, this can be done
 *	only if sampling is not running
 */

inline TInt DGeneralsDriver::MarkTraceActive(TInt samplerIdToActivate)
	{
	LOGSTRING2("DGeneralsDriver::MarkTraceActive %d",samplerIdToActivate);

	TInt cpus(0);
#ifdef __SMP__
	cpus = NKern::NumberOfCpus();
	if( samplerIdToActivate == PROFILER_GPP_SAMPLER_ID )
	    {
	    for(TInt cpu(0);cpu<cpus;cpu++)
            {
            LOGSTRING2("DGeneralsDriver::MarkTraceActive - activating CPU %d",cpu);
            iSamplers[cpu]->SetEnabledFlag(true);
            }
	    return KErrNone;
	    }
#endif
	for(TInt i(cpus);i<KSamplerAmount;i++)
	    {
		if(iSamplers[i]->iSamplerId == samplerIdToActivate)
		    {
			iSamplers[i]->SetEnabledFlag(true);
			return KErrNone;
            }
        }

	Kern::Printf("DGeneralsDriver::MarkTraceActive - %d not supported",samplerIdToActivate);
	return KErrNotSupported;
	}

inline TInt DGeneralsDriver::MarkTraceInactive(TInt samplerIdToDisable)
	{
	LOGSTRING2("DGeneralsDriver::MarkTraceInactive %d",samplerIdToDisable);

    TInt cpus(0);
#ifdef __SMP__
    cpus = NKern::NumberOfCpus();
    if( samplerIdToDisable == PROFILER_GPP_SAMPLER_ID )
        {
        for(TInt cpu(0);cpu<cpus;cpu++)
             {
             iSamplers[cpu]->SetEnabledFlag(false);
             }
        return KErrNone;
        }
#endif
    for(TInt i(cpus);i<KSamplerAmount;i++)
	    {
		if(iSamplers[i]->iSamplerId == samplerIdToDisable)
		    {
			iSamplers[i]->SetEnabledFlag(false);
			return KErrNone;
            }
        }

	Kern::Printf("DGeneralsDriver::MarkTraceInactive - %d not supported",samplerIdToDisable);
	return KErrNotSupported;
	}

/*
 *	Set output settings for a trace
 */
 
inline TInt DGeneralsDriver::OutputSettingsForTrace(TInt samplerId,TInt settings)
	{
	LOGSTRING3("DGeneralsDriver::OutputSettingsForTrace id:%d set:%d",samplerId,settings);

    TInt cpus(0);
#ifdef __SMP__
    cpus = NKern::NumberOfCpus();
    if( samplerId == PROFILER_GPP_SAMPLER_ID )
        {
        for(TInt cpu(0);cpu<cpus;cpu++)
             {
             iSamplers[cpu]->SetOutputCombination(settings);
             }
        return KErrNone;
        }
#endif
    for(TInt i(cpus);i<KSamplerAmount;i++)
	    {
		if(iSamplers[i]->iSamplerId == samplerId)
		    {
			iSamplers[i]->SetOutputCombination(settings);
			return KErrNone;
		    }
	    }

	return KErrNotSupported;	
	}

/*
 *	Set additional settings for a trace
 */

inline TInt DGeneralsDriver::AdditionalTraceSettings(TInt samplerId,TInt settings)
	{
	LOGSTRING3("DGeneralsDriver::SetAdditionalTraceSettings id:%d set:%d",samplerId,settings);

    TInt cpus(0);
#ifdef __SMP__
    cpus = NKern::NumberOfCpus();
    if( samplerId == PROFILER_GPP_SAMPLER_ID )
        {
        for(TInt cpu(0);cpu<cpus;cpu++)
             {
             iSamplers[cpu]->SetAdditionalSettings(settings);
             }
        return KErrNone;
        }
#endif
    for(TInt i(cpus);i<KSamplerAmount;i++)
	    {
		if(iSamplers[i]->iSamplerId == samplerId)
		    {
			iSamplers[i]->SetAdditionalSettings(settings);
			return KErrNone;
            }
        }

	return KErrNotSupported;	
	}

inline TInt DGeneralsDriver::AdditionalTraceSettings2(TInt samplerId,TInt settings)
	{
	LOGSTRING3("DGeneralsDriver::SetAdditionalTraceSettings id:%d set:%d",samplerId,settings);

    TInt cpus(0);
#ifdef __SMP__
    cpus = NKern::NumberOfCpus();
    if( samplerId == PROFILER_GPP_SAMPLER_ID )
        {
        for(TInt cpu(0);cpu<cpus;cpu++)
             {
             iSamplers[cpu]->SetAdditionalSettings2(settings);
             }
        return KErrNone;
        }
#endif
    for(TInt i(cpus);i<KSamplerAmount;i++)
	    {
		if(iSamplers[i]->iSamplerId == samplerId)
		    {
			iSamplers[i]->SetAdditionalSettings2(settings);
			return KErrNone;
		    }
        }

	return KErrNotSupported;	
	}

inline TInt DGeneralsDriver::SetSamplingPeriod(TInt samplerId,TInt settings)
	{
	LOGSTRING2("DGeneralsDriver::SetSamplingPeriod - set:%d",settings);

	TInt cpus(0);
#ifdef __SMP__
    cpus = NKern::NumberOfCpus();
    if( samplerId == PROFILER_GPP_SAMPLER_ID )
        {
        for(TInt cpu(0);cpu<cpus;cpu++)
             {
             iSamplers[cpu]->SetSamplingPeriod(settings);
             }
        return KErrNone;
        }
#endif
    for(TInt i(cpus);i<KSamplerAmount;i++)
	    {
		if(iSamplers[i]->iSamplerId == samplerId)
		    {
			iSamplers[i]->SetSamplingPeriod(settings);
			return KErrNone;
		    }
	    }

	return KErrNotSupported;	
	}

/*
 *	Mark traces active or inactive, this can be done
 *	only if sampling is not running
 */
 
TInt DGeneralsDriver::StartSampling(TInt aRate, TInt aInterruptNumber)
	{
	LOGSTRING("DGeneralsDriver::StartSampling");

	if(iState == EStopped)
		{
		// reset iSampleStartTimeProp property value
		iSampleStartTime = NKern::TickCount();	// get the system tick value for sync purposes 
#ifdef __SMP__
		TInt err;
		iStartTime = (iSampleStartTime & 0xfffffff0);
#endif
		TInt r(iSampleStartTimeProp.Set(iSampleStartTime));
		
		Kern::Printf(("PIPROF SAMPLE TICK, #0")); // for remote profiling with Profiler Activator
		
		// reset all enabled samplers
		for(TInt i(0);i<KSamplerAmount;i++)
			{
			if(iSamplers[i]->iEnabled)
				{
				// reset with stream option
#ifndef __SMP__
				LOGSTRING2(("DGeneralsDriver::StartSampling - stream reset for generals driver, sync offset %d"), 0);
				iSamplers[i]->Reset(&iSampleStream, 0);
#else
				LOGSTRING2(("DGeneralsDriver::StartSampling - stream reset for generals driver, start time %d"), iStartTime);
                iSamplers[i]->Reset(&iSampleStream, iStartTime);
#endif
				}
			}
#ifdef __SMP__
		iRate = aRate;
		iIntNo = aInterruptNumber;
		// use HAL to understand the underlying hardware
        // not so elegant but used for two SMP pltaforms Bridge and Naviengine
        TVariantInfoV01 info;
        TPckg<TVariantInfoV01> infoPckg(info);
        err = Kern::HalFunction(EHalGroupVariant, EVariantHalVariantInfo, (TAny*)&infoPckg, NULL);
        
        if(err != KErrNone)
            {
            Kern::Printf("Error in reading HAL Entry EVariantHalVariantInfo %r ", err);
            }
        if (info.iMachineUniqueId.iData[0] == KBridgeMachineUID)
            {
            iPlatform = EBridge;
            LOGSTRING("DGeneralsDriver::StartSampling() - Bridge HW");
            }
        else if (info.iMachineUniqueId.iData[0] == KNaviengineMachineUID)
            {
            iPlatform = ENaviengine;
            LOGSTRING("DGeneralsDriver::StartSampling() - NaviEngine HW");
            }
        else
            {
            Kern::Printf("DGeneralsDriver::StartSampling() - Unknown HW, 0x%x", info.iMachineUniqueId.iData[0]);
            }
        
        //users are restricted to use the default Interrupt Number for Bridge
        if ((iPlatform == EBridge) && (aInterruptNumber != KValueZero) && (aInterruptNumber != KBridgeProfilerInterruptId) )
            {
            Kern::Printf("Invalid Interrupt Number for Bridge used %d interrupt...Please use %d Interrupt Number", iIntNo, KBridgeProfilerInterruptId);
            return KErrNotSupported;
            }
        if (aInterruptNumber == KValueZero)
                iIntNo = KDefaultInterruptNumber;
            
            if (iPlatform == EBridge)   
                /* By default for Bridge we are using KBridgeProfilerInterruptId */
                iIntNo = KBridgeProfilerInterruptId;
#endif		
		NewStart(gppSampler.GetPeriod());
		return KErrNone;
		}
	else
		{
		return KErrGeneral;
		}
	}

/*
 *  Mark traces active or inactive, this can be done
 *  only if sampling is not running
 */
 
TInt DGeneralsDriver::StopSampling()
    {
    LOGSTRING2("DGeneralsDriver::StopSampling - iState %", iState);
    TInt noofCpu(NKern::NumberOfCpus());

    if(iState == ERunning)
        {
        this->iState = EStopping;
        // reset all enabled samplers
        for(TInt i(0);i<KSamplerAmount;i++)
            {
            // do the reset only for memory and itt samplers
            if(iSamplers[i]->iEnabled && 
                    (iSamplers[i]->iSamplerId == PROFILER_ITT_SAMPLER_ID || 
                            iSamplers[i]->iSamplerId == PROFILER_MEM_SAMPLER_ID ))
                {
                // reset with stream option
                LOGSTRING(("DGeneralsDriver::StopSampling - stream reset for samplers"));
                iSamplers[i]->Reset(&iSampleStream, KStateSamplingEnding);
                }
            }
        LOGSTRING2("\nDGeneralsDriver::StopSampling - Number of times the Timer counter expired on CPU 0 = %d ", iInterruptCounter[0]);
        
        for(TInt nCpu(1); nCpu < noofCpu; nCpu++)
            {
            Kern::Printf( "\n Number of times we interrupted CPU[%d] = %d and Number of Missed CPU interrupts = %d", nCpu, iInterruptCounter[nCpu],(iInterruptCounter[0] - iInterruptCounter[nCpu]));  
            Kern::Printf( "\n Number of times CPU sampler[0] accessed: %d", gppSampler.GetExportData()->sampleNumber);
#ifdef __SMP__
            Kern::Printf( "\n Number of times CPU sampler[1] accessed: %d", gppSampler2.GetExportData()->sampleNumber);
#endif
            }

        return KErrNone;
        }
    else
        {
        return KErrGeneral;
        }
    }

DSamplerPowerHandler::DSamplerPowerHandler(DGeneralsDriver* aChannel)
    :   DPowerHandler(KPluginSamplerName), 
        iChannel(aChannel)
        {
        LOGSTRING("DSamplerPowerHandler::DSamplerPowerHandler\n");
        }
        
void DSamplerPowerHandler::PowerUp()
    {
    LOGSTRING("DSamplerPowerHandler::PowerUp()1\n");
    iChannel->iOff = (TUint8)EFalse;
    if (iChannel->iStarted)
        {
        LOGSTRING("DSamplerPowerHandler::PowerUp()2\n");
        iChannel->StartSampling(iChannel->iRate, iChannel->iIntNo);
        }
    PowerUpDone();
    }
    
void DSamplerPowerHandler::PowerDown(TPowerState)
    {
    LOGSTRING("DSamplerPowerHandler::PowerDown()\n");
    iChannel->iOff = (TUint8)ETrue;
    //iChannel->iState = EStopped;
    iChannel->StopSampling();
    PowerDownDone();
    }