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