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