--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32utils/profiler/profiler.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1018 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32utils\profiler\profiler.cpp
+//
+//
+
+#include <e32cons.h>
+#include <f32file.h>
+#include "profiler.h"
+#include "sampler.h"
+
+// The name of the output file use to save the sample data
+_LIT(KFileName,"?:\\PROFILER.DAT");
+const TInt KFileNameLen=15;
+
+// The name of the DLL used as an alternative UI controller
+_LIT(KProfilerKeysDll,"ProfilerKeys");
+
+// The size of the buffers used for reading sample data and writing to file
+const TInt KBufferSize = 0x800;
+
+// The sample rate used by the profiler
+const TInt KSampleRate = 1000;
+
+const TInt KCommandMask = 0x00ff;
+const TInt KCommandNone = 0x0010;
+const TInt KCommandNoUi = 0x0100;
+const TInt KCommandXIPOnly = 0x0200;
+
+// The controller class used to provide the Profiler functions.
+// This runs as a server in the engine thread
+class CPServer : public CServer2, public MProfilerController
+ {
+public:
+ static MProfilerController* NewL(TInt aPriority, MProfilerEngine& aEngine);
+private:
+ CPServer(TInt aPriority, MProfilerEngine& aEngine);
+ void Release();
+ CSession2* NewSessionL(const TVersion& aVersion,const RMessage2& aMessage) const;
+ };
+
+// The session class used by the server controller
+class CPSession : public CSession2
+ {
+private:
+ inline const CPServer& Server() const;
+ void ServiceL(const RMessage2& aMessage);
+ };
+
+
+// The default UI controller class which uses a Console
+class CConsole : public CActive, private MProfilerController
+ {
+public:
+ static MProfilerController* NewL(TInt aPriority, MProfilerEngine& aEngine);
+private:
+ CConsole(TInt aPriority, MProfilerEngine& aEngine);
+ void ConstructL();
+ ~CConsole();
+ void Release();
+//
+ void Help();
+ void Queue();
+//
+ void RunL();
+ void DoCancel();
+private:
+ CConsoleBase* iConsole;
+ };
+
+
+// The buffers used for transferring data from the device driver to the file
+struct TBuffer
+ {
+ TBuffer* iNext;
+ TBuf8<KBufferSize> iBuf;
+ };
+
+class CProfiler;
+
+// The active object responsible for reading data from the device
+class CReader : public CActive
+ {
+public:
+ CReader(TInt aPriority, CProfiler& aProfiler);
+ ~CReader();
+//
+ void ConstructL();
+ void Queue(TBuffer* aBuf);
+private:
+ void RunL();
+ void DoCancel();
+private:
+ CProfiler& iProfiler;
+ TBuffer* iBuf;
+public:
+ RSampler iSampler;
+ };
+
+// The active object responsible for writing data out (to file)
+class CWriter : public CActive
+ {
+public:
+ CWriter(TInt aPriority, CProfiler& aProfiler);
+ ~CWriter();
+ void ConstructL();
+ TInt Open(const TDesC& aFile);
+ void Close();
+ void Queue(TBuffer* aBuf);
+private:
+ void RunL();
+ void DoCancel();
+private:
+ CProfiler& iProfiler;
+ TBuffer* iBuf;
+ RFile iFile;
+ RFs iFs;
+ };
+
+
+// The profiler engine itself.
+class CProfiler : public CBase, private MProfilerEngine
+ {
+ enum {EControlPriority = 10, EReaderPriority = 0, EWriterPriority = -10};
+
+ /** Specifies the state of the engine*/
+ enum TState
+ {
+ /**
+ Initial state. The file is closed. Driver is inactive
+ */
+ EClosed,
+ /**
+ Engine enters this state on client's Start request (if -xiponly is not specified).
+ Opens the file.
+ Resets the driver and nonXIP code segments.
+ Sends GetSegments calls to the driver until driver returns zero length reply.
+ Leaves this state (goes into ERunning) when the last data (obtained by GetSegment) is
+ written into the file.
+ */
+ EGettingSegments,
+ /**
+ Sends async. read request to the driver. Once completed, it immediately sends another while
+ writing the collected records into the file.
+ */
+ ERunning,
+ /**
+ Get into this state from ERunning on the client's Stop, Close or Exit request.
+ Sends Drain calls to the driver until driver returns zero length reply.
+ Leaves this state when all records are written into the file.
+ */
+ EDraining,
+ /**
+ No active calls to the driver. On the client's Start request, will go back into ERunning mode.
+ */
+ EStopped,
+ /**
+ Get into this state on client's Close or Exit request.
+ Sends a single GetErrorReport request to the driver. After data has been recorded into the file,
+ it closes the file and goes into EClosed state or terminates application..
+ */
+ EGettingErrors
+ };
+public:
+ static CProfiler* NewLC(TInt aCmd, TDesC* aDrive);
+//
+ TInt Control(Profiler::TState aCommand);
+//
+ void ReadComplete(TBuffer* aBuf);
+ void WriteComplete(TBuffer* aBuf);
+private:
+ CProfiler();
+ ~CProfiler();
+ void ConstructL(TInt aCmd, TDesC* aDrive);
+ MProfilerController* CreateUiL();
+//
+ void Read();
+ void Write();
+ TBool GetSegments();
+ TBool Drain();
+ void GetErrors();
+//
+ Profiler::TState State() const;
+private:
+ CReader* iReader;
+ CWriter* iWriter;
+ MProfilerController* iServer;
+ RLibrary iUiCode;
+ MProfilerController* iUi;
+ TState iState;
+ TBool iXIPOnly;
+ Profiler::TState iLastCommand;
+//
+ // The FIFO queue of data that has to be written
+ TBuffer* iHead;
+ TBuffer* iTail;
+//
+ // The LIFO list of free buffers
+ TBuffer* iFree;
+ TDesC* iDrive;
+ };
+
+
+CProfiler* CProfiler::NewLC(TInt aCmd, TDesC* aDrive)
+ {
+ CProfiler* self = new(ELeave) CProfiler;
+ CleanupStack::PushL(self);
+ self->ConstructL(aCmd, aDrive);
+ return self;
+ }
+
+CProfiler::CProfiler()
+ {}
+
+CProfiler::~CProfiler()
+ {
+ delete iReader;
+ delete iWriter;
+ if (iServer)
+ iServer->Release();
+ if (iUi)
+ iUi->Release();
+ iUiCode.Close();
+
+ // discard the buffers in the free list
+ TBuffer* b=iFree;
+ while (b)
+ {
+ TBuffer* n = b->iNext;
+ delete b;
+ b = n;
+ }
+
+ // discard any buffers in the holding queue
+ b=iHead;
+ while (b)
+ {
+ TBuffer* n = b->iNext;
+ delete b;
+ b = n;
+ }
+ }
+
+void CProfiler::ConstructL(TInt aCmd, TDesC* aDrive)
+//
+// Build the profiler engine
+//
+ {
+ // Set drive letter of where to store profiler data
+ iDrive = aDrive;
+
+ // Run the engine at maximum priority to try and ensure that the sampler device
+ // does not get choked and start dropping samples
+ RThread me;
+ me.SetPriority(EPriorityRealTime);
+ User::LeaveIfError(User::RenameThread(KProfilerName));
+
+ CActiveScheduler::Install(new(ELeave) CActiveScheduler);
+ iReader = new(ELeave) CReader(EReaderPriority,*this);
+ iReader->ConstructL();
+ iWriter = new(ELeave) CWriter(EWriterPriority,*this);
+ iWriter->ConstructL();
+ iServer = CPServer::NewL(EControlPriority,*this);
+ if (!(aCmd & KCommandNoUi))
+ iUi = CreateUiL();
+
+ // Start off with two buffers in the free list for sample data
+ TBuffer* buf = new(ELeave) TBuffer;
+ buf->iNext = 0;
+ iFree = buf;
+ buf = new(ELeave) TBuffer;
+ buf->iNext = iFree;
+ iFree = buf;
+
+ // idenify the running mode
+ iXIPOnly = aCmd & KCommandXIPOnly;
+
+ // start profiling if requested
+ if ((aCmd & KCommandMask) == Profiler::EStart)
+ User::LeaveIfError(Control(Profiler::EStart));
+
+ }
+
+MProfilerController* CProfiler::CreateUiL()
+//
+// deal with the UI acquisition part of construction
+// If ProfilerKeys.Dll is available, use it; otherwise create a text console
+//
+ {
+ _LIT(KWindowServerName,"*WindowServer");
+ TFindServer find(KWindowServerName);
+ TFullName n;
+ if (find.Next(n) == KErrNotFound)
+ {
+ // No UI on this device [yet]. Run without one.
+ return 0;
+ }
+
+ if (iUiCode.Load(KProfilerKeysDll,TUidType(KNullUid, KUidProfilerKeys)) == KErrNone)
+ {
+ TProfilerControllerFactoryL factoryL = TProfilerControllerFactoryL(iUiCode.Lookup(1));
+ MProfilerController* ui = NULL;
+ TRAPD(error, ui = factoryL(EControlPriority, *this));
+ if (error == KErrNone)
+ return ui;
+
+ // Couldn't create alternative UI, so use the console
+ iUiCode.Close();
+ }
+ return CConsole::NewL(EControlPriority, *this);
+ }
+
+TInt CProfiler::Control(Profiler::TState aCommand)
+//
+// Handle a command from one of the controllers.
+// This method specifies the flow of the engine state (iState attr).
+// The most of transtions is not performed immediately but after all
+// current data are recorded into the file - see WriteComplete method.
+//
+ {
+
+ DEBUG_PROFILER(RDebug::Printf("*CTRL %d",iState);)
+
+ TInt r = KErrNone;
+ Profiler::TState oldCommand = iLastCommand;
+
+ //Record the command. In most cases, it is WriteComplete method
+ //to perform state transition (based on this value)
+ iLastCommand = aCommand;
+
+ switch (aCommand)
+ {
+ case Profiler::EStart:
+ switch (iState)
+ {
+ case EClosed:
+ {
+ // Set the path of the output file to include the drive letter
+ // specified at the command line or the default
+ TBuf<KFileNameLen> path;
+ path.Copy(KFileName);
+ path[0] = (*iDrive)[0];
+ r = iWriter->Open(path);
+ }
+ if (KErrNone != r) // Re-open the file
+ return r;
+ iReader->iSampler.Reset(iXIPOnly); // Reset the sampler
+ if(iXIPOnly)
+ {
+ iState = ERunning;
+ iReader->iSampler.Start(KSampleRate); // Start sampler
+ if (!iReader->IsActive())
+ Read(); // Start reading
+ }
+ else
+ {
+ iState = EGettingSegments;
+ iReader->iSampler.ResetSegments(); // Reset segments
+ GetSegments(); // Start getting segments
+ }
+ break;
+ case EStopped:
+ iState = ERunning;
+ iReader->iSampler.Start(KSampleRate); // Start sampler
+ if (!iReader->IsActive())
+ Read(); //Start reading
+ break;
+ case ERunning: //Already started. No action required.
+ case EGettingSegments: //Already started. No action required.
+ case EDraining: //Will restart after draining is completed.
+ case EGettingErrors: //Will restart after getting errors is completed;
+ break;
+ }
+ break; //end of case Profiler::EStart
+
+ case Profiler::EStop:
+ switch (iState)
+ {
+ case EClosed:
+ case EGettingErrors:
+ iLastCommand = oldCommand;
+ return KErrGeneral; //The command makes no sense in this state
+ case ERunning:
+ iReader->iSampler.Stop(); //Stop sampling.
+ break;
+ case EGettingSegments: //Will do GettingSegments->Running->Stopped transitions
+ case EDraining: //Stopping already in progress
+ case EStopped: //Already stopped.
+ break;
+ }
+ break; //end of case Profiler::EStop
+
+ case Profiler::EClose:
+ switch (iState)
+ {
+ case EStopped:
+ iState = EGettingErrors;
+ GetErrors();
+ break;
+ case ERunning:
+ iReader->iSampler.Stop();
+ break;
+ case EClosed: //Already closed.
+ case EGettingErrors: //Closing in progress
+ case EGettingSegments:
+ case EDraining:
+ break;
+ }
+ break; //end of case Profiler::EStop
+
+ case Profiler::EUnload:
+ switch (iState)
+ {
+ case EClosed:
+ CActiveScheduler::Stop(); // Terminate application.
+ break;
+ case EStopped:
+ iState = EGettingErrors;
+ GetErrors();
+ break;
+ case ERunning:
+ iReader->iSampler.Stop();
+ break;
+ case EDraining:
+ case EGettingErrors:
+ case EGettingSegments:
+ break;
+ }
+ break;//end of case Profiler::Unload
+ }
+
+ DEBUG_PROFILER(RDebug::Printf("*CTRL end %d",iState);)
+ return KErrNone;
+ }
+
+Profiler::TState CProfiler::State() const
+//
+// Report the current state of the engine
+//
+ {
+ switch (iState)
+ {
+ case EGettingErrors:
+ case EStopped:
+ return Profiler::EStop;
+ case EClosed:
+ return Profiler::EClose;
+ default:
+ return Profiler::EStart;
+ }
+ }
+
+void CProfiler::Read()
+//
+// Pass a free buffer to the reader, allocating one if necessary
+//
+ {
+ TBuffer* buf = iFree;
+ if (buf)
+ iFree = buf->iNext;
+ else
+ {
+ buf = new TBuffer;
+ if(!buf)
+ {
+ RDebug::Print(_L("PROFILER: No more memory ... stopping"));
+ CProfiler::Control(Profiler::EStop);
+ return;
+ }
+ }
+ iReader->Queue(buf);
+ }
+
+TBool CProfiler::GetSegments()
+//
+// Gets the list of the current non-XIP segments from device.
+// Returns true if zero-length desc is returned, otherwise ...
+// ...passes the buffer to write engine and returns false.
+ {
+ TBuffer* buf = iFree;
+ if (buf)
+ iFree = buf->iNext;
+ else
+ {
+ RDebug::Printf("PROFILER: No available buffer for GetSegments");
+ User::Invariant();
+ }
+
+ iReader->iSampler.GetSegments(buf->iBuf);
+ if (!buf->iBuf.Length())
+ {
+ buf->iNext = iFree;//Return empty buffer to the free list
+ iFree = buf;
+ return ETrue;
+ }
+
+ iWriter->Queue(buf);//Pass the buffer to the write engine.
+ return EFalse;
+ }
+
+TBool CProfiler::Drain()
+//
+// Drains all remaining records from the device
+// Returns true if zero-length desc is returned, otherwise ...
+// ...passes the buffer to the write engine and returns false.
+ {
+ TBuffer* buf = iFree;
+ if (buf)
+ iFree = buf->iNext;
+ else
+ {
+ RDebug::Printf("PROFILER: No available buffer for Drain");
+ User::Invariant();
+ }
+
+ iReader->iSampler.Drain(buf->iBuf);
+
+ if (!buf->iBuf.Length())
+ {
+ buf->iNext = iFree;//Return empty buffer to the free list
+ iFree = buf;
+ return ETrue;
+ }
+ iWriter->Queue(buf); //Pass the buffer to the write engine.
+ return EFalse;
+ }
+
+
+void CProfiler::GetErrors()
+//
+// Gets error report from the device and pass the buffer to the write engine
+//
+ {
+ TBuffer* buf = iFree;
+ if (buf)
+ iFree = buf->iNext;
+ else
+ {
+ RDebug::Printf("PROFILER: No available buffer for GetErrors");
+ User::Invariant();
+ }
+ iReader->iSampler.GetErrors(buf->iBuf);
+ iWriter->Queue(buf);
+ }
+
+void CProfiler::Write()
+//
+// Pass a queued buffer to the writer
+//
+ {
+ TBuffer* buf = iHead;
+ iHead = buf->iNext;
+ if (iHead == 0)
+ iTail = 0;
+ iWriter->Queue(buf);
+ }
+
+void CProfiler::ReadComplete(TBuffer* aBuf)
+//
+// Handle a completed read buffer
+//
+ {
+ DEBUG_PROFILER(RDebug::Printf("*RC %d",iState);)
+
+ //Add the buffer to the queue
+ aBuf->iNext = 0;
+ if (iTail)
+ iTail->iNext = aBuf;
+ else
+ iHead = aBuf;
+ iTail = aBuf;
+
+ if (!iWriter->IsActive())
+ Write();
+
+ if (iLastCommand == Profiler::EStart)
+ Read(); //Request another read
+
+ DEBUG_PROFILER(RDebug::Printf("*RC end %d",iState);)
+ }
+
+void CProfiler::WriteComplete(TBuffer* aBuf)
+//
+// Handle a flushed write buffer.
+//
+ {
+ DEBUG_PROFILER(RDebug::Printf("*WC %d",iState);)
+
+ aBuf->iNext = iFree;//Return empty buffer to the free list
+ iFree = aBuf;
+
+ switch (iState)
+ {
+ case EGettingSegments:
+ if (!GetSegments())
+ break;//More code segments to be completed
+
+ //Always go to the running state after the segments are collected....
+ iState = ERunning;
+ iReader->iSampler.Start(KSampleRate);
+ Read();
+
+ //...but stop sampler immediately if we got another user command
+ if (iLastCommand != Profiler::EStart)
+ {
+ iReader->iSampler.Stop();
+ }
+ break; //the end of EGettingSegments case
+
+ case ERunning:
+ if (iHead)
+ {
+ Write(); // There are more buffers to go to the file.
+ break;
+ }
+ if (iLastCommand != Profiler::EStart)
+ {//The user has stopped the profiler.
+ iState = EDraining;
+ if (!Drain())
+ break;//More data to drain.
+
+ //Drain returned empty. May progress further with the engine state
+ if (iLastCommand == Profiler::EStop)
+ iState = EStopped;
+ else
+ {
+ iState = EGettingErrors;
+ GetErrors();
+ }
+ }
+ break;//the end of ERunning case
+
+ case EDraining:
+ if (!Drain())
+ break; //still draining;
+
+ //Drain is completed
+ switch (iLastCommand)
+ {
+ case Profiler::EStart:
+ //While draining, we received another Start command
+ iState = ERunning;
+ iReader->iSampler.Start(KSampleRate);
+ Read();
+ break;
+ case Profiler::EStop:
+ iState = EStopped;
+ break;
+ default:
+ iState = EGettingErrors;
+ GetErrors();
+ }
+ break; //the end of EDraining case
+
+ case EGettingErrors:
+ iWriter->Close();
+ iState = EClosed;
+ switch (iLastCommand)
+ {
+ case Profiler::EUnload:
+ CActiveScheduler::Stop(); //Terminate application.
+ break;
+ case Profiler::EStart:
+ Control(Profiler::EStart);
+ break;
+ default:
+ break;
+ }
+ break; //the end of EGettingErrors case
+
+ default:
+ RDebug::Printf("PROFILER: WriteComplete in %d state", iState);
+ User::Invariant();
+ break;
+
+ }
+
+ DEBUG_PROFILER(RDebug::Printf("*WC end %d",iState);)
+ }
+
+
+
+CReader::CReader(TInt aPriority, CProfiler& aProfiler)
+ :CActive(aPriority), iProfiler(aProfiler)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+CReader::~CReader()
+ {
+ Cancel();
+ delete iBuf;
+ iSampler.Close();
+ User::FreeLogicalDevice(KSamplerName);
+ }
+
+void CReader::ConstructL()
+ {
+ TInt r=User::LoadLogicalDevice(KSamplerName);
+ if (r!=KErrNone && r!=KErrAlreadyExists)
+ User::Leave(r);
+ User::LeaveIfError(iSampler.Open());
+ }
+
+void CReader::RunL()
+//
+// Pass the full buffer to the engine
+//
+ {
+ TBuffer* data=iBuf;
+ iBuf = 0;
+ iProfiler.ReadComplete(data);
+ }
+
+void CReader::DoCancel()
+ {
+ iSampler.ReadCancel();
+ }
+
+void CReader::Queue(TBuffer* aBuf)
+//
+// Queue a request to read data into the empty buffer
+//
+ {
+ iBuf = aBuf;
+ iSampler.Read(aBuf->iBuf, iStatus);
+ SetActive();
+ }
+
+CWriter::CWriter(TInt aPriority, CProfiler& aProfiler)
+ :CActive(aPriority), iProfiler(aProfiler)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+CWriter::~CWriter()
+ {
+ Cancel();
+ delete iBuf;
+ iFile.Close();
+ iFs.Close();
+ }
+
+void CWriter::ConstructL()
+ {
+ User::LeaveIfError(iFs.Connect());
+ }
+
+TInt CWriter::Open(const TDesC& aFile)
+//
+// Open the file for saving the sample data
+//
+ {
+ return iFile.Replace(iFs,aFile,EFileWrite);
+ }
+
+void CWriter::Close()
+//
+// Release the file
+//
+ {
+ iFile.Close();
+ }
+
+void CWriter::Queue(TBuffer* aBuf)
+//
+// Queue a request to write the full buffer into the file
+//
+ {
+ iBuf = aBuf;
+ iFile.Write(aBuf->iBuf, iStatus);
+ SetActive();
+ }
+
+void CWriter::RunL()
+//
+// Return the empty buffer back to the engine
+//
+ {
+ TBuffer* data=iBuf;
+ iBuf = 0;
+ iProfiler.WriteComplete(data);
+ }
+
+void CWriter::DoCancel()
+//
+// RFile does not provide a WriteCancel() function
+//
+ {}
+
+
+// Server controller
+
+inline const CPServer& CPSession::Server() const
+ {return *static_cast<const CPServer*>(CSession2::Server());}
+
+void CPSession::ServiceL(const RMessage2& aMessage)
+//
+// Handle a IPC request to control the profiler
+//
+ {
+ aMessage.Complete(Server().Control(Profiler::TState(aMessage.Function())));
+ }
+
+MProfilerController* CPServer::NewL(TInt aPriority, MProfilerEngine& aEngine)
+//
+// Create and start the server to provide the Profiler interface
+//
+ {
+ CPServer* self = new(ELeave) CPServer(aPriority, aEngine);
+ CleanupStack::PushL(self);
+ self->StartL(KProfilerName);
+ CleanupStack::Pop();
+ return self;
+ }
+
+CPServer::CPServer(TInt aPriority, MProfilerEngine& aEngine)
+ :CServer2(aPriority), MProfilerController(aEngine)
+ {}
+
+void CPServer::Release()
+ {
+ delete this;
+ }
+
+CSession2* CPServer::NewSessionL(const TVersion&,const RMessage2&) const
+ {
+ return new(ELeave) CPSession();
+ }
+
+
+// Console Controller
+
+MProfilerController* CConsole::NewL(TInt aPriority, MProfilerEngine& aEngine)
+//
+// Create and start the console UI for the profiler
+//
+ {
+ CConsole* self = new(ELeave) CConsole(aPriority, aEngine);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+CConsole::CConsole(TInt aPriority, MProfilerEngine& aEngine)
+ :CActive(aPriority), MProfilerController(aEngine)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CConsole::ConstructL()
+ {
+ iConsole = Console::NewL(KProfilerName, TSize(KConsFullScreen,KConsFullScreen));
+ Help();
+ Queue();
+ }
+
+CConsole::~CConsole()
+ {
+ Cancel();
+ delete iConsole;
+ }
+
+void CConsole::Release()
+ {
+ delete this;
+ }
+
+void CConsole::Help()
+//
+// Display the instructions on the console
+//
+ {
+ _LIT(KInstructions,"[S]tart, Sto[p], [C]lose or E[x]it\r\n");
+ iConsole->Write(KInstructions);
+ }
+
+void CConsole::Queue()
+//
+// Request a key press from the console
+//
+ {
+ iConsole->Read(iStatus);
+ SetActive();
+ }
+
+void CConsole::RunL()
+//
+// Handle a key press from the console
+//
+ {
+ TInt key = iConsole->KeyCode();
+ Queue();
+ Profiler::TState command;
+ switch (key)
+ {
+ case 's': case 'S':
+ command = Profiler::EStart;
+ break;
+ case 'p': case 'P':
+ command = Profiler::EStop;
+ break;
+ case 'c': case 'C':
+ command = Profiler::EClose;
+ break;
+ case 'x': case 'X':
+ command = Profiler::EUnload;
+ break;
+ case '?': case 'h': case 'H':
+ Help();
+ return;
+ default:
+ return;
+ }
+ Control(command);
+ }
+
+void CConsole::DoCancel()
+ {
+ iConsole->ReadCancel();
+ }
+
+
+void MainL(TInt aCmd, TDesC* aDrive)
+//
+// Construct and run the profile engine
+//
+ {
+ CProfiler* p = CProfiler::NewLC(aCmd, aDrive);
+ CActiveScheduler::Start();
+ CleanupStack::PopAndDestroy(p);
+ }
+
+TInt GetCommand(TDes &aDrive)
+//
+// Decode the command line arguments into a profiler control request
+// aDrive is the drive number to store the profiler data on
+//
+ {
+ _LIT(KStart,"start");
+ _LIT(KStop,"stop");
+ _LIT(KClose,"close");
+ _LIT(KUnload,"unload");
+ _LIT(KExit,"exit");
+ _LIT(KNoUi,"-noui");
+ _LIT(KXIPOnly,"-xiponly");
+ _LIT(KDrive,"-drive=");
+ const TInt KDriveOffset=7;
+ TBuf<64> c;
+ User::CommandLine(c);
+ TInt cmd = 0;
+ if (c.FindF(KNoUi) >= 0)
+ cmd |= KCommandNoUi;
+ if (c.FindF(KXIPOnly) >= 0)
+ cmd |= KCommandXIPOnly;
+
+ // get the drive letter if any
+ TInt pos = c.FindF(KDrive);
+ if(pos >= 0)
+ {
+ pos += KDriveOffset;
+ TBuf<1> driveLet;
+ driveLet.SetLength(1);
+ driveLet[0] = c[pos];
+ driveLet.UpperCase();
+ if (driveLet[0] >= 'A' && driveLet[0] <= 'Z')
+ {
+ aDrive[0] = driveLet[0];
+ }
+ }
+ if (c.FindF(KStart) >= 0)
+ return cmd | Profiler::EStart;
+ if (c.FindF(KStop) >= 0)
+ return cmd | Profiler::EStop;
+ if (c.FindF(KClose) >= 0)
+ return cmd | Profiler::EClose;
+ if (c.FindF(KUnload) >= 0)
+ return cmd | Profiler::EUnload;
+ if (c.FindF(KExit) >= 0)
+ return cmd | Profiler::EUnload;
+ return cmd | KCommandNone;
+ }
+
+TInt E32Main()
+//
+// Profiler.exe entry point
+// Decode any command-line argument - which can be used to control a running profile engine
+// Otherwise start the engine in this process
+//
+ {
+ TBuf<1> drive;
+ drive.SetLength(1);
+ drive[0] = 'C';
+ TInt command = GetCommand(drive);
+ if ((command & KCommandMask) != KCommandNone)
+ {
+ TInt r = Profiler::Control(Profiler::TState(command & KCommandMask));
+ if (r != KErrNotFound || (command & KCommandMask) != Profiler::EStart)
+ return r;
+ }
+ CTrapCleanup::New();
+ TRAPD(r,MainL(command, &drive));
+ if (r != KErrNone)
+ RDebug::Print(_L("PROFILER: Error starting profiler"));
+ return r;
+ }