kerneltest/e32utils/profiler/profiler.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32utils\profiler\profiler.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <e32cons.h>
       
    19 #include <f32file.h>
       
    20 #include "profiler.h"
       
    21 #include "sampler.h"
       
    22 
       
    23 // The name of the output file use to save the sample data
       
    24 _LIT(KFileName,"?:\\PROFILER.DAT");
       
    25 const TInt KFileNameLen=15;
       
    26 
       
    27 // The name of the DLL used as an alternative UI controller
       
    28 _LIT(KProfilerKeysDll,"ProfilerKeys");
       
    29 
       
    30 // The size of the buffers used for reading sample data and writing to file
       
    31 const TInt KBufferSize = 0x800;
       
    32 
       
    33 // The sample rate used by the profiler
       
    34 const TInt KSampleRate = 1000;
       
    35 
       
    36 const TInt KCommandMask  = 0x00ff;
       
    37 const TInt KCommandNone  = 0x0010;
       
    38 const TInt KCommandNoUi  = 0x0100;
       
    39 const TInt KCommandXIPOnly = 0x0200;
       
    40 
       
    41 // The controller class used to provide the Profiler functions.
       
    42 // This runs as a server in the engine thread
       
    43 class CPServer : public CServer2, public MProfilerController
       
    44 	{
       
    45 public:
       
    46 	static MProfilerController* NewL(TInt aPriority, MProfilerEngine& aEngine);
       
    47 private:
       
    48 	CPServer(TInt aPriority, MProfilerEngine& aEngine);
       
    49 	void Release();
       
    50 	CSession2* NewSessionL(const TVersion& aVersion,const RMessage2& aMessage) const;
       
    51 	};
       
    52 
       
    53 // The session class used by the server controller
       
    54 class CPSession : public CSession2
       
    55 	{
       
    56 private:
       
    57 	inline const CPServer& Server() const;
       
    58 	void ServiceL(const RMessage2& aMessage);
       
    59 	};
       
    60 
       
    61 
       
    62 // The default UI controller class which uses a Console
       
    63 class CConsole : public CActive, private MProfilerController
       
    64 	{
       
    65 public:
       
    66 	static MProfilerController* NewL(TInt aPriority, MProfilerEngine& aEngine);
       
    67 private:
       
    68 	CConsole(TInt aPriority, MProfilerEngine& aEngine);
       
    69 	void ConstructL();
       
    70 	~CConsole();
       
    71 	void Release();
       
    72 //
       
    73 	void Help();
       
    74 	void Queue();
       
    75 //
       
    76 	void RunL();
       
    77 	void DoCancel();
       
    78 private:
       
    79 	CConsoleBase* iConsole;
       
    80 	};
       
    81 
       
    82 
       
    83 // The buffers used for transferring data from the device driver to the file
       
    84 struct TBuffer
       
    85 	{
       
    86 	TBuffer* iNext;
       
    87 	TBuf8<KBufferSize> iBuf;
       
    88 	};
       
    89 
       
    90 class CProfiler;
       
    91 
       
    92 // The active object responsible for reading data from the device
       
    93 class CReader : public CActive
       
    94 	{
       
    95 public:
       
    96 	CReader(TInt aPriority, CProfiler& aProfiler);
       
    97 	~CReader();
       
    98 //
       
    99 	void ConstructL();
       
   100 	void Queue(TBuffer* aBuf);
       
   101 private:
       
   102 	void RunL();
       
   103 	void DoCancel();
       
   104 private:
       
   105 	CProfiler& iProfiler;
       
   106 	TBuffer* iBuf;
       
   107 public:
       
   108 	RSampler iSampler;
       
   109 	};
       
   110 
       
   111 // The active object responsible for writing data out (to file)
       
   112 class CWriter : public CActive
       
   113 	{
       
   114 public:
       
   115 	CWriter(TInt aPriority, CProfiler& aProfiler);
       
   116 	~CWriter();
       
   117 	void ConstructL();
       
   118 	TInt Open(const TDesC& aFile);
       
   119 	void Close();
       
   120 	void Queue(TBuffer* aBuf);
       
   121 private:
       
   122 	void RunL();
       
   123 	void DoCancel();
       
   124 private:
       
   125 	CProfiler& iProfiler;
       
   126 	TBuffer* iBuf;
       
   127 	RFile iFile;
       
   128 	RFs iFs;
       
   129 	};
       
   130 
       
   131 
       
   132 // The profiler engine itself.
       
   133 class CProfiler : public CBase, private MProfilerEngine
       
   134 	{
       
   135 	enum {EControlPriority = 10, EReaderPriority = 0, EWriterPriority = -10};
       
   136 	
       
   137 	/** Specifies the state of the engine*/
       
   138 	enum TState 
       
   139 		{
       
   140 		/**
       
   141 		Initial state. The file is closed. Driver is inactive
       
   142 		*/
       
   143 		EClosed,
       
   144 		/**
       
   145 		Engine enters this state on client's Start request (if -xiponly is not specified).
       
   146 		Opens the file.
       
   147 		Resets the driver and nonXIP code segments.
       
   148 		Sends GetSegments calls to the driver until driver returns zero length reply.
       
   149 		Leaves this state (goes into ERunning) when the last data (obtained by GetSegment) is
       
   150 		written into the file.		 
       
   151 		*/
       
   152 		EGettingSegments,
       
   153 		/**
       
   154 		Sends async. read request to the driver. Once completed, it immediately sends another while 
       
   155 		writing the collected records into the file.
       
   156 		*/
       
   157 		ERunning,
       
   158 		/**
       
   159 		Get into this state from ERunning on the client's Stop, Close or Exit request.
       
   160 		Sends Drain calls to the driver until driver returns zero length reply.
       
   161 		Leaves this state when all records are written into the file.
       
   162 		*/
       
   163 		EDraining,
       
   164 		/**
       
   165 		No active calls to the driver. On the client's Start request, will go back into ERunning mode.
       
   166 		*/
       
   167 		EStopped,
       
   168 		/**
       
   169 		Get into this state on client's Close or Exit request.
       
   170 		Sends a single GetErrorReport request to the driver. After data has been recorded into the file,
       
   171 		it closes the file and goes into EClosed state or terminates application..
       
   172 		*/
       
   173 		EGettingErrors
       
   174 		};
       
   175 public:
       
   176 	static CProfiler* NewLC(TInt aCmd, TDesC* aDrive);
       
   177 //
       
   178 	TInt Control(Profiler::TState aCommand);
       
   179 //
       
   180 	void ReadComplete(TBuffer* aBuf);
       
   181 	void WriteComplete(TBuffer* aBuf);
       
   182 private:
       
   183 	CProfiler();
       
   184 	~CProfiler();
       
   185 	void ConstructL(TInt aCmd, TDesC* aDrive);
       
   186 	MProfilerController* CreateUiL();
       
   187 //
       
   188 	void Read();
       
   189 	void Write();
       
   190 	TBool GetSegments();
       
   191 	TBool Drain();
       
   192 	void GetErrors();
       
   193 //
       
   194 	Profiler::TState State() const;
       
   195 private:
       
   196 	CReader* iReader;
       
   197 	CWriter* iWriter;
       
   198 	MProfilerController* iServer;
       
   199 	RLibrary iUiCode;
       
   200 	MProfilerController* iUi;
       
   201 	TState iState;
       
   202 	TBool iXIPOnly;
       
   203 	Profiler::TState iLastCommand;
       
   204 //
       
   205 	// The FIFO queue of data that has to be written
       
   206 	TBuffer* iHead;
       
   207 	TBuffer* iTail;
       
   208 //
       
   209 	// The LIFO list of free buffers 
       
   210 	TBuffer* iFree;
       
   211 	TDesC* iDrive;
       
   212 	};
       
   213 
       
   214 
       
   215 CProfiler* CProfiler::NewLC(TInt aCmd, TDesC* aDrive)
       
   216 	{
       
   217 	CProfiler* self = new(ELeave) CProfiler;
       
   218 	CleanupStack::PushL(self);
       
   219 	self->ConstructL(aCmd, aDrive);
       
   220 	return self;
       
   221 	}
       
   222 
       
   223 CProfiler::CProfiler()
       
   224 	{}
       
   225 
       
   226 CProfiler::~CProfiler()
       
   227 	{
       
   228 	delete iReader;
       
   229 	delete iWriter;
       
   230 	if (iServer)
       
   231 		iServer->Release();
       
   232 	if (iUi)
       
   233 		iUi->Release();
       
   234 	iUiCode.Close();
       
   235 
       
   236 	// discard the buffers in the free list
       
   237 	TBuffer* b=iFree;
       
   238 	while (b)
       
   239 		{
       
   240 		TBuffer* n = b->iNext;
       
   241 		delete b;
       
   242 		b = n;
       
   243 		}
       
   244 
       
   245 	// discard any buffers in the holding queue
       
   246 	b=iHead;
       
   247 	while (b)
       
   248 		{
       
   249 		TBuffer* n = b->iNext;
       
   250 		delete b;
       
   251 		b = n;
       
   252 		}
       
   253 	}
       
   254 
       
   255 void CProfiler::ConstructL(TInt aCmd, TDesC* aDrive)
       
   256 //
       
   257 // Build the profiler engine
       
   258 //
       
   259 	{
       
   260 	// Set drive letter of where to store profiler data
       
   261 	iDrive = aDrive;
       
   262 	
       
   263 	// Run the engine at maximum priority to try and ensure that the sampler device
       
   264 	// does not get choked and start dropping samples
       
   265 	RThread me;
       
   266 	me.SetPriority(EPriorityRealTime);
       
   267 	User::LeaveIfError(User::RenameThread(KProfilerName));
       
   268 
       
   269 	CActiveScheduler::Install(new(ELeave) CActiveScheduler);
       
   270 	iReader = new(ELeave) CReader(EReaderPriority,*this);
       
   271 	iReader->ConstructL();
       
   272 	iWriter = new(ELeave) CWriter(EWriterPriority,*this);
       
   273 	iWriter->ConstructL();
       
   274 	iServer = CPServer::NewL(EControlPriority,*this);
       
   275 	if (!(aCmd & KCommandNoUi))
       
   276 		iUi = CreateUiL();
       
   277 
       
   278 	// Start off with two buffers in the free list for sample data
       
   279 	TBuffer* buf = new(ELeave) TBuffer;
       
   280 	buf->iNext = 0;
       
   281 	iFree = buf;
       
   282 	buf = new(ELeave) TBuffer;
       
   283 	buf->iNext = iFree;
       
   284 	iFree = buf;
       
   285 	
       
   286 	// idenify the running mode
       
   287 	iXIPOnly = aCmd & KCommandXIPOnly;
       
   288 
       
   289 	// start profiling if requested
       
   290 	if ((aCmd & KCommandMask) == Profiler::EStart)
       
   291 		User::LeaveIfError(Control(Profiler::EStart));
       
   292 			
       
   293 	}
       
   294 
       
   295 MProfilerController* CProfiler::CreateUiL()
       
   296 //
       
   297 // deal with the UI acquisition part of construction
       
   298 // If ProfilerKeys.Dll is available, use it; otherwise create a text console
       
   299 //
       
   300 	{
       
   301 	_LIT(KWindowServerName,"*WindowServer");
       
   302 	TFindServer find(KWindowServerName);
       
   303 	TFullName n;
       
   304 	if (find.Next(n) == KErrNotFound)
       
   305 		{
       
   306 		// No UI on this device [yet]. Run without one.
       
   307 		return 0;
       
   308 		}
       
   309 
       
   310 	if (iUiCode.Load(KProfilerKeysDll,TUidType(KNullUid, KUidProfilerKeys)) == KErrNone)
       
   311 		{
       
   312 		TProfilerControllerFactoryL factoryL = TProfilerControllerFactoryL(iUiCode.Lookup(1));
       
   313 		MProfilerController* ui = NULL;
       
   314 		TRAPD(error, ui = factoryL(EControlPriority, *this));
       
   315 		if (error == KErrNone)
       
   316 			return ui;
       
   317 
       
   318 		// Couldn't create alternative UI, so use the console
       
   319 		iUiCode.Close();
       
   320 		}
       
   321 	return CConsole::NewL(EControlPriority, *this);
       
   322 	}
       
   323 
       
   324 TInt CProfiler::Control(Profiler::TState aCommand)
       
   325 //
       
   326 // Handle a command from one of the controllers.
       
   327 // This method specifies the flow of the engine state (iState attr).
       
   328 // The most of transtions is not performed immediately but after all 
       
   329 // current data are recorded into the file - see WriteComplete method.
       
   330 //
       
   331 	{
       
   332 	
       
   333 	DEBUG_PROFILER(RDebug::Printf("*CTRL %d",iState);)
       
   334 	
       
   335 	TInt r = KErrNone;
       
   336 	Profiler::TState oldCommand = iLastCommand;
       
   337 	
       
   338 	//Record the command. In most cases, it is WriteComplete method
       
   339 	//to perform state transition (based on this value)
       
   340 	iLastCommand = aCommand;
       
   341 	
       
   342 	switch (aCommand)
       
   343 		{
       
   344 	case Profiler::EStart:
       
   345 		switch (iState)
       
   346 			{
       
   347 		case EClosed:
       
   348 			{
       
   349 			// Set the path of the output file to include the drive letter
       
   350 			// specified at the command line or the default
       
   351 			TBuf<KFileNameLen> path;
       
   352 			path.Copy(KFileName);
       
   353 			path[0] = (*iDrive)[0];
       
   354 		 	r = iWriter->Open(path);
       
   355 			}
       
   356 			if (KErrNone != r)	 	// Re-open the file
       
   357 				return r;
       
   358 			iReader->iSampler.Reset(iXIPOnly);				// Reset the sampler
       
   359 			if(iXIPOnly)
       
   360 				{
       
   361 				iState = ERunning;
       
   362 				iReader->iSampler.Start(KSampleRate);		// Start sampler
       
   363 				if (!iReader->IsActive())
       
   364 					Read();									// Start reading
       
   365 				}
       
   366 			else	
       
   367 				{
       
   368 				iState = EGettingSegments;
       
   369 				iReader->iSampler.ResetSegments();			// Reset segments
       
   370 				GetSegments();								// Start getting segments
       
   371 				}
       
   372 			break;
       
   373 		case EStopped:
       
   374 			iState = ERunning;
       
   375 			iReader->iSampler.Start(KSampleRate);			// Start sampler
       
   376 			if (!iReader->IsActive())
       
   377 				Read();										//Start reading
       
   378 			break;
       
   379 		case ERunning:			//Already started. No action required.
       
   380 		case EGettingSegments:	//Already started. No action required.
       
   381 		case EDraining:			//Will restart after draining is completed.
       
   382 		case EGettingErrors:    //Will restart after getting errors is completed;
       
   383 			break;
       
   384 			}
       
   385 		break; //end of case Profiler::EStart
       
   386 		
       
   387 	case Profiler::EStop:
       
   388 		switch (iState)
       
   389 			{
       
   390 		case EClosed:
       
   391 		case EGettingErrors:
       
   392 			iLastCommand = oldCommand; 		
       
   393 			return KErrGeneral; 			//The command makes no sense in this state
       
   394 		case ERunning:
       
   395 			iReader->iSampler.Stop();		//Stop sampling.
       
   396 			break;
       
   397 		case EGettingSegments:	//Will do GettingSegments->Running->Stopped transitions
       
   398 		case EDraining:			//Stopping already in progress
       
   399 		case EStopped:			//Already stopped.
       
   400 			break;
       
   401 			}
       
   402 		break; //end of case Profiler::EStop
       
   403 		
       
   404 	case Profiler::EClose:
       
   405 		switch (iState)
       
   406 			{
       
   407 		case EStopped:
       
   408 			iState = EGettingErrors;
       
   409 			GetErrors();
       
   410 			break;
       
   411 		case ERunning:
       
   412 			iReader->iSampler.Stop();
       
   413 			break;
       
   414 		case EClosed:   		//Already closed.
       
   415 		case EGettingErrors:	//Closing in progress
       
   416 		case EGettingSegments:
       
   417 		case EDraining:
       
   418 			break;
       
   419 			}
       
   420 		break; //end of case Profiler::EStop
       
   421 
       
   422 	case Profiler::EUnload:
       
   423 		switch (iState)
       
   424 			{
       
   425 		case EClosed:
       
   426 			CActiveScheduler::Stop();	// Terminate application.
       
   427 			break;
       
   428 		case EStopped:
       
   429 			iState = EGettingErrors;
       
   430 			GetErrors();
       
   431 			break;
       
   432 		case ERunning:
       
   433 			iReader->iSampler.Stop();
       
   434 			break;
       
   435 		case EDraining:
       
   436 		case EGettingErrors:
       
   437 		case EGettingSegments:
       
   438 			break;
       
   439 			}
       
   440 		break;//end of case Profiler::Unload
       
   441 		}
       
   442 
       
   443 	DEBUG_PROFILER(RDebug::Printf("*CTRL end %d",iState);)
       
   444 	return KErrNone;
       
   445 	}
       
   446 
       
   447 Profiler::TState CProfiler::State() const
       
   448 //
       
   449 // Report the current state of the engine
       
   450 //
       
   451 	{
       
   452 	switch (iState)
       
   453 		{
       
   454 	case EGettingErrors:
       
   455 	case EStopped:
       
   456 		return Profiler::EStop;
       
   457 	case EClosed:
       
   458 		return Profiler::EClose;
       
   459 	default:
       
   460 		return Profiler::EStart;
       
   461 		}
       
   462 	}
       
   463 
       
   464 void CProfiler::Read()
       
   465 //
       
   466 // Pass a free buffer to the reader, allocating one if necessary
       
   467 //
       
   468 	{
       
   469 	TBuffer* buf = iFree;
       
   470 	if (buf)
       
   471 		iFree = buf->iNext;
       
   472 	else
       
   473 		{
       
   474 		buf = new TBuffer;
       
   475 		if(!buf)
       
   476 			{
       
   477 			RDebug::Print(_L("PROFILER: No more memory ... stopping"));
       
   478 			CProfiler::Control(Profiler::EStop);
       
   479 			return;
       
   480 			}
       
   481 		}
       
   482 	iReader->Queue(buf);
       
   483 	}
       
   484 
       
   485 TBool CProfiler::GetSegments()
       
   486 //
       
   487 // Gets the list of the current non-XIP segments from device.
       
   488 // Returns true if zero-length desc is returned, otherwise ...
       
   489 // ...passes the buffer to write engine and returns false.
       
   490 	{
       
   491 	TBuffer* buf = iFree;
       
   492 	if (buf)
       
   493 		iFree = buf->iNext;
       
   494 	else
       
   495 		{
       
   496 		RDebug::Printf("PROFILER: No available buffer for GetSegments");
       
   497 		User::Invariant();
       
   498 		}
       
   499 		
       
   500 	iReader->iSampler.GetSegments(buf->iBuf);
       
   501 	if (!buf->iBuf.Length())
       
   502 		{
       
   503 		buf->iNext = iFree;//Return empty buffer to the free list
       
   504 		iFree = buf;
       
   505 		return ETrue;
       
   506 		}
       
   507 		
       
   508 	iWriter->Queue(buf);//Pass the buffer to the write engine.
       
   509 	return EFalse;
       
   510 	}
       
   511 
       
   512 TBool CProfiler::Drain()
       
   513 //
       
   514 // Drains all remaining records from the device
       
   515 // Returns true if zero-length desc is returned, otherwise ...
       
   516 // ...passes the buffer to the write engine and returns false.
       
   517 	{
       
   518 	TBuffer* buf = iFree;
       
   519 	if (buf)
       
   520 		iFree = buf->iNext;
       
   521 	else
       
   522 		{
       
   523 		RDebug::Printf("PROFILER: No available buffer for Drain");
       
   524 		User::Invariant();
       
   525 		}
       
   526 		
       
   527 	iReader->iSampler.Drain(buf->iBuf);
       
   528 
       
   529 	if (!buf->iBuf.Length())
       
   530 		{
       
   531 		buf->iNext = iFree;//Return empty buffer to the free list
       
   532 		iFree = buf;
       
   533 		return ETrue;
       
   534 		}
       
   535 	iWriter->Queue(buf); //Pass the buffer to the write engine.
       
   536 	return EFalse;
       
   537 	}
       
   538 
       
   539 
       
   540 void CProfiler::GetErrors()
       
   541 //
       
   542 // Gets error report from the device and pass the buffer to the write engine
       
   543 //
       
   544 	{
       
   545 	TBuffer* buf = iFree;
       
   546 	if (buf)
       
   547 		iFree = buf->iNext;
       
   548 	else
       
   549 		{
       
   550 		RDebug::Printf("PROFILER: No available buffer for GetErrors");
       
   551 		User::Invariant();
       
   552 		}
       
   553 	iReader->iSampler.GetErrors(buf->iBuf);
       
   554 	iWriter->Queue(buf);
       
   555 	}
       
   556 
       
   557 void CProfiler::Write()
       
   558 //
       
   559 // Pass a queued buffer to the writer
       
   560 //
       
   561 	{
       
   562 	TBuffer* buf = iHead;
       
   563 	iHead = buf->iNext;
       
   564 	if (iHead == 0)
       
   565 		iTail = 0;
       
   566 	iWriter->Queue(buf);
       
   567 	}
       
   568 
       
   569 void CProfiler::ReadComplete(TBuffer* aBuf)
       
   570 //
       
   571 // Handle a completed read buffer
       
   572 //
       
   573 	{
       
   574 	DEBUG_PROFILER(RDebug::Printf("*RC %d",iState);)
       
   575 
       
   576 	//Add the buffer to the queue
       
   577 	aBuf->iNext = 0;
       
   578 	if (iTail)
       
   579 		iTail->iNext = aBuf;
       
   580 	else
       
   581 		iHead = aBuf;
       
   582 	iTail = aBuf;
       
   583 
       
   584 	if (!iWriter->IsActive())
       
   585 		Write();
       
   586 	
       
   587 	if (iLastCommand == Profiler::EStart)
       
   588 		Read();	//Request another read
       
   589 
       
   590 	DEBUG_PROFILER(RDebug::Printf("*RC end %d",iState);)
       
   591 	}
       
   592 
       
   593 void CProfiler::WriteComplete(TBuffer* aBuf)
       
   594 //
       
   595 // Handle a flushed write buffer.
       
   596 //
       
   597 	{
       
   598 	DEBUG_PROFILER(RDebug::Printf("*WC %d",iState);)
       
   599 	
       
   600 	aBuf->iNext = iFree;//Return empty buffer to the free list
       
   601 	iFree = aBuf;
       
   602 
       
   603 	switch (iState)
       
   604 		{
       
   605 	case EGettingSegments:
       
   606 		if (!GetSegments())
       
   607 			break;//More code segments to be completed
       
   608 
       
   609 		//Always go to the running state after the segments are collected....
       
   610 		iState = ERunning;
       
   611 		iReader->iSampler.Start(KSampleRate);
       
   612 		Read();
       
   613 		
       
   614 		//...but stop sampler immediately if we got another user command 
       
   615 		if (iLastCommand != Profiler::EStart)
       
   616 			{
       
   617 			iReader->iSampler.Stop();
       
   618 			}
       
   619 		break; //the end of EGettingSegments case
       
   620 
       
   621 	case ERunning:
       
   622 		if (iHead)
       
   623 			{
       
   624 			Write(); // There are more buffers to go to the file.
       
   625 			break;
       
   626 			}
       
   627 		if (iLastCommand != Profiler::EStart)
       
   628 			{//The user has stopped the profiler.
       
   629 			iState = EDraining;
       
   630 			if (!Drain())
       
   631 				break;//More data to drain.
       
   632 				
       
   633 			//Drain returned empty. May progress further with the engine state
       
   634 			if (iLastCommand == Profiler::EStop)
       
   635 				iState = EStopped;
       
   636 			else
       
   637 				{
       
   638 				iState = EGettingErrors;
       
   639 				GetErrors();
       
   640 				}
       
   641 			}
       
   642 		break;//the end of ERunning case
       
   643 		
       
   644 	case EDraining:
       
   645 		if (!Drain())
       
   646 			break; //still draining;
       
   647 		
       
   648 		//Drain is completed
       
   649 		switch (iLastCommand)
       
   650 			{
       
   651 		case Profiler::EStart:
       
   652 			//While draining, we received another Start command	
       
   653 			iState = ERunning;
       
   654 			iReader->iSampler.Start(KSampleRate);
       
   655 			Read();
       
   656 			break;
       
   657 		case Profiler::EStop:
       
   658 			iState = EStopped;
       
   659 			break;
       
   660 		default:			
       
   661 			iState = EGettingErrors;
       
   662 			GetErrors();
       
   663 			}
       
   664 		break; //the end of EDraining case
       
   665 		
       
   666 	case EGettingErrors:
       
   667 		iWriter->Close();
       
   668 		iState = EClosed;
       
   669 		switch (iLastCommand)
       
   670 			{
       
   671 		case Profiler::EUnload:
       
   672 			CActiveScheduler::Stop(); //Terminate application.
       
   673 			break;
       
   674 		case Profiler::EStart:
       
   675 			Control(Profiler::EStart);
       
   676 			break;			
       
   677 		default:
       
   678 			break;			
       
   679 			}
       
   680 		break; //the end of EGettingErrors case
       
   681 		
       
   682 	default:
       
   683 		RDebug::Printf("PROFILER: WriteComplete in %d state", iState);
       
   684 		User::Invariant();
       
   685 		break;
       
   686 		
       
   687 		}
       
   688 
       
   689 	DEBUG_PROFILER(RDebug::Printf("*WC end %d",iState);)
       
   690 	}
       
   691 
       
   692 
       
   693 
       
   694 CReader::CReader(TInt aPriority, CProfiler& aProfiler)
       
   695 	:CActive(aPriority), iProfiler(aProfiler)
       
   696 	{
       
   697 	CActiveScheduler::Add(this);
       
   698 	}
       
   699 
       
   700 CReader::~CReader()
       
   701 	{
       
   702 	Cancel();
       
   703 	delete iBuf;
       
   704 	iSampler.Close();
       
   705 	User::FreeLogicalDevice(KSamplerName);
       
   706 	}
       
   707 
       
   708 void CReader::ConstructL()
       
   709 	{
       
   710 	TInt r=User::LoadLogicalDevice(KSamplerName);
       
   711 	if (r!=KErrNone && r!=KErrAlreadyExists)
       
   712 		User::Leave(r);
       
   713 	User::LeaveIfError(iSampler.Open());
       
   714 	}
       
   715 
       
   716 void CReader::RunL()
       
   717 //
       
   718 // Pass the full buffer to the engine
       
   719 //
       
   720 	{
       
   721 	TBuffer* data=iBuf;
       
   722 	iBuf = 0;
       
   723 	iProfiler.ReadComplete(data);
       
   724 	}
       
   725 
       
   726 void CReader::DoCancel()
       
   727 	{
       
   728 	iSampler.ReadCancel();
       
   729 	}
       
   730 
       
   731 void CReader::Queue(TBuffer* aBuf)
       
   732 //
       
   733 // Queue a request to read data into the empty buffer
       
   734 //
       
   735 	{
       
   736 	iBuf = aBuf;
       
   737 	iSampler.Read(aBuf->iBuf, iStatus);
       
   738 	SetActive();
       
   739 	}
       
   740 
       
   741 CWriter::CWriter(TInt aPriority, CProfiler& aProfiler)
       
   742 	:CActive(aPriority), iProfiler(aProfiler)
       
   743 	{
       
   744 	CActiveScheduler::Add(this);
       
   745 	}
       
   746 
       
   747 CWriter::~CWriter()
       
   748 	{
       
   749 	Cancel();
       
   750 	delete iBuf;
       
   751 	iFile.Close();
       
   752 	iFs.Close();
       
   753 	}
       
   754 
       
   755 void CWriter::ConstructL()
       
   756 	{
       
   757 	User::LeaveIfError(iFs.Connect());
       
   758 	}
       
   759 
       
   760 TInt CWriter::Open(const TDesC& aFile)
       
   761 //
       
   762 // Open the file for saving the sample data
       
   763 //
       
   764 	{
       
   765 	return iFile.Replace(iFs,aFile,EFileWrite);
       
   766 	}
       
   767 
       
   768 void CWriter::Close()
       
   769 //
       
   770 // Release the file
       
   771 //
       
   772 	{
       
   773 	iFile.Close();
       
   774 	}
       
   775 
       
   776 void CWriter::Queue(TBuffer* aBuf)
       
   777 //
       
   778 // Queue a request to write the full buffer into the file
       
   779 //
       
   780 	{
       
   781 	iBuf = aBuf;
       
   782 	iFile.Write(aBuf->iBuf, iStatus);
       
   783 	SetActive();
       
   784 	}
       
   785 
       
   786 void CWriter::RunL()
       
   787 //
       
   788 // Return the empty buffer back to the engine
       
   789 //
       
   790 	{
       
   791 	TBuffer* data=iBuf;
       
   792 	iBuf = 0;
       
   793 	iProfiler.WriteComplete(data);
       
   794 	}
       
   795 
       
   796 void CWriter::DoCancel()
       
   797 //
       
   798 // RFile does not provide a WriteCancel() function
       
   799 //
       
   800 	{}
       
   801 
       
   802 
       
   803 // Server controller
       
   804 
       
   805 inline const CPServer& CPSession::Server() const
       
   806 	{return *static_cast<const CPServer*>(CSession2::Server());}
       
   807 
       
   808 void CPSession::ServiceL(const RMessage2& aMessage)
       
   809 //
       
   810 // Handle a IPC request to control the profiler
       
   811 //
       
   812 	{
       
   813 	aMessage.Complete(Server().Control(Profiler::TState(aMessage.Function())));
       
   814 	}
       
   815 
       
   816 MProfilerController* CPServer::NewL(TInt aPriority, MProfilerEngine& aEngine)
       
   817 //
       
   818 // Create and start the server to provide the Profiler interface
       
   819 //
       
   820 	{
       
   821 	CPServer* self = new(ELeave) CPServer(aPriority, aEngine);
       
   822 	CleanupStack::PushL(self);
       
   823 	self->StartL(KProfilerName);
       
   824 	CleanupStack::Pop();
       
   825 	return self;
       
   826 	}
       
   827 
       
   828 CPServer::CPServer(TInt aPriority, MProfilerEngine& aEngine)
       
   829 	:CServer2(aPriority), MProfilerController(aEngine)
       
   830 	{}
       
   831 
       
   832 void CPServer::Release()
       
   833 	{
       
   834 	delete this;
       
   835 	}
       
   836 
       
   837 CSession2* CPServer::NewSessionL(const TVersion&,const RMessage2&) const
       
   838 	{
       
   839 	return new(ELeave) CPSession();
       
   840 	}
       
   841 
       
   842 
       
   843 // Console Controller
       
   844 
       
   845 MProfilerController* CConsole::NewL(TInt aPriority, MProfilerEngine& aEngine)
       
   846 //
       
   847 // Create and start the console UI for the profiler
       
   848 //
       
   849 	{
       
   850 	CConsole* self = new(ELeave) CConsole(aPriority, aEngine);
       
   851 	CleanupStack::PushL(self);
       
   852 	self->ConstructL();
       
   853 	CleanupStack::Pop();
       
   854 	return self;
       
   855 	}
       
   856 
       
   857 CConsole::CConsole(TInt aPriority, MProfilerEngine& aEngine)
       
   858 	:CActive(aPriority), MProfilerController(aEngine)
       
   859 	{
       
   860 	CActiveScheduler::Add(this);
       
   861 	}
       
   862 
       
   863 void CConsole::ConstructL()
       
   864 	{
       
   865 	iConsole = Console::NewL(KProfilerName, TSize(KConsFullScreen,KConsFullScreen));
       
   866 	Help();
       
   867 	Queue();
       
   868 	}
       
   869 
       
   870 CConsole::~CConsole()
       
   871 	{
       
   872 	Cancel();
       
   873 	delete iConsole;
       
   874 	}
       
   875 
       
   876 void CConsole::Release()
       
   877 	{
       
   878 	delete this;
       
   879 	}
       
   880 
       
   881 void CConsole::Help()
       
   882 //
       
   883 // Display the instructions on the console
       
   884 //
       
   885 	{
       
   886 	_LIT(KInstructions,"[S]tart, Sto[p], [C]lose or E[x]it\r\n");
       
   887 	iConsole->Write(KInstructions);
       
   888 	}
       
   889 
       
   890 void CConsole::Queue()
       
   891 //
       
   892 // Request a key press from the console
       
   893 //
       
   894 	{
       
   895 	iConsole->Read(iStatus);
       
   896 	SetActive();
       
   897 	}
       
   898 
       
   899 void CConsole::RunL()
       
   900 //
       
   901 // Handle a key press from the console
       
   902 //
       
   903 	{
       
   904 	TInt key = iConsole->KeyCode();
       
   905 	Queue();
       
   906 	Profiler::TState command;
       
   907 	switch (key)
       
   908 		{
       
   909 	case 's': case 'S':
       
   910 		command = Profiler::EStart;
       
   911 		break;
       
   912 	case 'p': case 'P':
       
   913 		command = Profiler::EStop;
       
   914 		break;
       
   915 	case 'c': case 'C':
       
   916 		command = Profiler::EClose;
       
   917 		break;
       
   918 	case 'x': case 'X':
       
   919 		command = Profiler::EUnload;
       
   920 		break;
       
   921 	case '?': case 'h': case 'H':
       
   922 		Help();
       
   923 		return;
       
   924 	default:
       
   925 		return;
       
   926 		}
       
   927 	Control(command);
       
   928 	}
       
   929 
       
   930 void CConsole::DoCancel()
       
   931 	{
       
   932 	iConsole->ReadCancel();
       
   933 	}
       
   934 
       
   935 
       
   936 void MainL(TInt aCmd, TDesC* aDrive)
       
   937 //
       
   938 // Construct and run the profile engine
       
   939 //
       
   940 	{
       
   941 	CProfiler* p = CProfiler::NewLC(aCmd, aDrive);
       
   942 	CActiveScheduler::Start();
       
   943 	CleanupStack::PopAndDestroy(p);
       
   944 	}
       
   945 
       
   946 TInt GetCommand(TDes &aDrive)
       
   947 //
       
   948 // Decode the command line arguments into a profiler control request
       
   949 //		aDrive is the drive number to store the profiler data on
       
   950 //
       
   951 	{
       
   952 	_LIT(KStart,"start");
       
   953 	_LIT(KStop,"stop");
       
   954 	_LIT(KClose,"close");
       
   955 	_LIT(KUnload,"unload");
       
   956 	_LIT(KExit,"exit");
       
   957 	_LIT(KNoUi,"-noui");
       
   958 	_LIT(KXIPOnly,"-xiponly");
       
   959 	_LIT(KDrive,"-drive=");
       
   960 	const TInt KDriveOffset=7;
       
   961 	TBuf<64> c;
       
   962 	User::CommandLine(c);
       
   963 	TInt cmd = 0;
       
   964 	if (c.FindF(KNoUi) >= 0)
       
   965 		cmd |= KCommandNoUi;
       
   966 	if (c.FindF(KXIPOnly) >= 0)
       
   967 		cmd |= KCommandXIPOnly;
       
   968 			
       
   969 	// get the drive letter if any
       
   970 	TInt pos = c.FindF(KDrive);
       
   971 	if(pos >= 0)
       
   972 		{
       
   973 		pos += KDriveOffset;
       
   974 		TBuf<1> driveLet;
       
   975 		driveLet.SetLength(1);
       
   976 		driveLet[0] = c[pos];
       
   977 		driveLet.UpperCase();
       
   978 		if (driveLet[0] >= 'A' && driveLet[0] <= 'Z')
       
   979 			{
       
   980 			aDrive[0] = driveLet[0];
       
   981 			}
       
   982 		}
       
   983 	if (c.FindF(KStart) >= 0)
       
   984 		return cmd | Profiler::EStart;
       
   985 	if (c.FindF(KStop) >= 0)
       
   986 		return cmd | Profiler::EStop;
       
   987 	if (c.FindF(KClose) >= 0)
       
   988 		return cmd | Profiler::EClose;
       
   989 	if (c.FindF(KUnload) >= 0)
       
   990 		return cmd | Profiler::EUnload;
       
   991 	if (c.FindF(KExit) >= 0)
       
   992 		return cmd | Profiler::EUnload;
       
   993 	return cmd | KCommandNone;
       
   994 	}
       
   995 
       
   996 TInt E32Main()
       
   997 //
       
   998 // Profiler.exe entry point
       
   999 // Decode any command-line argument - which can be used to control a running profile engine
       
  1000 // Otherwise start the engine in this process
       
  1001 //
       
  1002 	{
       
  1003 	TBuf<1> drive;
       
  1004 	drive.SetLength(1);
       
  1005 	drive[0] = 'C';
       
  1006 	TInt command = GetCommand(drive);
       
  1007 	if ((command & KCommandMask) != KCommandNone)
       
  1008 		{
       
  1009 		TInt r = Profiler::Control(Profiler::TState(command & KCommandMask));
       
  1010 		if (r != KErrNotFound || (command & KCommandMask) != Profiler::EStart)
       
  1011 			return r;
       
  1012 		}
       
  1013 	CTrapCleanup::New();
       
  1014 	TRAPD(r,MainL(command, &drive));
       
  1015 	if (r != KErrNone)
       
  1016 		RDebug::Print(_L("PROFILER: Error starting profiler"));
       
  1017 	return r;
       
  1018 	}