os/kernelhwsrv/kerneltest/e32utils/profiler/profiler.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 	}