|         |      1 /* | 
|         |      2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).  | 
|         |      3 * All rights reserved. | 
|         |      4 * This component and the accompanying materials are made available | 
|         |      5 * under the terms of "Eclipse Public License v1.0" | 
|         |      6 * which accompanies this distribution, and is available | 
|         |      7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". | 
|         |      8 * | 
|         |      9 * Initial Contributors: | 
|         |     10 * Nokia Corporation - initial contribution. | 
|         |     11 * | 
|         |     12 * Contributors: | 
|         |     13 * | 
|         |     14 * Description:   | 
|         |     15 * | 
|         |     16 */ | 
|         |     17  | 
|         |     18  | 
|         |     19 #ifndef PROFILER_MEM_SAMPLER_H | 
|         |     20 #define PROFILER_MEM_SAMPLER_H | 
|         |     21  | 
|         |     22 #include "GeneralsConfig.h" | 
|         |     23  | 
|         |     24 #include <kern_priv.h> | 
|         |     25  | 
|         |     26 #include <piprofiler/ProfilerGenericClassesKrn.h> | 
|         |     27 #include <piprofiler/ProfilerTraces.h> | 
|         |     28 #include "GppSamplerImpl.h" | 
|         |     29 #include "MemoryEventHandler.h" | 
|         |     30 #include <e32btrace.h> | 
|         |     31  | 
|         |     32  | 
|         |     33 // constants | 
|         |     34 // defines the maximum thread amount that is assumed to | 
|         |     35 // be possible with MEM trace | 
|         |     36 const TInt KSampleBufferSize = 257; | 
|         |     37 const TInt KProfilerMaxThreadsAmount = 512; | 
|         |     38 const TInt KProfilerMaxChunksAmount = 1024; | 
|         |     39 const TInt KProfilerMaxLibrariesAmount = 1024; | 
|         |     40 const TInt KProfilerTotalMemorySamplePeriod = 100; | 
|         |     41  | 
|         |     42 // flags | 
|         |     43 #define MEM_EVENT_HANDLER | 
|         |     44 //#define MEM_EVENT_HANDLER_LIBRARY_EVENTS | 
|         |     45  | 
|         |     46 /* | 
|         |     47  *	 | 
|         |     48  *	MEM sampler definition | 
|         |     49  *	 | 
|         |     50  */ | 
|         |     51  | 
|         |     52 class DMemoryEventHandler; | 
|         |     53  | 
|         |     54 class DMemSamplerImpl //: public DBase | 
|         |     55 { | 
|         |     56 public: | 
|         |     57 	enum EProcessingState | 
|         |     58 	{ | 
|         |     59 		EStartingToProcess, | 
|         |     60 		EProcessingNames, | 
|         |     61 		EProcessingData, | 
|         |     62 		ENothingToProcess | 
|         |     63 	}; | 
|         |     64 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS | 
|         |     65 	enum ESampleType | 
|         |     66 	{ | 
|         |     67 	    ESampleChunks, | 
|         |     68 	    ESampleThreads, | 
|         |     69 	    ESampleLibraries | 
|         |     70 	}; | 
|         |     71 #endif | 
|         |     72  | 
|         |     73 	DMemSamplerImpl(); | 
|         |     74 	~DMemSamplerImpl(); | 
|         |     75  | 
|         |     76 	TInt	CreateFirstSample(); | 
|         |     77 	TInt	SampleImpl(); | 
|         |     78 	TBool	SampleNeeded(); | 
|         |     79 	void	Reset(); | 
|         |     80 	TInt	ProcessChunks(); | 
|         |     81 	TInt    ProcessThreads(); | 
|         |     82     TInt    GatherChunks(); | 
|         |     83     TInt    GatherThreads(); | 
|         |     84  | 
|         |     85 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS | 
|         |     86     TInt    GatherLibraries(); | 
|         |     87     TInt    ProcessLibraries(); | 
|         |     88 #endif | 
|         |     89      | 
|         |     90 	TInt	EncodeChunkData(DChunk& chunk); | 
|         |     91 	TInt	EncodeChunkName(DChunk& chunk); | 
|         |     92 	TInt	EncodeChunkData(DThread& thread); | 
|         |     93 	TInt	EncodeChunkName(DThread& thread); | 
|         |     94 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS | 
|         |     95 	TInt    EncodeChunkData(DLibrary& library); | 
|         |     96 	TInt    EncodeChunkName(DLibrary& library); | 
|         |     97 #endif | 
|         |     98  | 
|         |     99 	TInt 	EncodeTotalMemoryName(); | 
|         |    100 	TInt 	EncodeTotalMemory(); | 
|         |    101 	 | 
|         |    102 	TInt	EncodeNameCode(); | 
|         |    103 	TInt	EncodeDataCode(); | 
|         |    104  | 
|         |    105 	DChunk*		heapChunksToSample[KProfilerMaxChunksAmount]; | 
|         |    106 	DChunk*		heapChunkNamesToReport[KProfilerMaxChunksAmount]; | 
|         |    107 	TInt		iCount; | 
|         |    108 	TInt		iChunkCount; | 
|         |    109 	TInt		iNewChunkCount; | 
|         |    110 	TBuf8<0x50> name; | 
|         |    111 	DThread*	threadsToSample[KProfilerMaxThreadsAmount]; | 
|         |    112 	DThread*	threadNamesToReport[KProfilerMaxThreadsAmount]; | 
|         |    113 	TInt		iThreadCount; | 
|         |    114 	TInt		iNewThreadCount; | 
|         |    115 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS | 
|         |    116 	DLibrary*   librariesToSample[KProfilerMaxLibrariesAmount]; | 
|         |    117 	DLibrary*   libraryNamesToReport[KProfilerMaxLibrariesAmount]; | 
|         |    118 	TInt        iLibraryCount; | 
|         |    119 	TInt        iNewLibraryCount; | 
|         |    120 	TInt        iLibrariesProcessing; | 
|         |    121 #endif | 
|         |    122  | 
|         |    123 	TInt		iChunksProcessing; | 
|         |    124     TInt        iThreadsProcessing; | 
|         |    125 	TInt		iMemSamplingPeriod; | 
|         |    126 	TInt		iMemSamplingPeriodDiv2; | 
|         |    127 	TInt        iMemSamplingPeriodDiv3; | 
|         |    128 	 | 
|         |    129 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS | 
|         |    130 	ESampleType iSampleType; | 
|         |    131 #else | 
|         |    132 	TBool		iSampleThreads; | 
|         |    133 #endif	 | 
|         |    134 	 | 
|         |    135 	TBool       iTimeToSample; | 
|         |    136 	 | 
|         |    137 	TBool 		iTotalMemoryOk; | 
|         |    138 	TBool		iTotalMemoryNameOk; | 
|         |    139  | 
|         |    140 	TUint8		sample[KSampleBufferSize]; | 
|         |    141 	TPtr8		sampleDescriptor; | 
|         |    142 	 | 
|         |    143 	// test | 
|         |    144 #ifdef MEM_EVENT_HANDLER | 
|         |    145 //	DMemoryEventHandler*   iEventHandler; | 
|         |    146 	TBool      iChunksGathered; | 
|         |    147 	TBool      iThreadsGathered; | 
|         |    148 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS | 
|         |    149 	TBool      iLibrariesGathered; | 
|         |    150 #endif | 
|         |    151 #endif | 
|         |    152 }; | 
|         |    153  | 
|         |    154  | 
|         |    155 template <int BufferSize> | 
|         |    156 class DProfilerMemSampler : public DProfilerGenericSampler<BufferSize> | 
|         |    157 { | 
|         |    158 public: | 
|         |    159 	DProfilerMemSampler(struct TProfilerGppSamplerData*, TInt id); | 
|         |    160 	~DProfilerMemSampler(); | 
|         |    161  | 
|         |    162 	void	Sample(); | 
|         |    163 	TInt	Reset(DProfilerSampleStream* aStream, TUint32 aSyncOffset); | 
|         |    164 	TInt	PostSample(); | 
|         |    165 	TBool	PostSampleNeeded(); | 
|         |    166 	 | 
|         |    167 private: | 
|         |    168 #ifdef MEM_EVENT_HANDLER | 
|         |    169     DMemoryEventHandler*               iEventHandler; | 
|         |    170 #endif | 
|         |    171 	DMemSamplerImpl			           memSamplerImpl; | 
|         |    172 	struct TProfilerGppSamplerData*    gppSamplerData; | 
|         |    173 	TBool                              sampleNeeded; | 
|         |    174 }; | 
|         |    175  | 
|         |    176 /* | 
|         |    177  *	 | 
|         |    178  *	MEM sampler implementation | 
|         |    179  *	 | 
|         |    180  */ | 
|         |    181  | 
|         |    182 template <int BufferSize> | 
|         |    183 DProfilerMemSampler<BufferSize>::DProfilerMemSampler(struct TProfilerGppSamplerData* gppSamplerDataIn, TInt id) : | 
|         |    184 	DProfilerGenericSampler<BufferSize>(PROFILER_MEM_SAMPLER_ID) | 
|         |    185     { | 
|         |    186     LOGSTRING2("DProfilerMemSampler<%d>::CProfilerMemSampler",BufferSize); | 
|         |    187 	this->gppSamplerData = gppSamplerDataIn; | 
|         |    188 	this->iSamplingPeriod = 3000;	// set default setting | 
|         |    189     } | 
|         |    190  | 
|         |    191 template <int BufferSize> | 
|         |    192 TInt DProfilerMemSampler<BufferSize>::Reset(DProfilerSampleStream* aStream, TUint32 aSyncOffset) | 
|         |    193     { | 
|         |    194 //#ifdef MEM_EVENT_HANDLER | 
|         |    195 //    Kern::Printf("DProfilerMemSampler<%d>::Reset - calling superclass reset",BufferSize); | 
|         |    196      | 
|         |    197 //#endif | 
|         |    198     // check if reset called in stop (by driver) | 
|         |    199     if(aSyncOffset != 999999) | 
|         |    200         { | 
|         |    201         DProfilerGenericSampler<BufferSize>::Reset(aStream); | 
|         |    202         memSamplerImpl.Reset(); | 
|         |    203  | 
|         |    204 #ifdef MEM_EVENT_HANDLER | 
|         |    205         // reset member variables | 
|         |    206         this->memSamplerImpl.iThreadsGathered = false; | 
|         |    207         this->memSamplerImpl.iChunksGathered = false; | 
|         |    208 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS | 
|         |    209         this->memSamplerImpl.iLibrariesGathered = false; | 
|         |    210 #endif | 
|         |    211          | 
|         |    212         // memory event handler | 
|         |    213         if(iEventHandler) | 
|         |    214             { | 
|         |    215             // stop previous sampling if still running | 
|         |    216 //            Kern::Printf("Stopping DMemoryEventHandler"); | 
|         |    217             iEventHandler->Stop(); | 
|         |    218             iEventHandler->Close(); | 
|         |    219             iEventHandler = NULL; | 
|         |    220             } | 
|         |    221      | 
|         |    222 //        Kern::Printf("Initiating DMemoryEventHandler"); | 
|         |    223         iEventHandler = new DMemoryEventHandler(this->iSampleBuffer); | 
|         |    224         if(iEventHandler) | 
|         |    225             { | 
|         |    226 //            Kern::Printf("Creating DMemoryEventHandler"); | 
|         |    227             TInt err(iEventHandler->Create()); | 
|         |    228             if(err != KErrNone) | 
|         |    229                 { | 
|         |    230                 Kern::Printf("Error in creation of DMemoryEventHandler, error %d", err); | 
|         |    231                 return err; | 
|         |    232                 } | 
|         |    233             } | 
|         |    234         else | 
|         |    235             { | 
|         |    236             Kern::Printf("Could not initiate DMemoryEventHandler"); | 
|         |    237             return KErrGeneral; | 
|         |    238             } | 
|         |    239      | 
|         |    240         // set first chunk&thread memory lookup at the 5 ms, should be enough | 
|         |    241 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS | 
|         |    242         this->memSamplerImpl.iMemSamplingPeriod = 45; | 
|         |    243 #else | 
|         |    244         this->memSamplerImpl.iMemSamplingPeriod = 10; | 
|         |    245 #endif | 
|         |    246          | 
|         |    247 #else | 
|         |    248         this->memSamplerImpl.iMemSamplingPeriod = this->iSamplingPeriod; | 
|         |    249 #endif | 
|         |    250         this->memSamplerImpl.iMemSamplingPeriodDiv2 = (TInt)(this->memSamplerImpl.iMemSamplingPeriod / 2); | 
|         |    251 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS | 
|         |    252         this->memSamplerImpl.iMemSamplingPeriodDiv3 = (TInt)(this->memSamplerImpl.iMemSamplingPeriod / 3); | 
|         |    253 #endif | 
|         |    254 	 | 
|         |    255         LOGSTRING3("CProfilerMemSampler<%d>::Reset - set mem sampling period to %d", | 
|         |    256                                 BufferSize,this->memSamplerImpl.iMemSamplingPeriod); | 
|         |    257         } | 
|         |    258 	else | 
|         |    259         { | 
|         |    260         LOGSTRING2("DProfilerMemSampler<%d>::Reset - reset in stop", BufferSize); | 
|         |    261 #ifdef MEM_EVENT_HANDLER | 
|         |    262         // destroy memory event handler | 
|         |    263         if(iEventHandler) | 
|         |    264             { | 
|         |    265             // stop previous sampling if still running | 
|         |    266 //            Kern::Printf("Stopping DMemoryEventHandler"); | 
|         |    267             iEventHandler->Stop(); | 
|         |    268             iEventHandler->Close(); | 
|         |    269             iEventHandler = NULL; | 
|         |    270             } | 
|         |    271 #endif | 
|         |    272         return KErrNone;    // return if reset called in stop | 
|         |    273         } | 
|         |    274  | 
|         |    275 	// add MEM sample header | 
|         |    276 	TInt length(memSamplerImpl.CreateFirstSample()); | 
|         |    277 	this->iSampleBuffer->AddSample(memSamplerImpl.sample,length); | 
|         |    278 	 | 
|         |    279 	this->sampleNeeded = false; | 
|         |    280 	LOGSTRING("DProfilerMemSampler::Reset - exit"); | 
|         |    281 	return KErrNone; | 
|         |    282     } | 
|         |    283  | 
|         |    284 template <int BufferSize>  | 
|         |    285 TInt DProfilerMemSampler<BufferSize>::PostSample() | 
|         |    286     { | 
|         |    287     this->sampleNeeded = false; | 
|         |    288  | 
|         |    289     LOGSTRING3("DProfilerMemSampler<%d>::PostSample - state %d",BufferSize,this->iSampleBuffer->GetBufferStatus()); | 
|         |    290      | 
|         |    291 #ifdef MEM_EVENT_HANDLER | 
|         |    292     // check if all threads and chunks (and libraries) are gathered | 
|         |    293 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS | 
|         |    294     if(!memSamplerImpl.iThreadsGathered || !memSamplerImpl.iChunksGathered || !memSamplerImpl.iLibrariesGathered) | 
|         |    295 #else | 
|         |    296     if(!memSamplerImpl.iThreadsGathered || !memSamplerImpl.iChunksGathered) | 
|         |    297 #endif | 
|         |    298         { | 
|         |    299 #endif | 
|         |    300         // disable interrupts for checking the kernel containers (EChunk, EThread) | 
|         |    301 //        TInt interruptLevel(NKern::DisableInterrupts(0)); | 
|         |    302          | 
|         |    303         // first collect chunk data | 
|         |    304         TInt length(this->memSamplerImpl.SampleImpl()); | 
|         |    305         if(length != 0) | 
|         |    306             { | 
|         |    307             // then, encode the sample to the buffer until no further data available | 
|         |    308             while(length > 0) | 
|         |    309                 { | 
|         |    310                 this->iSampleBuffer->AddSample(memSamplerImpl.sample,length); | 
|         |    311                 length = this->memSamplerImpl.SampleImpl(); | 
|         |    312                  | 
|         |    313                 // indicate that the whole MEM sample ends by having a 0x00 in the end | 
|         |    314                 if(length == 0) | 
|         |    315                     { | 
|         |    316                     TUint8 number(0); | 
|         |    317                     LOGSTRING("MEM sampler PostSample - all samples generated!"); | 
|         |    318                      | 
|         |    319                     this->iSampleBuffer->AddSample(&number,1); | 
|         |    320                     LOGSTRING2("MEM sampler PostSample - end mark added, time: %d", gppSamplerData->sampleNumber); | 
|         |    321                     } | 
|         |    322                 }  | 
|         |    323             } | 
|         |    324         // restore interrupts and continue normal execution | 
|         |    325 //        NKern::RestoreInterrupts(interruptLevel); | 
|         |    326 #ifdef MEM_EVENT_HANDLER | 
|         |    327     } | 
|         |    328     // check if all threads and chunks are gathered | 
|         |    329 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS | 
|         |    330     if(memSamplerImpl.iThreadsGathered && memSamplerImpl.iChunksGathered && memSamplerImpl.iLibrariesGathered) | 
|         |    331 #else | 
|         |    332     if(memSamplerImpl.iThreadsGathered && memSamplerImpl.iChunksGathered) | 
|         |    333 #endif | 
|         |    334         { | 
|         |    335         // start memory event tracking after checking the current memory status | 
|         |    336         if(!iEventHandler->Tracking()) | 
|         |    337             { | 
|         |    338             iEventHandler->Start(); | 
|         |    339 //            Kern::Printf("DProfilerMemSampler<%d>::PostSample - memory event handler started",BufferSize); | 
|         |    340             } | 
|         |    341          | 
|         |    342         } | 
|         |    343 #endif | 
|         |    344      | 
|         |    345     LOGSTRING2("MEM sampler PostSample - finished sampling, time: %d", gppSamplerData->sampleNumber); | 
|         |    346      | 
|         |    347     // finally perform superclass postsample | 
|         |    348 	TInt i(this->DProfilerGenericSampler<BufferSize>::PostSample()); | 
|         |    349 	return i; | 
|         |    350     } | 
|         |    351  | 
|         |    352 template <int BufferSize>  | 
|         |    353 TBool DProfilerMemSampler<BufferSize>::PostSampleNeeded() | 
|         |    354     { | 
|         |    355 	LOGSTRING3("DProfilerMemSampler<%d>::PostSampleNeeded - state %d",BufferSize,this->iSampleBuffer->GetBufferStatus()); | 
|         |    356  | 
|         |    357 	TUint32 status(this->iSampleBuffer->iBufferStatus); | 
|         |    358  | 
|         |    359 	if(status == DProfilerSampleBuffer::BufferCopyAsap || status == DProfilerSampleBuffer::BufferFull || this->sampleNeeded == true) | 
|         |    360 	    { | 
|         |    361 		return true; | 
|         |    362 	    } | 
|         |    363 	 | 
|         |    364 	return false; | 
|         |    365     } | 
|         |    366  | 
|         |    367 template <int BufferSize> | 
|         |    368 void DProfilerMemSampler<BufferSize>::Sample() | 
|         |    369     { | 
|         |    370     LOGSTRING2("DProfilerMemSampler<%d>::Sample",BufferSize);	 | 
|         |    371  | 
|         |    372     // check if sample is needed, i.e. the sampling interval is met | 
|         |    373 	if(memSamplerImpl.SampleNeeded())  | 
|         |    374 	    { | 
|         |    375         // set the flag for post sampling | 
|         |    376 		this->sampleNeeded = true; | 
|         |    377  | 
|         |    378 		// start the MEM sample with the sample time | 
|         |    379 		TUint8 number(4);    // mem sampler id | 
|         |    380 		this->iSampleBuffer->AddSample(&number,1); | 
|         |    381 		this->iSampleBuffer->AddSample((TUint8*)&(gppSamplerData->sampleNumber),4); | 
|         |    382  | 
|         |    383 		// leave the rest of the processing for PostSample() | 
|         |    384 	    }	 | 
|         |    385 	 | 
|         |    386 #ifdef MEM_EVENT_HANDLER | 
|         |    387 	// call this to increase the time stamp | 
|         |    388 	else if(iEventHandler->SampleNeeded()) | 
|         |    389 	    { | 
|         |    390         // set the flag for post sampling | 
|         |    391         this->sampleNeeded = true; | 
|         |    392 	    } | 
|         |    393 	 | 
|         |    394 //	// check if time stamp is divibable with  | 
|         |    395 //	if((memSamplerImpl.iCount % KProfilerTotalMemorySamplePeriod) == 0 &&  | 
|         |    396 //	        memSamplerImpl.iCount > 0) | 
|         |    397 //	    { | 
|         |    398 //        // sample total memory once per 100 ms  | 
|         |    399 //        memSamplerImpl.EncodeTotalMemory(); | 
|         |    400 // | 
|         |    401 //        // add end mark | 
|         |    402 //        TUint8 number(0); | 
|         |    403 //        this->iSampleBuffer->AddSample(&number,1); | 
|         |    404 //	    } | 
|         |    405 #endif | 
|         |    406 	 | 
|         |    407 	LOGSTRING2("CProfilerMemSampler<%d>::Sample",BufferSize); | 
|         |    408 	return; | 
|         |    409     } | 
|         |    410  | 
|         |    411 template <int BufferSize> | 
|         |    412 DProfilerMemSampler<BufferSize>::~DProfilerMemSampler() | 
|         |    413     { | 
|         |    414 	LOGSTRING2("CProfilerMemSampler<%d>::~CProfilerMemSampler",BufferSize);		 | 
|         |    415 #ifdef MEM_EVENT_HANDLER | 
|         |    416     // memory event handler | 
|         |    417      if(iEventHandler) | 
|         |    418          { | 
|         |    419          // stop previous sampling if still running | 
|         |    420 //         Kern::Printf("Stopping DMemoryEventHandler"); | 
|         |    421          iEventHandler->Stop(); | 
|         |    422          iEventHandler->Close(); | 
|         |    423          iEventHandler = NULL; | 
|         |    424          } | 
|         |    425 #endif | 
|         |    426     } | 
|         |    427 #endif |