1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32utils/profiler/profiler.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1018 @@
1.4 +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32utils\profiler\profiler.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include <e32cons.h>
1.22 +#include <f32file.h>
1.23 +#include "profiler.h"
1.24 +#include "sampler.h"
1.25 +
1.26 +// The name of the output file use to save the sample data
1.27 +_LIT(KFileName,"?:\\PROFILER.DAT");
1.28 +const TInt KFileNameLen=15;
1.29 +
1.30 +// The name of the DLL used as an alternative UI controller
1.31 +_LIT(KProfilerKeysDll,"ProfilerKeys");
1.32 +
1.33 +// The size of the buffers used for reading sample data and writing to file
1.34 +const TInt KBufferSize = 0x800;
1.35 +
1.36 +// The sample rate used by the profiler
1.37 +const TInt KSampleRate = 1000;
1.38 +
1.39 +const TInt KCommandMask = 0x00ff;
1.40 +const TInt KCommandNone = 0x0010;
1.41 +const TInt KCommandNoUi = 0x0100;
1.42 +const TInt KCommandXIPOnly = 0x0200;
1.43 +
1.44 +// The controller class used to provide the Profiler functions.
1.45 +// This runs as a server in the engine thread
1.46 +class CPServer : public CServer2, public MProfilerController
1.47 + {
1.48 +public:
1.49 + static MProfilerController* NewL(TInt aPriority, MProfilerEngine& aEngine);
1.50 +private:
1.51 + CPServer(TInt aPriority, MProfilerEngine& aEngine);
1.52 + void Release();
1.53 + CSession2* NewSessionL(const TVersion& aVersion,const RMessage2& aMessage) const;
1.54 + };
1.55 +
1.56 +// The session class used by the server controller
1.57 +class CPSession : public CSession2
1.58 + {
1.59 +private:
1.60 + inline const CPServer& Server() const;
1.61 + void ServiceL(const RMessage2& aMessage);
1.62 + };
1.63 +
1.64 +
1.65 +// The default UI controller class which uses a Console
1.66 +class CConsole : public CActive, private MProfilerController
1.67 + {
1.68 +public:
1.69 + static MProfilerController* NewL(TInt aPriority, MProfilerEngine& aEngine);
1.70 +private:
1.71 + CConsole(TInt aPriority, MProfilerEngine& aEngine);
1.72 + void ConstructL();
1.73 + ~CConsole();
1.74 + void Release();
1.75 +//
1.76 + void Help();
1.77 + void Queue();
1.78 +//
1.79 + void RunL();
1.80 + void DoCancel();
1.81 +private:
1.82 + CConsoleBase* iConsole;
1.83 + };
1.84 +
1.85 +
1.86 +// The buffers used for transferring data from the device driver to the file
1.87 +struct TBuffer
1.88 + {
1.89 + TBuffer* iNext;
1.90 + TBuf8<KBufferSize> iBuf;
1.91 + };
1.92 +
1.93 +class CProfiler;
1.94 +
1.95 +// The active object responsible for reading data from the device
1.96 +class CReader : public CActive
1.97 + {
1.98 +public:
1.99 + CReader(TInt aPriority, CProfiler& aProfiler);
1.100 + ~CReader();
1.101 +//
1.102 + void ConstructL();
1.103 + void Queue(TBuffer* aBuf);
1.104 +private:
1.105 + void RunL();
1.106 + void DoCancel();
1.107 +private:
1.108 + CProfiler& iProfiler;
1.109 + TBuffer* iBuf;
1.110 +public:
1.111 + RSampler iSampler;
1.112 + };
1.113 +
1.114 +// The active object responsible for writing data out (to file)
1.115 +class CWriter : public CActive
1.116 + {
1.117 +public:
1.118 + CWriter(TInt aPriority, CProfiler& aProfiler);
1.119 + ~CWriter();
1.120 + void ConstructL();
1.121 + TInt Open(const TDesC& aFile);
1.122 + void Close();
1.123 + void Queue(TBuffer* aBuf);
1.124 +private:
1.125 + void RunL();
1.126 + void DoCancel();
1.127 +private:
1.128 + CProfiler& iProfiler;
1.129 + TBuffer* iBuf;
1.130 + RFile iFile;
1.131 + RFs iFs;
1.132 + };
1.133 +
1.134 +
1.135 +// The profiler engine itself.
1.136 +class CProfiler : public CBase, private MProfilerEngine
1.137 + {
1.138 + enum {EControlPriority = 10, EReaderPriority = 0, EWriterPriority = -10};
1.139 +
1.140 + /** Specifies the state of the engine*/
1.141 + enum TState
1.142 + {
1.143 + /**
1.144 + Initial state. The file is closed. Driver is inactive
1.145 + */
1.146 + EClosed,
1.147 + /**
1.148 + Engine enters this state on client's Start request (if -xiponly is not specified).
1.149 + Opens the file.
1.150 + Resets the driver and nonXIP code segments.
1.151 + Sends GetSegments calls to the driver until driver returns zero length reply.
1.152 + Leaves this state (goes into ERunning) when the last data (obtained by GetSegment) is
1.153 + written into the file.
1.154 + */
1.155 + EGettingSegments,
1.156 + /**
1.157 + Sends async. read request to the driver. Once completed, it immediately sends another while
1.158 + writing the collected records into the file.
1.159 + */
1.160 + ERunning,
1.161 + /**
1.162 + Get into this state from ERunning on the client's Stop, Close or Exit request.
1.163 + Sends Drain calls to the driver until driver returns zero length reply.
1.164 + Leaves this state when all records are written into the file.
1.165 + */
1.166 + EDraining,
1.167 + /**
1.168 + No active calls to the driver. On the client's Start request, will go back into ERunning mode.
1.169 + */
1.170 + EStopped,
1.171 + /**
1.172 + Get into this state on client's Close or Exit request.
1.173 + Sends a single GetErrorReport request to the driver. After data has been recorded into the file,
1.174 + it closes the file and goes into EClosed state or terminates application..
1.175 + */
1.176 + EGettingErrors
1.177 + };
1.178 +public:
1.179 + static CProfiler* NewLC(TInt aCmd, TDesC* aDrive);
1.180 +//
1.181 + TInt Control(Profiler::TState aCommand);
1.182 +//
1.183 + void ReadComplete(TBuffer* aBuf);
1.184 + void WriteComplete(TBuffer* aBuf);
1.185 +private:
1.186 + CProfiler();
1.187 + ~CProfiler();
1.188 + void ConstructL(TInt aCmd, TDesC* aDrive);
1.189 + MProfilerController* CreateUiL();
1.190 +//
1.191 + void Read();
1.192 + void Write();
1.193 + TBool GetSegments();
1.194 + TBool Drain();
1.195 + void GetErrors();
1.196 +//
1.197 + Profiler::TState State() const;
1.198 +private:
1.199 + CReader* iReader;
1.200 + CWriter* iWriter;
1.201 + MProfilerController* iServer;
1.202 + RLibrary iUiCode;
1.203 + MProfilerController* iUi;
1.204 + TState iState;
1.205 + TBool iXIPOnly;
1.206 + Profiler::TState iLastCommand;
1.207 +//
1.208 + // The FIFO queue of data that has to be written
1.209 + TBuffer* iHead;
1.210 + TBuffer* iTail;
1.211 +//
1.212 + // The LIFO list of free buffers
1.213 + TBuffer* iFree;
1.214 + TDesC* iDrive;
1.215 + };
1.216 +
1.217 +
1.218 +CProfiler* CProfiler::NewLC(TInt aCmd, TDesC* aDrive)
1.219 + {
1.220 + CProfiler* self = new(ELeave) CProfiler;
1.221 + CleanupStack::PushL(self);
1.222 + self->ConstructL(aCmd, aDrive);
1.223 + return self;
1.224 + }
1.225 +
1.226 +CProfiler::CProfiler()
1.227 + {}
1.228 +
1.229 +CProfiler::~CProfiler()
1.230 + {
1.231 + delete iReader;
1.232 + delete iWriter;
1.233 + if (iServer)
1.234 + iServer->Release();
1.235 + if (iUi)
1.236 + iUi->Release();
1.237 + iUiCode.Close();
1.238 +
1.239 + // discard the buffers in the free list
1.240 + TBuffer* b=iFree;
1.241 + while (b)
1.242 + {
1.243 + TBuffer* n = b->iNext;
1.244 + delete b;
1.245 + b = n;
1.246 + }
1.247 +
1.248 + // discard any buffers in the holding queue
1.249 + b=iHead;
1.250 + while (b)
1.251 + {
1.252 + TBuffer* n = b->iNext;
1.253 + delete b;
1.254 + b = n;
1.255 + }
1.256 + }
1.257 +
1.258 +void CProfiler::ConstructL(TInt aCmd, TDesC* aDrive)
1.259 +//
1.260 +// Build the profiler engine
1.261 +//
1.262 + {
1.263 + // Set drive letter of where to store profiler data
1.264 + iDrive = aDrive;
1.265 +
1.266 + // Run the engine at maximum priority to try and ensure that the sampler device
1.267 + // does not get choked and start dropping samples
1.268 + RThread me;
1.269 + me.SetPriority(EPriorityRealTime);
1.270 + User::LeaveIfError(User::RenameThread(KProfilerName));
1.271 +
1.272 + CActiveScheduler::Install(new(ELeave) CActiveScheduler);
1.273 + iReader = new(ELeave) CReader(EReaderPriority,*this);
1.274 + iReader->ConstructL();
1.275 + iWriter = new(ELeave) CWriter(EWriterPriority,*this);
1.276 + iWriter->ConstructL();
1.277 + iServer = CPServer::NewL(EControlPriority,*this);
1.278 + if (!(aCmd & KCommandNoUi))
1.279 + iUi = CreateUiL();
1.280 +
1.281 + // Start off with two buffers in the free list for sample data
1.282 + TBuffer* buf = new(ELeave) TBuffer;
1.283 + buf->iNext = 0;
1.284 + iFree = buf;
1.285 + buf = new(ELeave) TBuffer;
1.286 + buf->iNext = iFree;
1.287 + iFree = buf;
1.288 +
1.289 + // idenify the running mode
1.290 + iXIPOnly = aCmd & KCommandXIPOnly;
1.291 +
1.292 + // start profiling if requested
1.293 + if ((aCmd & KCommandMask) == Profiler::EStart)
1.294 + User::LeaveIfError(Control(Profiler::EStart));
1.295 +
1.296 + }
1.297 +
1.298 +MProfilerController* CProfiler::CreateUiL()
1.299 +//
1.300 +// deal with the UI acquisition part of construction
1.301 +// If ProfilerKeys.Dll is available, use it; otherwise create a text console
1.302 +//
1.303 + {
1.304 + _LIT(KWindowServerName,"*WindowServer");
1.305 + TFindServer find(KWindowServerName);
1.306 + TFullName n;
1.307 + if (find.Next(n) == KErrNotFound)
1.308 + {
1.309 + // No UI on this device [yet]. Run without one.
1.310 + return 0;
1.311 + }
1.312 +
1.313 + if (iUiCode.Load(KProfilerKeysDll,TUidType(KNullUid, KUidProfilerKeys)) == KErrNone)
1.314 + {
1.315 + TProfilerControllerFactoryL factoryL = TProfilerControllerFactoryL(iUiCode.Lookup(1));
1.316 + MProfilerController* ui = NULL;
1.317 + TRAPD(error, ui = factoryL(EControlPriority, *this));
1.318 + if (error == KErrNone)
1.319 + return ui;
1.320 +
1.321 + // Couldn't create alternative UI, so use the console
1.322 + iUiCode.Close();
1.323 + }
1.324 + return CConsole::NewL(EControlPriority, *this);
1.325 + }
1.326 +
1.327 +TInt CProfiler::Control(Profiler::TState aCommand)
1.328 +//
1.329 +// Handle a command from one of the controllers.
1.330 +// This method specifies the flow of the engine state (iState attr).
1.331 +// The most of transtions is not performed immediately but after all
1.332 +// current data are recorded into the file - see WriteComplete method.
1.333 +//
1.334 + {
1.335 +
1.336 + DEBUG_PROFILER(RDebug::Printf("*CTRL %d",iState);)
1.337 +
1.338 + TInt r = KErrNone;
1.339 + Profiler::TState oldCommand = iLastCommand;
1.340 +
1.341 + //Record the command. In most cases, it is WriteComplete method
1.342 + //to perform state transition (based on this value)
1.343 + iLastCommand = aCommand;
1.344 +
1.345 + switch (aCommand)
1.346 + {
1.347 + case Profiler::EStart:
1.348 + switch (iState)
1.349 + {
1.350 + case EClosed:
1.351 + {
1.352 + // Set the path of the output file to include the drive letter
1.353 + // specified at the command line or the default
1.354 + TBuf<KFileNameLen> path;
1.355 + path.Copy(KFileName);
1.356 + path[0] = (*iDrive)[0];
1.357 + r = iWriter->Open(path);
1.358 + }
1.359 + if (KErrNone != r) // Re-open the file
1.360 + return r;
1.361 + iReader->iSampler.Reset(iXIPOnly); // Reset the sampler
1.362 + if(iXIPOnly)
1.363 + {
1.364 + iState = ERunning;
1.365 + iReader->iSampler.Start(KSampleRate); // Start sampler
1.366 + if (!iReader->IsActive())
1.367 + Read(); // Start reading
1.368 + }
1.369 + else
1.370 + {
1.371 + iState = EGettingSegments;
1.372 + iReader->iSampler.ResetSegments(); // Reset segments
1.373 + GetSegments(); // Start getting segments
1.374 + }
1.375 + break;
1.376 + case EStopped:
1.377 + iState = ERunning;
1.378 + iReader->iSampler.Start(KSampleRate); // Start sampler
1.379 + if (!iReader->IsActive())
1.380 + Read(); //Start reading
1.381 + break;
1.382 + case ERunning: //Already started. No action required.
1.383 + case EGettingSegments: //Already started. No action required.
1.384 + case EDraining: //Will restart after draining is completed.
1.385 + case EGettingErrors: //Will restart after getting errors is completed;
1.386 + break;
1.387 + }
1.388 + break; //end of case Profiler::EStart
1.389 +
1.390 + case Profiler::EStop:
1.391 + switch (iState)
1.392 + {
1.393 + case EClosed:
1.394 + case EGettingErrors:
1.395 + iLastCommand = oldCommand;
1.396 + return KErrGeneral; //The command makes no sense in this state
1.397 + case ERunning:
1.398 + iReader->iSampler.Stop(); //Stop sampling.
1.399 + break;
1.400 + case EGettingSegments: //Will do GettingSegments->Running->Stopped transitions
1.401 + case EDraining: //Stopping already in progress
1.402 + case EStopped: //Already stopped.
1.403 + break;
1.404 + }
1.405 + break; //end of case Profiler::EStop
1.406 +
1.407 + case Profiler::EClose:
1.408 + switch (iState)
1.409 + {
1.410 + case EStopped:
1.411 + iState = EGettingErrors;
1.412 + GetErrors();
1.413 + break;
1.414 + case ERunning:
1.415 + iReader->iSampler.Stop();
1.416 + break;
1.417 + case EClosed: //Already closed.
1.418 + case EGettingErrors: //Closing in progress
1.419 + case EGettingSegments:
1.420 + case EDraining:
1.421 + break;
1.422 + }
1.423 + break; //end of case Profiler::EStop
1.424 +
1.425 + case Profiler::EUnload:
1.426 + switch (iState)
1.427 + {
1.428 + case EClosed:
1.429 + CActiveScheduler::Stop(); // Terminate application.
1.430 + break;
1.431 + case EStopped:
1.432 + iState = EGettingErrors;
1.433 + GetErrors();
1.434 + break;
1.435 + case ERunning:
1.436 + iReader->iSampler.Stop();
1.437 + break;
1.438 + case EDraining:
1.439 + case EGettingErrors:
1.440 + case EGettingSegments:
1.441 + break;
1.442 + }
1.443 + break;//end of case Profiler::Unload
1.444 + }
1.445 +
1.446 + DEBUG_PROFILER(RDebug::Printf("*CTRL end %d",iState);)
1.447 + return KErrNone;
1.448 + }
1.449 +
1.450 +Profiler::TState CProfiler::State() const
1.451 +//
1.452 +// Report the current state of the engine
1.453 +//
1.454 + {
1.455 + switch (iState)
1.456 + {
1.457 + case EGettingErrors:
1.458 + case EStopped:
1.459 + return Profiler::EStop;
1.460 + case EClosed:
1.461 + return Profiler::EClose;
1.462 + default:
1.463 + return Profiler::EStart;
1.464 + }
1.465 + }
1.466 +
1.467 +void CProfiler::Read()
1.468 +//
1.469 +// Pass a free buffer to the reader, allocating one if necessary
1.470 +//
1.471 + {
1.472 + TBuffer* buf = iFree;
1.473 + if (buf)
1.474 + iFree = buf->iNext;
1.475 + else
1.476 + {
1.477 + buf = new TBuffer;
1.478 + if(!buf)
1.479 + {
1.480 + RDebug::Print(_L("PROFILER: No more memory ... stopping"));
1.481 + CProfiler::Control(Profiler::EStop);
1.482 + return;
1.483 + }
1.484 + }
1.485 + iReader->Queue(buf);
1.486 + }
1.487 +
1.488 +TBool CProfiler::GetSegments()
1.489 +//
1.490 +// Gets the list of the current non-XIP segments from device.
1.491 +// Returns true if zero-length desc is returned, otherwise ...
1.492 +// ...passes the buffer to write engine and returns false.
1.493 + {
1.494 + TBuffer* buf = iFree;
1.495 + if (buf)
1.496 + iFree = buf->iNext;
1.497 + else
1.498 + {
1.499 + RDebug::Printf("PROFILER: No available buffer for GetSegments");
1.500 + User::Invariant();
1.501 + }
1.502 +
1.503 + iReader->iSampler.GetSegments(buf->iBuf);
1.504 + if (!buf->iBuf.Length())
1.505 + {
1.506 + buf->iNext = iFree;//Return empty buffer to the free list
1.507 + iFree = buf;
1.508 + return ETrue;
1.509 + }
1.510 +
1.511 + iWriter->Queue(buf);//Pass the buffer to the write engine.
1.512 + return EFalse;
1.513 + }
1.514 +
1.515 +TBool CProfiler::Drain()
1.516 +//
1.517 +// Drains all remaining records from the device
1.518 +// Returns true if zero-length desc is returned, otherwise ...
1.519 +// ...passes the buffer to the write engine and returns false.
1.520 + {
1.521 + TBuffer* buf = iFree;
1.522 + if (buf)
1.523 + iFree = buf->iNext;
1.524 + else
1.525 + {
1.526 + RDebug::Printf("PROFILER: No available buffer for Drain");
1.527 + User::Invariant();
1.528 + }
1.529 +
1.530 + iReader->iSampler.Drain(buf->iBuf);
1.531 +
1.532 + if (!buf->iBuf.Length())
1.533 + {
1.534 + buf->iNext = iFree;//Return empty buffer to the free list
1.535 + iFree = buf;
1.536 + return ETrue;
1.537 + }
1.538 + iWriter->Queue(buf); //Pass the buffer to the write engine.
1.539 + return EFalse;
1.540 + }
1.541 +
1.542 +
1.543 +void CProfiler::GetErrors()
1.544 +//
1.545 +// Gets error report from the device and pass the buffer to the write engine
1.546 +//
1.547 + {
1.548 + TBuffer* buf = iFree;
1.549 + if (buf)
1.550 + iFree = buf->iNext;
1.551 + else
1.552 + {
1.553 + RDebug::Printf("PROFILER: No available buffer for GetErrors");
1.554 + User::Invariant();
1.555 + }
1.556 + iReader->iSampler.GetErrors(buf->iBuf);
1.557 + iWriter->Queue(buf);
1.558 + }
1.559 +
1.560 +void CProfiler::Write()
1.561 +//
1.562 +// Pass a queued buffer to the writer
1.563 +//
1.564 + {
1.565 + TBuffer* buf = iHead;
1.566 + iHead = buf->iNext;
1.567 + if (iHead == 0)
1.568 + iTail = 0;
1.569 + iWriter->Queue(buf);
1.570 + }
1.571 +
1.572 +void CProfiler::ReadComplete(TBuffer* aBuf)
1.573 +//
1.574 +// Handle a completed read buffer
1.575 +//
1.576 + {
1.577 + DEBUG_PROFILER(RDebug::Printf("*RC %d",iState);)
1.578 +
1.579 + //Add the buffer to the queue
1.580 + aBuf->iNext = 0;
1.581 + if (iTail)
1.582 + iTail->iNext = aBuf;
1.583 + else
1.584 + iHead = aBuf;
1.585 + iTail = aBuf;
1.586 +
1.587 + if (!iWriter->IsActive())
1.588 + Write();
1.589 +
1.590 + if (iLastCommand == Profiler::EStart)
1.591 + Read(); //Request another read
1.592 +
1.593 + DEBUG_PROFILER(RDebug::Printf("*RC end %d",iState);)
1.594 + }
1.595 +
1.596 +void CProfiler::WriteComplete(TBuffer* aBuf)
1.597 +//
1.598 +// Handle a flushed write buffer.
1.599 +//
1.600 + {
1.601 + DEBUG_PROFILER(RDebug::Printf("*WC %d",iState);)
1.602 +
1.603 + aBuf->iNext = iFree;//Return empty buffer to the free list
1.604 + iFree = aBuf;
1.605 +
1.606 + switch (iState)
1.607 + {
1.608 + case EGettingSegments:
1.609 + if (!GetSegments())
1.610 + break;//More code segments to be completed
1.611 +
1.612 + //Always go to the running state after the segments are collected....
1.613 + iState = ERunning;
1.614 + iReader->iSampler.Start(KSampleRate);
1.615 + Read();
1.616 +
1.617 + //...but stop sampler immediately if we got another user command
1.618 + if (iLastCommand != Profiler::EStart)
1.619 + {
1.620 + iReader->iSampler.Stop();
1.621 + }
1.622 + break; //the end of EGettingSegments case
1.623 +
1.624 + case ERunning:
1.625 + if (iHead)
1.626 + {
1.627 + Write(); // There are more buffers to go to the file.
1.628 + break;
1.629 + }
1.630 + if (iLastCommand != Profiler::EStart)
1.631 + {//The user has stopped the profiler.
1.632 + iState = EDraining;
1.633 + if (!Drain())
1.634 + break;//More data to drain.
1.635 +
1.636 + //Drain returned empty. May progress further with the engine state
1.637 + if (iLastCommand == Profiler::EStop)
1.638 + iState = EStopped;
1.639 + else
1.640 + {
1.641 + iState = EGettingErrors;
1.642 + GetErrors();
1.643 + }
1.644 + }
1.645 + break;//the end of ERunning case
1.646 +
1.647 + case EDraining:
1.648 + if (!Drain())
1.649 + break; //still draining;
1.650 +
1.651 + //Drain is completed
1.652 + switch (iLastCommand)
1.653 + {
1.654 + case Profiler::EStart:
1.655 + //While draining, we received another Start command
1.656 + iState = ERunning;
1.657 + iReader->iSampler.Start(KSampleRate);
1.658 + Read();
1.659 + break;
1.660 + case Profiler::EStop:
1.661 + iState = EStopped;
1.662 + break;
1.663 + default:
1.664 + iState = EGettingErrors;
1.665 + GetErrors();
1.666 + }
1.667 + break; //the end of EDraining case
1.668 +
1.669 + case EGettingErrors:
1.670 + iWriter->Close();
1.671 + iState = EClosed;
1.672 + switch (iLastCommand)
1.673 + {
1.674 + case Profiler::EUnload:
1.675 + CActiveScheduler::Stop(); //Terminate application.
1.676 + break;
1.677 + case Profiler::EStart:
1.678 + Control(Profiler::EStart);
1.679 + break;
1.680 + default:
1.681 + break;
1.682 + }
1.683 + break; //the end of EGettingErrors case
1.684 +
1.685 + default:
1.686 + RDebug::Printf("PROFILER: WriteComplete in %d state", iState);
1.687 + User::Invariant();
1.688 + break;
1.689 +
1.690 + }
1.691 +
1.692 + DEBUG_PROFILER(RDebug::Printf("*WC end %d",iState);)
1.693 + }
1.694 +
1.695 +
1.696 +
1.697 +CReader::CReader(TInt aPriority, CProfiler& aProfiler)
1.698 + :CActive(aPriority), iProfiler(aProfiler)
1.699 + {
1.700 + CActiveScheduler::Add(this);
1.701 + }
1.702 +
1.703 +CReader::~CReader()
1.704 + {
1.705 + Cancel();
1.706 + delete iBuf;
1.707 + iSampler.Close();
1.708 + User::FreeLogicalDevice(KSamplerName);
1.709 + }
1.710 +
1.711 +void CReader::ConstructL()
1.712 + {
1.713 + TInt r=User::LoadLogicalDevice(KSamplerName);
1.714 + if (r!=KErrNone && r!=KErrAlreadyExists)
1.715 + User::Leave(r);
1.716 + User::LeaveIfError(iSampler.Open());
1.717 + }
1.718 +
1.719 +void CReader::RunL()
1.720 +//
1.721 +// Pass the full buffer to the engine
1.722 +//
1.723 + {
1.724 + TBuffer* data=iBuf;
1.725 + iBuf = 0;
1.726 + iProfiler.ReadComplete(data);
1.727 + }
1.728 +
1.729 +void CReader::DoCancel()
1.730 + {
1.731 + iSampler.ReadCancel();
1.732 + }
1.733 +
1.734 +void CReader::Queue(TBuffer* aBuf)
1.735 +//
1.736 +// Queue a request to read data into the empty buffer
1.737 +//
1.738 + {
1.739 + iBuf = aBuf;
1.740 + iSampler.Read(aBuf->iBuf, iStatus);
1.741 + SetActive();
1.742 + }
1.743 +
1.744 +CWriter::CWriter(TInt aPriority, CProfiler& aProfiler)
1.745 + :CActive(aPriority), iProfiler(aProfiler)
1.746 + {
1.747 + CActiveScheduler::Add(this);
1.748 + }
1.749 +
1.750 +CWriter::~CWriter()
1.751 + {
1.752 + Cancel();
1.753 + delete iBuf;
1.754 + iFile.Close();
1.755 + iFs.Close();
1.756 + }
1.757 +
1.758 +void CWriter::ConstructL()
1.759 + {
1.760 + User::LeaveIfError(iFs.Connect());
1.761 + }
1.762 +
1.763 +TInt CWriter::Open(const TDesC& aFile)
1.764 +//
1.765 +// Open the file for saving the sample data
1.766 +//
1.767 + {
1.768 + return iFile.Replace(iFs,aFile,EFileWrite);
1.769 + }
1.770 +
1.771 +void CWriter::Close()
1.772 +//
1.773 +// Release the file
1.774 +//
1.775 + {
1.776 + iFile.Close();
1.777 + }
1.778 +
1.779 +void CWriter::Queue(TBuffer* aBuf)
1.780 +//
1.781 +// Queue a request to write the full buffer into the file
1.782 +//
1.783 + {
1.784 + iBuf = aBuf;
1.785 + iFile.Write(aBuf->iBuf, iStatus);
1.786 + SetActive();
1.787 + }
1.788 +
1.789 +void CWriter::RunL()
1.790 +//
1.791 +// Return the empty buffer back to the engine
1.792 +//
1.793 + {
1.794 + TBuffer* data=iBuf;
1.795 + iBuf = 0;
1.796 + iProfiler.WriteComplete(data);
1.797 + }
1.798 +
1.799 +void CWriter::DoCancel()
1.800 +//
1.801 +// RFile does not provide a WriteCancel() function
1.802 +//
1.803 + {}
1.804 +
1.805 +
1.806 +// Server controller
1.807 +
1.808 +inline const CPServer& CPSession::Server() const
1.809 + {return *static_cast<const CPServer*>(CSession2::Server());}
1.810 +
1.811 +void CPSession::ServiceL(const RMessage2& aMessage)
1.812 +//
1.813 +// Handle a IPC request to control the profiler
1.814 +//
1.815 + {
1.816 + aMessage.Complete(Server().Control(Profiler::TState(aMessage.Function())));
1.817 + }
1.818 +
1.819 +MProfilerController* CPServer::NewL(TInt aPriority, MProfilerEngine& aEngine)
1.820 +//
1.821 +// Create and start the server to provide the Profiler interface
1.822 +//
1.823 + {
1.824 + CPServer* self = new(ELeave) CPServer(aPriority, aEngine);
1.825 + CleanupStack::PushL(self);
1.826 + self->StartL(KProfilerName);
1.827 + CleanupStack::Pop();
1.828 + return self;
1.829 + }
1.830 +
1.831 +CPServer::CPServer(TInt aPriority, MProfilerEngine& aEngine)
1.832 + :CServer2(aPriority), MProfilerController(aEngine)
1.833 + {}
1.834 +
1.835 +void CPServer::Release()
1.836 + {
1.837 + delete this;
1.838 + }
1.839 +
1.840 +CSession2* CPServer::NewSessionL(const TVersion&,const RMessage2&) const
1.841 + {
1.842 + return new(ELeave) CPSession();
1.843 + }
1.844 +
1.845 +
1.846 +// Console Controller
1.847 +
1.848 +MProfilerController* CConsole::NewL(TInt aPriority, MProfilerEngine& aEngine)
1.849 +//
1.850 +// Create and start the console UI for the profiler
1.851 +//
1.852 + {
1.853 + CConsole* self = new(ELeave) CConsole(aPriority, aEngine);
1.854 + CleanupStack::PushL(self);
1.855 + self->ConstructL();
1.856 + CleanupStack::Pop();
1.857 + return self;
1.858 + }
1.859 +
1.860 +CConsole::CConsole(TInt aPriority, MProfilerEngine& aEngine)
1.861 + :CActive(aPriority), MProfilerController(aEngine)
1.862 + {
1.863 + CActiveScheduler::Add(this);
1.864 + }
1.865 +
1.866 +void CConsole::ConstructL()
1.867 + {
1.868 + iConsole = Console::NewL(KProfilerName, TSize(KConsFullScreen,KConsFullScreen));
1.869 + Help();
1.870 + Queue();
1.871 + }
1.872 +
1.873 +CConsole::~CConsole()
1.874 + {
1.875 + Cancel();
1.876 + delete iConsole;
1.877 + }
1.878 +
1.879 +void CConsole::Release()
1.880 + {
1.881 + delete this;
1.882 + }
1.883 +
1.884 +void CConsole::Help()
1.885 +//
1.886 +// Display the instructions on the console
1.887 +//
1.888 + {
1.889 + _LIT(KInstructions,"[S]tart, Sto[p], [C]lose or E[x]it\r\n");
1.890 + iConsole->Write(KInstructions);
1.891 + }
1.892 +
1.893 +void CConsole::Queue()
1.894 +//
1.895 +// Request a key press from the console
1.896 +//
1.897 + {
1.898 + iConsole->Read(iStatus);
1.899 + SetActive();
1.900 + }
1.901 +
1.902 +void CConsole::RunL()
1.903 +//
1.904 +// Handle a key press from the console
1.905 +//
1.906 + {
1.907 + TInt key = iConsole->KeyCode();
1.908 + Queue();
1.909 + Profiler::TState command;
1.910 + switch (key)
1.911 + {
1.912 + case 's': case 'S':
1.913 + command = Profiler::EStart;
1.914 + break;
1.915 + case 'p': case 'P':
1.916 + command = Profiler::EStop;
1.917 + break;
1.918 + case 'c': case 'C':
1.919 + command = Profiler::EClose;
1.920 + break;
1.921 + case 'x': case 'X':
1.922 + command = Profiler::EUnload;
1.923 + break;
1.924 + case '?': case 'h': case 'H':
1.925 + Help();
1.926 + return;
1.927 + default:
1.928 + return;
1.929 + }
1.930 + Control(command);
1.931 + }
1.932 +
1.933 +void CConsole::DoCancel()
1.934 + {
1.935 + iConsole->ReadCancel();
1.936 + }
1.937 +
1.938 +
1.939 +void MainL(TInt aCmd, TDesC* aDrive)
1.940 +//
1.941 +// Construct and run the profile engine
1.942 +//
1.943 + {
1.944 + CProfiler* p = CProfiler::NewLC(aCmd, aDrive);
1.945 + CActiveScheduler::Start();
1.946 + CleanupStack::PopAndDestroy(p);
1.947 + }
1.948 +
1.949 +TInt GetCommand(TDes &aDrive)
1.950 +//
1.951 +// Decode the command line arguments into a profiler control request
1.952 +// aDrive is the drive number to store the profiler data on
1.953 +//
1.954 + {
1.955 + _LIT(KStart,"start");
1.956 + _LIT(KStop,"stop");
1.957 + _LIT(KClose,"close");
1.958 + _LIT(KUnload,"unload");
1.959 + _LIT(KExit,"exit");
1.960 + _LIT(KNoUi,"-noui");
1.961 + _LIT(KXIPOnly,"-xiponly");
1.962 + _LIT(KDrive,"-drive=");
1.963 + const TInt KDriveOffset=7;
1.964 + TBuf<64> c;
1.965 + User::CommandLine(c);
1.966 + TInt cmd = 0;
1.967 + if (c.FindF(KNoUi) >= 0)
1.968 + cmd |= KCommandNoUi;
1.969 + if (c.FindF(KXIPOnly) >= 0)
1.970 + cmd |= KCommandXIPOnly;
1.971 +
1.972 + // get the drive letter if any
1.973 + TInt pos = c.FindF(KDrive);
1.974 + if(pos >= 0)
1.975 + {
1.976 + pos += KDriveOffset;
1.977 + TBuf<1> driveLet;
1.978 + driveLet.SetLength(1);
1.979 + driveLet[0] = c[pos];
1.980 + driveLet.UpperCase();
1.981 + if (driveLet[0] >= 'A' && driveLet[0] <= 'Z')
1.982 + {
1.983 + aDrive[0] = driveLet[0];
1.984 + }
1.985 + }
1.986 + if (c.FindF(KStart) >= 0)
1.987 + return cmd | Profiler::EStart;
1.988 + if (c.FindF(KStop) >= 0)
1.989 + return cmd | Profiler::EStop;
1.990 + if (c.FindF(KClose) >= 0)
1.991 + return cmd | Profiler::EClose;
1.992 + if (c.FindF(KUnload) >= 0)
1.993 + return cmd | Profiler::EUnload;
1.994 + if (c.FindF(KExit) >= 0)
1.995 + return cmd | Profiler::EUnload;
1.996 + return cmd | KCommandNone;
1.997 + }
1.998 +
1.999 +TInt E32Main()
1.1000 +//
1.1001 +// Profiler.exe entry point
1.1002 +// Decode any command-line argument - which can be used to control a running profile engine
1.1003 +// Otherwise start the engine in this process
1.1004 +//
1.1005 + {
1.1006 + TBuf<1> drive;
1.1007 + drive.SetLength(1);
1.1008 + drive[0] = 'C';
1.1009 + TInt command = GetCommand(drive);
1.1010 + if ((command & KCommandMask) != KCommandNone)
1.1011 + {
1.1012 + TInt r = Profiler::Control(Profiler::TState(command & KCommandMask));
1.1013 + if (r != KErrNotFound || (command & KCommandMask) != Profiler::EStart)
1.1014 + return r;
1.1015 + }
1.1016 + CTrapCleanup::New();
1.1017 + TRAPD(r,MainL(command, &drive));
1.1018 + if (r != KErrNone)
1.1019 + RDebug::Print(_L("PROFILER: Error starting profiler"));
1.1020 + return r;
1.1021 + }