kerneltest/e32utils/profiler/sampler.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32utils\profiler\sampler.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "platform.h"
       
    19 
       
    20 #include "sampler.h"
       
    21 #include <kernel/kern_priv.h>		//temporary
       
    22 #include <memmodel/epoc/plat_priv.h> // needed for DEpocCodeSeg
       
    23 _LIT(KLddName,"Sampler");
       
    24 
       
    25 TKName KiDFCThread = _L("Running from iDFC");
       
    26 TKName KiDFCProcess = _L("N/A");
       
    27 TUint  KiDFCId = (TUint)-1; //both process and thread assigned to iDFC will have 'fake' id=-1
       
    28 
       
    29 const TInt KMajorVersionNumber=2;
       
    30 const TInt KMinorVersionNumber=0;
       
    31 const TInt KBuildVersionNumber=0;
       
    32 
       
    33 const TInt KMinRate=10;
       
    34 const TInt KMaxRate=1000;
       
    35 const TInt KRawBufSize=256;
       
    36 const TInt KCookedBufSize=0x2000;
       
    37 const TInt KCodeBufSize=0x2000;
       
    38 
       
    39 const TInt KMaxCreateCodeSegRecordSize = 300; //Max size of the encoded CodeSegCreate record.
       
    40 const TInt KMaxErrorReportRecordSize = 18;    //Max size of the encoded ErrorReport record. (3 zeros and 3 integers)
       
    41 const TInt KRequiredFreeSpace=512;
       
    42 
       
    43 //Bit mask in report
       
    44 const TInt KNonXIPModeActive=1; 
       
    45 const TInt KNoDebugSupport=2;
       
    46 
       
    47 
       
    48 #define PUT(p,x,e,s)	{*(p)++=(x); if ((p)==(e)) (p)-=(s);}
       
    49 #define GET_A_BYTE(p,x,e,s)	{*(x)++=*(p)++; if ((p)==(e)) (p)-=(s);}
       
    50 
       
    51 #define	TAG(obj)		(*(TUint32*)&(obj->iAsyncDeleteNext))
       
    52 
       
    53 #define CODESEGBUFEND (iCodeSegBuffer+KCodeBufSize)
       
    54 #define COOKEDBUFEND (iCookedBuf+KCookedBufSize)
       
    55 
       
    56 extern TUint IntStackPtr();
       
    57 extern TUint32 SPSR();
       
    58 extern TUint IDFCRunning();
       
    59 
       
    60 // global Dfc Que
       
    61 TDynamicDfcQue* gDfcQ;
       
    62 
       
    63 class DDeviceSampler : public DLogicalDevice
       
    64 	{
       
    65 public:
       
    66 	DDeviceSampler();
       
    67 	~DDeviceSampler();
       
    68 	virtual TInt Install();
       
    69 	virtual void GetCaps(TDes8& aDes) const;
       
    70 	virtual TInt Create(DLogicalChannelBase*& aChannel);
       
    71 	};
       
    72 
       
    73 struct SRawSample
       
    74 	{
       
    75 	TLinAddr iPC;
       
    76 	TUint32 iSampleCounter;
       
    77 	TUint32 iThreadId;
       
    78 	};
       
    79 
       
    80 class DProfile : public DLogicalChannel
       
    81 	{
       
    82 public:
       
    83 	DProfile();
       
    84 	~DProfile();
       
    85 protected:
       
    86 	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
       
    87 	virtual void HandleMsg(TMessageBase* aMsg);
       
    88 private:
       
    89 	TInt GetSegments(TDes8* aDes);
       
    90 	TInt StartSampling(TInt aRate);
       
    91 	TInt StopSampling();
       
    92 	TInt Reset(TBool aXIPOnly);
       
    93 	TInt ResetSegments();
       
    94 	TInt Drain(TDes8* aDes);
       
    95 	TInt GetErrors(TDes8* aDes);
       
    96 	TInt ProcessReadRequest();
       
    97 	TInt DoDrainCooked();
       
    98 	TInt Cook();
       
    99 	void Complete(TInt aResult);
       
   100 	inline TBool Running()
       
   101 		{return iTimer.iState!=NTimer::EIdle;}
       
   102 private:
       
   103 	static void Sample(TAny*);
       
   104 	static void Dfc(TAny*);
       
   105 	static TUint KernelEventHandler(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aPrivateData);
       
   106 	void LogCodeSegEvent(TKernelEvent aEvent, DEpocCodeSeg *pCodeSeg);
       
   107 
       
   108 private:
       
   109 	static TUint8* EncodeTag(TUint8* p, TUint8* e);
       
   110 	static TUint8* EncodeInt(TUint8* p, TUint8* e, TInt aValue);
       
   111 	static TUint8* EncodeUint(TUint8* p, TUint8* e, TUint aValue);
       
   112 	static TUint8* EncodeText(TUint8* p, TUint8* e, const TDesC& aDes);
       
   113 	static TUint8* EncodeRepeat(TUint8* p, TUint8* e, DProfile* aProfile);
       
   114 	TUint8* EncodeThread(TUint8* p, TUint8* e, DThread* aThread);
       
   115 	TUint8* EncodeIDFC(TUint8* p, TUint8* e);
       
   116 	
       
   117 	TUint8* PutStream(TUint8* p, TUint8* e, const TUint8* aSource, TInt aSize);
       
   118 	TUint8* GetStream(TUint8* p, TUint8* e, TInt8* aDest, TInt aSize);	
       
   119 	TBool CookCodeSeg(TBool aPutAll, TInt aSampleCounter);
       
   120 
       
   121 private:
       
   122 	TUint32 iStartTime;
       
   123 	TInt iRepeat;
       
   124 	SRawSample iLast;
       
   125 	TInt iPeriod;
       
   126 	NTimer iTimer;
       
   127 	TDfc iDfc;
       
   128 	TUint* iIntStackTop;
       
   129 	DThread* iClient;
       
   130 	TRequestStatus* iReqStatus;
       
   131 	TInt iPos;			// client des pos
       
   132 	TInt iRemain;		// space left in client des
       
   133 	TDes8* iDes;		// client des pointer
       
   134 	TUint8 iRPut;		// raw buffer put index
       
   135 	TUint8 iRGet;		// raw buffer get index
       
   136 	TUint8* iCPut;		// cooked buffer put
       
   137 	TUint8* iCGet;		// cooked buffer get
       
   138 	SRawSample iRawBuf[KRawBufSize];
       
   139 	TUint8 iCookedBuf[KCookedBufSize];
       
   140 	
       
   141 	DKernelEventHandler* iKernelEvHandler;
       
   142 
       
   143 	TInt iNextSampleCounter;
       
   144 	TBool iXIPOnly;
       
   145 	TBool iMarkedOnlySegments;	// True during GettingSegments phase in which event handler...
       
   146 								// ... collects only the events from marked segments.
       
   147 	TUint8 iCodeSegBuffer[KCodeBufSize];
       
   148 	TUint8* iCSPut;		// CodeSeg buffer put
       
   149 	TUint8* iCSGet;		// CodeSeg buffer get
       
   150 	TUint iIDFCSeenBefore;
       
   151 	struct TReport
       
   152 		{
       
   153 		TUint iRowBufferErrCounter;
       
   154 		TUint iCodeSegErrCounter;
       
   155 		TInt  iReportMask; 
       
   156 		} iReport;
       
   157 	};
       
   158 
       
   159 DECLARE_STANDARD_LDD()
       
   160 	{
       
   161 	return new DDeviceSampler;
       
   162 	}
       
   163 
       
   164 DDeviceSampler::DDeviceSampler()
       
   165 //
       
   166 // Constructor
       
   167 //
       
   168 	{
       
   169 	//iParseMask=0;
       
   170 	//iUnitsMask=0;
       
   171 	iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
       
   172 	}
       
   173 
       
   174 const TInt KDSamplerThreadPriority = 27;
       
   175 _LIT(KDSamplerThread,"DSamplerThread");
       
   176 
       
   177 TInt DDeviceSampler::Install()
       
   178 //
       
   179 // Install the device driver.
       
   180 //
       
   181 	{
       
   182 	// Allocate a kernel thread to run the DFC 
       
   183 	TInt r = Kern::DynamicDfcQCreate(gDfcQ, KDSamplerThreadPriority, KDSamplerThread);
       
   184 
       
   185 	if (r != KErrNone)
       
   186 		return r; 	
       
   187 
       
   188 	r=SetName(&KLddName);
       
   189 	return r;
       
   190 	}
       
   191 
       
   192 void DDeviceSampler::GetCaps(TDes8& aDes) const
       
   193 //
       
   194 // Return the capabilities.
       
   195 //
       
   196 	{
       
   197 	}
       
   198 
       
   199 /**
       
   200   Destructor
       
   201 */
       
   202 DDeviceSampler::~DDeviceSampler()
       
   203 	{
       
   204 	if (gDfcQ)
       
   205 		gDfcQ->Destroy();
       
   206 	}
       
   207 
       
   208 TInt DDeviceSampler::Create(DLogicalChannelBase*& aChannel)
       
   209 //
       
   210 // Create a channel on the device.
       
   211 //
       
   212 	{
       
   213 	aChannel=new DProfile;
       
   214 	return aChannel?KErrNone:KErrNoMemory;
       
   215 	}
       
   216 
       
   217 DProfile::DProfile()
       
   218 	:	iTimer(Sample,this),
       
   219 		iDfc(Dfc,this,NULL,7)
       
   220 //
       
   221 // Constructor
       
   222 //
       
   223 	{
       
   224 	}
       
   225 
       
   226 DProfile::~DProfile()
       
   227 //
       
   228 // Destructor
       
   229 //
       
   230 	{
       
   231 	Kern::SafeClose((DObject*&)iClient, NULL);
       
   232 	}
       
   233 
       
   234 TInt DProfile::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
       
   235 //
       
   236 // Create the channel from the passed info.
       
   237 //
       
   238 	{
       
   239 	if (!Kern::QueryVersionSupported(TVersion(1,0,1),aVer))
       
   240 		return KErrNotSupported;
       
   241 	iClient=&Kern::CurrentThread();
       
   242 	iClient->Open();
       
   243 	Kern::SetThreadPriority(24);
       
   244 	iIntStackTop=(TUint*)IntStackPtr();
       
   245 	SetDfcQ(gDfcQ);
       
   246 	iDfc.SetDfcQ(iDfcQ);
       
   247 	iMsgQ.Receive();
       
   248 	return KErrNone;
       
   249 	}
       
   250 
       
   251 void DProfile::Complete(TInt aResult)
       
   252 //Completes user request
       
   253 	{
       
   254 	DEBUG_PROFILER(Kern::Printf("C");)
       
   255 	Kern::RequestComplete(iClient,iReqStatus,aResult);
       
   256 	}
       
   257 
       
   258 TInt DProfile::StartSampling(TInt aRate)
       
   259 	{
       
   260 	DEBUG_PROFILER(Kern::Printf("START");)
       
   261 	//Activate timer
       
   262 	aRate=Min(KMaxRate, Max(KMinRate, aRate));
       
   263 	iPeriod=1000/aRate;
       
   264 	if (!Running())
       
   265 		iTimer.OneShot(iPeriod);
       
   266 	
       
   267 	DEBUG_PROFILER(Kern::Printf("START end");)
       
   268 	return KErrNone;
       
   269 	}
       
   270 
       
   271 TInt DProfile::GetSegments(TDes8* aDes)
       
   272 //
       
   273 // Collects and marks all non-XIP segments.
       
   274 //
       
   275 	{
       
   276 	DEBUG_PROFILER(Kern::Printf("GS");)
       
   277 	TInt max=Kern::ThreadGetDesMaxLength(iClient,aDes);
       
   278 	Kern::ThreadDesWrite(iClient,aDes,KNullDesC8,0,0,iClient);//Set length to zero
       
   279 	TInt current = 0;
       
   280 
       
   281 	Kern::AccessCode();
       
   282 	
       
   283 	// Take all records that are collected by event handler first. They may be only Delete CodeSeg 
       
   284 	// events of tagged(marked) segments. On the first GetSegments call, cooked buffer also contains Profile Tag.
       
   285 
       
   286 	CookCodeSeg(ETrue, 0); // Transfer/encode from CodeSeg buffer into cooked buffer
       
   287 	current = iCPut-iCGet;
       
   288 	if (current)
       
   289 		{
       
   290 		if (current < max)
       
   291 			{//Copy data into user side descriptor
       
   292 			TPtrC8 aPtr(iCGet, current);
       
   293 			Kern::ThreadDesWrite(iClient,aDes,aPtr,0,KChunkShiftBy0,iClient);
       
   294 			}
       
   295 		else
       
   296 			{	
       
   297 			//This is very unlikely as in this stage we collect only CodeSeg Delete events of the marked segments.
       
   298 			//It cannot happen on the first call, as there are no marked segments - which means that Profiler Tag is OK.
       
   299 			iReport.iCodeSegErrCounter++;
       
   300 			}
       
   301 		}
       
   302 	iCGet = iCPut = iCookedBuf; //Reset the cooked buffer
       
   303 	
       
   304 	//Collect all non-XIP segments that are not already marked.
       
   305 
       
   306 	SDblQue* p = Kern::CodeSegList();
       
   307 	SDblQueLink* anchor=&p->iA;
       
   308 	SDblQueLink* a=anchor->iNext;
       
   309 	for (; a!=anchor; a=a->iNext) 
       
   310 		{
       
   311 		DEpocCodeSeg* pSeg = (DEpocCodeSeg*) _LOFF(a, DCodeSeg, iLink);
       
   312 		if (pSeg->iXIP || pSeg->iMark&DCodeSeg::EMarkProfilerTAG)
       
   313 			continue;
       
   314 		if (current > (max-KMaxCreateCodeSegRecordSize))
       
   315 			break;//No more space. Finish now and wait for another GetSegments request.
       
   316 			
       
   317 		pSeg->iMark |= DCodeSeg::EMarkProfilerTAG;	//Mark this segment
       
   318 		LogCodeSegEvent(EEventAddCodeSeg, pSeg); 	//Place this record into CodeSeg buffer ...
       
   319 		CookCodeSeg(ETrue, 0);						//...and encode it into cooked buffer
       
   320 		TPtrC8 aPtr(iCGet, iCPut-iCGet);
       
   321 		Kern::ThreadDesWrite(iClient,aDes,aPtr,current,KChunkShiftBy0,iClient);//Copy record into user desc.
       
   322 		current += iCPut-iCGet;
       
   323 		iCPut = iCGet = iCookedBuf; //Reset cooked buffer
       
   324 		}
       
   325 
       
   326 	if (!current)//This will be the last GetSegments call. From now on, all events have to be recorded.
       
   327 		iMarkedOnlySegments = EFalse;
       
   328 	
       
   329 	Kern::EndAccessCode();
       
   330 	DEBUG_PROFILER(Kern::Printf("GS end %d",current);)
       
   331 	return KErrNone;
       
   332 	}
       
   333 
       
   334 TInt DProfile::ResetSegments()
       
   335 //
       
   336 // Unmarks all non-XIP segments 
       
   337 // Sets device into GettingSegments mode in which only the events of the marked Code Segments will be recorder
       
   338 // 
       
   339 	{
       
   340 	DEBUG_PROFILER(Kern::Printf("RS");)
       
   341 	if (iXIPOnly)
       
   342 		return KErrGeneral;
       
   343 	
       
   344 	Kern::AccessCode();
       
   345 	SDblQue* p = Kern::CodeSegList();
       
   346 	SDblQueLink* anchor=&p->iA;
       
   347 	SDblQueLink* a=anchor->iNext;
       
   348 	for (; a!=anchor; a=a->iNext) 
       
   349 		{
       
   350 		DEpocCodeSeg* pSeg = (DEpocCodeSeg*) _LOFF(a, DCodeSeg, iLink);
       
   351 		if (!pSeg->iXIP)
       
   352 			pSeg->iMark &= ~DCodeSeg::EMarkProfilerTAG;
       
   353 		}
       
   354 
       
   355 	if (DKernelEventHandler::DebugSupportEnabled())
       
   356 		{
       
   357 		DEBUG_PROFILER(Kern::Printf("RS add handler");)
       
   358 		iKernelEvHandler->Add();
       
   359 		iReport.iReportMask|= KNonXIPModeActive;
       
   360 		}
       
   361 	else
       
   362 		iReport.iReportMask|= KNoDebugSupport;	
       
   363 	
       
   364 	iMarkedOnlySegments = ETrue;	
       
   365 	Kern::EndAccessCode();
       
   366 	DEBUG_PROFILER(Kern::Printf("RS end");)
       
   367 	return KErrNone;
       
   368 	}
       
   369 
       
   370 TInt DProfile::Reset(TBool aXIPOnly)
       
   371 	{
       
   372 //
       
   373 // Resets the device. It is the first message sent by profiler application.
       
   374 //	
       
   375 	if (Running())
       
   376 		return KErrGeneral;
       
   377 	
       
   378 	DEBUG_PROFILER(Kern::Printf("RST %d", aXIPOnly);)
       
   379 
       
   380 	iXIPOnly = aXIPOnly;
       
   381 
       
   382 	iTimer.Cancel();
       
   383 	iDfc.Cancel();
       
   384 	iLast.iPC=0;
       
   385 	iLast.iSampleCounter=0;
       
   386 	iLast.iThreadId=0;
       
   387 	iRepeat=0;
       
   388 	iPeriod=1;
       
   389 	iReqStatus=NULL;
       
   390 	iRPut=0;				// raw buffer put index
       
   391 	iRGet=0;				// raw buffer get index
       
   392 	iCPut=EncodeTag(iCookedBuf,COOKEDBUFEND); //cooked buffer put
       
   393 	iCGet=iCookedBuf;		// cooked buffer get
       
   394 	iPos=0;					// client des pos
       
   395 	iDes=NULL;				// client des pointer
       
   396 	iStartTime=NKern::TickCount();
       
   397 
       
   398 	iReport.iRowBufferErrCounter = 0;
       
   399 	iReport.iCodeSegErrCounter = 0;
       
   400 	iReport.iReportMask = 0;
       
   401 	iNextSampleCounter = 0;
       
   402 	iCSPut=iCodeSegBuffer;	// CodeSeg buffer put
       
   403 	iCSGet=iCodeSegBuffer;	// CodeSeg buffer get
       
   404 	iMarkedOnlySegments = EFalse;
       
   405 	iIDFCSeenBefore = EFalse;
       
   406 	if (!iXIPOnly)
       
   407 		iKernelEvHandler = new DKernelEventHandler(KernelEventHandler, this);
       
   408 	
       
   409 	DEBUG_PROFILER(Kern::Printf("RST end");)
       
   410 	return KErrNone;
       
   411 	}
       
   412 
       
   413 TInt DProfile::StopSampling()
       
   414 //
       
   415 // Stops sampling
       
   416 //
       
   417 	{
       
   418 	DEBUG_PROFILER(Kern::Printf("STOP");)
       
   419 	if (Running())
       
   420 		{
       
   421 		iTimer.Cancel();
       
   422 		Dfc(this);
       
   423 		}
       
   424 	if (iReqStatus)
       
   425 		Complete(KErrNone);
       
   426 	
       
   427 	DEBUG_PROFILER(Kern::Printf("STOP end");)
       
   428 	return KErrNone;
       
   429 	}
       
   430 
       
   431 TInt DProfile::GetErrors(TDes8* aDes)
       
   432 //
       
   433 // Returns error report and closes event handler
       
   434 //
       
   435 	{
       
   436 	TInt r = KErrNone;
       
   437 	TBuf8<KMaxErrorReportRecordSize> localBuf; //Enough space to encode 3 zeros and 3 integers
       
   438 	DEBUG_PROFILER(Kern::Printf("GE");)
       
   439 
       
   440 	TInt max=Kern::ThreadGetDesMaxLength(iClient,aDes);
       
   441 	if (max<KMaxErrorReportRecordSize)
       
   442 		return KErrArgument;
       
   443 	
       
   444 	Kern::ThreadDesWrite(iClient,aDes,KNullDesC8,0,0,iClient);//set zero length
       
   445 	
       
   446 	TUint8* p = (TUint8*)localBuf.Ptr();
       
   447 	TUint8* e = p+KMaxErrorReportRecordSize;
       
   448 	p = EncodeInt (p, e, 0);
       
   449 	p = EncodeUint(p, e, 0);
       
   450 	p = EncodeUint(p, e, 0);
       
   451 
       
   452 	p = EncodeUint(p, e, iReport.iRowBufferErrCounter);
       
   453 	p = EncodeUint(p, e, iReport.iCodeSegErrCounter);
       
   454 	p = EncodeUint(p, e, iReport.iReportMask);
       
   455 
       
   456 	localBuf.SetLength(p-localBuf.Ptr());
       
   457 	r=Kern::ThreadDesWrite(iClient,aDes,localBuf,0,KChunkShiftBy0,iClient);
       
   458 	
       
   459 	if(iKernelEvHandler && iKernelEvHandler->IsQueued())
       
   460 		iKernelEvHandler->Close();
       
   461 
       
   462 	DEBUG_PROFILER(Kern::Printf("GE end %d %d %d", iReport.iRowBufferErrCounter, iReport.iCodeSegErrCounter, iReport.iReportMask);)
       
   463 	return r;
       
   464 	}
       
   465 
       
   466 
       
   467 TInt DProfile::Drain(TDes8* aDes)
       
   468 //
       
   469 // Collects any remaining data
       
   470 //
       
   471 	{
       
   472 	DEBUG_PROFILER(Kern::Printf("D");)		
       
   473 	if (Running())
       
   474 		return KErrGeneral;
       
   475 	// we can assume read request is not pending
       
   476 	TInt max=Kern::ThreadGetDesMaxLength(iClient,aDes);
       
   477 	if (max<0)
       
   478 		return max;
       
   479 	if (max==0)
       
   480 		return KErrArgument;
       
   481 	TInt r=Kern::ThreadDesWrite(iClient,aDes,KNullDesC8,0,0,iClient);		// set client descriptor length to zero
       
   482 	if (r!=KErrNone)
       
   483 		return r;
       
   484 	iDes=aDes;
       
   485 	iRemain=max;
       
   486 	iPos=0;
       
   487 	iReqStatus=NULL;
       
   488 	TInt n=-1;
       
   489 	while (n)
       
   490 		{
       
   491 		r=DoDrainCooked();				// drain any cooked data if possible
       
   492 		if (r<0 && r!=KErrUnderflow)
       
   493 			return r;					// error writing client buffer
       
   494 		n=Cook();						// cook the samples, return number cooked
       
   495 		}
       
   496 
       
   497 	// there might still be data left over
       
   498 	DEBUG_PROFILER(Kern::Printf("D end");)
       
   499 	return KErrNone;
       
   500 	}
       
   501 
       
   502 TInt DProfile::ProcessReadRequest()
       
   503 	{
       
   504 // If the profiler is stopped and there is available data, return it immediately and complete the request
       
   505 // If the profiler is stopped and there is no data, wait.
       
   506 // If the profiler is running, retrieve any data available now, if more is req'd set the trigger
       
   507 	DEBUG_PROFILER(Kern::Printf("READ");)
       
   508 	TInt max=Kern::ThreadGetDesMaxLength(iClient,iDes);
       
   509 	if (max<0)
       
   510 		return max;
       
   511 	if (max==0)
       
   512 		return KErrArgument;
       
   513 	TInt r=Kern::ThreadDesWrite(iClient,iDes,KNullDesC8,0,0,iClient);		// set client descriptor length to zero
       
   514 	if (r!=KErrNone)
       
   515 		return r;
       
   516 	iRemain=max;
       
   517 	iPos=0;
       
   518 	TInt n=-1;
       
   519 	TBool read=EFalse;
       
   520 	while (n)
       
   521 		{
       
   522 		r=DoDrainCooked();				// drain any cooked data if possible
       
   523 		if (r!=KErrUnderflow)
       
   524 			read=ETrue;					// we've got something
       
   525 		if (r>0)
       
   526 			return KErrNone;			// request completed, so finish
       
   527 		if (r!=KErrNone && r!=KErrUnderflow)
       
   528 			return r;					// error writing client buffer
       
   529 		n=Cook();						// cook the samples, return number cooked
       
   530 		}
       
   531 	if (!Running() && read)
       
   532 		return KErrCompletion;			// if stopped and data read, return it
       
   533 	return KErrNone;					// wait
       
   534 	}
       
   535 
       
   536 TInt DProfile::DoDrainCooked()
       
   537 //
       
   538 // Copies encoded data from Cook buffer into user side descriptor (iDes).
       
   539 // Returns:
       
   540 // KErrUnderflow if all the data was already transfered or the desciptor was already full before the call.
       
   541 // KErrNone if there is still remaining space available in the descriptor.
       
   542 // 1  - descriptor is full and user request is completed.
       
   543 // Error code other then KErrNone if writing to the user memory fails
       
   544 //
       
   545 	{
       
   546 	TInt avail=iCPut-iCGet;
       
   547 	if (avail<0)
       
   548 		avail+=KCookedBufSize;
       
   549 	TInt len=Min(avail,iRemain);
       
   550 	if (len)
       
   551 		{
       
   552 		TUint8* pE=iCookedBuf+KCookedBufSize;
       
   553 		TInt len1=Min(len,pE-iCGet);
       
   554 		TPtrC8 local(iCGet,len1);
       
   555 		TInt r=Kern::ThreadDesWrite(iClient, iDes, local, iPos, KChunkShiftBy0, iClient);
       
   556 		if (r!=KErrNone)
       
   557 			return r;
       
   558 		len-=len1;
       
   559 		TUint8* pG=iCGet+len1;
       
   560 		if (pG==pE)
       
   561 			pG=iCookedBuf;
       
   562 		iCGet=pG;
       
   563 		iRemain-=len1;
       
   564 		iPos+=len1;
       
   565 		if (len) // will be > 0 if there are remaining data at the beginning of Cooked buffer to be copied.
       
   566 			{
       
   567 			TPtrC8 local(iCGet,len);
       
   568 			r=Kern::ThreadDesWrite(iClient, iDes, local, iPos, KChunkShiftBy0, iClient);
       
   569 			if (r!=KErrNone)
       
   570 				return r;
       
   571 			iCGet+=len;
       
   572 			iRemain-=len;
       
   573 			iPos+=len;
       
   574 			}
       
   575 		if (iRemain==0 && iReqStatus)
       
   576 			{
       
   577 			Complete(KErrNone);
       
   578 			return 1;
       
   579 			}
       
   580 		return KErrNone;
       
   581 		}
       
   582 	return KErrUnderflow;
       
   583 	}
       
   584 
       
   585 void DProfile::HandleMsg(TMessageBase* aMsg)
       
   586 //
       
   587 // Client requests
       
   588 //
       
   589 	{
       
   590 	TInt r=KErrNone;
       
   591 	TThreadMessage& m=*(TThreadMessage*)aMsg;
       
   592 	TInt id=m.iValue;
       
   593 	// Allow the client thread to send a message or system critical thread
       
   594 	// to send a close message as this is probably the supervisor thread doing clean up
       
   595 	if (m.Client()!=iClient && 
       
   596 		!((m.Client()->iFlags&KThreadFlagSystemCritical) && id==(TInt)ECloseMsg))
       
   597 		{
       
   598 		m.PanicClient(_L("SAMPLER"),EAccessDenied);
       
   599 		return;
       
   600 		}
       
   601 	if (id==(TInt)ECloseMsg)
       
   602 		{
       
   603 		DEBUG_PROFILER(Kern::Printf("CLOSE");)
       
   604 		iTimer.Cancel();
       
   605 		iDfc.Cancel();
       
   606 		m.Complete(KErrNone,EFalse);
       
   607 		iMsgQ.CompleteAll(KErrServerTerminated);
       
   608 		DEBUG_PROFILER(Kern::Printf("CLOSE end");)
       
   609 		return;
       
   610 		}
       
   611 	else if (id<0)
       
   612 		{
       
   613 		if (id!=~RSampler::ERequestRead)
       
   614 			{
       
   615 			TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
       
   616 			Kern::RequestComplete(iClient,pS,KErrNotSupported);
       
   617 			}
       
   618 		if (iReqStatus)
       
   619 			{
       
   620 			m.PanicClient(_L("SAMPLER"),ERequestAlreadyPending);
       
   621 			return;
       
   622 			}
       
   623 		iReqStatus=(TRequestStatus*)m.Ptr0();
       
   624 		iDes=(TDes8*)m.Ptr1();
       
   625 		r=ProcessReadRequest();
       
   626 		if (r!=KErrNone)
       
   627 			{
       
   628 			if (r==KErrCompletion)
       
   629 				r=KErrNone;
       
   630 			Complete(r);
       
   631 			}
       
   632 		r=KErrNone;
       
   633 		}
       
   634 	else if (id==KMaxTInt)
       
   635 		{
       
   636 		TInt mask=m.Int0();
       
   637 		if (mask & (1<<RSampler::ERequestRead))
       
   638 			{
       
   639 			Complete(KErrCancel);
       
   640 			}
       
   641 		}
       
   642 	else
       
   643 		{
       
   644 		switch(id)
       
   645 			{
       
   646 			case RSampler::EControlGetSegments:
       
   647 				r=GetSegments((TDes8*)m.Ptr0());
       
   648 				break;
       
   649 			case RSampler::EControlStartProfile:
       
   650 				r=StartSampling(m.Int0());
       
   651 				break;
       
   652 			case RSampler::EControlStopProfile:
       
   653 				r=StopSampling();
       
   654 				break;
       
   655 			case RSampler::EControlResetProfile:
       
   656 				r=Reset((TBool)m.Ptr0());
       
   657 				break;
       
   658 			case RSampler::EControlResetSegments:
       
   659 				r=ResetSegments();
       
   660 				break;
       
   661 			case RSampler::EControlDrain:
       
   662 				r=Drain((TDes8*)m.Ptr0());
       
   663 				break;
       
   664 			case RSampler::EControlGetErrors:
       
   665 				r=GetErrors((TDes8*)m.Ptr0());
       
   666 				break;
       
   667 			default:
       
   668 				r=KErrNotSupported;
       
   669 				break;
       
   670 			}
       
   671 		}
       
   672 	m.Complete(r,ETrue);
       
   673 	}
       
   674 
       
   675 TUint8* DProfile::EncodeTag(TUint8* p, TUint8* e)
       
   676 //
       
   677 // Encode a tag and version to the trace data. This allows the offline analyser to 
       
   678 // identify the sample data.
       
   679 //
       
   680 	{
       
   681 	_LIT(KTraceTag,"profile");
       
   682 	p=EncodeText(p,e,KTraceTag);
       
   683 	p=EncodeUint(p,e,KMajorVersionNumber);
       
   684 	return p;
       
   685 	}
       
   686 
       
   687 TUint8* DProfile::EncodeInt(TUint8* p, TUint8* e, TInt aValue)
       
   688 //
       
   689 // Encode a 32 bit signed integer into the data stream
       
   690 // This has to deal with wrap around at the end of the buffer
       
   691 //
       
   692 	{
       
   693 	TUint byte;
       
   694 	for (;;)
       
   695 		{
       
   696 		byte = aValue & 0x7f;
       
   697 		if ((aValue >> 6) == (aValue >> 7))
       
   698 			break;
       
   699 		aValue >>= 7;
       
   700 		PUT(p,(TUint8)byte,e,KCookedBufSize);
       
   701 		}
       
   702 	PUT(p,(TUint8)(byte|0x80),e,KCookedBufSize);
       
   703 	return p;
       
   704 	}
       
   705 
       
   706 TUint8* DProfile::EncodeUint(TUint8* p, TUint8* e, TUint aValue)
       
   707 //
       
   708 // Encode a 32 bit unsigned integer into the data stream
       
   709 // This has to deal with wrap around at the end of the buffer
       
   710 //
       
   711 	{
       
   712 	TUint byte;
       
   713 	for (;;)
       
   714 		{
       
   715 		byte = aValue & 0x7f;
       
   716 		aValue >>= 7;
       
   717 		if (aValue == 0)
       
   718 			break;
       
   719 		PUT(p,(TUint8)byte,e,KCookedBufSize);
       
   720 		}
       
   721 	PUT(p,(TUint8)(byte|0x80),e,KCookedBufSize);
       
   722 	return p;
       
   723 	}
       
   724 
       
   725 TUint8* DProfile::EncodeText(TUint8* p, TUint8* e, const TDesC& aDes)
       
   726 //
       
   727 // Encode a descriptor into the data stream
       
   728 // This is currently limited to a descriptor that is up to 255 characters in length,
       
   729 // and Unicode characters are truncated to 8 bits
       
   730 //
       
   731 	{
       
   732 	TInt len=aDes.Length();
       
   733 	PUT(p,(TUint8)len,e,KCookedBufSize);
       
   734 	const TText* s = aDes.Ptr();
       
   735 	while (--len >= 0)
       
   736 		PUT(p,*s++,e,KCookedBufSize);
       
   737 	return p;
       
   738 	}
       
   739 
       
   740 TUint8* DProfile::EncodeIDFC(TUint8* p, TUint8* e)
       
   741 //
       
   742 // iDFC samples do not really belong to any thread.
       
   743 // However, the profiler protocol requires each sample to be associated to a particular thread.
       
   744 // This method will encode 'fake' process ID & name and thread name for iDFC sample in the data stream.
       
   745 // It will be embedded only for the very first sample from iDFCs.
       
   746 // (For the rest of iDFCs samples, threadID is sufficient - as for the real threads.)
       
   747 //
       
   748 	{
       
   749 	p=EncodeUint(p,e,KiDFCId);     //processID for iDFC
       
   750 	p=EncodeText(p,e,KiDFCProcess);//process name for iDFC
       
   751 	p=EncodeText(p,e,KiDFCThread); //thread name for iDFC
       
   752 	return p;
       
   753 	}
       
   754 
       
   755 TUint8* DProfile::EncodeThread(TUint8* p, TUint8* e, DThread* aThread)
       
   756 //
       
   757 // Encode a thread name in the data stream.
       
   758 // The thread is identified by its name, and the identity of its owning process.
       
   759 // If the process has not been identified in the data stream already, it's name is
       
   760 // also encoded.
       
   761 //
       
   762 	{
       
   763 	DProcess* pP=aThread->iOwningProcess;
       
   764 	TKName n;
       
   765 	p=EncodeUint(p,e,pP->iId);
       
   766 	if (TAG(pP)!=iStartTime)	// not seen this before
       
   767 		{
       
   768 		TAG(pP)=iStartTime;
       
   769 		// Provide the name matching this process ID
       
   770 		pP->Name(n);
       
   771 		p=EncodeText(p,e,n);
       
   772 		}
       
   773 	aThread->Name(n);
       
   774 	p=EncodeText(p,e,n);
       
   775 	return p;
       
   776 	}
       
   777 
       
   778 TUint8* DProfile::EncodeRepeat(TUint8* p, TUint8* e, DProfile* aP)
       
   779 //
       
   780 // Encode a repeated sequence of samples
       
   781 //
       
   782 	{
       
   783 	p=EncodeInt(p,e,0);
       
   784 	p=EncodeUint(p,e,aP->iRepeat);
       
   785 	aP->iRepeat = 0;
       
   786 	return p;
       
   787 	}
       
   788 
       
   789 TInt DProfile::CookCodeSeg(TBool aPutAll, TInt aSampleCounter)
       
   790 //
       
   791 // Transfers and encodes CodeSeg Create/Delete records from CodeSeg buffer into Cooked buffer.
       
   792 // If aPutAll = Etrue, all records will be transferred.
       
   793 // If aPutAll = EFalse, only records at the beginning of the queue that matches aSampleCounter will be transferred.
       
   794 // It stopps if there is less then KRequiredFreeSpace bytes available in cooked buffer.
       
   795 // Returns the number of the transferred records.
       
   796 //
       
   797 	{
       
   798 	if (iXIPOnly)
       
   799 		return 0;
       
   800 	
       
   801 	TInt n = 0;
       
   802 	TInt codeSampleCounter;//Will hold the sample counter of the record
       
   803 	TInt runAddress;
       
   804 	TInt codeSize;
       
   805 	TInt8 textLen;
       
   806 	TBuf<255> text;
       
   807 	TUint8* localCSGet = iCSGet;
       
   808 
       
   809 	FOREVER
       
   810 		{
       
   811 		//Check if there is any Code Seg record left.
       
   812 		if (iCSGet==iCSPut)
       
   813 			return n;//No records left
       
   814 		
       
   815 		//Check if the next record is due to be encoded. Both Create & Delete CodeSeg records start with sample counter.
       
   816 		localCSGet = iCSGet;
       
   817 		localCSGet = GetStream(localCSGet, CODESEGBUFEND, (TInt8*)(&codeSampleCounter), sizeof(TInt));
       
   818 		if (!aPutAll && codeSampleCounter!=aSampleCounter)
       
   819 			return n; //Still too early to insert the record into Cook Buffer
       
   820 			
       
   821 		//Check for the space in cook buffer
       
   822 		TInt cookAvailable = (TInt)iCGet - (TInt)iCPut;
       
   823 		if (cookAvailable <= 0)	
       
   824 			cookAvailable+=KCookedBufSize;
       
   825 		if (cookAvailable < KRequiredFreeSpace)
       
   826 			return n;//No space in Cook Buffer.
       
   827 		
       
   828 		//At this point it is for sure that we have to transfer some record to cook buffer
       
   829 		
       
   830 		n++;
       
   831 		iCSGet = localCSGet;
       
   832 		//The next field for both Create & Delete CodeSeg records is run address:
       
   833 		iCSGet = GetStream(iCSGet, CODESEGBUFEND, (TInt8*)(&runAddress), sizeof(TInt));
       
   834 		
       
   835 		if (runAddress & 1)//LSB in run address idenifies the type of the record
       
   836 			{//CodeSegment Delete record. To be encoded as Int(0), UInt(0), UInt(RunAddress | 1)
       
   837 			iCPut = EncodeInt (iCPut, COOKEDBUFEND, 0);
       
   838 			iCPut = EncodeUint(iCPut, COOKEDBUFEND, 0);
       
   839 			iCPut = EncodeUint(iCPut, COOKEDBUFEND, runAddress);
       
   840 			}
       
   841 		else
       
   842 			{//CodeSegment Create record.
       
   843 			iCSGet = GetStream(iCSGet, CODESEGBUFEND, (TInt8*)(&codeSize), sizeof(TInt));
       
   844 			iCSGet = GetStream(iCSGet, CODESEGBUFEND, (TInt8*)(&textLen), sizeof(TInt8));
       
   845 			iCSGet = GetStream(iCSGet, CODESEGBUFEND, (TInt8*)(text.Ptr()), textLen);
       
   846 			text.SetLength(textLen);
       
   847 			//To be encoded as Int(0), UInt(0), UInt(RunAddress), UInt(SegmentSize), Text(FileNeme)
       
   848 			iCPut = EncodeInt(iCPut, COOKEDBUFEND, 0);
       
   849 			iCPut = EncodeUint(iCPut, COOKEDBUFEND, 0);
       
   850 			iCPut = EncodeUint(iCPut, COOKEDBUFEND, runAddress);
       
   851 			iCPut = EncodeUint(iCPut, COOKEDBUFEND, codeSize);
       
   852 			iCPut = EncodeText(iCPut, COOKEDBUFEND, text);
       
   853 			}
       
   854 		}
       
   855 	}
       
   856 
       
   857 TInt DProfile::Cook()
       
   858 //
       
   859 // Transfers/encodes row data and code segments record into cooked buffer.
       
   860 // Returns the number of records (incl. both samples and codeSeg records) cooked.
       
   861 //
       
   862 	{
       
   863 	TUint8* p=iCPut;
       
   864 	TUint8* e=iCookedBuf+KCookedBufSize;
       
   865 	TInt n=0;
       
   866 	
       
   867 	FOREVER
       
   868 		{
       
   869 		iCPut=p; //update iCPut before calling CookCodeSeg
       
   870 		if ((iRGet==iRPut))
       
   871 			{//No more samples.
       
   872 			n+=CookCodeSeg(ETrue, 0); //Cook the remaining content of CodeSeg buffer.
       
   873 			break;
       
   874 			}
       
   875 
       
   876 		SRawSample* s=iRawBuf+iRGet;	// pointer to the next sample to be cooked
       
   877 
       
   878 		n+=CookCodeSeg(EFalse, s->iSampleCounter);//cook all codeSeg records than matches this sample counter
       
   879 		p=iCPut; //CookCodeSeg might have changed iCPut
       
   880 
       
   881 		TInt space=iCGet-p;
       
   882 		if (space<=0)
       
   883 			space+=KCookedBufSize;		// space remaining in cooked buffer
       
   884 		if (space<KRequiredFreeSpace)
       
   885 			break;						// if insufficient, finish
       
   886 
       
   887 		//Cook the next sample record from Row buffer		
       
   888 		++iRGet;
       
   889 		++n;
       
   890 		TBool newthread=s->iPC & 1;		// bit 0 of PC means so far unknown thread
       
   891 		TLinAddr pc=s->iPC &~ 1;
       
   892 		TUint rp = iRepeat;
       
   893 		TInt diff=TInt(pc-iLast.iPC);
       
   894 		if (!newthread)
       
   895 			{
       
   896 			if (s->iThreadId!=iLast.iThreadId)
       
   897 				diff|=1;
       
   898 			if (diff == 0)
       
   899 				{
       
   900 				iRepeat = rp + 1;	// Identical sample, bump up the repeat count
       
   901 				continue;
       
   902 				}
       
   903 			if (rp)
       
   904 				{
       
   905 				// Encode the repeat data
       
   906 				p = EncodeRepeat(p,e,this);
       
   907 				}
       
   908 			// Encode the PC difference
       
   909 			p = EncodeInt(p, e, diff);
       
   910 			if (diff & 1)
       
   911 				{
       
   912 				// Encode the new thread ID
       
   913 				iLast.iThreadId = s->iThreadId;
       
   914 				p = EncodeUint(p, e, s->iThreadId);
       
   915 				}
       
   916 			}
       
   917 		else
       
   918 			{
       
   919 			if (rp)
       
   920 				{
       
   921 				// Encode the repeat data
       
   922 				p = EncodeRepeat(p,e,this);
       
   923 				}
       
   924 			// Encode the PC difference
       
   925 			p = EncodeInt(p, e, diff|1);
       
   926 
       
   927 			if (s->iThreadId == KiDFCId)
       
   928 				{
       
   929 				// This is the first sample from iDFC. Encode 'threadID'
       
   930 				iLast.iThreadId = KiDFCId;
       
   931 				p = EncodeUint(p, e, KiDFCId);
       
   932 				// and encode processID, processName & threadName for this sample
       
   933 				p = EncodeIDFC(p, e);
       
   934 				}
       
   935 			else
       
   936 				{
       
   937 				// Encode the new thread ID
       
   938 				DThread* pT=(DThread*)s->iThreadId;
       
   939 				iLast.iThreadId = pT->iId;
       
   940 				p = EncodeUint(p, e, pT->iId);
       
   941 				// The thread is 'unknown' to this sample, so encode the thread name
       
   942 				p = EncodeThread(p, e, pT);
       
   943 				}
       
   944 			}
       
   945 		iLast.iPC=pc;
       
   946 		}
       
   947 	return n;
       
   948 	}
       
   949 
       
   950 void DProfile::Dfc(TAny* aPtr)
       
   951 //
       
   952 // Tranfers/encodes Row & CodeSeg buffers' content into Cook buffer (by Cook()), 
       
   953 // and copies encoded data into user side descriptor (by DoDrainCooked())
       
   954 //
       
   955 	{
       
   956 	DProfile& d=*(DProfile*)aPtr;
       
   957 	TInt n=-1;
       
   958 	while (n)
       
   959 		{
       
   960 		TInt r=d.DoDrainCooked();		// drain any cooked data if possible
       
   961 		if (r<0 && r!=KErrUnderflow)
       
   962 			{
       
   963 			d.Complete(r);				// error writing client buffer
       
   964 			break;
       
   965 			}
       
   966 		n=d.Cook();						// cook the samples, return number cooked
       
   967 		}
       
   968 	}
       
   969 
       
   970 TUint8* DProfile::PutStream(TUint8* p, TUint8* e, const TUint8* aSource, TInt aSize)
       
   971 //
       
   972 // Put data into CodeSeg stream 
       
   973 // This has to deal with wrap around at the end of the buffer
       
   974 //
       
   975 	{
       
   976 	for (TInt i = 0 ; i< aSize ; i++)
       
   977 		{
       
   978 		PUT(p,(TUint8)(*aSource),e,KCodeBufSize);
       
   979 		aSource++;
       
   980 		}
       
   981 	return p;
       
   982 	}
       
   983 
       
   984 TUint8* DProfile::GetStream(TUint8* p, TUint8* e, TInt8* aDest, TInt aSize)
       
   985 //
       
   986 // Get 32 bits from CodeSeg stream.
       
   987 // This has to deal with wrap around at the end of the buffer
       
   988 //
       
   989 	{
       
   990 	for (TInt i = 0 ; i< aSize ; i++)
       
   991 		GET_A_BYTE(p,aDest,e,KCodeBufSize);
       
   992 	return p;
       
   993 	}
       
   994 
       
   995 void DProfile::LogCodeSegEvent(TKernelEvent aEvent, DEpocCodeSeg *pCodeSeg)
       
   996 //
       
   997 // Records the event in CodeSeg buffer.
       
   998 //
       
   999 	{
       
  1000 ///
       
  1001 ///	
       
  1002 	TUint8* localCSPut = iCSPut;
       
  1003 	TInt available = KCodeBufSize + (TInt)iCSGet - (TInt)iCSPut;
       
  1004 	if (available > KCodeBufSize)
       
  1005 		available -= KCodeBufSize;
       
  1006 
       
  1007 	switch (aEvent)
       
  1008 		{
       
  1009 	case EEventAddCodeSeg:
       
  1010 		{
       
  1011 		TInt textOffset = 0;
       
  1012 		TInt textSize= pCodeSeg->iFileName->Length();
       
  1013 		//Restrict file name to max 255 sharacters. If bigger, record the last 255 bytes only
       
  1014 		if (textSize > 255)
       
  1015 			{
       
  1016 			textOffset = textSize-255;
       
  1017 			textSize = 255;
       
  1018 			}
       
  1019 		if ((available -= 13+textSize) < 0) //13 bytes needed for sample counter, run address, size and text size) 
       
  1020 			{
       
  1021 			iReport.iCodeSegErrCounter++;
       
  1022 			return;
       
  1023 			}
       
  1024 		localCSPut = PutStream(localCSPut, CODESEGBUFEND, (TUint8*)(&iNextSampleCounter), sizeof(TInt));
       
  1025 		localCSPut = PutStream(localCSPut, CODESEGBUFEND, (TUint8*)(&pCodeSeg->iRunAddress), sizeof(TInt));
       
  1026 		localCSPut = PutStream(localCSPut, CODESEGBUFEND, (TUint8*)(&pCodeSeg->iSize), sizeof(TInt));
       
  1027 		localCSPut = PutStream(localCSPut, CODESEGBUFEND, (TUint8*)(&textSize), sizeof(TInt8));
       
  1028 		localCSPut = PutStream(	localCSPut, CODESEGBUFEND, pCodeSeg->iFileName->Ptr()+textOffset, textSize);
       
  1029 		iCSPut = localCSPut;
       
  1030 
       
  1031 		DEBUG_PROFILER
       
  1032 			(
       
  1033 			TBuf<256> buf(textSize+1);
       
  1034 			buf.Copy(pCodeSeg->iFileName->Ptr()+textOffset,textSize); buf.SetLength(textSize+1); buf[textSize]=0;
       
  1035 			Kern::Printf("CREATE CS:%s, %x, %x,", buf.Ptr(), pCodeSeg->iRunAddress, pCodeSeg->iSize);
       
  1036 			)
       
  1037 		break;
       
  1038 		}
       
  1039 	case EEventRemoveCodeSeg:
       
  1040 		{
       
  1041 		if ((available-=8) < 0) //8 bytes needed for sample counter and run address
       
  1042 			{
       
  1043 			iReport.iCodeSegErrCounter++;
       
  1044 			return;
       
  1045 			}
       
  1046 		TInt runAddress = pCodeSeg->iRunAddress | 1; 
       
  1047 		localCSPut = PutStream(localCSPut, CODESEGBUFEND, (TUint8*)(&iNextSampleCounter), sizeof(TInt));
       
  1048 		localCSPut = PutStream(localCSPut, CODESEGBUFEND, (TUint8*)(&runAddress), sizeof(TInt));
       
  1049 		iCSPut = localCSPut;
       
  1050 
       
  1051 		DEBUG_PROFILER(Kern::Printf("DELETE CS:%x", pCodeSeg->iRunAddress);)
       
  1052 		break;
       
  1053 		}
       
  1054 	default:
       
  1055 		return;
       
  1056 	}
       
  1057 	if (available < KCodeBufSize/2) //Start emptying CodeSeg (and Raw Buffer, as well) Buffer if more then a half full.
       
  1058 		iDfc.Enque();
       
  1059 }
       
  1060 
       
  1061 TUint DProfile::KernelEventHandler(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aPrivateData)
       
  1062 //
       
  1063 // Logs non-XIP CodeSeg Create/Delete events.
       
  1064 // In GettingSegments mode, it logs only deletion of the marked segments.
       
  1065 // Runs in the content of the Kernel scheduler
       
  1066 //
       
  1067 {
       
  1068 	if (aEvent==EEventAddCodeSeg || aEvent==EEventRemoveCodeSeg) 
       
  1069 	{
       
  1070 		DProfile *p = (DProfile*)aPrivateData;
       
  1071 		DEpocCodeSeg* pCodeSeg = (DEpocCodeSeg*)(DCodeSeg*)a1;
       
  1072 
       
  1073 		Kern::AccessCode();
       
  1074 		if ((!pCodeSeg->iXIP) && (!p->iMarkedOnlySegments || pCodeSeg->iMark&DCodeSeg::EMarkProfilerTAG))
       
  1075 			p->LogCodeSegEvent(aEvent, pCodeSeg);
       
  1076 		Kern::EndAccessCode();
       
  1077 
       
  1078 	}
       
  1079 	return DKernelEventHandler::ERunNext;
       
  1080 }
       
  1081 
       
  1082 
       
  1083 void DProfile::Sample(TAny* aPtr)
       
  1084 	{
       
  1085 	DProfile& d=*(DProfile*)aPtr;
       
  1086 	d.iTimer.Again(d.iPeriod);
       
  1087 	TUint8 next_put=(TUint8)(d.iRPut+1);
       
  1088 	if (next_put!=d.iRGet)		// space in raw buffer
       
  1089 		{
       
  1090 		DThread* pT=Kern::NThreadToDThread(NKern::CurrentThread());
       
  1091 		if (pT!=NULL)
       
  1092 			{
       
  1093 			SRawSample* p=d.iRawBuf+d.iRPut;
       
  1094 			d.iRPut=next_put;
       
  1095 			p->iPC=((d.iIntStackTop)[-1]) & ~1; //clear LSB bit (in case of Jazelle code)
       
  1096 			p->iSampleCounter=d.iNextSampleCounter++;
       
  1097 			
       
  1098 			if (IDFCRunning())
       
  1099 				{
       
  1100 				p->iThreadId=KiDFCId; //indicates iDFC running
       
  1101 				if (!d.iIDFCSeenBefore)
       
  1102 					{
       
  1103 					d.iIDFCSeenBefore = ETrue;
       
  1104 					p->iPC|=1;				// set bit 0 of PC to indicate new thread
       
  1105 					}
       
  1106 				else
       
  1107 					{
       
  1108 					TUint8 used=(TUint8)(d.iRPut-d.iRGet);
       
  1109 					if (used<=KRawBufSize/2)
       
  1110 						return;
       
  1111 					}
       
  1112 				}
       
  1113 			else
       
  1114 				{
       
  1115 				
       
  1116 				if (TAG(pT)!=d.iStartTime)	// not seen this before
       
  1117 					{
       
  1118 					TAG(pT)=d.iStartTime;
       
  1119 					p->iThreadId=(TUint)pT;
       
  1120 					p->iPC|=1;				// set bit 0 of PC to indicate new thread
       
  1121 					}
       
  1122 				else
       
  1123 					{
       
  1124 					p->iThreadId=pT->iId;
       
  1125 					TUint8 used=(TUint8)(d.iRPut-d.iRGet);
       
  1126 					if (used<=KRawBufSize/2)
       
  1127 						return;
       
  1128 					}
       
  1129 				}
       
  1130 			d.iDfc.Add();	// queue DFC if new thread seen or buffer more than half full
       
  1131 			}
       
  1132 		}
       
  1133 	else
       
  1134 		d.iReport.iRowBufferErrCounter++;
       
  1135 	}
       
  1136