os/kernelhwsrv/kerneltest/e32utils/profiler/sampler.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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