os/kernelhwsrv/kerneltest/e32utils/profiler/sampler.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/kerneltest/e32utils/profiler/sampler.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1136 @@
     1.4 +// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of the License "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +// e32utils\profiler\sampler.cpp
    1.18 +// 
    1.19 +//
    1.20 +
    1.21 +#include "platform.h"
    1.22 +
    1.23 +#include "sampler.h"
    1.24 +#include <kernel/kern_priv.h>		//temporary
    1.25 +#include <memmodel/epoc/plat_priv.h> // needed for DEpocCodeSeg
    1.26 +_LIT(KLddName,"Sampler");
    1.27 +
    1.28 +TKName KiDFCThread = _L("Running from iDFC");
    1.29 +TKName KiDFCProcess = _L("N/A");
    1.30 +TUint  KiDFCId = (TUint)-1; //both process and thread assigned to iDFC will have 'fake' id=-1
    1.31 +
    1.32 +const TInt KMajorVersionNumber=2;
    1.33 +const TInt KMinorVersionNumber=0;
    1.34 +const TInt KBuildVersionNumber=0;
    1.35 +
    1.36 +const TInt KMinRate=10;
    1.37 +const TInt KMaxRate=1000;
    1.38 +const TInt KRawBufSize=256;
    1.39 +const TInt KCookedBufSize=0x2000;
    1.40 +const TInt KCodeBufSize=0x2000;
    1.41 +
    1.42 +const TInt KMaxCreateCodeSegRecordSize = 300; //Max size of the encoded CodeSegCreate record.
    1.43 +const TInt KMaxErrorReportRecordSize = 18;    //Max size of the encoded ErrorReport record. (3 zeros and 3 integers)
    1.44 +const TInt KRequiredFreeSpace=512;
    1.45 +
    1.46 +//Bit mask in report
    1.47 +const TInt KNonXIPModeActive=1; 
    1.48 +const TInt KNoDebugSupport=2;
    1.49 +
    1.50 +
    1.51 +#define PUT(p,x,e,s)	{*(p)++=(x); if ((p)==(e)) (p)-=(s);}
    1.52 +#define GET_A_BYTE(p,x,e,s)	{*(x)++=*(p)++; if ((p)==(e)) (p)-=(s);}
    1.53 +
    1.54 +#define	TAG(obj)		(*(TUint32*)&(obj->iAsyncDeleteNext))
    1.55 +
    1.56 +#define CODESEGBUFEND (iCodeSegBuffer+KCodeBufSize)
    1.57 +#define COOKEDBUFEND (iCookedBuf+KCookedBufSize)
    1.58 +
    1.59 +extern TUint IntStackPtr();
    1.60 +extern TUint32 SPSR();
    1.61 +extern TUint IDFCRunning();
    1.62 +
    1.63 +// global Dfc Que
    1.64 +TDynamicDfcQue* gDfcQ;
    1.65 +
    1.66 +class DDeviceSampler : public DLogicalDevice
    1.67 +	{
    1.68 +public:
    1.69 +	DDeviceSampler();
    1.70 +	~DDeviceSampler();
    1.71 +	virtual TInt Install();
    1.72 +	virtual void GetCaps(TDes8& aDes) const;
    1.73 +	virtual TInt Create(DLogicalChannelBase*& aChannel);
    1.74 +	};
    1.75 +
    1.76 +struct SRawSample
    1.77 +	{
    1.78 +	TLinAddr iPC;
    1.79 +	TUint32 iSampleCounter;
    1.80 +	TUint32 iThreadId;
    1.81 +	};
    1.82 +
    1.83 +class DProfile : public DLogicalChannel
    1.84 +	{
    1.85 +public:
    1.86 +	DProfile();
    1.87 +	~DProfile();
    1.88 +protected:
    1.89 +	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
    1.90 +	virtual void HandleMsg(TMessageBase* aMsg);
    1.91 +private:
    1.92 +	TInt GetSegments(TDes8* aDes);
    1.93 +	TInt StartSampling(TInt aRate);
    1.94 +	TInt StopSampling();
    1.95 +	TInt Reset(TBool aXIPOnly);
    1.96 +	TInt ResetSegments();
    1.97 +	TInt Drain(TDes8* aDes);
    1.98 +	TInt GetErrors(TDes8* aDes);
    1.99 +	TInt ProcessReadRequest();
   1.100 +	TInt DoDrainCooked();
   1.101 +	TInt Cook();
   1.102 +	void Complete(TInt aResult);
   1.103 +	inline TBool Running()
   1.104 +		{return iTimer.iState!=NTimer::EIdle;}
   1.105 +private:
   1.106 +	static void Sample(TAny*);
   1.107 +	static void Dfc(TAny*);
   1.108 +	static TUint KernelEventHandler(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aPrivateData);
   1.109 +	void LogCodeSegEvent(TKernelEvent aEvent, DEpocCodeSeg *pCodeSeg);
   1.110 +
   1.111 +private:
   1.112 +	static TUint8* EncodeTag(TUint8* p, TUint8* e);
   1.113 +	static TUint8* EncodeInt(TUint8* p, TUint8* e, TInt aValue);
   1.114 +	static TUint8* EncodeUint(TUint8* p, TUint8* e, TUint aValue);
   1.115 +	static TUint8* EncodeText(TUint8* p, TUint8* e, const TDesC& aDes);
   1.116 +	static TUint8* EncodeRepeat(TUint8* p, TUint8* e, DProfile* aProfile);
   1.117 +	TUint8* EncodeThread(TUint8* p, TUint8* e, DThread* aThread);
   1.118 +	TUint8* EncodeIDFC(TUint8* p, TUint8* e);
   1.119 +	
   1.120 +	TUint8* PutStream(TUint8* p, TUint8* e, const TUint8* aSource, TInt aSize);
   1.121 +	TUint8* GetStream(TUint8* p, TUint8* e, TInt8* aDest, TInt aSize);	
   1.122 +	TBool CookCodeSeg(TBool aPutAll, TInt aSampleCounter);
   1.123 +
   1.124 +private:
   1.125 +	TUint32 iStartTime;
   1.126 +	TInt iRepeat;
   1.127 +	SRawSample iLast;
   1.128 +	TInt iPeriod;
   1.129 +	NTimer iTimer;
   1.130 +	TDfc iDfc;
   1.131 +	TUint* iIntStackTop;
   1.132 +	DThread* iClient;
   1.133 +	TRequestStatus* iReqStatus;
   1.134 +	TInt iPos;			// client des pos
   1.135 +	TInt iRemain;		// space left in client des
   1.136 +	TDes8* iDes;		// client des pointer
   1.137 +	TUint8 iRPut;		// raw buffer put index
   1.138 +	TUint8 iRGet;		// raw buffer get index
   1.139 +	TUint8* iCPut;		// cooked buffer put
   1.140 +	TUint8* iCGet;		// cooked buffer get
   1.141 +	SRawSample iRawBuf[KRawBufSize];
   1.142 +	TUint8 iCookedBuf[KCookedBufSize];
   1.143 +	
   1.144 +	DKernelEventHandler* iKernelEvHandler;
   1.145 +
   1.146 +	TInt iNextSampleCounter;
   1.147 +	TBool iXIPOnly;
   1.148 +	TBool iMarkedOnlySegments;	// True during GettingSegments phase in which event handler...
   1.149 +								// ... collects only the events from marked segments.
   1.150 +	TUint8 iCodeSegBuffer[KCodeBufSize];
   1.151 +	TUint8* iCSPut;		// CodeSeg buffer put
   1.152 +	TUint8* iCSGet;		// CodeSeg buffer get
   1.153 +	TUint iIDFCSeenBefore;
   1.154 +	struct TReport
   1.155 +		{
   1.156 +		TUint iRowBufferErrCounter;
   1.157 +		TUint iCodeSegErrCounter;
   1.158 +		TInt  iReportMask; 
   1.159 +		} iReport;
   1.160 +	};
   1.161 +
   1.162 +DECLARE_STANDARD_LDD()
   1.163 +	{
   1.164 +	return new DDeviceSampler;
   1.165 +	}
   1.166 +
   1.167 +DDeviceSampler::DDeviceSampler()
   1.168 +//
   1.169 +// Constructor
   1.170 +//
   1.171 +	{
   1.172 +	//iParseMask=0;
   1.173 +	//iUnitsMask=0;
   1.174 +	iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
   1.175 +	}
   1.176 +
   1.177 +const TInt KDSamplerThreadPriority = 27;
   1.178 +_LIT(KDSamplerThread,"DSamplerThread");
   1.179 +
   1.180 +TInt DDeviceSampler::Install()
   1.181 +//
   1.182 +// Install the device driver.
   1.183 +//
   1.184 +	{
   1.185 +	// Allocate a kernel thread to run the DFC 
   1.186 +	TInt r = Kern::DynamicDfcQCreate(gDfcQ, KDSamplerThreadPriority, KDSamplerThread);
   1.187 +
   1.188 +	if (r != KErrNone)
   1.189 +		return r; 	
   1.190 +
   1.191 +	r=SetName(&KLddName);
   1.192 +	return r;
   1.193 +	}
   1.194 +
   1.195 +void DDeviceSampler::GetCaps(TDes8& aDes) const
   1.196 +//
   1.197 +// Return the capabilities.
   1.198 +//
   1.199 +	{
   1.200 +	}
   1.201 +
   1.202 +/**
   1.203 +  Destructor
   1.204 +*/
   1.205 +DDeviceSampler::~DDeviceSampler()
   1.206 +	{
   1.207 +	if (gDfcQ)
   1.208 +		gDfcQ->Destroy();
   1.209 +	}
   1.210 +
   1.211 +TInt DDeviceSampler::Create(DLogicalChannelBase*& aChannel)
   1.212 +//
   1.213 +// Create a channel on the device.
   1.214 +//
   1.215 +	{
   1.216 +	aChannel=new DProfile;
   1.217 +	return aChannel?KErrNone:KErrNoMemory;
   1.218 +	}
   1.219 +
   1.220 +DProfile::DProfile()
   1.221 +	:	iTimer(Sample,this),
   1.222 +		iDfc(Dfc,this,NULL,7)
   1.223 +//
   1.224 +// Constructor
   1.225 +//
   1.226 +	{
   1.227 +	}
   1.228 +
   1.229 +DProfile::~DProfile()
   1.230 +//
   1.231 +// Destructor
   1.232 +//
   1.233 +	{
   1.234 +	Kern::SafeClose((DObject*&)iClient, NULL);
   1.235 +	}
   1.236 +
   1.237 +TInt DProfile::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
   1.238 +//
   1.239 +// Create the channel from the passed info.
   1.240 +//
   1.241 +	{
   1.242 +	if (!Kern::QueryVersionSupported(TVersion(1,0,1),aVer))
   1.243 +		return KErrNotSupported;
   1.244 +	iClient=&Kern::CurrentThread();
   1.245 +	iClient->Open();
   1.246 +	Kern::SetThreadPriority(24);
   1.247 +	iIntStackTop=(TUint*)IntStackPtr();
   1.248 +	SetDfcQ(gDfcQ);
   1.249 +	iDfc.SetDfcQ(iDfcQ);
   1.250 +	iMsgQ.Receive();
   1.251 +	return KErrNone;
   1.252 +	}
   1.253 +
   1.254 +void DProfile::Complete(TInt aResult)
   1.255 +//Completes user request
   1.256 +	{
   1.257 +	DEBUG_PROFILER(Kern::Printf("C");)
   1.258 +	Kern::RequestComplete(iClient,iReqStatus,aResult);
   1.259 +	}
   1.260 +
   1.261 +TInt DProfile::StartSampling(TInt aRate)
   1.262 +	{
   1.263 +	DEBUG_PROFILER(Kern::Printf("START");)
   1.264 +	//Activate timer
   1.265 +	aRate=Min(KMaxRate, Max(KMinRate, aRate));
   1.266 +	iPeriod=1000/aRate;
   1.267 +	if (!Running())
   1.268 +		iTimer.OneShot(iPeriod);
   1.269 +	
   1.270 +	DEBUG_PROFILER(Kern::Printf("START end");)
   1.271 +	return KErrNone;
   1.272 +	}
   1.273 +
   1.274 +TInt DProfile::GetSegments(TDes8* aDes)
   1.275 +//
   1.276 +// Collects and marks all non-XIP segments.
   1.277 +//
   1.278 +	{
   1.279 +	DEBUG_PROFILER(Kern::Printf("GS");)
   1.280 +	TInt max=Kern::ThreadGetDesMaxLength(iClient,aDes);
   1.281 +	Kern::ThreadDesWrite(iClient,aDes,KNullDesC8,0,0,iClient);//Set length to zero
   1.282 +	TInt current = 0;
   1.283 +
   1.284 +	Kern::AccessCode();
   1.285 +	
   1.286 +	// Take all records that are collected by event handler first. They may be only Delete CodeSeg 
   1.287 +	// events of tagged(marked) segments. On the first GetSegments call, cooked buffer also contains Profile Tag.
   1.288 +
   1.289 +	CookCodeSeg(ETrue, 0); // Transfer/encode from CodeSeg buffer into cooked buffer
   1.290 +	current = iCPut-iCGet;
   1.291 +	if (current)
   1.292 +		{
   1.293 +		if (current < max)
   1.294 +			{//Copy data into user side descriptor
   1.295 +			TPtrC8 aPtr(iCGet, current);
   1.296 +			Kern::ThreadDesWrite(iClient,aDes,aPtr,0,KChunkShiftBy0,iClient);
   1.297 +			}
   1.298 +		else
   1.299 +			{	
   1.300 +			//This is very unlikely as in this stage we collect only CodeSeg Delete events of the marked segments.
   1.301 +			//It cannot happen on the first call, as there are no marked segments - which means that Profiler Tag is OK.
   1.302 +			iReport.iCodeSegErrCounter++;
   1.303 +			}
   1.304 +		}
   1.305 +	iCGet = iCPut = iCookedBuf; //Reset the cooked buffer
   1.306 +	
   1.307 +	//Collect all non-XIP segments that are not already marked.
   1.308 +
   1.309 +	SDblQue* p = Kern::CodeSegList();
   1.310 +	SDblQueLink* anchor=&p->iA;
   1.311 +	SDblQueLink* a=anchor->iNext;
   1.312 +	for (; a!=anchor; a=a->iNext) 
   1.313 +		{
   1.314 +		DEpocCodeSeg* pSeg = (DEpocCodeSeg*) _LOFF(a, DCodeSeg, iLink);
   1.315 +		if (pSeg->iXIP || pSeg->iMark&DCodeSeg::EMarkProfilerTAG)
   1.316 +			continue;
   1.317 +		if (current > (max-KMaxCreateCodeSegRecordSize))
   1.318 +			break;//No more space. Finish now and wait for another GetSegments request.
   1.319 +			
   1.320 +		pSeg->iMark |= DCodeSeg::EMarkProfilerTAG;	//Mark this segment
   1.321 +		LogCodeSegEvent(EEventAddCodeSeg, pSeg); 	//Place this record into CodeSeg buffer ...
   1.322 +		CookCodeSeg(ETrue, 0);						//...and encode it into cooked buffer
   1.323 +		TPtrC8 aPtr(iCGet, iCPut-iCGet);
   1.324 +		Kern::ThreadDesWrite(iClient,aDes,aPtr,current,KChunkShiftBy0,iClient);//Copy record into user desc.
   1.325 +		current += iCPut-iCGet;
   1.326 +		iCPut = iCGet = iCookedBuf; //Reset cooked buffer
   1.327 +		}
   1.328 +
   1.329 +	if (!current)//This will be the last GetSegments call. From now on, all events have to be recorded.
   1.330 +		iMarkedOnlySegments = EFalse;
   1.331 +	
   1.332 +	Kern::EndAccessCode();
   1.333 +	DEBUG_PROFILER(Kern::Printf("GS end %d",current);)
   1.334 +	return KErrNone;
   1.335 +	}
   1.336 +
   1.337 +TInt DProfile::ResetSegments()
   1.338 +//
   1.339 +// Unmarks all non-XIP segments 
   1.340 +// Sets device into GettingSegments mode in which only the events of the marked Code Segments will be recorder
   1.341 +// 
   1.342 +	{
   1.343 +	DEBUG_PROFILER(Kern::Printf("RS");)
   1.344 +	if (iXIPOnly)
   1.345 +		return KErrGeneral;
   1.346 +	
   1.347 +	Kern::AccessCode();
   1.348 +	SDblQue* p = Kern::CodeSegList();
   1.349 +	SDblQueLink* anchor=&p->iA;
   1.350 +	SDblQueLink* a=anchor->iNext;
   1.351 +	for (; a!=anchor; a=a->iNext) 
   1.352 +		{
   1.353 +		DEpocCodeSeg* pSeg = (DEpocCodeSeg*) _LOFF(a, DCodeSeg, iLink);
   1.354 +		if (!pSeg->iXIP)
   1.355 +			pSeg->iMark &= ~DCodeSeg::EMarkProfilerTAG;
   1.356 +		}
   1.357 +
   1.358 +	if (DKernelEventHandler::DebugSupportEnabled())
   1.359 +		{
   1.360 +		DEBUG_PROFILER(Kern::Printf("RS add handler");)
   1.361 +		iKernelEvHandler->Add();
   1.362 +		iReport.iReportMask|= KNonXIPModeActive;
   1.363 +		}
   1.364 +	else
   1.365 +		iReport.iReportMask|= KNoDebugSupport;	
   1.366 +	
   1.367 +	iMarkedOnlySegments = ETrue;	
   1.368 +	Kern::EndAccessCode();
   1.369 +	DEBUG_PROFILER(Kern::Printf("RS end");)
   1.370 +	return KErrNone;
   1.371 +	}
   1.372 +
   1.373 +TInt DProfile::Reset(TBool aXIPOnly)
   1.374 +	{
   1.375 +//
   1.376 +// Resets the device. It is the first message sent by profiler application.
   1.377 +//	
   1.378 +	if (Running())
   1.379 +		return KErrGeneral;
   1.380 +	
   1.381 +	DEBUG_PROFILER(Kern::Printf("RST %d", aXIPOnly);)
   1.382 +
   1.383 +	iXIPOnly = aXIPOnly;
   1.384 +
   1.385 +	iTimer.Cancel();
   1.386 +	iDfc.Cancel();
   1.387 +	iLast.iPC=0;
   1.388 +	iLast.iSampleCounter=0;
   1.389 +	iLast.iThreadId=0;
   1.390 +	iRepeat=0;
   1.391 +	iPeriod=1;
   1.392 +	iReqStatus=NULL;
   1.393 +	iRPut=0;				// raw buffer put index
   1.394 +	iRGet=0;				// raw buffer get index
   1.395 +	iCPut=EncodeTag(iCookedBuf,COOKEDBUFEND); //cooked buffer put
   1.396 +	iCGet=iCookedBuf;		// cooked buffer get
   1.397 +	iPos=0;					// client des pos
   1.398 +	iDes=NULL;				// client des pointer
   1.399 +	iStartTime=NKern::TickCount();
   1.400 +
   1.401 +	iReport.iRowBufferErrCounter = 0;
   1.402 +	iReport.iCodeSegErrCounter = 0;
   1.403 +	iReport.iReportMask = 0;
   1.404 +	iNextSampleCounter = 0;
   1.405 +	iCSPut=iCodeSegBuffer;	// CodeSeg buffer put
   1.406 +	iCSGet=iCodeSegBuffer;	// CodeSeg buffer get
   1.407 +	iMarkedOnlySegments = EFalse;
   1.408 +	iIDFCSeenBefore = EFalse;
   1.409 +	if (!iXIPOnly)
   1.410 +		iKernelEvHandler = new DKernelEventHandler(KernelEventHandler, this);
   1.411 +	
   1.412 +	DEBUG_PROFILER(Kern::Printf("RST end");)
   1.413 +	return KErrNone;
   1.414 +	}
   1.415 +
   1.416 +TInt DProfile::StopSampling()
   1.417 +//
   1.418 +// Stops sampling
   1.419 +//
   1.420 +	{
   1.421 +	DEBUG_PROFILER(Kern::Printf("STOP");)
   1.422 +	if (Running())
   1.423 +		{
   1.424 +		iTimer.Cancel();
   1.425 +		Dfc(this);
   1.426 +		}
   1.427 +	if (iReqStatus)
   1.428 +		Complete(KErrNone);
   1.429 +	
   1.430 +	DEBUG_PROFILER(Kern::Printf("STOP end");)
   1.431 +	return KErrNone;
   1.432 +	}
   1.433 +
   1.434 +TInt DProfile::GetErrors(TDes8* aDes)
   1.435 +//
   1.436 +// Returns error report and closes event handler
   1.437 +//
   1.438 +	{
   1.439 +	TInt r = KErrNone;
   1.440 +	TBuf8<KMaxErrorReportRecordSize> localBuf; //Enough space to encode 3 zeros and 3 integers
   1.441 +	DEBUG_PROFILER(Kern::Printf("GE");)
   1.442 +
   1.443 +	TInt max=Kern::ThreadGetDesMaxLength(iClient,aDes);
   1.444 +	if (max<KMaxErrorReportRecordSize)
   1.445 +		return KErrArgument;
   1.446 +	
   1.447 +	Kern::ThreadDesWrite(iClient,aDes,KNullDesC8,0,0,iClient);//set zero length
   1.448 +	
   1.449 +	TUint8* p = (TUint8*)localBuf.Ptr();
   1.450 +	TUint8* e = p+KMaxErrorReportRecordSize;
   1.451 +	p = EncodeInt (p, e, 0);
   1.452 +	p = EncodeUint(p, e, 0);
   1.453 +	p = EncodeUint(p, e, 0);
   1.454 +
   1.455 +	p = EncodeUint(p, e, iReport.iRowBufferErrCounter);
   1.456 +	p = EncodeUint(p, e, iReport.iCodeSegErrCounter);
   1.457 +	p = EncodeUint(p, e, iReport.iReportMask);
   1.458 +
   1.459 +	localBuf.SetLength(p-localBuf.Ptr());
   1.460 +	r=Kern::ThreadDesWrite(iClient,aDes,localBuf,0,KChunkShiftBy0,iClient);
   1.461 +	
   1.462 +	if(iKernelEvHandler && iKernelEvHandler->IsQueued())
   1.463 +		iKernelEvHandler->Close();
   1.464 +
   1.465 +	DEBUG_PROFILER(Kern::Printf("GE end %d %d %d", iReport.iRowBufferErrCounter, iReport.iCodeSegErrCounter, iReport.iReportMask);)
   1.466 +	return r;
   1.467 +	}
   1.468 +
   1.469 +
   1.470 +TInt DProfile::Drain(TDes8* aDes)
   1.471 +//
   1.472 +// Collects any remaining data
   1.473 +//
   1.474 +	{
   1.475 +	DEBUG_PROFILER(Kern::Printf("D");)		
   1.476 +	if (Running())
   1.477 +		return KErrGeneral;
   1.478 +	// we can assume read request is not pending
   1.479 +	TInt max=Kern::ThreadGetDesMaxLength(iClient,aDes);
   1.480 +	if (max<0)
   1.481 +		return max;
   1.482 +	if (max==0)
   1.483 +		return KErrArgument;
   1.484 +	TInt r=Kern::ThreadDesWrite(iClient,aDes,KNullDesC8,0,0,iClient);		// set client descriptor length to zero
   1.485 +	if (r!=KErrNone)
   1.486 +		return r;
   1.487 +	iDes=aDes;
   1.488 +	iRemain=max;
   1.489 +	iPos=0;
   1.490 +	iReqStatus=NULL;
   1.491 +	TInt n=-1;
   1.492 +	while (n)
   1.493 +		{
   1.494 +		r=DoDrainCooked();				// drain any cooked data if possible
   1.495 +		if (r<0 && r!=KErrUnderflow)
   1.496 +			return r;					// error writing client buffer
   1.497 +		n=Cook();						// cook the samples, return number cooked
   1.498 +		}
   1.499 +
   1.500 +	// there might still be data left over
   1.501 +	DEBUG_PROFILER(Kern::Printf("D end");)
   1.502 +	return KErrNone;
   1.503 +	}
   1.504 +
   1.505 +TInt DProfile::ProcessReadRequest()
   1.506 +	{
   1.507 +// If the profiler is stopped and there is available data, return it immediately and complete the request
   1.508 +// If the profiler is stopped and there is no data, wait.
   1.509 +// If the profiler is running, retrieve any data available now, if more is req'd set the trigger
   1.510 +	DEBUG_PROFILER(Kern::Printf("READ");)
   1.511 +	TInt max=Kern::ThreadGetDesMaxLength(iClient,iDes);
   1.512 +	if (max<0)
   1.513 +		return max;
   1.514 +	if (max==0)
   1.515 +		return KErrArgument;
   1.516 +	TInt r=Kern::ThreadDesWrite(iClient,iDes,KNullDesC8,0,0,iClient);		// set client descriptor length to zero
   1.517 +	if (r!=KErrNone)
   1.518 +		return r;
   1.519 +	iRemain=max;
   1.520 +	iPos=0;
   1.521 +	TInt n=-1;
   1.522 +	TBool read=EFalse;
   1.523 +	while (n)
   1.524 +		{
   1.525 +		r=DoDrainCooked();				// drain any cooked data if possible
   1.526 +		if (r!=KErrUnderflow)
   1.527 +			read=ETrue;					// we've got something
   1.528 +		if (r>0)
   1.529 +			return KErrNone;			// request completed, so finish
   1.530 +		if (r!=KErrNone && r!=KErrUnderflow)
   1.531 +			return r;					// error writing client buffer
   1.532 +		n=Cook();						// cook the samples, return number cooked
   1.533 +		}
   1.534 +	if (!Running() && read)
   1.535 +		return KErrCompletion;			// if stopped and data read, return it
   1.536 +	return KErrNone;					// wait
   1.537 +	}
   1.538 +
   1.539 +TInt DProfile::DoDrainCooked()
   1.540 +//
   1.541 +// Copies encoded data from Cook buffer into user side descriptor (iDes).
   1.542 +// Returns:
   1.543 +// KErrUnderflow if all the data was already transfered or the desciptor was already full before the call.
   1.544 +// KErrNone if there is still remaining space available in the descriptor.
   1.545 +// 1  - descriptor is full and user request is completed.
   1.546 +// Error code other then KErrNone if writing to the user memory fails
   1.547 +//
   1.548 +	{
   1.549 +	TInt avail=iCPut-iCGet;
   1.550 +	if (avail<0)
   1.551 +		avail+=KCookedBufSize;
   1.552 +	TInt len=Min(avail,iRemain);
   1.553 +	if (len)
   1.554 +		{
   1.555 +		TUint8* pE=iCookedBuf+KCookedBufSize;
   1.556 +		TInt len1=Min(len,pE-iCGet);
   1.557 +		TPtrC8 local(iCGet,len1);
   1.558 +		TInt r=Kern::ThreadDesWrite(iClient, iDes, local, iPos, KChunkShiftBy0, iClient);
   1.559 +		if (r!=KErrNone)
   1.560 +			return r;
   1.561 +		len-=len1;
   1.562 +		TUint8* pG=iCGet+len1;
   1.563 +		if (pG==pE)
   1.564 +			pG=iCookedBuf;
   1.565 +		iCGet=pG;
   1.566 +		iRemain-=len1;
   1.567 +		iPos+=len1;
   1.568 +		if (len) // will be > 0 if there are remaining data at the beginning of Cooked buffer to be copied.
   1.569 +			{
   1.570 +			TPtrC8 local(iCGet,len);
   1.571 +			r=Kern::ThreadDesWrite(iClient, iDes, local, iPos, KChunkShiftBy0, iClient);
   1.572 +			if (r!=KErrNone)
   1.573 +				return r;
   1.574 +			iCGet+=len;
   1.575 +			iRemain-=len;
   1.576 +			iPos+=len;
   1.577 +			}
   1.578 +		if (iRemain==0 && iReqStatus)
   1.579 +			{
   1.580 +			Complete(KErrNone);
   1.581 +			return 1;
   1.582 +			}
   1.583 +		return KErrNone;
   1.584 +		}
   1.585 +	return KErrUnderflow;
   1.586 +	}
   1.587 +
   1.588 +void DProfile::HandleMsg(TMessageBase* aMsg)
   1.589 +//
   1.590 +// Client requests
   1.591 +//
   1.592 +	{
   1.593 +	TInt r=KErrNone;
   1.594 +	TThreadMessage& m=*(TThreadMessage*)aMsg;
   1.595 +	TInt id=m.iValue;
   1.596 +	// Allow the client thread to send a message or system critical thread
   1.597 +	// to send a close message as this is probably the supervisor thread doing clean up
   1.598 +	if (m.Client()!=iClient && 
   1.599 +		!((m.Client()->iFlags&KThreadFlagSystemCritical) && id==(TInt)ECloseMsg))
   1.600 +		{
   1.601 +		m.PanicClient(_L("SAMPLER"),EAccessDenied);
   1.602 +		return;
   1.603 +		}
   1.604 +	if (id==(TInt)ECloseMsg)
   1.605 +		{
   1.606 +		DEBUG_PROFILER(Kern::Printf("CLOSE");)
   1.607 +		iTimer.Cancel();
   1.608 +		iDfc.Cancel();
   1.609 +		m.Complete(KErrNone,EFalse);
   1.610 +		iMsgQ.CompleteAll(KErrServerTerminated);
   1.611 +		DEBUG_PROFILER(Kern::Printf("CLOSE end");)
   1.612 +		return;
   1.613 +		}
   1.614 +	else if (id<0)
   1.615 +		{
   1.616 +		if (id!=~RSampler::ERequestRead)
   1.617 +			{
   1.618 +			TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
   1.619 +			Kern::RequestComplete(iClient,pS,KErrNotSupported);
   1.620 +			}
   1.621 +		if (iReqStatus)
   1.622 +			{
   1.623 +			m.PanicClient(_L("SAMPLER"),ERequestAlreadyPending);
   1.624 +			return;
   1.625 +			}
   1.626 +		iReqStatus=(TRequestStatus*)m.Ptr0();
   1.627 +		iDes=(TDes8*)m.Ptr1();
   1.628 +		r=ProcessReadRequest();
   1.629 +		if (r!=KErrNone)
   1.630 +			{
   1.631 +			if (r==KErrCompletion)
   1.632 +				r=KErrNone;
   1.633 +			Complete(r);
   1.634 +			}
   1.635 +		r=KErrNone;
   1.636 +		}
   1.637 +	else if (id==KMaxTInt)
   1.638 +		{
   1.639 +		TInt mask=m.Int0();
   1.640 +		if (mask & (1<<RSampler::ERequestRead))
   1.641 +			{
   1.642 +			Complete(KErrCancel);
   1.643 +			}
   1.644 +		}
   1.645 +	else
   1.646 +		{
   1.647 +		switch(id)
   1.648 +			{
   1.649 +			case RSampler::EControlGetSegments:
   1.650 +				r=GetSegments((TDes8*)m.Ptr0());
   1.651 +				break;
   1.652 +			case RSampler::EControlStartProfile:
   1.653 +				r=StartSampling(m.Int0());
   1.654 +				break;
   1.655 +			case RSampler::EControlStopProfile:
   1.656 +				r=StopSampling();
   1.657 +				break;
   1.658 +			case RSampler::EControlResetProfile:
   1.659 +				r=Reset((TBool)m.Ptr0());
   1.660 +				break;
   1.661 +			case RSampler::EControlResetSegments:
   1.662 +				r=ResetSegments();
   1.663 +				break;
   1.664 +			case RSampler::EControlDrain:
   1.665 +				r=Drain((TDes8*)m.Ptr0());
   1.666 +				break;
   1.667 +			case RSampler::EControlGetErrors:
   1.668 +				r=GetErrors((TDes8*)m.Ptr0());
   1.669 +				break;
   1.670 +			default:
   1.671 +				r=KErrNotSupported;
   1.672 +				break;
   1.673 +			}
   1.674 +		}
   1.675 +	m.Complete(r,ETrue);
   1.676 +	}
   1.677 +
   1.678 +TUint8* DProfile::EncodeTag(TUint8* p, TUint8* e)
   1.679 +//
   1.680 +// Encode a tag and version to the trace data. This allows the offline analyser to 
   1.681 +// identify the sample data.
   1.682 +//
   1.683 +	{
   1.684 +	_LIT(KTraceTag,"profile");
   1.685 +	p=EncodeText(p,e,KTraceTag);
   1.686 +	p=EncodeUint(p,e,KMajorVersionNumber);
   1.687 +	return p;
   1.688 +	}
   1.689 +
   1.690 +TUint8* DProfile::EncodeInt(TUint8* p, TUint8* e, TInt aValue)
   1.691 +//
   1.692 +// Encode a 32 bit signed integer into the data stream
   1.693 +// This has to deal with wrap around at the end of the buffer
   1.694 +//
   1.695 +	{
   1.696 +	TUint byte;
   1.697 +	for (;;)
   1.698 +		{
   1.699 +		byte = aValue & 0x7f;
   1.700 +		if ((aValue >> 6) == (aValue >> 7))
   1.701 +			break;
   1.702 +		aValue >>= 7;
   1.703 +		PUT(p,(TUint8)byte,e,KCookedBufSize);
   1.704 +		}
   1.705 +	PUT(p,(TUint8)(byte|0x80),e,KCookedBufSize);
   1.706 +	return p;
   1.707 +	}
   1.708 +
   1.709 +TUint8* DProfile::EncodeUint(TUint8* p, TUint8* e, TUint aValue)
   1.710 +//
   1.711 +// Encode a 32 bit unsigned integer into the data stream
   1.712 +// This has to deal with wrap around at the end of the buffer
   1.713 +//
   1.714 +	{
   1.715 +	TUint byte;
   1.716 +	for (;;)
   1.717 +		{
   1.718 +		byte = aValue & 0x7f;
   1.719 +		aValue >>= 7;
   1.720 +		if (aValue == 0)
   1.721 +			break;
   1.722 +		PUT(p,(TUint8)byte,e,KCookedBufSize);
   1.723 +		}
   1.724 +	PUT(p,(TUint8)(byte|0x80),e,KCookedBufSize);
   1.725 +	return p;
   1.726 +	}
   1.727 +
   1.728 +TUint8* DProfile::EncodeText(TUint8* p, TUint8* e, const TDesC& aDes)
   1.729 +//
   1.730 +// Encode a descriptor into the data stream
   1.731 +// This is currently limited to a descriptor that is up to 255 characters in length,
   1.732 +// and Unicode characters are truncated to 8 bits
   1.733 +//
   1.734 +	{
   1.735 +	TInt len=aDes.Length();
   1.736 +	PUT(p,(TUint8)len,e,KCookedBufSize);
   1.737 +	const TText* s = aDes.Ptr();
   1.738 +	while (--len >= 0)
   1.739 +		PUT(p,*s++,e,KCookedBufSize);
   1.740 +	return p;
   1.741 +	}
   1.742 +
   1.743 +TUint8* DProfile::EncodeIDFC(TUint8* p, TUint8* e)
   1.744 +//
   1.745 +// iDFC samples do not really belong to any thread.
   1.746 +// However, the profiler protocol requires each sample to be associated to a particular thread.
   1.747 +// This method will encode 'fake' process ID & name and thread name for iDFC sample in the data stream.
   1.748 +// It will be embedded only for the very first sample from iDFCs.
   1.749 +// (For the rest of iDFCs samples, threadID is sufficient - as for the real threads.)
   1.750 +//
   1.751 +	{
   1.752 +	p=EncodeUint(p,e,KiDFCId);     //processID for iDFC
   1.753 +	p=EncodeText(p,e,KiDFCProcess);//process name for iDFC
   1.754 +	p=EncodeText(p,e,KiDFCThread); //thread name for iDFC
   1.755 +	return p;
   1.756 +	}
   1.757 +
   1.758 +TUint8* DProfile::EncodeThread(TUint8* p, TUint8* e, DThread* aThread)
   1.759 +//
   1.760 +// Encode a thread name in the data stream.
   1.761 +// The thread is identified by its name, and the identity of its owning process.
   1.762 +// If the process has not been identified in the data stream already, it's name is
   1.763 +// also encoded.
   1.764 +//
   1.765 +	{
   1.766 +	DProcess* pP=aThread->iOwningProcess;
   1.767 +	TKName n;
   1.768 +	p=EncodeUint(p,e,pP->iId);
   1.769 +	if (TAG(pP)!=iStartTime)	// not seen this before
   1.770 +		{
   1.771 +		TAG(pP)=iStartTime;
   1.772 +		// Provide the name matching this process ID
   1.773 +		pP->Name(n);
   1.774 +		p=EncodeText(p,e,n);
   1.775 +		}
   1.776 +	aThread->Name(n);
   1.777 +	p=EncodeText(p,e,n);
   1.778 +	return p;
   1.779 +	}
   1.780 +
   1.781 +TUint8* DProfile::EncodeRepeat(TUint8* p, TUint8* e, DProfile* aP)
   1.782 +//
   1.783 +// Encode a repeated sequence of samples
   1.784 +//
   1.785 +	{
   1.786 +	p=EncodeInt(p,e,0);
   1.787 +	p=EncodeUint(p,e,aP->iRepeat);
   1.788 +	aP->iRepeat = 0;
   1.789 +	return p;
   1.790 +	}
   1.791 +
   1.792 +TInt DProfile::CookCodeSeg(TBool aPutAll, TInt aSampleCounter)
   1.793 +//
   1.794 +// Transfers and encodes CodeSeg Create/Delete records from CodeSeg buffer into Cooked buffer.
   1.795 +// If aPutAll = Etrue, all records will be transferred.
   1.796 +// If aPutAll = EFalse, only records at the beginning of the queue that matches aSampleCounter will be transferred.
   1.797 +// It stopps if there is less then KRequiredFreeSpace bytes available in cooked buffer.
   1.798 +// Returns the number of the transferred records.
   1.799 +//
   1.800 +	{
   1.801 +	if (iXIPOnly)
   1.802 +		return 0;
   1.803 +	
   1.804 +	TInt n = 0;
   1.805 +	TInt codeSampleCounter;//Will hold the sample counter of the record
   1.806 +	TInt runAddress;
   1.807 +	TInt codeSize;
   1.808 +	TInt8 textLen;
   1.809 +	TBuf<255> text;
   1.810 +	TUint8* localCSGet = iCSGet;
   1.811 +
   1.812 +	FOREVER
   1.813 +		{
   1.814 +		//Check if there is any Code Seg record left.
   1.815 +		if (iCSGet==iCSPut)
   1.816 +			return n;//No records left
   1.817 +		
   1.818 +		//Check if the next record is due to be encoded. Both Create & Delete CodeSeg records start with sample counter.
   1.819 +		localCSGet = iCSGet;
   1.820 +		localCSGet = GetStream(localCSGet, CODESEGBUFEND, (TInt8*)(&codeSampleCounter), sizeof(TInt));
   1.821 +		if (!aPutAll && codeSampleCounter!=aSampleCounter)
   1.822 +			return n; //Still too early to insert the record into Cook Buffer
   1.823 +			
   1.824 +		//Check for the space in cook buffer
   1.825 +		TInt cookAvailable = (TInt)iCGet - (TInt)iCPut;
   1.826 +		if (cookAvailable <= 0)	
   1.827 +			cookAvailable+=KCookedBufSize;
   1.828 +		if (cookAvailable < KRequiredFreeSpace)
   1.829 +			return n;//No space in Cook Buffer.
   1.830 +		
   1.831 +		//At this point it is for sure that we have to transfer some record to cook buffer
   1.832 +		
   1.833 +		n++;
   1.834 +		iCSGet = localCSGet;
   1.835 +		//The next field for both Create & Delete CodeSeg records is run address:
   1.836 +		iCSGet = GetStream(iCSGet, CODESEGBUFEND, (TInt8*)(&runAddress), sizeof(TInt));
   1.837 +		
   1.838 +		if (runAddress & 1)//LSB in run address idenifies the type of the record
   1.839 +			{//CodeSegment Delete record. To be encoded as Int(0), UInt(0), UInt(RunAddress | 1)
   1.840 +			iCPut = EncodeInt (iCPut, COOKEDBUFEND, 0);
   1.841 +			iCPut = EncodeUint(iCPut, COOKEDBUFEND, 0);
   1.842 +			iCPut = EncodeUint(iCPut, COOKEDBUFEND, runAddress);
   1.843 +			}
   1.844 +		else
   1.845 +			{//CodeSegment Create record.
   1.846 +			iCSGet = GetStream(iCSGet, CODESEGBUFEND, (TInt8*)(&codeSize), sizeof(TInt));
   1.847 +			iCSGet = GetStream(iCSGet, CODESEGBUFEND, (TInt8*)(&textLen), sizeof(TInt8));
   1.848 +			iCSGet = GetStream(iCSGet, CODESEGBUFEND, (TInt8*)(text.Ptr()), textLen);
   1.849 +			text.SetLength(textLen);
   1.850 +			//To be encoded as Int(0), UInt(0), UInt(RunAddress), UInt(SegmentSize), Text(FileNeme)
   1.851 +			iCPut = EncodeInt(iCPut, COOKEDBUFEND, 0);
   1.852 +			iCPut = EncodeUint(iCPut, COOKEDBUFEND, 0);
   1.853 +			iCPut = EncodeUint(iCPut, COOKEDBUFEND, runAddress);
   1.854 +			iCPut = EncodeUint(iCPut, COOKEDBUFEND, codeSize);
   1.855 +			iCPut = EncodeText(iCPut, COOKEDBUFEND, text);
   1.856 +			}
   1.857 +		}
   1.858 +	}
   1.859 +
   1.860 +TInt DProfile::Cook()
   1.861 +//
   1.862 +// Transfers/encodes row data and code segments record into cooked buffer.
   1.863 +// Returns the number of records (incl. both samples and codeSeg records) cooked.
   1.864 +//
   1.865 +	{
   1.866 +	TUint8* p=iCPut;
   1.867 +	TUint8* e=iCookedBuf+KCookedBufSize;
   1.868 +	TInt n=0;
   1.869 +	
   1.870 +	FOREVER
   1.871 +		{
   1.872 +		iCPut=p; //update iCPut before calling CookCodeSeg
   1.873 +		if ((iRGet==iRPut))
   1.874 +			{//No more samples.
   1.875 +			n+=CookCodeSeg(ETrue, 0); //Cook the remaining content of CodeSeg buffer.
   1.876 +			break;
   1.877 +			}
   1.878 +
   1.879 +		SRawSample* s=iRawBuf+iRGet;	// pointer to the next sample to be cooked
   1.880 +
   1.881 +		n+=CookCodeSeg(EFalse, s->iSampleCounter);//cook all codeSeg records than matches this sample counter
   1.882 +		p=iCPut; //CookCodeSeg might have changed iCPut
   1.883 +
   1.884 +		TInt space=iCGet-p;
   1.885 +		if (space<=0)
   1.886 +			space+=KCookedBufSize;		// space remaining in cooked buffer
   1.887 +		if (space<KRequiredFreeSpace)
   1.888 +			break;						// if insufficient, finish
   1.889 +
   1.890 +		//Cook the next sample record from Row buffer		
   1.891 +		++iRGet;
   1.892 +		++n;
   1.893 +		TBool newthread=s->iPC & 1;		// bit 0 of PC means so far unknown thread
   1.894 +		TLinAddr pc=s->iPC &~ 1;
   1.895 +		TUint rp = iRepeat;
   1.896 +		TInt diff=TInt(pc-iLast.iPC);
   1.897 +		if (!newthread)
   1.898 +			{
   1.899 +			if (s->iThreadId!=iLast.iThreadId)
   1.900 +				diff|=1;
   1.901 +			if (diff == 0)
   1.902 +				{
   1.903 +				iRepeat = rp + 1;	// Identical sample, bump up the repeat count
   1.904 +				continue;
   1.905 +				}
   1.906 +			if (rp)
   1.907 +				{
   1.908 +				// Encode the repeat data
   1.909 +				p = EncodeRepeat(p,e,this);
   1.910 +				}
   1.911 +			// Encode the PC difference
   1.912 +			p = EncodeInt(p, e, diff);
   1.913 +			if (diff & 1)
   1.914 +				{
   1.915 +				// Encode the new thread ID
   1.916 +				iLast.iThreadId = s->iThreadId;
   1.917 +				p = EncodeUint(p, e, s->iThreadId);
   1.918 +				}
   1.919 +			}
   1.920 +		else
   1.921 +			{
   1.922 +			if (rp)
   1.923 +				{
   1.924 +				// Encode the repeat data
   1.925 +				p = EncodeRepeat(p,e,this);
   1.926 +				}
   1.927 +			// Encode the PC difference
   1.928 +			p = EncodeInt(p, e, diff|1);
   1.929 +
   1.930 +			if (s->iThreadId == KiDFCId)
   1.931 +				{
   1.932 +				// This is the first sample from iDFC. Encode 'threadID'
   1.933 +				iLast.iThreadId = KiDFCId;
   1.934 +				p = EncodeUint(p, e, KiDFCId);
   1.935 +				// and encode processID, processName & threadName for this sample
   1.936 +				p = EncodeIDFC(p, e);
   1.937 +				}
   1.938 +			else
   1.939 +				{
   1.940 +				// Encode the new thread ID
   1.941 +				DThread* pT=(DThread*)s->iThreadId;
   1.942 +				iLast.iThreadId = pT->iId;
   1.943 +				p = EncodeUint(p, e, pT->iId);
   1.944 +				// The thread is 'unknown' to this sample, so encode the thread name
   1.945 +				p = EncodeThread(p, e, pT);
   1.946 +				}
   1.947 +			}
   1.948 +		iLast.iPC=pc;
   1.949 +		}
   1.950 +	return n;
   1.951 +	}
   1.952 +
   1.953 +void DProfile::Dfc(TAny* aPtr)
   1.954 +//
   1.955 +// Tranfers/encodes Row & CodeSeg buffers' content into Cook buffer (by Cook()), 
   1.956 +// and copies encoded data into user side descriptor (by DoDrainCooked())
   1.957 +//
   1.958 +	{
   1.959 +	DProfile& d=*(DProfile*)aPtr;
   1.960 +	TInt n=-1;
   1.961 +	while (n)
   1.962 +		{
   1.963 +		TInt r=d.DoDrainCooked();		// drain any cooked data if possible
   1.964 +		if (r<0 && r!=KErrUnderflow)
   1.965 +			{
   1.966 +			d.Complete(r);				// error writing client buffer
   1.967 +			break;
   1.968 +			}
   1.969 +		n=d.Cook();						// cook the samples, return number cooked
   1.970 +		}
   1.971 +	}
   1.972 +
   1.973 +TUint8* DProfile::PutStream(TUint8* p, TUint8* e, const TUint8* aSource, TInt aSize)
   1.974 +//
   1.975 +// Put data into CodeSeg stream 
   1.976 +// This has to deal with wrap around at the end of the buffer
   1.977 +//
   1.978 +	{
   1.979 +	for (TInt i = 0 ; i< aSize ; i++)
   1.980 +		{
   1.981 +		PUT(p,(TUint8)(*aSource),e,KCodeBufSize);
   1.982 +		aSource++;
   1.983 +		}
   1.984 +	return p;
   1.985 +	}
   1.986 +
   1.987 +TUint8* DProfile::GetStream(TUint8* p, TUint8* e, TInt8* aDest, TInt aSize)
   1.988 +//
   1.989 +// Get 32 bits from CodeSeg stream.
   1.990 +// This has to deal with wrap around at the end of the buffer
   1.991 +//
   1.992 +	{
   1.993 +	for (TInt i = 0 ; i< aSize ; i++)
   1.994 +		GET_A_BYTE(p,aDest,e,KCodeBufSize);
   1.995 +	return p;
   1.996 +	}
   1.997 +
   1.998 +void DProfile::LogCodeSegEvent(TKernelEvent aEvent, DEpocCodeSeg *pCodeSeg)
   1.999 +//
  1.1000 +// Records the event in CodeSeg buffer.
  1.1001 +//
  1.1002 +	{
  1.1003 +///
  1.1004 +///	
  1.1005 +	TUint8* localCSPut = iCSPut;
  1.1006 +	TInt available = KCodeBufSize + (TInt)iCSGet - (TInt)iCSPut;
  1.1007 +	if (available > KCodeBufSize)
  1.1008 +		available -= KCodeBufSize;
  1.1009 +
  1.1010 +	switch (aEvent)
  1.1011 +		{
  1.1012 +	case EEventAddCodeSeg:
  1.1013 +		{
  1.1014 +		TInt textOffset = 0;
  1.1015 +		TInt textSize= pCodeSeg->iFileName->Length();
  1.1016 +		//Restrict file name to max 255 sharacters. If bigger, record the last 255 bytes only
  1.1017 +		if (textSize > 255)
  1.1018 +			{
  1.1019 +			textOffset = textSize-255;
  1.1020 +			textSize = 255;
  1.1021 +			}
  1.1022 +		if ((available -= 13+textSize) < 0) //13 bytes needed for sample counter, run address, size and text size) 
  1.1023 +			{
  1.1024 +			iReport.iCodeSegErrCounter++;
  1.1025 +			return;
  1.1026 +			}
  1.1027 +		localCSPut = PutStream(localCSPut, CODESEGBUFEND, (TUint8*)(&iNextSampleCounter), sizeof(TInt));
  1.1028 +		localCSPut = PutStream(localCSPut, CODESEGBUFEND, (TUint8*)(&pCodeSeg->iRunAddress), sizeof(TInt));
  1.1029 +		localCSPut = PutStream(localCSPut, CODESEGBUFEND, (TUint8*)(&pCodeSeg->iSize), sizeof(TInt));
  1.1030 +		localCSPut = PutStream(localCSPut, CODESEGBUFEND, (TUint8*)(&textSize), sizeof(TInt8));
  1.1031 +		localCSPut = PutStream(	localCSPut, CODESEGBUFEND, pCodeSeg->iFileName->Ptr()+textOffset, textSize);
  1.1032 +		iCSPut = localCSPut;
  1.1033 +
  1.1034 +		DEBUG_PROFILER
  1.1035 +			(
  1.1036 +			TBuf<256> buf(textSize+1);
  1.1037 +			buf.Copy(pCodeSeg->iFileName->Ptr()+textOffset,textSize); buf.SetLength(textSize+1); buf[textSize]=0;
  1.1038 +			Kern::Printf("CREATE CS:%s, %x, %x,", buf.Ptr(), pCodeSeg->iRunAddress, pCodeSeg->iSize);
  1.1039 +			)
  1.1040 +		break;
  1.1041 +		}
  1.1042 +	case EEventRemoveCodeSeg:
  1.1043 +		{
  1.1044 +		if ((available-=8) < 0) //8 bytes needed for sample counter and run address
  1.1045 +			{
  1.1046 +			iReport.iCodeSegErrCounter++;
  1.1047 +			return;
  1.1048 +			}
  1.1049 +		TInt runAddress = pCodeSeg->iRunAddress | 1; 
  1.1050 +		localCSPut = PutStream(localCSPut, CODESEGBUFEND, (TUint8*)(&iNextSampleCounter), sizeof(TInt));
  1.1051 +		localCSPut = PutStream(localCSPut, CODESEGBUFEND, (TUint8*)(&runAddress), sizeof(TInt));
  1.1052 +		iCSPut = localCSPut;
  1.1053 +
  1.1054 +		DEBUG_PROFILER(Kern::Printf("DELETE CS:%x", pCodeSeg->iRunAddress);)
  1.1055 +		break;
  1.1056 +		}
  1.1057 +	default:
  1.1058 +		return;
  1.1059 +	}
  1.1060 +	if (available < KCodeBufSize/2) //Start emptying CodeSeg (and Raw Buffer, as well) Buffer if more then a half full.
  1.1061 +		iDfc.Enque();
  1.1062 +}
  1.1063 +
  1.1064 +TUint DProfile::KernelEventHandler(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aPrivateData)
  1.1065 +//
  1.1066 +// Logs non-XIP CodeSeg Create/Delete events.
  1.1067 +// In GettingSegments mode, it logs only deletion of the marked segments.
  1.1068 +// Runs in the content of the Kernel scheduler
  1.1069 +//
  1.1070 +{
  1.1071 +	if (aEvent==EEventAddCodeSeg || aEvent==EEventRemoveCodeSeg) 
  1.1072 +	{
  1.1073 +		DProfile *p = (DProfile*)aPrivateData;
  1.1074 +		DEpocCodeSeg* pCodeSeg = (DEpocCodeSeg*)(DCodeSeg*)a1;
  1.1075 +
  1.1076 +		Kern::AccessCode();
  1.1077 +		if ((!pCodeSeg->iXIP) && (!p->iMarkedOnlySegments || pCodeSeg->iMark&DCodeSeg::EMarkProfilerTAG))
  1.1078 +			p->LogCodeSegEvent(aEvent, pCodeSeg);
  1.1079 +		Kern::EndAccessCode();
  1.1080 +
  1.1081 +	}
  1.1082 +	return DKernelEventHandler::ERunNext;
  1.1083 +}
  1.1084 +
  1.1085 +
  1.1086 +void DProfile::Sample(TAny* aPtr)
  1.1087 +	{
  1.1088 +	DProfile& d=*(DProfile*)aPtr;
  1.1089 +	d.iTimer.Again(d.iPeriod);
  1.1090 +	TUint8 next_put=(TUint8)(d.iRPut+1);
  1.1091 +	if (next_put!=d.iRGet)		// space in raw buffer
  1.1092 +		{
  1.1093 +		DThread* pT=Kern::NThreadToDThread(NKern::CurrentThread());
  1.1094 +		if (pT!=NULL)
  1.1095 +			{
  1.1096 +			SRawSample* p=d.iRawBuf+d.iRPut;
  1.1097 +			d.iRPut=next_put;
  1.1098 +			p->iPC=((d.iIntStackTop)[-1]) & ~1; //clear LSB bit (in case of Jazelle code)
  1.1099 +			p->iSampleCounter=d.iNextSampleCounter++;
  1.1100 +			
  1.1101 +			if (IDFCRunning())
  1.1102 +				{
  1.1103 +				p->iThreadId=KiDFCId; //indicates iDFC running
  1.1104 +				if (!d.iIDFCSeenBefore)
  1.1105 +					{
  1.1106 +					d.iIDFCSeenBefore = ETrue;
  1.1107 +					p->iPC|=1;				// set bit 0 of PC to indicate new thread
  1.1108 +					}
  1.1109 +				else
  1.1110 +					{
  1.1111 +					TUint8 used=(TUint8)(d.iRPut-d.iRGet);
  1.1112 +					if (used<=KRawBufSize/2)
  1.1113 +						return;
  1.1114 +					}
  1.1115 +				}
  1.1116 +			else
  1.1117 +				{
  1.1118 +				
  1.1119 +				if (TAG(pT)!=d.iStartTime)	// not seen this before
  1.1120 +					{
  1.1121 +					TAG(pT)=d.iStartTime;
  1.1122 +					p->iThreadId=(TUint)pT;
  1.1123 +					p->iPC|=1;				// set bit 0 of PC to indicate new thread
  1.1124 +					}
  1.1125 +				else
  1.1126 +					{
  1.1127 +					p->iThreadId=pT->iId;
  1.1128 +					TUint8 used=(TUint8)(d.iRPut-d.iRGet);
  1.1129 +					if (used<=KRawBufSize/2)
  1.1130 +						return;
  1.1131 +					}
  1.1132 +				}
  1.1133 +			d.iDfc.Add();	// queue DFC if new thread seen or buffer more than half full
  1.1134 +			}
  1.1135 +		}
  1.1136 +	else
  1.1137 +		d.iReport.iRowBufferErrCounter++;
  1.1138 +	}
  1.1139 +