commands/top/sampler.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // sampler.cpp
       
     2 // 
       
     3 // Copyright (c) 1999 - 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 
       
    13 #include <platform.h>
       
    14 
       
    15 #include "sampler.h"
       
    16 //#include <nkern.h>
       
    17 //#include <kernel.h>
       
    18 #include <kern_priv.h>
       
    19 _LIT(KLddName,"topsampler");
       
    20 
       
    21 const TInt KMinRate=10;
       
    22 const TInt KMaxRate=1000;
       
    23 const TInt KRawBufSize = 20000; // Enough for 20 seconds of samples - since max expected refresh rate in UI is 10s we can do everything nice and simply with one buffer
       
    24 
       
    25 class DDeviceSampler : public DLogicalDevice
       
    26 	{
       
    27 public:
       
    28 	DDeviceSampler();
       
    29 	virtual TInt Install();
       
    30 	virtual void GetCaps(TDes8& aDes) const;
       
    31 	virtual TInt Create(DLogicalChannelBase*& aChannel);
       
    32 	};
       
    33 
       
    34 class DProfile : public DLogicalChannel
       
    35 	{
       
    36 public:
       
    37 	DProfile();
       
    38 	~DProfile();
       
    39 protected:
       
    40 	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
       
    41 	virtual void HandleMsg(TMessageBase* aMsg);
       
    42 private:
       
    43 	TInt StartSampling(TInt aRate);
       
    44 	TInt StopSampling();
       
    45 	TInt Reset();
       
    46 	//TInt GetErrors(TDes8* aDes);
       
    47 	TInt ProcessReadRequest();
       
    48 	void Complete(TInt aResult);
       
    49 	inline TBool Running()
       
    50 		{return iTimer.iState!=NTimer::EIdle;}
       
    51 private:
       
    52 	static void Sample(TAny*);
       
    53 	void DoSample();
       
    54 
       
    55 	
       
    56 private:
       
    57 	TUint32 iStartTime;
       
    58 	TInt iRepeat;
       
    59 	TInt iPeriod;
       
    60 	DThread* iClient;
       
    61 	TRequestStatus* iReqStatus;
       
    62 	TDes8* iClientDes;		// client des pointer
       
    63 	TUint32 iBuf1[KRawBufSize]; // First word is the current position in the buffer
       
    64 	TUint32 iBuf2[KRawBufSize]; // Have two buffers that we can switch between, this avoids us having to stop the sampler timer, or disable interrupts or whatever, when we want to drain the buffer
       
    65 	TUint32* iCurrentBuf; // Pointer to either iBuf1 or iBuf2
       
    66 
       
    67 	struct TReport
       
    68 		{
       
    69 		TUint iRawBufferErrCounter;
       
    70 		TUint iCodeSegErrCounter;
       
    71 		TInt  iReportMask; 
       
    72 		} iReport;
       
    73 
       
    74 	NTimer iTimer;
       
    75 	};
       
    76 
       
    77 DECLARE_STANDARD_LDD()
       
    78 	{
       
    79 	return new DDeviceSampler;
       
    80 	}
       
    81 
       
    82 DDeviceSampler::DDeviceSampler()
       
    83 //
       
    84 // Constructor
       
    85 //
       
    86 	{
       
    87 	//iParseMask=0;
       
    88 	//iUnitsMask=0;
       
    89 	iVersion=TVersion(1,0,0);
       
    90 	}
       
    91 
       
    92 TInt DDeviceSampler::Install()
       
    93 //
       
    94 // Install the device driver.
       
    95 //
       
    96 	{
       
    97 	TInt r=SetName(&KLddName);
       
    98 	return r;
       
    99 	}
       
   100 
       
   101 void DDeviceSampler::GetCaps(TDes8& /*aDes*/) const
       
   102 //
       
   103 // Return the capabilities.
       
   104 //
       
   105 	{
       
   106 	}
       
   107 
       
   108 TInt DDeviceSampler::Create(DLogicalChannelBase*& aChannel)
       
   109 //
       
   110 // Create a channel on the device.
       
   111 //
       
   112 	{
       
   113 	aChannel=new DProfile;
       
   114 	return aChannel?KErrNone:KErrNoMemory;
       
   115 	}
       
   116 
       
   117 DProfile::DProfile()
       
   118 	:	iTimer(Sample,this)
       
   119 //
       
   120 // Constructor
       
   121 //
       
   122 	{
       
   123 	iCurrentBuf = iBuf1;
       
   124 	iCurrentBuf[0] = 1;
       
   125 	}
       
   126 
       
   127 DProfile::~DProfile()
       
   128 //
       
   129 // Destructor
       
   130 //
       
   131 	{
       
   132 	iTimer.Cancel();
       
   133 	Kern::SafeClose((DObject*&)iClient, NULL);
       
   134 	}
       
   135 
       
   136 TInt DProfile::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
       
   137 //
       
   138 // Create the channel from the passed info.
       
   139 //
       
   140 	{
       
   141 	if (!Kern::QueryVersionSupported(TVersion(1,0,1),aVer))
       
   142 		return KErrNotSupported;
       
   143 
       
   144 	iClient=&Kern::CurrentThread();
       
   145 	iClient->Open();
       
   146 	//Kern::SetThreadPriority(24);
       
   147 	SetDfcQ(Kern::DfcQue0());
       
   148 	iMsgQ.Receive();
       
   149 	return KErrNone;
       
   150 	}
       
   151 
       
   152 void DProfile::Complete(TInt aResult)
       
   153 //Completes user request
       
   154 	{
       
   155 	DEBUG_PROFILER(Kern::Printf("C");)
       
   156 	Kern::RequestComplete(iClient,iReqStatus,aResult);
       
   157 	}
       
   158 
       
   159 TInt DProfile::StartSampling(TInt aRate)
       
   160 	{
       
   161 	DEBUG_PROFILER(Kern::Printf("START");)
       
   162 	//Activate timer
       
   163 	aRate=Min(KMaxRate, Max(KMinRate, aRate));
       
   164 	iPeriod=1000/aRate;
       
   165 
       
   166 	if (!Running())
       
   167 		{
       
   168 		iCurrentBuf = iBuf1;
       
   169 		iCurrentBuf[0] = 1;
       
   170 		iTimer.OneShot(iPeriod);
       
   171 		}
       
   172 	
       
   173 	DEBUG_PROFILER(Kern::Printf("START end");)
       
   174 	return KErrNone;
       
   175 	}
       
   176 
       
   177 TInt DProfile::Reset()
       
   178 	{
       
   179 //
       
   180 // Resets the device. It is the first message sent by profiler application.
       
   181 //	
       
   182 	if (Running())
       
   183 		return KErrGeneral;
       
   184 	
       
   185 	DEBUG_PROFILER(Kern::Printf("RST %d", aXIPOnly);)
       
   186 
       
   187 	iTimer.Cancel();
       
   188 	iPeriod=1;
       
   189 	iReqStatus=NULL;
       
   190 	iClientDes=NULL;
       
   191 
       
   192 	iReport.iRawBufferErrCounter = 0;
       
   193 	iReport.iCodeSegErrCounter = 0;
       
   194 	iReport.iReportMask = 0;
       
   195 	DEBUG_PROFILER(Kern::Printf("RST end");)
       
   196 	return KErrNone;
       
   197 	}
       
   198 
       
   199 TInt DProfile::StopSampling()
       
   200 //
       
   201 // Stops sampling
       
   202 //
       
   203 	{
       
   204 	DEBUG_PROFILER(Kern::Printf("STOP");)
       
   205 	if (Running())
       
   206 		{
       
   207 		iTimer.Cancel();
       
   208 		}
       
   209 	if (iReqStatus)
       
   210 		Complete(KErrNone);
       
   211 	
       
   212 	DEBUG_PROFILER(Kern::Printf("STOP end");)
       
   213 	return KErrNone;
       
   214 	}
       
   215 
       
   216 TInt DProfile::ProcessReadRequest()
       
   217 	{
       
   218 	// Whatever the status of the profiler, return the contents of the current sampling buffer
       
   219 	DEBUG_PROFILER(Kern::Printf("READ");)
       
   220 	TInt max=Kern::ThreadGetDesMaxLength(iClient, iClientDes);
       
   221 	if (max<0)
       
   222 		return max;
       
   223 	if (max==0)
       
   224 		return KErrArgument;
       
   225 
       
   226 	TUint32* otherBuf = (iCurrentBuf == iBuf1 ? iBuf2 : iBuf1);
       
   227 	otherBuf[0] = 1; // Reset other buf
       
   228 	TUint32* bufToWrite = iCurrentBuf;
       
   229 	iCurrentBuf = otherBuf; // And switch do it, so we can safely mess with bufToWrite without the sampling ISR adding more data under our feet
       
   230 	TInt numSamples = bufToWrite[0] - 1; // Because bufToWrite[0] is an index and the data actually starts at index 1
       
   231 	TPtrC8 desToWrite((TUint8*)&bufToWrite[1], (numSamples)*sizeof(TUint32));
       
   232 	
       
   233 	TInt r = Kern::ThreadDesWrite(iClient, iClientDes, desToWrite, 0, 0, iClient);
       
   234 	return r;
       
   235 	}
       
   236 
       
   237 void DProfile::HandleMsg(TMessageBase* aMsg)
       
   238 //
       
   239 // Client requests
       
   240 //
       
   241 	{
       
   242 	TInt r=KErrNone;
       
   243 	TThreadMessage& m=*(TThreadMessage*)aMsg;
       
   244 	//BEGIN TOMSCI commented out this check as it is too strict
       
   245 	/*
       
   246 	if (m.Client()!=iClient)
       
   247 		{
       
   248 		m.PanicClient(_L("SAMPLER"),EAccessDenied);
       
   249 		return;
       
   250 		}
       
   251 	*/
       
   252 	//END TOMSCI
       
   253 	TInt id=m.iValue;
       
   254 	if (id==(TInt)ECloseMsg)
       
   255 		{
       
   256 		DEBUG_PROFILER(Kern::Printf("CLOSE");)
       
   257 		iTimer.Cancel();
       
   258 		m.Complete(KErrNone,EFalse);
       
   259 		iMsgQ.CompleteAll(KErrServerTerminated);
       
   260 		DEBUG_PROFILER(Kern::Printf("CLOSE end");)
       
   261 		return;
       
   262 		}
       
   263 	else if (id<0)
       
   264 		{
       
   265 		if (id!=~RSampler::ERequestRead)
       
   266 			{
       
   267 			TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
       
   268 			Kern::RequestComplete(iClient,pS,KErrNotSupported);
       
   269 			}
       
   270 		if (iReqStatus)
       
   271 			{
       
   272 			m.PanicClient(_L("SAMPLER"),ERequestAlreadyPending);
       
   273 			return;
       
   274 			}
       
   275 		iReqStatus=(TRequestStatus*)m.Ptr0();
       
   276 		iClientDes=(TDes8*)m.Ptr1();
       
   277 		TInt err = ProcessReadRequest();
       
   278 		Complete(err);
       
   279 		}
       
   280 	else if (id==KMaxTInt)
       
   281 		{
       
   282 		TInt mask=m.Int0();
       
   283 		if (mask & (1<<RSampler::ERequestRead))
       
   284 			{
       
   285 			Complete(KErrCancel);
       
   286 			}
       
   287 		}
       
   288 	else
       
   289 		{
       
   290 		switch(id)
       
   291 			{
       
   292 			case RSampler::EControlStartProfile:
       
   293 				r=StartSampling(m.Int0());
       
   294 				break;
       
   295 			case RSampler::EControlStopProfile:
       
   296 				r=StopSampling();
       
   297 				break;
       
   298 			case RSampler::EControlResetProfile:
       
   299 				r=Reset();
       
   300 				break;
       
   301 			//case RSampler::EControlGetErrors:
       
   302 			//	r=GetErrors((TDes8*)m.Ptr0());
       
   303 			//	break;
       
   304 			default:
       
   305 				r=KErrNotSupported;
       
   306 				break;
       
   307 			}
       
   308 		}
       
   309 	m.Complete(r,ETrue);
       
   310 	}
       
   311 
       
   312 void DProfile::Sample(TAny* aPtr)
       
   313 	{
       
   314 	DProfile& d=*(DProfile*)aPtr;
       
   315 	d.DoSample();
       
   316 	}
       
   317 
       
   318 void DProfile::DoSample()
       
   319 	{
       
   320 	iTimer.Again(iPeriod);
       
   321 
       
   322 	TUint32& currentPos = iCurrentBuf[0];
       
   323 	if (currentPos < (TUint)KRawBufSize) // space in buffer
       
   324 		{
       
   325 		DThread* pT=Kern::NThreadToDThread(NKern::CurrentThread());
       
   326 		if (pT!=NULL)
       
   327 			{
       
   328 			iCurrentBuf[currentPos] = pT->iId;
       
   329 			currentPos++;
       
   330 			}
       
   331 		}
       
   332 	else
       
   333 		iReport.iRawBufferErrCounter++;
       
   334 	}