--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/piprofiler/plugins/GeneralsPlugin/src/GeneralsDriver.cpp Tue May 25 14:22:58 2010 +0300
@@ -0,0 +1,1152 @@
+/*
+* 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>
+
+#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 );
+
+#define SEPARATE_DFC_QUEUE
+// CONSTANTS
+
+//_LIT(DProfilerThread,"DProfilerThread");
+//const TInt KDProfilerThreadPriority = 27;
+
+#ifdef SEPARATE_DFC_QUEUE
+const TInt KGeneralsDriverThreadPriority = 24;
+_LIT(KGeneralsDriverThread, "PIGeneralsDriver");
+
+#endif
+
+// global Dfc Que
+//TDynamicDfcQue* gDfcQ;
+
+//#ifdef __SMP__
+//
+//enum TNaviEngineAsspInterruptIdExtension
+//{
+// KIntProfilerBase = 99 // Sampling profiler interrupt base.
+// // Each CPU is assigned a sampling interrupt from this base
+// // CPU-0's sampling interrupt is KIntIdSamplingBase + 0
+// // CPU-n's sampling interrupt is KIntIdSamplingBase + n
+//};
+//#endif
+
+/*
+ *
+ *
+ * Class DGfcProfilerFactory definition
+ *
+ *
+ */
+
+class DGeneralsProfilerFactory : public DLogicalDevice
+{
+ public:
+ DGeneralsProfilerFactory();
+ ~DGeneralsProfilerFactory();
+
+ public:
+ virtual TInt Install();
+ virtual void GetCaps(TDes8& aDes) const;
+ virtual TInt Create(DLogicalChannelBase*& aChannel);
+};
+
+/*
+ *
+ *
+ * Class DGfcDriver definition
+ *
+ *
+ */
+class DPluginDriver;
+
+class DGeneralsDriver : public DPluginDriver
+{
+
+public:
+ DGeneralsDriver();
+ ~DGeneralsDriver();
+
+private:
+ TInt NewStart(TInt aRate);
+ static void NewDoProfilerProfile(TAny*);
+ static void NewDoDfc(TAny*);
+
+ // called by each core
+ static void Sample(TAny*);
+
+ TInt GetSampleTime(TUint32* time);
+ //TInt Test(TUint32 testCase);
+
+ TInt StartSampling();
+ TInt StopSampling();
+
+ 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<40000> 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];
+ TInt iMaxCpus;
+ TUint32 iStartTime;
+
+#ifdef SEPARATE_DFC_QUEUE
+ TDynamicDfcQue* iDfcQ;
+#endif
+};
+
+/*
+ *
+ *
+ * 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()
+ {
+ 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;
+ 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();
+#else
+ iMaxCpus = 0;
+#endif
+
+ // initialize synchronizing property
+ LOGSTRING("DGeneralsDriver::InitialiseSamplerList() - initializing property");
+ TInt r(iSampleStartTimeProp.Attach(KGppPropertyCat, EGppPropertySyncSampleNumber));
+ if (r!=KErrNone)
+ {
+ LOGSTRING2("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)
+ {
+ LOGSTRING2("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);
+
+ 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")))
+ return KErrPermissionDenied;
+ if(!Kern::CurrentThreadHasCapability(ECapabilityAllFiles,__PLATSEC_DIAGNOSTIC_STRING("Checked by GeneralsDriver.ldd")))
+ return KErrPermissionDenied;
+
+ SSecurityInfo secureInfo = clientProcess->iS;
+ if (secureInfo.iSecureId != KProfilerExeSecurUid)
+ {
+ return KErrPermissionDenied;
+ }
+ }
+
+ // initiate sample stream ready for collecting the trace data
+ iSampleStream.InsertCurrentClient(iClient);
+
+ iTimer.Cancel();
+ iNewDfc.Cancel();
+
+ Kern::SetThreadPriority(24);
+
+#ifdef SEPARATE_DFC_QUEUE
+ err = Kern::DynamicDfcQCreate(iDfcQ, KGeneralsDriverThreadPriority, TBuf8<32>( KGeneralsDriverThread ));
+ if (KErrNone == err)
+ {
+ SetDfcQ(iDfcQ);
+ iNewDfc.SetDfcQ(iDfcQ);
+ iMsgQ.Receive();
+ return err;
+ }
+#else
+ SetDfcQ(Kern::DfcQue0());
+ iNewDfc.SetDfcQ(iDfcQ);
+ iMsgQ.Receive();
+#endif
+ return err;
+ }
+
+DGeneralsDriver::~DGeneralsDriver()
+ {
+ if (iState!=EStopped)
+ iTimer.Cancel();
+ iNewDfc.Cancel();
+
+#ifdef SEPARATE_DFC_QUEUE
+ if(iDfcQ)
+ iDfcQ->Destroy();
+#endif
+
+ 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 interupts associated with each core.
+ */
+ TInt err(0);
+
+ TUint32 flags = NKern::EIrqBind_Count;
+
+// Kern::Printf(" > Interrupt::InterruptBind KIntProfilerBase - 32=%d", KIntProfilerBase -32 );
+ err = NKern::InterruptBind( KIntProfilerBase - 32 , DGeneralsDriver::Sample, this, flags, 0);
+ if(err < 0)
+ Kern::Printf(" InterruptBind KIntProfilerBase - 32 ret = %d", err );
+
+// Kern::Printf(" > Interrupt::InterruptBind KIntProfilerBase + 1 - 32=%d", KIntProfilerBase + 1-32 );
+ err = NKern::InterruptBind( KIntProfilerBase + 1 - 32 , DGeneralsDriver::Sample, this, flags, 0);
+ if(err < 0)
+ Kern::Printf(" InterruptBind KIntProfilerBase + 1 - 32 ret = %d", err );
+
+// Kern::Printf(" > Interrupt::InterruptBind KIntProfilerBase + 2 - 32=%d", KIntProfilerBase + 2 - 32 );
+ err = NKern::InterruptBind(KIntProfilerBase + 2 - 32 , DGeneralsDriver::Sample, this, flags, 0);
+ if(err < 0)
+ Kern::Printf(" InterruptBind KIntProfilerBase + 2 - 32 ret = %d", err );
+
+// Kern::Printf(" > Interrupt::InterruptBind KIntProfilerBase + 3 - 32=%d", KIntProfilerBase + 3 - 32 );
+ err = NKern::InterruptBind(KIntProfilerBase + 3 - 32 , DGeneralsDriver::Sample, this, flags, 0);
+ if(err < 0)
+ Kern::Printf(" InterruptBind KIntProfilerBase + 3 - 32 ret = %d", err );
+
+
+ err = NKern::InterruptEnable(KIntProfilerBase - 32);
+ if(err < 0)
+ Kern::Printf(" InterruptEnable KIntProfilerBase - 32 ret = %d", err );
+
+ err = NKern::InterruptEnable(KIntProfilerBase + 1 - 32);
+ if(err < 0)
+ Kern::Printf(" InterruptEnable KIntProfilerBase + 1 - 32 ret = %d", err );
+
+ err = NKern::InterruptEnable(KIntProfilerBase + 2 - 32);
+ if(err < 0)
+ Kern::Printf(" InterruptEnable KIntProfilerBase + 2 - 32 ret = %d", err );
+
+ err = NKern::InterruptEnable(KIntProfilerBase + 3 - 32);
+ if(err < 0)
+ Kern::Printf(" InterruptEnable KIntProfilerBase + 3 - 32 ret = %d", err );
+
+#endif
+
+ iTimer.OneShot(aDelay);
+
+ iState = ERunning;
+
+ return KErrNone;
+ }
+
+/*
+ * This function is run in each interrupt
+ */
+// EKA-2 implementation of the sampler method
+
+void DGeneralsDriver::NewDoProfilerProfile(TAny* aPtr)
+ {
+ LOGSTRING("DGeneralsDriver::NewDoProfilerProfile - entry");
+
+#ifdef __SMP__
+ TInt currCpu(NKern::CurrentCpu());
+#endif
+ TInt8 postSampleNeeded(0);
+ DGeneralsDriver& d=*(DGeneralsDriver*)aPtr;
+
+ 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);
+
+ // post-sampling for NTimer interrupted CPU
+ postSampleNeeded += d.iSamplers[currCpu]->PostSampleNeeded();
+
+ /*
+ This is the master sampler from the watchdog timer, so
+ send interrupts to the other CPUs
+ */
+ TScheduler *theSched = TScheduler::Ptr();
+ GicDistributor* gicDist = (GicDistributor* )theSched->i_GicDistAddr;
+
+ for( TInt nCpu(0); nCpu < d.iMaxCpus; nCpu++ )
+ {
+ if( nCpu != currCpu )
+ {
+ gicDist->iSoftIrq = ( 0x10000 << nCpu ) | (KIntProfilerBase + nCpu);
+ }
+ // post-sampling for CPUs with specifically generated interrupts
+ postSampleNeeded += d.iSamplers[nCpu]->PostSampleNeeded();
+ }
+ arm_dsb();
+#endif
+ // then sample the rest of non-cpu samplers
+ for(TInt i(d.iMaxCpus);i<KSamplerAmount;i++)
+ {
+ if(d.iSamplers[i]->iEnabled)
+ {
+ d.iSamplers[i]->Sample();
+ postSampleNeeded += d.iSamplers[i]->PostSampleNeeded();
+ }
+ }
+
+ if(postSampleNeeded > 0 && d.doingDfc == 0)
+ {
+ d.doingDfc++;
+ d.iNewDfc.Add();
+
+ d.sampleRunning--;
+ return;
+ }
+ d.sampleRunning--;
+ }
+ else if (d.iState == EStopping && d.sampleRunning == 0)
+ {
+ // add a dfc for this final time
+ d.iNewDfc.Add();
+ Kern::Printf("DGeneralsDriver::Sample - 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");
+ }
+
+
+
+void DGeneralsDriver::Sample(TAny* aPtr)
+ {
+ LOGSTRING("DGeneralsDriver::Sample - entry");
+
+#ifdef __SMP__
+ DGeneralsDriver& d=*(DGeneralsDriver*)aPtr;
+
+// TInt currCpu(NKern::CurrentCpu());
+
+ // sample the current cpu load
+// if(d.iSamplers[currCpu]->iEnabled)
+// {
+ d.iSamplers[NKern::CurrentCpu()]->Sample();
+// postSampleNeeded += d.iSamplers[currCpu]->PostSampleNeeded();
+// }
+#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())
+ {
+ d.iSamplers[i]->PostSample();
+ }
+ }
+ }
+ d.doingDfc--;
+ }
+
+ else if(d.iState == EStopping)
+ {
+ // 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");
+ // 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);
+ }
+ }
+ }
+
+
+/*
+ * 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");
+ 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:
+ LOGSTRING2("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 interrupts when sampling stops, enabled again on start
+ err = NKern::InterruptDisable(KIntProfilerBase - 32);
+ if(err < 0)
+ Kern::Printf(" InterruptDisable KIntProfilerBase - 32 ret = %d", err );
+
+ err = NKern::InterruptDisable(KIntProfilerBase + 1 - 32);
+ if(err < 0)
+ Kern::Printf(" InterruptDisable KIntProfilerBase + 1 - 32 ret = %d", err );
+
+ err = NKern::InterruptDisable(KIntProfilerBase + 2 - 32);
+ if(err < 0)
+ Kern::Printf(" InterruptDisable KIntProfilerBase + 2 - 32 ret = %d", err );
+
+ err = NKern::InterruptDisable(KIntProfilerBase + 3 - 32);
+ if(err < 0)
+ Kern::Printf(" InterruptDisable KIntProfilerBase + 3 - 32 ret = %d", err );
+
+// Kern::Printf(" > Interrupt::InterruptBind KIntProfilerBase - 32=%d", KIntProfilerBase -32 );
+ err = NKern::InterruptUnbind( KIntProfilerBase - 32);
+ if(err < 0)
+ Kern::Printf(" InterruptUnbind KIntProfilerBase - 32 ret = %d", err );
+
+// Kern::Printf(" > Interrupt::InterruptBind KIntProfilerBase + 1 - 32=%d", KIntProfilerBase + 1-32 );
+ err = NKern::InterruptUnbind( KIntProfilerBase + 1 - 32);
+ if(err < 0)
+ Kern::Printf(" InterruptUnbind KIntProfilerBase + 1 - 32 ret = %d", err );
+
+// Kern::Printf(" > Interrupt::InterruptBind KIntProfilerBase + 2 - 32=%d", KIntProfilerBase + 2 - 32 );
+ err = NKern::InterruptUnbind(KIntProfilerBase + 2 - 32);
+ if(err < 0)
+ Kern::Printf(" InterruptUnbind KIntProfilerBase + 2 - 32 ret = %d", err );
+
+// Kern::Printf(" > Interrupt::InterruptBind KIntProfilerBase + 3 - 32=%d", KIntProfilerBase + 3 - 32 );
+ err = NKern::InterruptUnbind(KIntProfilerBase + 3 - 32);
+ if(err < 0)
+ Kern::Printf(" InterruptUnbind KIntProfilerBase + 3 - 32 ret = %d", 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 = true;
+ }
+ 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++)
+ {
+ Kern::Printf("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;
+ }
+ }
+
+ LOGSTRING2("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;
+ }
+ }
+
+ LOGSTRING2("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()
+ {
+ LOGSTRING("DGeneralsDriver::StartSampling");
+
+ if(iState == EStopped)
+ {
+ // reset iSampleStartTimeProp property value
+ iSampleStartTime = NKern::TickCount(); // get the system tick value for sync purposes
+#ifdef __SMP__
+ 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__
+ Kern::Printf(("DGeneralsDriver::StartSampling - stream reset for generals driver, sync offset %d"), 0);
+ iSamplers[i]->Reset(&iSampleStream, 0);
+#else
+ Kern::Printf(("DGeneralsDriver::StartSampling - stream reset for generals driver, start time %d"), iStartTime);
+ iSamplers[i]->Reset(&iSampleStream, iStartTime);
+#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()
+ {
+ LOGSTRING("DGeneralsDriver::StopSampling");
+
+ if(iState == ERunning)
+ {
+ this->iState = EStopping;
+ // reset all enabled samplers
+ for(TInt i(0);i<KSamplerAmount;i++)
+ {
+ // do the reset only for memory sampler
+ if(iSamplers[i]->iEnabled && iSamplers[i]->iSamplerId == 4)
+ {
+ // reset with stream option
+ LOGTEXT(("DGeneralsDriver::StopSampling - stream reset for samplers"));
+ iSamplers[i]->Reset(&iSampleStream, 999999);
+ }
+ }
+
+ return KErrNone;
+ }
+ else
+ {
+ return KErrGeneral;
+ }
+ }
+
+