os/kernelhwsrv/kerneltest/e32utils/trace/btrace_analyse.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2007-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 //
    15 
    16 #if defined(__EPOC32__) || defined(__WINS__)
    17 // compiling for Symbian OS...
    18 #include <e32std.h>
    19 #include <e32std_private.h>
    20 #include <e32svr.h>
    21 #include <e32def.h>
    22 #include <e32def_private.h>
    23 #include <d32btrace.h>
    24 #include "e32btrace.h"
    25 
    26 inline void* malloc(TInt aSize) { return User::Alloc(aSize); }
    27 inline void* realloc(void* aPtr,TInt aSize) { return User::ReAlloc(aPtr,aSize); }
    28 inline void free(void* aPtr) { User::Free(aPtr); }
    29 
    30 TUint8 PrintfBuffer[256];
    31 TUint PrintfBufferWidth = 0;
    32 
    33 static void printf(const char* aFormat,...)
    34 	{
    35 	VA_LIST list;
    36 	VA_START(list,aFormat);
    37 	TPtrC8 format((const TUint8*)aFormat);
    38 	TPtr8 buf(PrintfBuffer+PrintfBufferWidth,sizeof(PrintfBuffer)-PrintfBufferWidth);
    39 	buf.AppendFormatList(format,list);
    40 	PrintfBufferWidth += buf.Size();
    41 	for(;;)
    42 		{
    43 		TUint width = 0;
    44 		for(;;)
    45 			{
    46 			if(width>=PrintfBufferWidth)
    47 				return;
    48 			if(PrintfBuffer[width]=='\n')
    49 				break;
    50 			++width;
    51 			}
    52 		TPtrC8 line(PrintfBuffer,width);
    53 		++width;
    54 		RDebug::RawPrint(line);
    55 		_LIT(KLineEnd,"\r\n");
    56 		RDebug::RawPrint(KLineEnd);
    57 		memcpy(PrintfBuffer,PrintfBuffer+width,PrintfBufferWidth-width);
    58 		PrintfBufferWidth -= width;
    59 		}
    60 	}
    61 
    62 typedef TUint uintptr_t;
    63 
    64 #ifndef ASSERT
    65 #define ASSERT(c) (void)((c)||(AssertFailed(__LINE__)))
    66 TInt AssertFailed(TInt aLine)
    67 	{
    68 	_LIT(KPanicCategory,"BTRACE-ANALYSE");
    69 	User::Panic(KPanicCategory,aLine);
    70 	return 0;
    71 	}
    72 #endif // ASSERT
    73 
    74 
    75 //
    76 //	Trace buffer helper functions - for use on target only
    77 //
    78 RBTrace Trace;
    79 TUint8* AnalyseData;
    80 TUint AnalyseDataRemain = 0;
    81 
    82 void RePrime()
    83 	{
    84 	for(TInt i=0; i<256; ++i)
    85 		{
    86 		if(Trace.Filter(i))
    87 			{
    88 			// toggle filter to force a prime
    89 			Trace.SetFilter(i,0);
    90 			Trace.SetFilter(i,1);
    91 			}
    92 		}
    93 	}
    94 
    95 TUint AnalyseStream(TAny* aBuffer, TUint aMaxSize)
    96 	{
    97 	TUint size = AnalyseDataRemain;
    98 	if(!size)
    99 		{
   100 		Trace.DataUsed();
   101 		AnalyseDataRemain = Trace.GetData(AnalyseData);
   102 		size = AnalyseDataRemain;
   103 		}
   104 	if(size>aMaxSize)
   105 		size = aMaxSize;
   106 	memcpy(aBuffer,AnalyseData,size);
   107 	AnalyseData += size;
   108 	AnalyseDataRemain -= size;
   109 	return size;
   110 	}
   111 
   112 void ProcessAllTrace(TUint (*aInput)(TAny* aBuffer, TUint aMaxSize),TInt aReportLevel);
   113 
   114 void DoAnalyse(TInt aAnalysisLevel)
   115 	{
   116 	AnalyseDataRemain = 0;
   117 	TUint oldMode = Trace.Mode();
   118 	Trace.SetMode(0); // turn off trace capture while we dump
   119 	ProcessAllTrace(AnalyseStream, aAnalysisLevel);
   120 	Trace.SetMode(oldMode);
   121 	RePrime();
   122 	}
   123 
   124 TInt BTraceAnalyseSetup()
   125 	{
   126 	TInt r = Trace.Open();
   127 	if (r != KErrNone)
   128 		{
   129 		return r;
   130 		}
   131 	// Stop tracing
   132 	TUint oldMode = Trace.Mode();
   133 	Trace.SetMode(0);
   134 
   135 	// empty btrace buffer and reprime it
   136 	Trace.Empty();
   137 	Trace.SetMode(oldMode);
   138 	RePrime();
   139 	return KErrNone;
   140 	}
   141 
   142 void BTraceAnalyseEnd()
   143 	{
   144 	Trace.Close();
   145 	}
   146 
   147 void BTraceAnalyse(TInt aAnalysisLevel)
   148 	{
   149 	// Stop tracing
   150 	TUint oldMode = Trace.Mode();
   151 	Trace.SetMode(0);
   152 
   153 	AnalyseDataRemain = 0;
   154 	ProcessAllTrace(AnalyseStream, aAnalysisLevel);
   155 
   156 	// empty btrace buffer and reprime it
   157 	Trace.Empty();
   158 	Trace.SetMode(oldMode);
   159 	RePrime();
   160 	}
   161 
   162 #else
   163 // compiling for host...
   164 
   165 #include <stdio.h>
   166 #include <string.h>
   167 #include <malloc.h>
   168 
   169 #if defined(_MSC_VER)
   170 typedef __int64 longlong;
   171 typedef unsigned __int64 ulonglong;
   172 #define BREAKPOINT { _asm int 3 }			/**< Invoke debugger */
   173 #else
   174 typedef long long longlong;
   175 typedef long long ulonglong;
   176 #define BREAKPOINT
   177 #endif
   178 
   179 typedef signed char			TInt8;
   180 typedef unsigned char		TUint8;
   181 typedef unsigned short		TUint16;
   182 typedef unsigned int		TUint32;
   183 typedef ulonglong			TUint64;
   184 typedef unsigned int		uintptr_t;
   185 typedef int					TInt;
   186 typedef unsigned			TUint;
   187 typedef int					TBool;
   188 typedef void				TAny;
   189 typedef float				TReal;
   190 #define IMPORT_C
   191 #include "e32btrace.h"
   192 
   193 #define ASSERT(c) (void)((c)||(AssertFailed(__LINE__)))
   194 extern "C" void exit(int);
   195 TInt AssertFailed(TInt aLine)
   196 	{
   197 	fprintf(stderr,"Panic: BTRACE-ANALYSE %d",aLine);
   198 	BREAKPOINT;
   199 	exit(2);
   200 	return 0;
   201 	}
   202 
   203 #define __UHEAP_MARK
   204 #define __UHEAP_MARKEND
   205 
   206 TAny* operator new(size_t, TAny* p) {return p;}
   207 
   208 #endif // SYMBIAN_OS
   209 
   210 
   211 
   212 //
   213 // Global data
   214 //
   215 
   216 TInt ReportLevel = 0;
   217 TUint8 TraceBuffer[0x10000];
   218 TUint TraceBufferSize = 0;
   219 TUint64	Timestamp = 0;
   220 TUint64	TimestampBase = 0;
   221 TUint32	TraceRecordId = 0;
   222 TUint32	TimestampPeriod = 0;
   223 TUint32	Timestamp2Period = 0;
   224 TBool Timestamp64Bit = 0;
   225 TUint TraceFormatErrors = 0;
   226 TBool TraceBufferFilled = false;
   227 TBool SMP = true;
   228 TBool ErrorOnThisTrace = false;
   229 
   230 const TUint8 KJunkTraceSubcategory = 255; // Dummy sub-category for EMetaTrace
   231 
   232 const TInt KMaxCpus = 8;
   233 
   234 //
   235 // Utilities
   236 //
   237 
   238 void ToHex(TUint8* aString,TUint32 aValue)
   239 	{
   240 	TUint i=32;
   241 	do
   242 		{
   243 		i -= 4;
   244 		TUint8 c = (TUint8)((aValue>>i)&0xf);
   245 		if(c>=10)
   246 			c += 'a'-10;
   247 		else
   248 			c += '0';
   249 		*aString++ = c;
   250 		}
   251 	while(i);
   252 	}
   253 
   254 
   255 TUint MakeName(TUint8* aString,const char* aName,TUint32 aHexValue)
   256 	{
   257 	TUint8* start = aString;
   258 	for(;;)
   259 		{
   260 		TUint8 c = *aName++;
   261 		if(!c)
   262 			break;
   263 		*aString++ = c;
   264 		}
   265 	ToHex(aString,aHexValue);
   266 	aString[8] = 0;
   267 	return aString-start+8;
   268 	}
   269 
   270 
   271 /**
   272 Convert a timestamp into real time units (micro-seconds)
   273 */
   274 TUint32 Time(TUint64 aTimestamp)
   275 	{
   276 	if(!TimestampPeriod)
   277 		return (TUint32)aTimestamp;
   278 	TInt exponent = (TInt8)(TimestampPeriod>>24);
   279 	TUint64 mantissa = TimestampPeriod&0xffffff;
   280 	aTimestamp *= mantissa;
   281 	exponent += 32;
   282 	if(exponent<0)
   283 		aTimestamp >>= -exponent;
   284 	else
   285 		aTimestamp <<= exponent;
   286 	TUint64 timeLo = (aTimestamp&0xffffffffu)*1000000;
   287 	TUint64 timeHi = (aTimestamp>>32)*1000000;
   288 	TUint64 us = timeHi+(timeLo>>32)+((timeLo>>31)&1);
   289 	return TUint32(us);
   290 	}
   291 
   292 
   293 void ReportTimeUnits()
   294 	{
   295 	if(!TimestampPeriod)
   296 		printf("\nAll times are given in BTrace Timestamp1 units.\n\n");
   297 	else
   298 		{
   299 		TInt exponent = (TInt8)(TimestampPeriod>>24);
   300 		TUint64 mantissa = TimestampPeriod&0xffffff;
   301 		TUint64 period = 1000000;
   302 		period *= mantissa;
   303 		exponent += 32;
   304 		if(exponent<0)
   305 			period >>= -exponent;
   306 		else
   307 			period <<= exponent;
   308 		printf("\nAll times are given in microseconds, resolution %d.%03dus\n\n",(int)TUint32(period>>32),(int)TUint32((((period&0xffffffffu)*1000)+0x80000000u)>>32));
   309 		}
   310 	}
   311 
   312 
   313 TUint SetBits(TUint8* aData, TUint aOffset, TUint aSize)
   314 	{
   315 	TUint mask = 1<<(aOffset&7);
   316 	TUint8* data = aData+(aOffset>>3);
   317 	TUint errors = 0;
   318 	while(aSize)
   319 		{
   320 		if(*data&mask)
   321 			++errors;
   322 		*data |= (TUint8)mask;
   323 		mask <<= 1;
   324 		if(mask>0xFF)
   325 			{
   326 			mask = 0x01;
   327 			++data;
   328 			}
   329 		--aSize;
   330 		}
   331 	return errors;
   332 	}
   333 
   334 
   335 TUint ClearBits(TUint8* aData, TUint aOffset, TUint aSize)
   336 	{
   337 	TUint mask = 1<<(aOffset&7);
   338 	TUint8* data = aData+(aOffset>>3);
   339 	TUint errors = 0;
   340 	while(aSize)
   341 		{
   342 		if(!(*data&mask))
   343 			++errors;
   344 		*data &= (TUint8)~mask;
   345 		mask <<= 1;
   346 		if(mask>0xFF)
   347 			{
   348 			mask = 0x01;
   349 			++data;
   350 			}
   351 		--aSize;
   352 		}
   353 	return errors;
   354 	}
   355 
   356 
   357 void WarnIfError(TUint aErrorCount)
   358 	{
   359 	if (TraceBufferFilled)
   360 		printf("WARNING - BTRACE BUFFER IS FULL SO TRACE DATA MAY BE INCOMPLETE\n");
   361 
   362 	if(aErrorCount==0 && TraceFormatErrors==0)
   363 		return;
   364 	printf("CONSISTENCY ERRORS FOUND DURING TRACE ANALYSIS, RESULTS ARE UNRELIABLE!\n");
   365 	}
   366 
   367 
   368 #define CHECK_TRACE_DATA_WORDS(numWords)	\
   369 	if(aTrace.iDataSize<numWords*4 && ++TraceFormatErrors) return
   370 
   371 
   372 //
   373 // Category naming
   374 //
   375 
   376 const char* const UnknownNames[256] =
   377 	{
   378 	"?00","?01","?02","?03","?04","?05","?06","?07","?08","?09",
   379 	"?10","?11","?12","?13","?14","?15","?16","?17","?18","?19",
   380 	"?20","?21","?22","?23","?24","?25","?26","?27","?28","?29",
   381 	"?30","?31","?32","?33","?34","?35","?36","?37","?38","?39",
   382 	"?40","?41","?42","?43","?44","?45","?46","?47","?48","?49",
   383 	"?50","?51","?52","?53","?54","?55","?56","?57","?58","?59",
   384 	"?60","?61","?62","?63","?64","?65","?66","?67","?68","?69",
   385 	"?70","?71","?72","?73","?74","?75","?76","?77","?78","?79",
   386 	"?80","?81","?82","?83","?84","?85","?86","?87","?88","?89",
   387 	"?90","?91","?92","?93","?94","?95","?96","?97","?98","?99",
   388 	"?100","?101","?102","?103","?104","?105","?106","?107","?108","?109",
   389 	"?110","?111","?112","?113","?114","?115","?116","?117","?118","?119",
   390 	"?120","?121","?122","?123","?124","?125","?126","?127","?128","?129",
   391 	"?130","?131","?132","?133","?134","?135","?136","?137","?138","?139",
   392 	"?140","?141","?142","?143","?144","?145","?146","?147","?148","?149",
   393 	"?150","?151","?152","?153","?154","?155","?156","?157","?158","?159",
   394 	"?160","?161","?162","?163","?164","?165","?166","?167","?168","?169",
   395 	"?170","?171","?172","?173","?174","?175","?176","?177","?178","?179",
   396 	"?180","?181","?182","?183","?184","?185","?186","?187","?188","?189",
   397 	"?190","?191","?192","?193","?194","?195","?196","?197","?198","?199",
   398 	"?200","?201","?202","?203","?204","?205","?206","?207","?208","?209",
   399 	"?210","?211","?212","?213","?214","?215","?216","?217","?218","?219",
   400 	"?220","?221","?222","?223","?224","?225","?226","?227","?228","?229",
   401 	"?230","?231","?232","?233","?234","?235","?236","?237","?238","?239",
   402 	"?240","?241","?242","?243","?244","?245","?246","?247","?248","?249",
   403 	"?250","?251","?252","?253","?254","?255"
   404 	};
   405 
   406 
   407 #define STRINGIFY2(a) #a						/**< Helper for #STRINGIFY */
   408 #define STRINGIFY(a) STRINGIFY2(a)				/**< Convert \a a into a quoted string */
   409 #define CASE_CAT_NAME(name) case BTrace::name: return STRINGIFY(name)
   410 
   411 const char* CategoryName(TUint8 aCategory)
   412 	{
   413 	switch((BTrace::TCategory)aCategory)
   414 		{
   415 		CASE_CAT_NAME(ERDebugPrintf);
   416 		CASE_CAT_NAME(EKernPrintf);
   417 		CASE_CAT_NAME(EPlatsecPrintf);
   418 		case BTrace::EThreadIdentification: return "EThreadId"; //	CASE_CAT_NAME(EThreadIdentification)
   419 		CASE_CAT_NAME(ECpuUsage);
   420     	CASE_CAT_NAME(EKernPerfLog);
   421     	CASE_CAT_NAME(EClientServer);
   422     	CASE_CAT_NAME(ERequests);
   423     	CASE_CAT_NAME(EChunks);
   424     	CASE_CAT_NAME(ECodeSegs);
   425 		CASE_CAT_NAME(EPaging);
   426 		CASE_CAT_NAME(EThreadPriority);
   427 		CASE_CAT_NAME(EPagingMedia);
   428 		CASE_CAT_NAME(EKernelMemory);
   429 		CASE_CAT_NAME(EHeap);
   430 		CASE_CAT_NAME(EMetaTrace);
   431 
   432 		CASE_CAT_NAME(EFastMutex);
   433 		CASE_CAT_NAME(EProfiling);
   434 		CASE_CAT_NAME(ESymbianKernelSync);
   435 		CASE_CAT_NAME(EFlexibleMemModel);
   436 		CASE_CAT_NAME(ETest1);
   437 		CASE_CAT_NAME(ETest2);
   438 		default:
   439 			break;
   440 		}
   441 	return UnknownNames[aCategory];
   442 	}
   443 
   444 const char* SubCategoryName(TUint8 aCategory, TUint8 aSubCategory)
   445 	{
   446 	switch(aCategory)
   447 		{
   448 	case BTrace::ERDebugPrintf:
   449 	case BTrace::EKernPrintf:
   450 	case BTrace::EPlatsecPrintf:
   451 		return ""; // no subcategories for these
   452 
   453 	case BTrace::EThreadIdentification:
   454 		switch((BTrace::TThreadIdentification)aSubCategory)
   455 			{
   456 		CASE_CAT_NAME(ENanoThreadCreate);
   457 		CASE_CAT_NAME(ENanoThreadDestroy);
   458 		CASE_CAT_NAME(EThreadCreate);
   459 		CASE_CAT_NAME(EThreadDestroy);
   460 		CASE_CAT_NAME(EThreadName);
   461 		CASE_CAT_NAME(EProcessName);
   462 		CASE_CAT_NAME(EThreadId);
   463 		CASE_CAT_NAME(EProcessCreate);
   464 		CASE_CAT_NAME(EProcessDestroy);
   465 			}
   466 		break;
   467 
   468 	case BTrace::ECpuUsage:
   469 		switch((BTrace::TCpuUsage)aSubCategory)
   470 			{
   471 		CASE_CAT_NAME(EIrqStart);
   472 		CASE_CAT_NAME(EIrqEnd);
   473 		CASE_CAT_NAME(EFiqStart);
   474 		CASE_CAT_NAME(EFiqEnd);
   475 		CASE_CAT_NAME(EIDFCStart);
   476 		CASE_CAT_NAME(EIDFCEnd);
   477 		CASE_CAT_NAME(ENewThreadContext);
   478 			}
   479 		break;
   480 
   481 	case BTrace::EChunks:
   482 		switch((BTrace::TChunks)aSubCategory)
   483 			{
   484 		CASE_CAT_NAME(EChunkCreated);
   485 		CASE_CAT_NAME(EChunkInfo);
   486 		CASE_CAT_NAME(EChunkDestroyed);
   487 		CASE_CAT_NAME(EChunkMemoryAllocated);
   488 		CASE_CAT_NAME(EChunkMemoryDeallocated);
   489 		CASE_CAT_NAME(EChunkMemoryAdded);
   490 		CASE_CAT_NAME(EChunkMemoryRemoved);
   491 		CASE_CAT_NAME(EChunkOwner);
   492 			}
   493 		break;
   494 
   495 	case BTrace::ECodeSegs:
   496 		switch((BTrace::TCodeSegs)aSubCategory)
   497 			{
   498 		CASE_CAT_NAME(ECodeSegCreated);
   499 		CASE_CAT_NAME(ECodeSegInfo);
   500 		CASE_CAT_NAME(ECodeSegDestroyed);
   501 		CASE_CAT_NAME(ECodeSegMapped);
   502 		CASE_CAT_NAME(ECodeSegUnmapped);
   503 		CASE_CAT_NAME(ECodeSegMemoryAllocated);
   504 		CASE_CAT_NAME(ECodeSegMemoryDeallocated);
   505 			}
   506 		break;
   507 		
   508 	case BTrace::EPaging:
   509 		switch((BTrace::TPaging)aSubCategory)
   510 			{
   511 		CASE_CAT_NAME(EPagingPageInBegin);
   512 		CASE_CAT_NAME(EPagingPageInUnneeded);
   513 		CASE_CAT_NAME(EPagingPageInROM);
   514 		CASE_CAT_NAME(EPagingPageOutROM);
   515 		CASE_CAT_NAME(EPagingPageInFree);
   516 		CASE_CAT_NAME(EPagingPageOutFree);
   517 		CASE_CAT_NAME(EPagingRejuvenate);
   518 		CASE_CAT_NAME(EPagingPageNop);
   519 		CASE_CAT_NAME(EPagingPageLock);
   520 		CASE_CAT_NAME(EPagingPageUnlock);
   521 		CASE_CAT_NAME(EPagingPageOutCache);
   522 		CASE_CAT_NAME(EPagingPageInCode);
   523 		CASE_CAT_NAME(EPagingPageOutCode);
   524 		CASE_CAT_NAME(EPagingMapCode);
   525 		CASE_CAT_NAME(EPagingAged);
   526 		CASE_CAT_NAME(EPagingDecompressStart);
   527 		CASE_CAT_NAME(EPagingDecompressEnd);
   528 		CASE_CAT_NAME(EPagingMemoryModel);
   529 		CASE_CAT_NAME(EPagingChunkDonatePage);
   530 		CASE_CAT_NAME(EPagingChunkReclaimPage);
   531 		CASE_CAT_NAME(EPagingPageIn);
   532 		CASE_CAT_NAME(EPagingPageOut);
   533 		CASE_CAT_NAME(EPagingMapPage);
   534 		CASE_CAT_NAME(EPagingDonatePage);
   535 		CASE_CAT_NAME(EPagingReclaimPage);
   536 		CASE_CAT_NAME(EPagingAgedClean);
   537 		CASE_CAT_NAME(EPagingAgedDirty);
   538 		CASE_CAT_NAME(EPagingPageTableAlloc);
   539 			}
   540 		break;
   541 
   542 	case BTrace::EKernelMemory:
   543 		switch((BTrace::TKernelMemory)aSubCategory)
   544 			{
   545 		CASE_CAT_NAME(EKernelMemoryInitialFree);
   546 		CASE_CAT_NAME(EKernelMemoryCurrentFree);
   547 		CASE_CAT_NAME(EKernelMemoryMiscAlloc);
   548 		CASE_CAT_NAME(EKernelMemoryMiscFree);
   549 		CASE_CAT_NAME(EKernelMemoryDemandPagingCache);
   550 		CASE_CAT_NAME(EKernelMemoryDrvPhysAlloc);
   551 		CASE_CAT_NAME(EKernelMemoryDrvPhysFree);
   552 			}
   553 		break;
   554 
   555 	case BTrace::EMetaTrace:
   556 		{
   557 		if(aSubCategory==KJunkTraceSubcategory)
   558 			return "*JUNK*";
   559 		else
   560 			{
   561 			switch((BTrace::TMetaTrace)aSubCategory)
   562 				{
   563 			CASE_CAT_NAME(EMetaTraceTimestampsInfo);
   564 			CASE_CAT_NAME(EMetaTraceMeasurementStart);
   565 			CASE_CAT_NAME(EMetaTraceMeasurementEnd);
   566 			CASE_CAT_NAME(EMetaTraceFilterChange);
   567 				}
   568 			}
   569 		}
   570 		break;
   571 
   572 	case BTrace::EFastMutex:
   573 		switch((BTrace::TFastMutex)aSubCategory)
   574 			{
   575 		CASE_CAT_NAME(EFastMutexWait);
   576 		CASE_CAT_NAME(EFastMutexSignal);
   577 		CASE_CAT_NAME(EFastMutexFlash);
   578 		CASE_CAT_NAME(EFastMutexName);
   579 		CASE_CAT_NAME(EFastMutexBlock);
   580 			}
   581 		break;
   582 
   583 	case BTrace::EProfiling:
   584 		switch((BTrace::TProfiling)aSubCategory)
   585 			{
   586 		CASE_CAT_NAME(ECpuFullSample);
   587 		CASE_CAT_NAME(ECpuOptimisedSample);
   588 		CASE_CAT_NAME(ECpuIdfcSample);
   589 		CASE_CAT_NAME(ECpuNonSymbianThreadSample);
   590 			}
   591 		break;
   592 
   593 	case BTrace::ESymbianKernelSync:
   594 		switch((BTrace::TSymbianKernelSync)aSubCategory)
   595 			{
   596 		CASE_CAT_NAME(ESemaphoreCreate);
   597 		CASE_CAT_NAME(ESemaphoreDestroy);
   598 		CASE_CAT_NAME(ESemaphoreAcquire);
   599 		CASE_CAT_NAME(ESemaphoreRelease);
   600 		CASE_CAT_NAME(ESemaphoreBlock);
   601 		CASE_CAT_NAME(EMutexCreate);
   602 		CASE_CAT_NAME(EMutexDestroy);
   603 		CASE_CAT_NAME(EMutexAcquire);
   604 		CASE_CAT_NAME(EMutexRelease);
   605 		CASE_CAT_NAME(EMutexBlock);
   606 		CASE_CAT_NAME(ECondVarCreate);
   607 		CASE_CAT_NAME(ECondVarDestroy);
   608 		CASE_CAT_NAME(ECondVarBlock);
   609 		CASE_CAT_NAME(ECondVarWakeUp);
   610 		CASE_CAT_NAME(ECondVarSignal);
   611 		CASE_CAT_NAME(ECondVarBroadcast);
   612 			}
   613 		break;
   614 
   615 	case BTrace::EFlexibleMemModel:
   616 		switch((BTrace::TFlexibleMemModel)aSubCategory)
   617 			{
   618 		CASE_CAT_NAME(EMemoryObjectCreate);
   619 		CASE_CAT_NAME(EMemoryObjectDestroy);
   620 		CASE_CAT_NAME(EMemoryMappingCreate);
   621 		CASE_CAT_NAME(EMemoryMappingDestroy);
   622 		CASE_CAT_NAME(EMemoryObjectIsChunk);
   623 		CASE_CAT_NAME(EMemoryObjectIsCodeSeg);
   624 		CASE_CAT_NAME(EMemoryObjectIsProcessStaticData);
   625 		CASE_CAT_NAME(EMemoryObjectIsDllStaticData);
   626 		CASE_CAT_NAME(EMemoryObjectIsSupervisorStack);
   627 		CASE_CAT_NAME(EMemoryObjectIsUserStack);
   628 		CASE_CAT_NAME(EAddressSpaceId);
   629 			}
   630 		break;
   631 
   632 		}
   633 	return UnknownNames[aSubCategory];
   634 	}
   635 
   636 
   637 
   638 //
   639 // Data structures
   640 //
   641 
   642 enum TDataType
   643 	{
   644 	EDataTypeNone = 0,
   645 	EDataTypeText,
   646 	EDataTypeObject,
   647 	};
   648 
   649 class Thread;
   650 class Cpu;
   651 
   652 struct TraceHeader
   653 	{
   654 	TUint8	iCpuNum;
   655 	TUint8	iCategory;
   656 	TUint8	iSubCategory;
   657 	TUint8	iFlags;
   658 	TUint32	iHeader2;
   659 	TUint64	iTimestamp;
   660 	TUint32	iTimestamp2;
   661 	Thread*	iContextID;
   662 	TUint32	iPC;
   663 	TUint32	iExtra;
   664 	TUint8	iDataTypes[4];
   665 	TUint32	iCalculatedData[2];
   666 	TUint	iDataSize;
   667 	Cpu*	iCpu;
   668 	TUint32	iError;
   669 	};
   670 
   671 
   672 struct TraceRecord : public TraceHeader
   673 	{
   674 	TUint32 iData[(8+KMaxBTraceDataArray)/4];
   675 	};
   676 
   677 
   678 
   679 //
   680 // ECpuUsage traces
   681 //
   682 
   683 enum TContext
   684 	{
   685 	EContextThread,
   686 	EContextFiq,
   687 	EContextIrq,
   688 	EContextIDFC,
   689 	EContextUnknown
   690 	};
   691 
   692 class Cpu
   693 	{
   694 public:
   695 	Cpu();
   696 	void ChangeContext(TContext aType, Thread* aThread=0);
   697 	void Reset();
   698 
   699 	TContext	iCurrentContext;
   700 	TInt		iFiqNest;
   701 	TInt		iIrqNest;
   702 	TInt		iIDFCNest;
   703 	TUint64		iFiqTime;
   704 	TUint64		iIrqTime;
   705 	TUint64		iIDFCTime;
   706 	Thread*		iCurrentThread;
   707 	TUint64		iBaseTimestamp;
   708 	};
   709 
   710 //
   711 // Objects
   712 //
   713 
   714 const TUint KMaxTraceNameLength = 10;
   715 
   716 class Object
   717 	{
   718 public:
   719 	Object(TUint32 aTraceId, const char* aTraceNamePrefix)
   720 		: iTraceId(aTraceId), iIndex(~0u), iOwner(0), iOwnerTraceId(0), iAlive(1), iNameSet(false), iNameLength(0),
   721 		  iTraceNamePrefix(aTraceNamePrefix)
   722 		{
   723 		iName[0] = 0;
   724 		}
   725 
   726 	void Destroy()
   727 		{
   728 		if(iAlive)
   729 			--iAlive;
   730 		if(iOwnerTraceId && !iOwner)
   731 			--UnknownOwners;
   732 		}
   733 
   734 	virtual ~Object()
   735 		{}
   736 
   737 	void SetName(void* aName, TUint aLength)
   738 		{
   739 		ASSERT(aLength<sizeof(iName));
   740 		iNameLength = (TUint8)aLength;
   741 		memcpy(iName,aName,aLength);
   742 		iName[aLength] = 0;
   743 		iNameSet = true;
   744 		}
   745 
   746 	void SetName(TraceRecord& aTrace, TUint aIndex)
   747 		{
   748 		SetName(aTrace.iData+aIndex,aTrace.iDataSize-aIndex*4);
   749 		aTrace.iDataTypes[aIndex] = EDataTypeText;
   750 		}
   751 
   752 	TBool IsName(void* aName, TUint aLength)
   753 		{
   754 		if(aLength!=iNameLength)
   755 			return false;
   756 		while(aLength--)
   757 			if(iName[aLength]!=((TUint8*)aName)[aLength])
   758 				return false;
   759 		return true;
   760 		}
   761 
   762 	typedef TUint8 TraceNameBuf[KMaxTraceNameLength+1];
   763 	typedef TUint8 FullNameBuf[KMaxBTraceDataArray+2+KMaxBTraceDataArray+2+KMaxBTraceDataArray+1]; // space for name1::name2::name3[tracename]
   764 	typedef TUint8 FullTraceNameBuf[KMaxBTraceDataArray+1+KMaxBTraceDataArray+2+KMaxBTraceDataArray+KMaxTraceNameLength+1+1]; // space for [tracename]'name1::name2::name3'
   765 
   766 	TUint FullName(FullNameBuf& aName)
   767 		{
   768 		TUint length = 0;
   769 		if(iOwner)
   770 			{
   771 			if(iOwner->iOwner)
   772 				{
   773 				memcpy(aName+length,iOwner->iOwner->iName,iOwner->iOwner->iNameLength);
   774 				length += iOwner->iOwner->iNameLength;
   775 				aName[length++] = ':';
   776 				aName[length++] = ':';
   777 				}
   778 			memcpy(aName+length,iOwner->iName,iOwner->iNameLength);
   779 			length += iOwner->iNameLength;
   780 			aName[length++] = ':';
   781 			aName[length++] = ':';
   782 			}
   783 		memcpy(aName+length,iName,iNameLength);
   784 		length += iNameLength;
   785 		aName[length] = 0;
   786 		return length;
   787 		}
   788 
   789 	TUint TraceName(TraceNameBuf& aName)
   790 		{
   791 		TInt i = 0;
   792 		const TUint KNumDigits = KMaxTraceNameLength-4;
   793 		aName[i++] = '<';
   794 		const char* prefix = iTraceNamePrefix;
   795 		if(prefix[0])
   796 			aName[i++] = *prefix++;
   797 		if(prefix[0])
   798 			aName[i++] = *prefix++;
   799 		TUint n = iIndex;
   800 		for(TUint d=KNumDigits; d>0; --d)
   801 			{
   802 			aName[i+d-1] = TUint8('0'+(n%10));
   803 			n /= 10;
   804 			}
   805 		i += KNumDigits;
   806 		aName[i++] = '>';
   807 		aName[i] = 0;
   808 		return i;
   809 		}
   810 
   811 	TUint FullTraceName(FullTraceNameBuf& aName)
   812 		{
   813 		TUint l1 = TraceName(*(TraceNameBuf*)aName);
   814 		aName[l1++] = '\'';
   815 		TUint l2 = FullName(*(FullNameBuf*)(aName+l1));
   816 		aName[l1+l2++] = '\'';
   817 		aName[l1+l2] = 0;
   818 		return l1+l2;
   819 		}
   820 
   821 public:
   822 	TUint32 iTraceId;					///< ID for object as found in raw trace data.
   823 	TUint iIndex;						///< Index into container for this object.
   824 	Object* iOwner;						///< Object which 'owns' this one, e.g. process which owns a thread.
   825 	TUint32 iOwnerTraceId;				///< Trace ID for owner if owner object as yet unknown
   826 	TUint8 iAlive;						///< True if object destroyed trace not yet parsed.
   827 	TUint8 iNameSet;					///< True if name has been set.
   828 	TUint8 iNameLength;				
   829 	TUint8 iName[KMaxBTraceDataArray+1];	
   830 	const char* iTraceNamePrefix;
   831 public:
   832 	static TUint32 UnknownOwners;
   833 	};
   834 TUint32 Object::UnknownOwners = 0;
   835 
   836 
   837 class ObjectContainer
   838 	{
   839 public:
   840 	ObjectContainer()
   841 		: iNumEntries(0), iEntriesLength(0) , iEntries(0)
   842 		{
   843 		iLink = iAllContainers;
   844 		iAllContainers = this;
   845 		}
   846 
   847 	static void Reset()
   848 		{
   849 		ObjectContainer* container = iAllContainers;
   850 		while(container)
   851 			{
   852 			TUint i = container->iNumEntries;
   853 			while(i--)
   854 				free(container->iEntries[i].iItem);
   855 			free(container->iEntries);
   856 			container->iEntries = 0;
   857 			container->iNumEntries = 0;
   858 			container->iEntriesLength = 0;
   859 			container = container->iLink;
   860 			}
   861 		}
   862 
   863 	void Add(Object* aObject)
   864 		{
   865 		if(iNumEntries>=iEntriesLength)
   866 			{
   867 			iEntriesLength += 128;
   868 			iEntries = (Entry*)realloc(iEntries,iEntriesLength*sizeof(Entry));
   869 			ASSERT(iEntries);
   870 			}
   871 		aObject->iIndex = iNumEntries;
   872 		Entry& entry = iEntries[iNumEntries++];
   873 		entry.iTraceId = aObject->iTraceId;
   874 		entry.iItem = aObject;
   875 		}
   876 
   877 	TUint Count()
   878 		{
   879 		return iNumEntries;
   880 		}
   881 
   882 	Object* operator[](TInt aIndex)
   883 		{
   884 		if(TUint(aIndex)<iNumEntries)
   885 			return iEntries[aIndex].iItem;
   886 		ASSERT(0);
   887 		return 0;
   888 		}
   889 
   890 	Object* Find(TUint32 aTraceId)
   891 		{
   892 		Entry* ptr = iEntries+iNumEntries;
   893 		Entry* end = iEntries;
   894 		while(ptr>end)
   895 			{
   896 			--ptr;
   897 			if(ptr->iTraceId==aTraceId)
   898 				{
   899 				if(ptr->iItem->iAlive)
   900 					return ptr->iItem;
   901 				else
   902 					break;
   903 				}
   904 			}
   905 		return 0;
   906 		}
   907 private:
   908 	struct Entry
   909 		{
   910 		TUint32 iTraceId;
   911 		Object* iItem;
   912 		};
   913 	TUint iNumEntries;
   914 	TUint iEntriesLength;
   915 	Entry* iEntries;
   916 	ObjectContainer* iLink;
   917 
   918 	static ObjectContainer* iAllContainers;
   919 	};
   920 ObjectContainer* ObjectContainer::iAllContainers = 0;
   921 
   922 
   923 #define GENERIC_OBJECT_DEFINITIONS(C)							\
   924 																\
   925 	static C* Find(TUint32 aTraceId)							\
   926 		{														\
   927 		return (C*)iContainer.Find(aTraceId);					\
   928 		}														\
   929 																\
   930 	static C* Create(TraceRecord& aTrace, TUint aIndex)			\
   931 		{														\
   932 		TUint32 traceId = aTrace.iData[aIndex];					\
   933 		C* object = new C(traceId);								\
   934 		aTrace.iDataTypes[aIndex] = EDataTypeObject;			\
   935 		aTrace.iData[aIndex] = (uintptr_t)object;				\
   936 		return object;											\
   937 		}														\
   938 																\
   939 	static C* Find(TraceRecord& aTrace, TUint aIndex)			\
   940 		{														\
   941 		TUint32 traceId = aTrace.iData[aIndex];					\
   942 		C* object = Find(traceId);								\
   943 		if(!object)												\
   944 			return 0;											\
   945 		aTrace.iDataTypes[aIndex] = EDataTypeObject;			\
   946 		aTrace.iData[aIndex] = (uintptr_t)object;				\
   947 		return object;											\
   948 		}														\
   949 																\
   950 	static C* FindOrCreate(TraceRecord& aTrace, TUint aIndex)	\
   951 		{														\
   952 		C* object = Find(aTrace,aIndex);						\
   953 		if(!object)												\
   954 			object = Create(aTrace,aIndex);						\
   955 		return object;											\
   956 		}
   957 
   958 
   959 
   960 //
   961 // Process
   962 //
   963 
   964 class Process : public Object
   965 	{
   966 public:
   967 	Process(TUint32 aTraceId)
   968 		: Object(aTraceId,"P"), iThreadCount(0), iMaxThreadCount(0)
   969 		{
   970 		iContainer.Add(this);
   971 		}
   972 
   973 	GENERIC_OBJECT_DEFINITIONS(Process);
   974 
   975 public:
   976 	TUint iThreadCount;
   977 	TUint iMaxThreadCount;
   978 
   979 	static ObjectContainer iContainer;
   980 	};
   981 ObjectContainer Process::iContainer;
   982 
   983 
   984 
   985 //
   986 // Thread
   987 //
   988 class FastMutex;
   989 class Thread : public Object
   990 	{
   991 public:
   992 	Thread(TUint32 aTraceId)
   993 		: Object(aTraceId,"T"), iId(~0u), iCpuTime(0), iSamples(0)
   994 		{
   995 		iContainer.Add(this);
   996 		iNameLength = (TUint8)MakeName(iName,"NThread-",aTraceId);
   997 		}
   998 
   999 	TUint64 CpuTime()
  1000 		{
  1001 		if(!iLastCpu || !iLastCpu->iBaseTimestamp)
  1002 			return 0;
  1003 		if(iLastCpu->iCurrentThread==this)
  1004 			return iCpuTime + Timestamp - iLastCpu->iBaseTimestamp;
  1005 		return iCpuTime;
  1006 		}
  1007 
  1008 	void Sampled()
  1009 		{
  1010 		if( iSamples+1 != 0xFFFFFFFF)
  1011 			{
  1012 			iSamples++;
  1013 			}
  1014 		}
  1015 
  1016 	GENERIC_OBJECT_DEFINITIONS(Thread);
  1017 
  1018 	static Object* FindThreadOrProcess(TraceRecord& aTrace, TUint aIndex)
  1019 		{
  1020 		if (!aTrace.iData[aIndex])
  1021 			return 0;
  1022 		Object* p = Find(aTrace, aIndex);
  1023 		if (!p)
  1024 			p = Process::Find(aTrace, aIndex);
  1025 		return p;
  1026 		}
  1027 public:
  1028 	TUint32 iId;
  1029 	Cpu* iLastCpu;
  1030 	TUint64 iCpuTime;
  1031 	TUint64 iFMBlockStartTime;
  1032 	FastMutex* iWaitFastMutex;
  1033 
  1034 	// Number of profiling samples
  1035 	TUint32 iSamples;
  1036 
  1037 	static ObjectContainer iContainer;
  1038 	};
  1039 
  1040 ObjectContainer Thread::iContainer;
  1041 
  1042 
  1043 
  1044 //
  1045 // Chunk
  1046 //
  1047 
  1048 TUint ChunkErrors = 0;
  1049 
  1050 const TUint KPageShift = 12; // chunk memory is allocated in 4kB pages
  1051 
  1052 class Chunk : public Object
  1053 	{
  1054 public:
  1055 	Chunk(TUint32 aTraceId)
  1056 		: Object(aTraceId,"C"), iCurrentSize(0), iPeakSize(0), iMaxSize(0), iPageMap(0), iTraceErrors(0)
  1057 		{
  1058 		iContainer.Add(this);
  1059 		}
  1060 
  1061 	~Chunk()
  1062 		{
  1063 		free(iPageMap);
  1064 		}
  1065 
  1066 	void SetMaxSize(TUint32 aMaxSize)
  1067 		{
  1068 		ASSERT(!iMaxSize);
  1069 		iMaxSize = aMaxSize;
  1070 		TUint mapSize = ((aMaxSize>>KPageShift)+7)>>3;
  1071 		iPageMap = (TUint8*)malloc(mapSize);
  1072 		ASSERT(iPageMap);
  1073 		memset(iPageMap,0,mapSize);
  1074 		iCurrentSize = 0;
  1075 		}
  1076 
  1077 	void Commit(TUint32 aStart,TUint32 aSize)
  1078 		{
  1079 		if(!iPageMap) // we havent been intialised yet
  1080 			return;
  1081 
  1082 		if(aStart+aSize<aStart || aStart+aSize>iMaxSize)
  1083 			{
  1084 			++iTraceErrors;
  1085 			++ChunkErrors;
  1086 			return;
  1087 			}
  1088 		if(SetBits(iPageMap,aStart>>KPageShift,aSize>>KPageShift))
  1089 			{
  1090 			++iTraceErrors;
  1091 			++ChunkErrors;
  1092 			ErrorOnThisTrace = true;
  1093 			}
  1094 		}
  1095 
  1096 	void Decommit(TUint32 aStart,TUint32 aSize)
  1097 		{
  1098 		if(!iPageMap) // we havent been intialised yet
  1099 			return;
  1100 
  1101 		// Decommit is complicated by the fact that aSize is the number of pages
  1102 		// actually decommited, which may be less than the region of the original
  1103 		// chunk decommit operation. E.g. if pages 1 and 3 were originally decommited
  1104 		// and the decommit operation was for pages 0-3, then the trace has a size of
  1105 		// 2 pages, even though the operation was on 4 pages.
  1106 		// We handle this, repeatedly decommiting from our iPageMap, until we have
  1107 		// freed aSize bytes worth of pages...
  1108 		while(aSize)
  1109 			{
  1110 			if(aStart+aSize<aStart || aStart+aSize>iMaxSize)
  1111 				{
  1112 				// we haven't found enough memory to decommit
  1113 				++iTraceErrors;
  1114 				++ChunkErrors;
  1115 				ErrorOnThisTrace = true;
  1116 				return;
  1117 				}
  1118 			TUint notDecommitted = ClearBits(iPageMap,aStart>>KPageShift,aSize>>KPageShift);
  1119 			aStart += aSize;
  1120 			aSize = notDecommitted<<KPageShift;
  1121 			}
  1122 		}
  1123 
  1124 	void ResetMemory()
  1125 		{
  1126 		}
  1127 
  1128 	GENERIC_OBJECT_DEFINITIONS(Chunk);
  1129 
  1130 public:
  1131 	TUint32 iCurrentSize;
  1132 	TUint32 iPeakSize;
  1133 	TUint32 iMaxSize;
  1134 	TUint8* iPageMap;
  1135 	TUint iTraceErrors;
  1136 
  1137 	static ObjectContainer iContainer;
  1138 	};
  1139 ObjectContainer Chunk::iContainer;
  1140 
  1141 
  1142 
  1143 //
  1144 // Semaphore, Mutex, CondVar
  1145 //
  1146 class Semaphore : public Object
  1147 	{
  1148 public:
  1149 	Semaphore(TUint32 aTraceId)
  1150 		: Object(aTraceId,"S")
  1151 		{
  1152 		iContainer.Add(this);
  1153 		}
  1154 
  1155 	~Semaphore()
  1156 		{
  1157 		}
  1158 
  1159 	GENERIC_OBJECT_DEFINITIONS(Semaphore);
  1160 public:
  1161 
  1162 	static ObjectContainer iContainer;
  1163 	};
  1164 ObjectContainer Semaphore::iContainer;
  1165 
  1166 
  1167 class Mutex : public Object
  1168 	{
  1169 public:
  1170 	Mutex(TUint32 aTraceId)
  1171 		: Object(aTraceId,"M")
  1172 		{
  1173 		iContainer.Add(this);
  1174 		}
  1175 
  1176 	~Mutex()
  1177 		{
  1178 		}
  1179 
  1180 	GENERIC_OBJECT_DEFINITIONS(Mutex);
  1181 public:
  1182 
  1183 	static ObjectContainer iContainer;
  1184 	};
  1185 ObjectContainer Mutex::iContainer;
  1186 
  1187 
  1188 class CondVar : public Object
  1189 	{
  1190 public:
  1191 	CondVar(TUint32 aTraceId)
  1192 		: Object(aTraceId,"V")
  1193 		{
  1194 		iContainer.Add(this);
  1195 		}
  1196 
  1197 	~CondVar()
  1198 		{
  1199 		}
  1200 
  1201 	GENERIC_OBJECT_DEFINITIONS(CondVar);
  1202 public:
  1203 
  1204 	static ObjectContainer iContainer;
  1205 	};
  1206 ObjectContainer CondVar::iContainer;
  1207 
  1208 
  1209 
  1210 
  1211 //
  1212 // CodeSeg
  1213 //
  1214 
  1215 TUint CodeSegErrors = 0;
  1216 
  1217 class CodeSeg : public Object
  1218 	{
  1219 public:
  1220 	CodeSeg(TUint32 aTraceId)
  1221 		: Object(aTraceId,"CS"), iAllocatedMemory(0)
  1222 		{
  1223 		iContainer.Add(this);
  1224 		}
  1225 
  1226 	GENERIC_OBJECT_DEFINITIONS(CodeSeg);
  1227 
  1228 	TUint iAllocatedMemory;
  1229 public:
  1230 	static ObjectContainer iContainer;
  1231 	};
  1232 ObjectContainer CodeSeg::iContainer;
  1233 
  1234 
  1235 
  1236 //
  1237 // FastMutex
  1238 //
  1239 
  1240 TUint FastMutexNestErrors = 0;
  1241 
  1242 class FastMutex : public Object
  1243 	{
  1244 public:
  1245 	FastMutex(TUint32 aTraceId)
  1246 		: Object(aTraceId,"FM"), iHoldingThread(0), iHeldCount(0), iTotalHeldTime(0),
  1247 		  iMaxHeldTime(0), iMaxHeldTimestamp(0), iMaxHeldPc(0), iBlockCount(0)
  1248 		{
  1249 		iContainer.Add(this);
  1250 		iNameLength = (TUint8)MakeName(iName,"NFastMutex-",aTraceId);
  1251 		iNameLength = 19;
  1252 		}
  1253 
  1254 	TUint32 Wait(Thread* aThread)
  1255 		{
  1256 		TUint32 time = 0;
  1257 		if(iHoldingThread)
  1258 			{
  1259 			++FastMutexNestErrors;
  1260 			ErrorOnThisTrace = true;
  1261 			}
  1262 		iHoldingThread = aThread;
  1263 		iWaitCpuTimeBase = aThread->CpuTime();
  1264 		if (aThread->iWaitFastMutex == this)
  1265 			{
  1266 			time = (TUint32)(Timestamp - aThread->iFMBlockStartTime);
  1267 			}
  1268 		aThread->iWaitFastMutex = 0;
  1269 		return time;
  1270 		}
  1271 
  1272 	void Block(Thread* aThread)
  1273 		{
  1274 		if (aThread->iWaitFastMutex != this)
  1275 			{
  1276 			aThread->iFMBlockStartTime = Timestamp;
  1277 			aThread->iWaitFastMutex = this;
  1278 			++iBlockCount;
  1279 			}
  1280 		};
  1281 
  1282 	TUint32 Signal(Thread* aThread, TUint32 aPc)
  1283 		{
  1284 		if (!iHoldingThread)	// First record for this mutex so ignore it as don't
  1285 			return 0;			// have waiting thread details
  1286 		
  1287 		if(iHoldingThread!=aThread)
  1288 			{
  1289 			++FastMutexNestErrors;
  1290 			ErrorOnThisTrace = true;
  1291 			iHoldingThread = 0;
  1292 			return 0;
  1293 			}
  1294 		iHoldingThread = 0;
  1295 		TUint64 time = aThread->CpuTime()-iWaitCpuTimeBase;
  1296 		++iHeldCount;
  1297 		iTotalHeldTime += time;
  1298 		if(time>iMaxHeldTime)
  1299 			{
  1300 			iMaxHeldTime = time;
  1301 			iMaxHeldPc = aPc;
  1302 			iMaxHeldTimestamp = Timestamp;
  1303 			}
  1304 		return (TUint32)time;
  1305 		}
  1306 
  1307 	GENERIC_OBJECT_DEFINITIONS(FastMutex);
  1308 
  1309 public:
  1310 	Thread* iHoldingThread;
  1311 	TUint32 iHeldCount;		// number of times mutex acquired
  1312 	TUint64 iTotalHeldTime;
  1313 	TUint64 iWaitCpuTimeBase;
  1314 	TUint64 iMaxHeldTime;
  1315 	TUint64 iMaxHeldTimestamp;
  1316 	TUint32 iMaxHeldPc;
  1317 	TUint32 iBlockCount;	// number of times mutex caused a thread to wait
  1318 
  1319 	static ObjectContainer iContainer;
  1320 	};
  1321 ObjectContainer FastMutex::iContainer;
  1322 
  1323 
  1324 
  1325 
  1326 //
  1327 // ProfilingSample
  1328 //
  1329 
  1330 TUint ProfilingSampleErrors = 0;
  1331 
  1332 class ProfilingSample : public Object
  1333 	{
  1334 public:
  1335 	ProfilingSample(TUint32 aTraceId)
  1336 		: Object(aTraceId,"PS")
  1337 		{
  1338 		iContainer.Add(this);
  1339 		iNameLength = (TUint8)MakeName(iName,"ProfilingSample-",aTraceId);
  1340 		}
  1341 
  1342 	void SetPC( TUint32 aPC )
  1343 		{
  1344 		iPC = aPC;
  1345 		}
  1346 
  1347 	void SetThread( TUint32 aThread )
  1348 		{
  1349 		if( 0 != aThread )
  1350 			iThread = aThread;
  1351 		}
  1352 
  1353 	void SetType(const BTrace::TProfiling aType)
  1354 		{
  1355 		iType = aType;
  1356 		}
  1357 
  1358 	GENERIC_OBJECT_DEFINITIONS(ProfilingSample);
  1359 
  1360 
  1361 public:
  1362 
  1363 	static ObjectContainer iContainer;
  1364 	static Thread* iTopTen[10];
  1365 	static TUint32 iSamples;
  1366 	static TUint32 iLastThread;
  1367 
  1368 	TUint32 iPC;
  1369 	TUint32 iThread;
  1370 	BTrace::TProfiling iType;
  1371 
  1372 	};
  1373 
  1374 TUint32 ProfilingSample::iSamples = 0;
  1375 TUint32 ProfilingSample::iLastThread = 0;
  1376 
  1377 ObjectContainer ProfilingSample::iContainer;
  1378 
  1379 
  1380 //
  1381 // EThreadIdentification traces
  1382 //
  1383 
  1384 void PreProcessThreadIdentification(TraceRecord& aTrace)
  1385 	{
  1386 	Thread* thread;
  1387 	Process* process;
  1388 
  1389 	switch((BTrace::TThreadIdentification)aTrace.iSubCategory)
  1390 		{
  1391 	case BTrace::ENanoThreadCreate:
  1392 		CHECK_TRACE_DATA_WORDS(1);
  1393 		thread = Thread::FindOrCreate(aTrace,0);
  1394 		break;
  1395 
  1396 	case BTrace::ENanoThreadDestroy:
  1397 		CHECK_TRACE_DATA_WORDS(1);
  1398 		thread = Thread::Find(aTrace,0);
  1399 		if(thread)
  1400 			thread->Destroy();
  1401 		break;
  1402 
  1403 	case BTrace::EThreadCreate:
  1404 	case BTrace::EThreadName:
  1405 		CHECK_TRACE_DATA_WORDS(2);
  1406 		thread = Thread::FindOrCreate(aTrace,0);
  1407 		if(aTrace.iSubCategory==BTrace::EThreadCreate)
  1408 			++thread->iAlive; // thread needs destroying twice (ENanoThreadDestroy+EThreadDestroy)
  1409 		process = Process::FindOrCreate(aTrace,1);
  1410 		thread->iOwner = process;
  1411 		++process->iThreadCount;
  1412 		if(process->iThreadCount>process->iMaxThreadCount)
  1413 			process->iMaxThreadCount = process->iThreadCount;
  1414 		thread->SetName(aTrace,2);
  1415 		break;
  1416 
  1417 	case BTrace::EThreadDestroy:
  1418 		CHECK_TRACE_DATA_WORDS(1);
  1419 		thread = Thread::Find(aTrace,0);
  1420 		if(thread)
  1421 			{
  1422 			thread->Destroy();
  1423 			process = (Process*)thread->iOwner;
  1424 			if(process && process->iThreadCount)
  1425 				--process->iThreadCount;
  1426 			}
  1427 		break;
  1428 
  1429 	case BTrace::EProcessName:
  1430 		CHECK_TRACE_DATA_WORDS(2);
  1431 		if(aTrace.iData[0])
  1432 			{
  1433 			thread = Thread::FindOrCreate(aTrace,0);
  1434 			process = Process::Find(aTrace.iData[1]);
  1435 			if(!process || (process->iNameLength && !process->IsName(aTrace.iData+2,aTrace.iDataSize-2*4)))
  1436 				{
  1437 				if(process)
  1438 					process->Destroy();
  1439 				process = Process::Create(aTrace,1); // no existing process, or name different
  1440 				}
  1441 			else
  1442 				process = Process::Find(aTrace,1); // find again (this will update trace data[1])
  1443 			}
  1444 		else
  1445 			process = Process::Find(aTrace,1);
  1446 		if(process)
  1447 			process->SetName(aTrace,2);
  1448 		break;
  1449 
  1450 	case BTrace::EThreadId:
  1451 		CHECK_TRACE_DATA_WORDS(2);
  1452 		thread = Thread::FindOrCreate(aTrace,0);
  1453 		process = Process::FindOrCreate(aTrace,1);
  1454 		thread->iId = aTrace.iData[2];
  1455 		break;
  1456 
  1457 	case BTrace::EProcessCreate:
  1458 		CHECK_TRACE_DATA_WORDS(1);
  1459 		process = Process::FindOrCreate(aTrace,0);
  1460 		break;
  1461 
  1462 	case BTrace::EProcessDestroy:
  1463 		CHECK_TRACE_DATA_WORDS(1);
  1464 		process = Process::FindOrCreate(aTrace,0);
  1465 		if(process)
  1466 			process->Destroy();
  1467 		break;
  1468 
  1469 	default:
  1470 		break;
  1471 		}
  1472 	}
  1473 
  1474 
  1475 //
  1476 // ECpuUsage traces
  1477 //
  1478 
  1479 Cpu TheCpus[KMaxCpus];
  1480 TUint InterruptNestErrors = 0;
  1481 TUint CpuUsagePresent = 0;
  1482 
  1483 Cpu::Cpu()
  1484 	:	iCurrentContext(EContextUnknown),
  1485 		iFiqNest(0),
  1486 		iIrqNest(0),
  1487 		iIDFCNest(0),
  1488 		iFiqTime(0),
  1489 		iIrqTime(0),
  1490 		iIDFCTime(0),
  1491 		iCurrentThread(0),
  1492 		iBaseTimestamp(0)
  1493 	{
  1494 	}
  1495 
  1496 void Cpu::Reset()
  1497 	{
  1498 	iCurrentContext = EContextUnknown;
  1499 	iFiqNest = 0;
  1500 	iIrqNest = 0;
  1501 	iIDFCNest = 0;
  1502 	iCurrentThread = 0;
  1503 	iBaseTimestamp = 0;
  1504 	}
  1505 
  1506 void ResetCpuUsage()
  1507 	{
  1508 	TInt i;
  1509 	for (i=0; i<KMaxCpus; ++i)
  1510 		TheCpus[i].Reset();
  1511 	}
  1512 
  1513 
  1514 void StartCpuUsage()
  1515 	{
  1516 	TInt i;
  1517 	for (i=0; i<KMaxCpus; ++i)
  1518 		new (&TheCpus[i]) Cpu;
  1519 	InterruptNestErrors = 0;
  1520 	}
  1521 
  1522 
  1523 void Cpu::ChangeContext(TContext aType, Thread* aThread)
  1524 	{
  1525 	TUint64 delta = Timestamp-iBaseTimestamp;
  1526 	switch(iCurrentContext)
  1527 		{
  1528 	case EContextThread:
  1529 		iCurrentThread->iCpuTime += delta;
  1530 		break;
  1531 	case EContextFiq:
  1532 		iFiqTime += delta;
  1533 		break;
  1534 	case EContextIrq:
  1535 		iIrqTime += delta;
  1536 		break;
  1537 	case EContextIDFC:
  1538 		iIDFCTime += delta;
  1539 		break;
  1540 	default:
  1541 		break;
  1542 		}
  1543 
  1544 	if(aType==EContextUnknown)
  1545 		{
  1546 		if(iFiqNest)
  1547 			aType = EContextFiq;
  1548 		else if(iIrqNest)
  1549 			aType = EContextIrq;
  1550 		else if(iIDFCNest)
  1551 			aType = EContextIDFC;
  1552 		else
  1553 			{
  1554 			aType = EContextThread;
  1555 			aThread = iCurrentThread;
  1556 			}
  1557 		}
  1558 
  1559 	if(aType==EContextThread && !aThread)
  1560 		{
  1561 		iCurrentContext = EContextUnknown;
  1562 		iBaseTimestamp = 0;
  1563 		return;
  1564 		}
  1565 
  1566 	iCurrentContext = aType;
  1567 	if(aType==EContextThread)
  1568 		{
  1569 		iCurrentThread = aThread;
  1570 		aThread->iLastCpu = this;
  1571 		}
  1572 
  1573 	iBaseTimestamp = Timestamp;
  1574 	}
  1575 
  1576 
  1577 void PreProcessCpuUsage(TraceRecord& aTrace)
  1578 	{
  1579 	CpuUsagePresent = true;
  1580 	Cpu& cpu = *aTrace.iCpu;
  1581 
  1582 	switch((BTrace::TCpuUsage)aTrace.iSubCategory)
  1583 		{
  1584 	case BTrace::EIrqStart:
  1585 		++cpu.iIrqNest;
  1586 		cpu.ChangeContext(EContextIrq);
  1587 		break;
  1588 
  1589 	case BTrace::EFiqStart:
  1590 		++cpu.iFiqNest;
  1591 		cpu.ChangeContext(EContextFiq);
  1592 		break;
  1593 
  1594 	case BTrace::EIDFCStart:
  1595 		if(cpu.iIrqNest+cpu.iFiqNest>1 || cpu.iIDFCNest!=0)
  1596 			{
  1597 			++InterruptNestErrors;
  1598 			ErrorOnThisTrace = true;
  1599 			}
  1600 		cpu.iIrqNest = 0;
  1601 		cpu.iFiqNest = 0;
  1602 		cpu.iIDFCNest = 1;
  1603 		cpu.ChangeContext(EContextIDFC);
  1604 		break;
  1605 
  1606 	case BTrace::EIrqEnd:
  1607 		if(cpu.iIrqNest)
  1608 			--cpu.iIrqNest;
  1609 		else
  1610 			{
  1611 			++InterruptNestErrors;
  1612 			ErrorOnThisTrace = true;
  1613 			}
  1614 		cpu.ChangeContext(EContextUnknown);
  1615 		break;
  1616 
  1617 	case BTrace::EFiqEnd:
  1618 		if(cpu.iFiqNest)
  1619 			--cpu.iFiqNest;
  1620 		else
  1621 			{
  1622 			++InterruptNestErrors;
  1623 			ErrorOnThisTrace = true;
  1624 			}
  1625 		cpu.ChangeContext(EContextUnknown);
  1626 		break;
  1627 
  1628 	case BTrace::EIDFCEnd:
  1629 		if(cpu.iIDFCNest!=1)
  1630 			{
  1631 			++InterruptNestErrors;
  1632 			ErrorOnThisTrace = true;
  1633 			}
  1634 		cpu.iIDFCNest = 0;
  1635 		cpu.ChangeContext(EContextUnknown);
  1636 		break;
  1637 
  1638 	case BTrace::ENewThreadContext:
  1639 		if(cpu.iIrqNest+cpu.iFiqNest>1 || cpu.iIDFCNest!=0)
  1640 			{
  1641 			++InterruptNestErrors;
  1642 			ErrorOnThisTrace = true;
  1643 			}
  1644 		cpu.iIrqNest = 0;
  1645 		cpu.iFiqNest = 0;
  1646 		cpu.iIDFCNest = 0;
  1647 		cpu.ChangeContext(EContextThread,aTrace.iContextID);
  1648 		break;
  1649 		}
  1650 	}
  1651 
  1652 
  1653 void ReportThreads()
  1654 	{
  1655 	TUint numThreads = Thread::iContainer.Count();
  1656 	if(!numThreads)
  1657 		return;
  1658 
  1659 	TUint64 totalTime = 0;
  1660 	printf("\nREPORT: Threads\n\n");
  1661 	WarnIfError(0);
  1662 	printf("%-10s %5s %10s %8s %s\n","","State","CPUTime","TraceId","Name");
  1663 	TUint i;
  1664 	for(i=0; i<numThreads; ++i)
  1665 		{
  1666 		Thread* thread = (Thread*)Thread::iContainer[i];
  1667 		Object::FullNameBuf fullName;
  1668 		thread->FullName(fullName);
  1669 		Object::TraceNameBuf name;
  1670 		thread->TraceName(name);
  1671 		printf("%-10s %5s %10d %08x '%s'\n",name,
  1672 			thread->iAlive?(const char*)"Alive":(const char*)"Dead",
  1673 			(int)Time(thread->iCpuTime),(int)thread->iTraceId,fullName);
  1674 		totalTime += thread->iCpuTime;
  1675 		}
  1676 	for (i=0; i<(TUint)KMaxCpus; ++i)
  1677 		{
  1678 		printf("CPU %1d\n", i);
  1679 		Cpu& cpu = TheCpus[i];
  1680 		printf("%-10s %5s %10d %s\n","FIQ","",(int)Time(cpu.iFiqTime),"");
  1681 		printf("%-10s %5s %10d %s\n","IRQ","",(int)Time(cpu.iIrqTime),"");
  1682 		printf("%-10s %5s %10d %s\n","IDFC","",(int)Time(cpu.iIDFCTime),"");
  1683 		totalTime += cpu.iFiqTime + cpu.iIrqTime + cpu.iIDFCTime;
  1684 		}
  1685 	printf("%-10s %5s ----------\n","","");
  1686 	printf("%-10s %5s %10d\n","","",(int)Time(totalTime));
  1687 	printf("\n");
  1688 	}
  1689 
  1690 
  1691 void ReportProcesses()
  1692 	{
  1693 	TUint numProcesses = Process::iContainer.Count();
  1694 	if(!numProcesses)
  1695 		return;
  1696 
  1697 	printf("\nREPORT: Processes\n\n");
  1698 	WarnIfError(0);
  1699 	printf("%-10s %5s %7s %8s %s\n","","State","Threads","TraceId","Name");
  1700 	TUint i;
  1701 	for(i=0; i<numProcesses; ++i)
  1702 		{
  1703 		Process* process = (Process*)Process::iContainer[i];
  1704 		Object::FullNameBuf fullName;
  1705 		process->FullName(fullName);
  1706 		Object::TraceNameBuf name;
  1707 		process->TraceName(name);
  1708 		printf("%-10s %5s %3u/%-3u %08x '%s'\n",name,
  1709 			process->iAlive?(const char*)"Alive":(const char*)"Dead",
  1710 			(unsigned int)process->iThreadCount,(unsigned int)process->iMaxThreadCount,
  1711 			(unsigned int)process->iTraceId,fullName);
  1712 		}
  1713 	printf("\n");
  1714 	}
  1715 
  1716 
  1717 void EndCpuUsage()
  1718 	{
  1719 	TInt i;
  1720 	for (i=0; i<KMaxCpus; ++i)
  1721 		TheCpus[i].ChangeContext(EContextUnknown);
  1722 	}
  1723 
  1724 
  1725 //
  1726 // EChunks traces
  1727 //
  1728 
  1729 void StartChunks()
  1730 	{
  1731 	ChunkErrors = 0;
  1732 	}
  1733 
  1734 
  1735 void PreProcessChunks(TraceRecord& aTrace)
  1736 	{
  1737 	CHECK_TRACE_DATA_WORDS(1);
  1738 	Chunk* chunk = Chunk::FindOrCreate(aTrace,0);
  1739 
  1740 	switch((BTrace::TChunks)aTrace.iSubCategory)
  1741 		{
  1742 	case BTrace::EChunkCreated:
  1743 		CHECK_TRACE_DATA_WORDS(2);
  1744 		chunk->SetName(aTrace,2);
  1745 		chunk->SetMaxSize(aTrace.iData[1]);
  1746 		// start by assuming thread is 'owned' by the thread which created it...
  1747 		chunk->iOwner = aTrace.iContextID;
  1748 		break;
  1749 
  1750 	case BTrace::EChunkInfo:
  1751 		CHECK_TRACE_DATA_WORDS(3);
  1752 		break; // ignore
  1753 
  1754 	case BTrace::EChunkDestroyed:
  1755 		chunk->Destroy();
  1756 		break;
  1757 
  1758 	case BTrace::EChunkMemoryAllocated:
  1759 		{
  1760 		CHECK_TRACE_DATA_WORDS(3);
  1761 		chunk->Commit(aTrace.iData[1],aTrace.iData[2]);
  1762 		TUint32 size = chunk->iCurrentSize+aTrace.iData[2];
  1763 		if(size<chunk->iCurrentSize || size>chunk->iMaxSize)
  1764 			size = chunk->iMaxSize;
  1765 		chunk->iCurrentSize = size;
  1766 		if(size>chunk->iPeakSize)
  1767 			chunk->iPeakSize = size;
  1768 		aTrace.iCalculatedData[0] = size/1024;
  1769 		}
  1770 		break;
  1771 
  1772 	case BTrace::EChunkMemoryDeallocated:
  1773 		{
  1774 		CHECK_TRACE_DATA_WORDS(3);
  1775 		chunk->Decommit(aTrace.iData[1],aTrace.iData[2]);
  1776 		TUint32 size = chunk->iCurrentSize-aTrace.iData[2];
  1777 		if(size>chunk->iCurrentSize)
  1778 			size = 0;
  1779 		chunk->iCurrentSize = size;
  1780 		aTrace.iCalculatedData[0] = size/1024;
  1781 		}
  1782 		break;
  1783 
  1784 	case BTrace::EChunkMemoryAdded:
  1785 		CHECK_TRACE_DATA_WORDS(3);
  1786 		chunk->Commit(aTrace.iData[1],aTrace.iData[2]);
  1787 		break;
  1788 
  1789 	case BTrace::EChunkMemoryRemoved:
  1790 		CHECK_TRACE_DATA_WORDS(3);
  1791 		chunk->Decommit(aTrace.iData[1],aTrace.iData[2]);
  1792 		break;
  1793 
  1794 	case BTrace::EChunkOwner:
  1795 		{
  1796 		CHECK_TRACE_DATA_WORDS(2);
  1797 		Process* process = Process::FindOrCreate(aTrace,1);
  1798 		// set owner, unless current owner is owned by the same process
  1799 		// (this preserves creating thread names in ownership list which is more useful)
  1800 		if(!chunk->iOwner || chunk->iOwner->iOwner!=process)
  1801 			chunk->iOwner = process;
  1802 		}
  1803 		break;
  1804 
  1805 		}
  1806 	}
  1807 
  1808 
  1809 void ReportChunks()
  1810 	{
  1811 	TUint numChunks = Chunk::iContainer.Count();
  1812 	if(!numChunks)
  1813 		return;
  1814 
  1815 	if(!ReportLevel)
  1816 		printf("\nREPORT: Chunks (Named objects only)\n\n");
  1817 	else
  1818 		printf("\nREPORT: Chunks\n\n");
  1819 	WarnIfError(ChunkErrors);
  1820 	printf("%-10s %5s %8s %8s %8s %8s %s\n",
  1821 		"","State","Size","Peak","Max","TraceId","Name");
  1822 	TUint totalSize = 0;
  1823 	TUint i;
  1824 	for(i=0; i<numChunks; ++i)
  1825 		{
  1826 		Chunk* chunk = (Chunk*)Chunk::iContainer[i];
  1827 		if(ReportLevel==0 && !chunk->iNameSet)
  1828 			continue; // only report explicitly named mutexes at report level 0
  1829 		Object::FullNameBuf fullName;
  1830 		chunk->FullName(fullName);
  1831 		Object::TraceNameBuf name;
  1832 		chunk->TraceName(name);
  1833 		printf("%-10s %5s %7uk %7uk %7uk %08x '%s'\n",
  1834 			name,chunk->iAlive?(const char*)"Alive":(const char*)"Dead",
  1835 			(unsigned int)chunk->iCurrentSize/1024,(unsigned int)chunk->iPeakSize/1024,(unsigned int)chunk->iMaxSize/1024,
  1836 			(unsigned int)chunk->iTraceId,fullName);
  1837 		totalSize += chunk->iCurrentSize/1024;
  1838 		}
  1839 	printf("%-10s %5s --------\n","","");
  1840 	printf("%-10s %5s %7uk\n","","",totalSize);
  1841 	printf("\n");
  1842 	}
  1843 
  1844 
  1845 
  1846 //
  1847 // CodeSeg
  1848 //
  1849 
  1850 void StartCodeSegs()
  1851 	{
  1852 	CodeSegErrors = 0;
  1853 	}
  1854 
  1855 
  1856 void PreProcessCodeSegs(TraceRecord& aTrace)
  1857 	{
  1858 	CHECK_TRACE_DATA_WORDS(1);
  1859 	CodeSeg* codeseg;
  1860 
  1861 	switch((BTrace::TCodeSegs)aTrace.iSubCategory)
  1862 		{
  1863 	case BTrace::ECodeSegCreated:
  1864 		codeseg = CodeSeg::FindOrCreate(aTrace,0);
  1865 		codeseg->SetName(aTrace,1);
  1866 		break;
  1867 
  1868 	case BTrace::ECodeSegInfo:
  1869 		CHECK_TRACE_DATA_WORDS(10);
  1870 		CodeSeg::FindOrCreate(aTrace,0);
  1871 /*		- 4 bytes containing the attributes.
  1872 		- 4 bytes containing the code base address (.text).
  1873 		- 4 bytes containing the size of the code section (.text).
  1874 		- 4 bytes containing the base address of the constant data section (.radata).
  1875 		- 4 bytes containing the size of the constant data section (.radata).
  1876 		- 4 bytes containing the base address of the initialised data section (.data).
  1877 		- 4 bytes containing the size of the initialised data section (.data).
  1878 		- 4 bytes containing the base address of the uninitialised data section (.bss).
  1879 		- 4 bytes containing the size of the uninitialised data section (.bss).
  1880 */		break;
  1881 
  1882 	case BTrace::ECodeSegDestroyed:
  1883 		codeseg = CodeSeg::FindOrCreate(aTrace,0);
  1884 		codeseg->Destroy();
  1885 		codeseg->iAllocatedMemory = 0; // clear this now because ECodeSegMemoryDeallocated comes after codeseg destroy
  1886 		break;
  1887 
  1888 	case BTrace::ECodeSegMapped:
  1889 		CHECK_TRACE_DATA_WORDS(2);
  1890 		codeseg = CodeSeg::FindOrCreate(aTrace,0);
  1891 		Process::FindOrCreate(aTrace,1);
  1892 		break;
  1893 
  1894 	case BTrace::ECodeSegUnmapped:
  1895 		CHECK_TRACE_DATA_WORDS(2);
  1896 		CodeSeg::FindOrCreate(aTrace,0);
  1897 		Process::FindOrCreate(aTrace,1);
  1898 		break;
  1899 
  1900 	case BTrace::ECodeSegMemoryAllocated:
  1901 		CHECK_TRACE_DATA_WORDS(2);
  1902 		codeseg = CodeSeg::FindOrCreate(aTrace,0);
  1903 		codeseg->iAllocatedMemory += aTrace.iData[1];
  1904 		if(codeseg->iAllocatedMemory<aTrace.iData[1])
  1905 			{
  1906 			codeseg->iAllocatedMemory = ~0u; // overflowed!
  1907 			++CodeSegErrors;
  1908 			ErrorOnThisTrace = true;
  1909 			}
  1910 		break;
  1911 
  1912 	case BTrace::ECodeSegMemoryDeallocated:
  1913 		{
  1914 		CHECK_TRACE_DATA_WORDS(2);
  1915 		codeseg = CodeSeg::Find(aTrace,0);
  1916 		if(codeseg)
  1917 			{
  1918 			TUint32 memory = codeseg->iAllocatedMemory-aTrace.iData[1];
  1919 			if(memory>codeseg->iAllocatedMemory)
  1920 				{
  1921 				memory = 0; // underflowed
  1922 				++CodeSegErrors;
  1923 				ErrorOnThisTrace = true;
  1924 				}
  1925 			codeseg->iAllocatedMemory = memory;
  1926 			}
  1927 		}
  1928 		break;
  1929 
  1930 		}
  1931 	}
  1932 
  1933 
  1934 void ReportCodeSegs()
  1935 	{
  1936 	TUint numCodeSegs = CodeSeg::iContainer.Count();
  1937 	if(!numCodeSegs)
  1938 		return;
  1939 
  1940 	if(!ReportLevel)
  1941 		printf("\nREPORT: CodeSegs (Named objects only)\n\n");
  1942 	else
  1943 		printf("\nREPORT: CodeSegs\n\n");
  1944 	WarnIfError(CodeSegErrors);
  1945 	printf("%-10s %5s %8s %8s %s\n",
  1946 		"","State","Memory","TraceId","Name");
  1947 	TUint totalSize = 0;
  1948 	TUint i;
  1949 	for(i=0; i<numCodeSegs; ++i)
  1950 		{
  1951 		CodeSeg* codeseg = (CodeSeg*)CodeSeg::iContainer[i];
  1952 		if(ReportLevel==0 && !codeseg->iNameSet)
  1953 			continue; // only report explicitly named mutexes at report level 0
  1954 		Object::FullNameBuf fullName;
  1955 		codeseg->FullName(fullName);
  1956 		Object::TraceNameBuf name;
  1957 		codeseg->TraceName(name);
  1958 		printf("%-10s %5s %7uk %08x '%s'\n",
  1959 			name,codeseg->iAlive?(const char*)"Alive":(const char*)"Dead",
  1960 			(unsigned int)codeseg->iAllocatedMemory/1024,(unsigned int)codeseg->iTraceId,fullName);
  1961 		totalSize += codeseg->iAllocatedMemory/1024;
  1962 		}
  1963 	printf("%-10s %5s --------\n","","");
  1964 	printf("%-10s %5s %7uk\n","","",totalSize);
  1965 	printf("\n");
  1966 	}
  1967 
  1968 
  1969 
  1970 //
  1971 // MetaTrace
  1972 //
  1973 
  1974 TUint KernelMemoryInitialFree = 0;
  1975 TUint KernelMemoryCurrentFree = 0;
  1976 TUint KernelMemoryMisc = 0;
  1977 TUint KernelMemoryDrvPhys = 0;
  1978 TUint KernelMemoryDemandPagingCache = 0;
  1979 TUint KernelMemoryErrors = 0;
  1980 TBool KernelMemoryTracesPresent = false;
  1981 
  1982 void StartKernelMemory()
  1983 	{
  1984 	KernelMemoryInitialFree = 0;
  1985 	KernelMemoryCurrentFree = 0;
  1986 	KernelMemoryMisc = 0;
  1987 	KernelMemoryDrvPhys = 0;
  1988 	KernelMemoryErrors = 0;
  1989 	KernelMemoryTracesPresent = false;
  1990 	}
  1991 
  1992 
  1993 void PreProcessKernelMemory(TraceRecord& aTrace)
  1994 	{
  1995 	CHECK_TRACE_DATA_WORDS(1);
  1996 	KernelMemoryTracesPresent = true;
  1997 	switch((BTrace::TKernelMemory)aTrace.iSubCategory)
  1998 		{
  1999 	case BTrace::EKernelMemoryInitialFree:
  2000 		KernelMemoryInitialFree = aTrace.iData[0];
  2001 		aTrace.iCalculatedData[0] = KernelMemoryInitialFree/1024;
  2002 		break;
  2003 
  2004 	case BTrace::EKernelMemoryCurrentFree:
  2005 		KernelMemoryCurrentFree = aTrace.iData[0];
  2006 		aTrace.iCalculatedData[0] = KernelMemoryCurrentFree/1024;
  2007 		break;
  2008 
  2009 	case BTrace::EKernelMemoryMiscAlloc:
  2010 		KernelMemoryMisc += aTrace.iData[0];
  2011 		if(KernelMemoryMisc < aTrace.iData[0])
  2012 			{
  2013 			KernelMemoryMisc = 0xffffffffu;
  2014 			++KernelMemoryErrors;
  2015 			ErrorOnThisTrace = true;
  2016 			}
  2017 		aTrace.iCalculatedData[0] = KernelMemoryMisc/1024;
  2018 		break;
  2019 
  2020 	case BTrace::EKernelMemoryMiscFree:
  2021 		if(KernelMemoryMisc >= aTrace.iData[0])
  2022 			KernelMemoryMisc -= aTrace.iData[0];
  2023 		else
  2024 			{
  2025 			KernelMemoryMisc = 0;
  2026 			++KernelMemoryErrors;
  2027 			ErrorOnThisTrace = true;
  2028 			}
  2029 		aTrace.iCalculatedData[0] = KernelMemoryMisc/1024;
  2030 		break;
  2031 
  2032 	case BTrace::EKernelMemoryDemandPagingCache:
  2033 		KernelMemoryDemandPagingCache = aTrace.iData[0];
  2034 		break;
  2035 
  2036 	case BTrace::EKernelMemoryDrvPhysAlloc:
  2037 		KernelMemoryDrvPhys += aTrace.iData[0];
  2038 		if(KernelMemoryDrvPhys < aTrace.iData[0])
  2039 			{
  2040 			KernelMemoryDrvPhys = 0xffffffffu;
  2041 			++KernelMemoryErrors;
  2042 			ErrorOnThisTrace = true;
  2043 			}
  2044 		aTrace.iCalculatedData[0] = KernelMemoryDrvPhys/1024;
  2045 		break;
  2046 
  2047 	case BTrace::EKernelMemoryDrvPhysFree:
  2048 		if(KernelMemoryDrvPhys >= aTrace.iData[0])
  2049 			KernelMemoryDrvPhys -= aTrace.iData[0];
  2050 		else
  2051 			{
  2052 			KernelMemoryDrvPhys = 0;
  2053 			++KernelMemoryErrors;
  2054 			ErrorOnThisTrace = true;
  2055 			}
  2056 		aTrace.iCalculatedData[0] = KernelMemoryDrvPhys/1024;
  2057 		break;
  2058 		}
  2059 	}
  2060 
  2061 void ReportKernelMemory()
  2062 	{
  2063 	if(!KernelMemoryTracesPresent)
  2064 		return;
  2065 
  2066 	printf("\nREPORT: Kernel Memory\n\n");
  2067 	WarnIfError(KernelMemoryErrors);
  2068 	printf("Total RAM size............................. %dk\n",KernelMemoryInitialFree/1024);
  2069 	printf("Miscelaneous RAM used by kernel............ %dk\n",KernelMemoryMisc/1024);
  2070 	printf("Physical RAM allocated by device drivers... %dk\n",KernelMemoryDrvPhys/1024);
  2071 	printf("Demand paging cache reserve................ %dk\n",KernelMemoryDemandPagingCache/1024);
  2072 	if(ReportLevel>1)
  2073 		printf("Last 'current free RAM' value seen......... %dk\n",KernelMemoryCurrentFree/1024);
  2074 
  2075 	printf("\n");
  2076 	}
  2077 
  2078 //
  2079 // MetaTrace
  2080 //
  2081 
  2082 void StartMetaTrace()
  2083 	{
  2084 	TimestampPeriod = 0;
  2085 	Timestamp2Period = 0;
  2086 	}
  2087 
  2088 
  2089 void PreProcessMetaTrace(TraceRecord& aTrace)
  2090 	{
  2091 	switch((BTrace::TMetaTrace)aTrace.iSubCategory)
  2092 		{
  2093 	case BTrace::EMetaTraceTimestampsInfo:
  2094 		CHECK_TRACE_DATA_WORDS(3);
  2095 		TimestampPeriod = aTrace.iData[0];
  2096 		Timestamp2Period = aTrace.iData[1];
  2097 		Timestamp64Bit = aTrace.iData[2]&1;
  2098 		break;
  2099 
  2100 	case BTrace::EMetaTraceMeasurementStart:
  2101 	case BTrace::EMetaTraceMeasurementEnd:
  2102 		CHECK_TRACE_DATA_WORDS(2);
  2103 		aTrace.iDataTypes[2] = EDataTypeText;
  2104 		break;
  2105 
  2106 	case BTrace::EMetaTraceFilterChange:
  2107 		CHECK_TRACE_DATA_WORDS(1);
  2108 		break;
  2109 		}
  2110 	}
  2111 
  2112 //
  2113 // EFastMutex traces
  2114 //
  2115 
  2116 void StartFastMutex()
  2117 	{
  2118 	FastMutexNestErrors = 0;
  2119 	}
  2120 
  2121 
  2122 void PreProcessFastMutex(TraceRecord& aTrace)
  2123 	{
  2124 	CHECK_TRACE_DATA_WORDS(1);
  2125 	FastMutex* mutex = FastMutex::FindOrCreate(aTrace,0);
  2126 	Thread* thread = aTrace.iContextID;
  2127 
  2128 	switch((BTrace::TFastMutex)aTrace.iSubCategory)
  2129 		{
  2130 	case BTrace::EFastMutexWait:
  2131 		aTrace.iCalculatedData[0] = Time(mutex->Wait(thread));
  2132 		break;
  2133 
  2134 	case BTrace::EFastMutexSignal:
  2135 		aTrace.iCalculatedData[0] = Time(mutex->Signal(thread,aTrace.iPC));
  2136 		break;
  2137 
  2138 	case BTrace::EFastMutexFlash:
  2139 		aTrace.iCalculatedData[0] = Time(mutex->Signal(thread,aTrace.iPC));
  2140 		mutex->Wait(thread);
  2141 		break;
  2142 
  2143 	case BTrace::EFastMutexName:
  2144 		CHECK_TRACE_DATA_WORDS(2);
  2145 		mutex->SetName(aTrace,2);
  2146 		break;
  2147 
  2148 	case BTrace::EFastMutexBlock:
  2149 		mutex->Block(thread);
  2150 		break;
  2151 
  2152 		}
  2153 	}
  2154 
  2155 
  2156 void PreProcessSymbianKernelSync(TraceRecord& aTrace)
  2157 	{
  2158 	switch((BTrace::TSymbianKernelSync)aTrace.iSubCategory)
  2159 		{
  2160 	case BTrace::ESemaphoreCreate:
  2161 		{
  2162 		CHECK_TRACE_DATA_WORDS(2);
  2163 		TUint32 ownerid = aTrace.iData[1];
  2164 		Semaphore* sem = Semaphore::FindOrCreate(aTrace,0);
  2165 		Object* owner = Thread::FindThreadOrProcess(aTrace,1);
  2166 		sem->iOwner = owner;
  2167 		if (!owner && ownerid)
  2168 			sem->iOwnerTraceId = ownerid, ++Object::UnknownOwners;
  2169 		sem->SetName(aTrace,2);
  2170 		break;
  2171 		}
  2172 
  2173 	case BTrace::ESemaphoreDestroy:
  2174 		{
  2175 		CHECK_TRACE_DATA_WORDS(1);
  2176 		Semaphore* sem = Semaphore::Find(aTrace,0);
  2177 		if (sem)
  2178 			sem->Destroy();
  2179 		break;
  2180 		}
  2181 
  2182 	case BTrace::ESemaphoreAcquire:
  2183 	case BTrace::ESemaphoreRelease:
  2184 	case BTrace::ESemaphoreBlock:
  2185 		{
  2186 		CHECK_TRACE_DATA_WORDS(1);
  2187 		Semaphore::FindOrCreate(aTrace,0);
  2188 		break;
  2189 		}
  2190 
  2191 
  2192 	case BTrace::EMutexCreate:
  2193 		{
  2194 		CHECK_TRACE_DATA_WORDS(2);
  2195 		TUint32 ownerid = aTrace.iData[1];
  2196 		Mutex* m = Mutex::FindOrCreate(aTrace,0);
  2197 		Object* owner = Thread::FindThreadOrProcess(aTrace,1);
  2198 		m->iOwner = owner;
  2199 		if (!owner && ownerid)
  2200 			m->iOwnerTraceId = ownerid, ++Object::UnknownOwners;
  2201 		m->SetName(aTrace,2);
  2202 		break;
  2203 		}
  2204 
  2205 	case BTrace::EMutexDestroy:
  2206 		{
  2207 		CHECK_TRACE_DATA_WORDS(1);
  2208 		Mutex* m = Mutex::Find(aTrace,0);
  2209 		if (m)
  2210 			m->Destroy();
  2211 		break;
  2212 		}
  2213 
  2214 	case BTrace::EMutexAcquire:
  2215 	case BTrace::EMutexRelease:
  2216 	case BTrace::EMutexBlock:
  2217 		{
  2218 		CHECK_TRACE_DATA_WORDS(1);
  2219 		Mutex::FindOrCreate(aTrace,0);
  2220 		break;
  2221 		}
  2222 
  2223 
  2224 	case BTrace::ECondVarCreate:
  2225 		{
  2226 		CHECK_TRACE_DATA_WORDS(2);
  2227 		TUint32 ownerid = aTrace.iData[1];
  2228 		CondVar* cv = CondVar::FindOrCreate(aTrace,0);
  2229 		Object* owner = Thread::FindThreadOrProcess(aTrace,1);
  2230 		cv->iOwner = owner;
  2231 		if (!owner && ownerid)
  2232 			cv->iOwnerTraceId = ownerid, ++Object::UnknownOwners;
  2233 		cv->SetName(aTrace,2);
  2234 		break;
  2235 		}
  2236 
  2237 	case BTrace::ECondVarDestroy:
  2238 		{
  2239 		CHECK_TRACE_DATA_WORDS(1);
  2240 		CondVar* cv = CondVar::Find(aTrace,0);
  2241 		if (cv)
  2242 			cv->Destroy();
  2243 		break;
  2244 		}
  2245 
  2246 	case BTrace::ECondVarBlock:
  2247 	case BTrace::ECondVarWakeUp:
  2248 	case BTrace::ECondVarSignal:
  2249 	case BTrace::ECondVarBroadcast:
  2250 		{
  2251 		CHECK_TRACE_DATA_WORDS(1);
  2252 		CondVar::FindOrCreate(aTrace,0);
  2253 		break;
  2254 		}
  2255 
  2256 
  2257 	default:
  2258 		break;
  2259 		}
  2260 	}
  2261 
  2262 
  2263 void ReportFastMutex()
  2264 	{
  2265 	TUint numMutexes = FastMutex::iContainer.Count();
  2266 	if(!numMutexes)
  2267 		return;
  2268 
  2269 	if(!ReportLevel)
  2270 		printf("\nREPORT: FastMutexes (Named objects only)\n\n");
  2271 	else
  2272 		printf("\nREPORT: FastMutexes\n\n");
  2273 	WarnIfError(0);
  2274 	printf("%-10s %8s %8s %10s %10s %-8s %12s %8s %s\n",
  2275 		"","MaxTime","AveTime","HeldCount","BlockCount","MaxPC","MaxTimestamp","TraceId","Name");
  2276 	TUint i;
  2277 	for(i=0; i<numMutexes; ++i)
  2278 		{
  2279 		FastMutex* mutex = (FastMutex*)FastMutex::iContainer[i];
  2280 		if(ReportLevel==0 && !mutex->iNameSet)
  2281 			continue; // only report explicitly named mutexes at report level 0
  2282 		Object::FullNameBuf fullName;
  2283 		mutex->FullName(fullName);
  2284 		Object::TraceNameBuf name;
  2285 		mutex->TraceName(name);
  2286 		TUint32 averageHeldTime = mutex->iHeldCount ? Time(mutex->iTotalHeldTime/mutex->iHeldCount) : 0;
  2287 		printf("%-10s %8u %8u %10u %10u %08x %12u %08x '%s'\n",
  2288 			name,(unsigned int)Time(mutex->iMaxHeldTime),(unsigned int)averageHeldTime,(unsigned int)mutex->iHeldCount,(unsigned int)mutex->iBlockCount,
  2289 			(unsigned int)mutex->iMaxHeldPc,(unsigned int)Time(mutex->iMaxHeldTimestamp-TimestampBase),(unsigned int)mutex->iTraceId,fullName);
  2290 		}
  2291 	printf("\n");
  2292 	}
  2293 
  2294 
  2295 //
  2296 // ProfilingSample
  2297 //
  2298 
  2299 void StartProfilingSample()
  2300 	{
  2301 	ProfilingSampleErrors = 0;
  2302 	}
  2303 
  2304 
  2305 /** 
  2306 	Index 0 of TraceRecord is the program counter
  2307 	The only one not having it are ECpuNonSymbianThreadSample samples.
  2308 	Index 1 of TraceRecord is the NThread pointer.
  2309 	The only one that has it is ECpuFullSample.
  2310 	The samples are identified by their index, which is maintained by 
  2311 	ProfilingSample::iSamples. Thus to create a ProfilingSample object we
  2312 	need to put this value in the data at index 0 after copying the PC 
  2313 	and Thread id (if present).
  2314 	The reasoning is that all samples need to be represented and thus we 
  2315 	need to create a ProfilingSample object, even when they are on the same 
  2316 	PC and or thread. Each sample important and should not be discarded.
  2317 */
  2318 void PreProcessProfiling(TraceRecord& aTrace)
  2319 	{
  2320 
  2321 	ProfilingSample* sample;
  2322 	Thread* thread;
  2323 
  2324 	switch((BTrace::TProfiling)aTrace.iSubCategory)
  2325 		{
  2326 
  2327 	case BTrace::ECpuFullSample:
  2328 		{
  2329 		CHECK_TRACE_DATA_WORDS(2);
  2330 
  2331 		TUint32 aThread = aTrace.iData[1];
  2332 		// The thread id is aTrace.iData[1], so find or create it
  2333 		// This action can modify aTrace.iData[1], that is why we took a copy above
  2334 		thread = Thread::FindOrCreate(aTrace,1);
  2335 		if( thread )
  2336 			thread->Sampled();
  2337 
  2338 		TUint32 aPC = aTrace.iData[0];
  2339 
  2340 		// Always create a sample identified by the running counter ProfilingSample::iSamples
  2341 		aTrace.iData[0] = ProfilingSample::iSamples;
  2342 		sample = ProfilingSample::Create(aTrace,0);
  2343 		if( sample )
  2344 			{
  2345 			sample->SetPC( aPC );
  2346 			sample->SetThread( aThread );
  2347 			sample->SetType(BTrace::ECpuFullSample);
  2348 			}
  2349 
  2350 		ProfilingSample::iLastThread = aThread;
  2351 		}
  2352 		break;
  2353 
  2354 	case BTrace::ECpuOptimisedSample:
  2355 		{
  2356 		CHECK_TRACE_DATA_WORDS(1);
  2357 		TUint32 aPC = aTrace.iData[0];
  2358 
  2359 		aTrace.iData[0] = ProfilingSample::iSamples;
  2360 		sample = ProfilingSample::Create(aTrace,0);
  2361 		if( sample )
  2362 			{
  2363 			sample->SetPC( aPC );
  2364 			sample->SetType( BTrace::ECpuOptimisedSample );
  2365 			sample->SetThread(ProfilingSample::iLastThread);
  2366 			}
  2367 
  2368 		if( 0 != ProfilingSample::iLastThread )
  2369 			{
  2370 			thread = Thread::Find(ProfilingSample::iLastThread);
  2371 			if( thread )
  2372 				{
  2373 				thread->Sampled();
  2374 				}
  2375 			}
  2376 
  2377 		}
  2378 		break;
  2379 
  2380 	case BTrace::ECpuIdfcSample:
  2381 		{
  2382 		CHECK_TRACE_DATA_WORDS(1);
  2383 		TUint32 aPC = aTrace.iData[0];
  2384 
  2385 		aTrace.iData[0] = ProfilingSample::iSamples;
  2386 		sample = ProfilingSample::Create(aTrace,0);
  2387 
  2388 		sample->SetPC( aPC );
  2389 		sample->SetType(BTrace::ECpuIdfcSample);
  2390 
  2391 		}
  2392 		break;
  2393 
  2394 	case BTrace::ECpuNonSymbianThreadSample:
  2395 		{
  2396 		// No data
  2397 		aTrace.iData[0] = ProfilingSample::iSamples;
  2398 		sample = ProfilingSample::Create(aTrace,0);
  2399 		sample->SetType(BTrace::ECpuNonSymbianThreadSample);
  2400 
  2401 		}
  2402 		break;
  2403 
  2404 	default:
  2405 		ProfilingSampleErrors++;
  2406 		ErrorOnThisTrace = true;
  2407 		}
  2408 
  2409 	ProfilingSample::iSamples++;
  2410 
  2411 	}
  2412 
  2413 
  2414 void ReportSampleProfiling()
  2415 	{
  2416 	printf("\nREPORT: Profiling\n\n");
  2417 
  2418 	TUint numSamples = ProfilingSample::iContainer.Count();
  2419 	if(!numSamples)
  2420 		{
  2421 		printf("\n        No Samples\n\n");
  2422 		return;
  2423 		}
  2424 
  2425 	WarnIfError(0);
  2426 
  2427 
  2428 	// Print thread samples
  2429 	TUint numThreads = Thread::iContainer.Count();
  2430 	if(numThreads)
  2431 		{
  2432 		printf(" Samples by Thread\n\n");
  2433 		printf("%-11s %-8s %-8s\t%-12s\t%s\n\n", "", "TraceId", "Samples", "%", "Name");
  2434 		TUint i;
  2435 		TReal threadPercentage;
  2436 		for(i=0; i<numThreads; ++i)
  2437 			{
  2438 			Thread* thread = (Thread*)Thread::iContainer[i];
  2439 
  2440 			if( thread && thread->iSamples )
  2441 				{
  2442 				Object::FullNameBuf fullName;
  2443 				thread->FullName(fullName);
  2444 				Object::TraceNameBuf name;
  2445 				thread->TraceName(name);
  2446 
  2447 				threadPercentage = thread->iSamples*100.0/numSamples;
  2448 
  2449 				printf("%-10s %08x %8d\t%02.2f\t'%s'\n",
  2450 							name,
  2451 							(unsigned int)thread->iTraceId,
  2452 							(unsigned int)(thread->iSamples),
  2453 							threadPercentage,
  2454 							fullName );
  2455 
  2456 				}//if samples
  2457 			}//for numThreads
  2458 		}//if threads
  2459 
  2460 
  2461 	if(ReportLevel>0)
  2462 		{
  2463 
  2464 		printf("\nAll samples\n\n%-21s %-8s %-8s\n\n", "Type", "ThreadId", "PC");
  2465 
  2466 		TUint i;
  2467 		TUint fullSamples = 0;
  2468 		TUint optSamples = 0;
  2469 		TUint dfcSamples = 0;
  2470 		TUint nonSymbSamples = 0;
  2471 
  2472 		for(i=0; i<numSamples; ++i)
  2473 			{
  2474 			ProfilingSample* sample = (ProfilingSample*)ProfilingSample::iContainer[i];
  2475 			switch((BTrace::TProfiling)sample->iType)
  2476 				{
  2477 				case BTrace::ECpuFullSample:
  2478 					{
  2479 					if( ReportLevel>1)
  2480 						printf("ECpuFull              %08x %08x\n",
  2481 							 (unsigned int)(sample->iThread), (unsigned int)(sample->iPC) );
  2482 
  2483 					fullSamples++;
  2484 					}
  2485 					break;
  2486 				case BTrace::ECpuOptimisedSample:
  2487 					{
  2488 					if( ReportLevel>1)
  2489 						printf("ECpuOptimised         %08x %08x\n",
  2490 							 (unsigned int)(sample->iThread), (unsigned int)(sample->iPC) );
  2491 
  2492 					optSamples++;
  2493 					}
  2494 					break;
  2495 				case BTrace::ECpuIdfcSample:
  2496 					{
  2497 					if( ReportLevel>1)
  2498 						printf("ECpuIdfc              %08x\n", (unsigned int)(sample->iPC) );
  2499 
  2500 					dfcSamples++;
  2501 					}
  2502 					break;
  2503 				case BTrace::ECpuNonSymbianThreadSample:
  2504 					{
  2505 					if( ReportLevel>1)
  2506 						printf("ECpuNonSymbianThread\n");
  2507 
  2508 					nonSymbSamples++;
  2509 					}
  2510 					break;
  2511 				}//switch
  2512 			}//for
  2513 
  2514 
  2515 		TReal typePercentage;
  2516 
  2517 		printf("\nSamples by type\n");
  2518 
  2519 		typePercentage = fullSamples * 100.0 / numSamples;
  2520 		printf(" Samples of type ECpuFullSample :\t\t%-10d\t%02.2f %%\n", fullSamples, typePercentage  );
  2521 
  2522 		typePercentage = optSamples * 100.0 / numSamples;
  2523 		printf(" Samples of type ECpuOptimisedSample :\t\t%-10d\t%02.2f %%\n", optSamples, typePercentage  );
  2524 
  2525 		typePercentage = dfcSamples * 100.0 / numSamples;
  2526 		printf(" Samples of type ECpuIdfcSample :\t\t%-10d\t%02.2f %%\n", dfcSamples, typePercentage  );
  2527 
  2528 		typePercentage = nonSymbSamples * 100.0 / numSamples;
  2529 		printf(" Samples of type ECpuNonSymbianThreadSample :\t%-10d\t%02.2f %%\n", nonSymbSamples, typePercentage  );
  2530 
  2531 		printf(" Total Samples : \t\t\t\t%d\n", numSamples );
  2532 
  2533 		}//report level
  2534 
  2535 	printf("\n");
  2536 	}
  2537 
  2538 //
  2539 // Trace processing
  2540 //
  2541 
  2542 TraceRecord** TraceIndex = 0;
  2543 TUint TraceIndexSize = 0;
  2544 TUint32 NextTraceId = 0;
  2545 TraceRecord* LastTrace = 0;
  2546 TBool Timestamp2Present = 0;
  2547 TBool TraceDumpStarted = false;
  2548 
  2549 
  2550 void StartTrace()
  2551 	{
  2552 	TraceDumpStarted = false;
  2553 	TraceFormatErrors = 0;
  2554 	TraceBufferFilled = false;
  2555 	Timestamp2Present = false;
  2556 	}
  2557 
  2558 
  2559 TUint32 ReadTraceWord(const TUint8*& header)
  2560 	{
  2561 	TUint32 word;
  2562 	memcpy(&word, header, sizeof(TUint32));
  2563 	header += sizeof(TUint32);
  2564 	return word;
  2565 	}
  2566 
  2567 
  2568 TBool PreProcessTrace(TraceRecord& aTrace, const TUint8* aData)
  2569 	{
  2570 	ErrorOnThisTrace = false;
  2571 	aTrace.iError = 0;
  2572 
  2573 	aTrace.iDataSize = 0; // initialise to safe value
  2574 
  2575 	// process aTrace header...
  2576 	TUint traceSize = aData[BTrace::ESizeIndex];
  2577 	if(traceSize<4u || traceSize>(TUint)KMaxBTraceRecordSize)
  2578 		{
  2579 		aTrace.iError = 1;
  2580 		return false; // bad size
  2581 		}
  2582 	aTrace.iCpuNum = 0;
  2583 
  2584 	TUint8 flags = aData[BTrace::EFlagsIndex];
  2585 	if(!TraceRecordId)						// first trace record...?
  2586 		flags &= ~BTrace::EMissingRecord;	// ignore missing traces before log start
  2587 	aTrace.iFlags = flags;
  2588 
  2589 	TUint8 category = aData[BTrace::ECategoryIndex];
  2590 	aTrace.iCategory = category;
  2591 
  2592 	TUint8 subCategory = aData[BTrace::ESubCategoryIndex];
  2593 	aTrace.iSubCategory = subCategory;
  2594 
  2595 	const TUint8* header = aData+4;
  2596 
  2597 	TUint32 header2 = 0;
  2598 	if(flags&BTrace::EHeader2Present)
  2599 		{
  2600 		header2 = ReadTraceWord(header);
  2601 		aTrace.iCpuNum = (TUint8)(header2>>20);
  2602 		}
  2603 	aTrace.iHeader2 = header2;
  2604 	aTrace.iCpu = TheCpus + aTrace.iCpuNum;
  2605 
  2606 	// process timestamp and timestamp2...
  2607 	TUint32 ts1 = 0;
  2608 	TUint32 ts2 = 0;
  2609 	TUint64 timestamp = 0;
  2610 	if(flags&BTrace::ETimestampPresent)
  2611 		ts1 = ReadTraceWord(header);
  2612 	if(flags&BTrace::ETimestamp2Present)
  2613 		{
  2614 		Timestamp2Present = true;
  2615 		ts2 = ReadTraceWord(header);
  2616 		}
  2617 	aTrace.iTimestamp2 = ts2;
  2618 	if(flags&BTrace::ETimestampPresent)
  2619 		{
  2620 		if (Timestamp64Bit)
  2621 			{
  2622 			timestamp = ts2;
  2623 			timestamp <<= 32;
  2624 			timestamp |= ts1;
  2625 			Timestamp = timestamp;
  2626 			}
  2627 		else
  2628 			{
  2629 			timestamp = ts1;
  2630 			if(timestamp<(Timestamp&0xffffffffu))
  2631 				Timestamp += TUint64(1)<<32;
  2632 			Timestamp &= TUint64(0xffffffff)<<32;
  2633 			Timestamp |= timestamp; 
  2634 			timestamp = Timestamp;
  2635 			}
  2636 		if(!TraceRecordId)
  2637 			TimestampBase = timestamp; // record timestamp of first trace
  2638 		}
  2639 	aTrace.iTimestamp = timestamp;
  2640 
  2641 	// process context...
  2642 	// coverity[assign_zero]
  2643 	aTrace.iContextID = 0;
  2644 	if(flags&BTrace::EContextIdPresent)
  2645 		{
  2646 		TUint32 contextId = ReadTraceWord(header);
  2647 		Thread* thread = Thread::Find(contextId);
  2648 		if(!thread)
  2649 			thread = new Thread(contextId);
  2650 		aTrace.iContextID = thread;
  2651 		}
  2652 
  2653 	// process pc...
  2654 	TUint32 pc = 0;
  2655 	if(flags&BTrace::EPcPresent)
  2656 		pc = ReadTraceWord(header);
  2657 	aTrace.iPC = pc;
  2658 
  2659 	// process extra...
  2660 	TUint32 extra = 0;
  2661 	if(flags&BTrace::EExtraPresent)
  2662 		extra = ReadTraceWord(header);
  2663 	aTrace.iExtra = extra;
  2664 
  2665 	// process payload data...
  2666 	TUint headerSize = header-aData;
  2667 	aData = (TUint8*)header;
  2668 	if(headerSize>traceSize)
  2669 		{
  2670 		aTrace.iError = 1;
  2671 		return false; // bad trace record
  2672 		}
  2673 	TUint dataSize = traceSize-headerSize;
  2674 	if(dataSize>sizeof(aTrace.iData))
  2675 		{
  2676 		aTrace.iError = 1;
  2677 		return false; // bad trace record
  2678 		}
  2679 	aTrace.iDataSize = dataSize;
  2680 	memcpy(&aTrace.iData,aData,dataSize);
  2681 
  2682 	// clear pre-processor specific data...
  2683 	aTrace.iDataTypes[0] = 0;
  2684 	aTrace.iDataTypes[1] = 0;
  2685 	aTrace.iDataTypes[2] = 0;
  2686 	aTrace.iDataTypes[3] = 0;
  2687 	aTrace.iCalculatedData[0] = 0;
  2688 	aTrace.iCalculatedData[1] = 0;
  2689 
  2690 	// check for missing.
  2691 	if(flags & BTrace::EMissingRecord)
  2692 		{// Some trace was missing as the btrace buffer must have been filled.
  2693 		TraceBufferFilled = true;
  2694 		aTrace.iError = 1;
  2695 		return false;
  2696 		}
  2697 
  2698 	// category specific processing...
  2699 	switch(aTrace.iCategory)
  2700 		{
  2701 	case BTrace::ERDebugPrintf:
  2702 	case BTrace::EKernPrintf:
  2703 	case BTrace::EPlatsecPrintf:
  2704 		if((flags&BTrace::EHeader2Present) && (header2&BTrace::EMultipartFlagMask))
  2705 			aTrace.iDataTypes[2] = EDataTypeText;
  2706 		else
  2707 			aTrace.iDataTypes[1] = EDataTypeText;
  2708 		break;
  2709 	case BTrace::EThreadIdentification:
  2710 		PreProcessThreadIdentification(aTrace); break;
  2711 	case BTrace::ECpuUsage:
  2712 		PreProcessCpuUsage(aTrace); break;
  2713 	case BTrace::EChunks:
  2714 		PreProcessChunks(aTrace); break;
  2715 	case BTrace::ECodeSegs:
  2716 		PreProcessCodeSegs(aTrace); break;
  2717 	case BTrace::EKernelMemory:
  2718 		PreProcessKernelMemory(aTrace); break;
  2719 	case BTrace::EMetaTrace:
  2720 		PreProcessMetaTrace(aTrace); break;
  2721 	case BTrace::EFastMutex:
  2722 		PreProcessFastMutex(aTrace); break;
  2723 	case BTrace::EProfiling:
  2724 		PreProcessProfiling(aTrace); break;
  2725 	case BTrace::ESymbianKernelSync:
  2726 		PreProcessSymbianKernelSync(aTrace); break;
  2727 	default:
  2728 		break;
  2729 		}
  2730 
  2731 	// update trace ID...
  2732 	++TraceRecordId;
  2733 	if (ErrorOnThisTrace)
  2734 		aTrace.iError = 1;
  2735 	return true;
  2736 	}
  2737 
  2738 
  2739 void DumpTrace(TraceRecord& aTrace)
  2740 	{
  2741 	if(!TraceDumpStarted)
  2742 		{
  2743 		// print heading...
  2744 		if(SMP)
  2745 			printf("C ");
  2746 		if(Timestamp2Present)
  2747 			printf("%10s ","TimeStamp2");
  2748 		printf("%10s ","Time");
  2749 		printf("%-8s ","PC");
  2750 		if(ReportLevel>2)
  2751 			{
  2752 			printf("%-60s ","Context");
  2753 			printf("%18s ","Category");
  2754 			printf("%24s ","SubCategory");
  2755 			}
  2756 		else
  2757 			{
  2758 			printf("%-10s ","Context");
  2759 			printf("%24s ","SubCategory");
  2760 			}
  2761 		printf("Data...\n");
  2762 		TraceDumpStarted = true;
  2763 		}
  2764 
  2765 	if(aTrace.iFlags&BTrace::EMissingRecord)
  2766 		printf("MISSING TRACE RECORD(S)\n");
  2767 
  2768 	// print CPU number
  2769 	if (SMP)
  2770 		{
  2771 		printf("%1d ", aTrace.iCpuNum);
  2772 		}
  2773 
  2774 	// print timestamp...
  2775 	if(Timestamp2Present)
  2776 		{
  2777 		if(aTrace.iFlags&BTrace::ETimestamp2Present)
  2778 			printf("%10u ",(unsigned int)aTrace.iTimestamp2);
  2779 		else
  2780 			printf("           ");
  2781 		}
  2782 
  2783 	if(aTrace.iFlags&BTrace::ETimestampPresent)
  2784 		printf("%10u ",(unsigned int)Time(aTrace.iTimestamp-TimestampBase));
  2785 	else
  2786 		printf("           ");
  2787 
  2788 	// print PC...
  2789 	if(aTrace.iFlags&BTrace::EPcPresent)
  2790 		printf("%08x ",(unsigned int)aTrace.iPC);
  2791 	else
  2792 		printf("         ");
  2793 
  2794 	// print context...
  2795 	if(ReportLevel>2)
  2796 		{
  2797 		Object::FullTraceNameBuf fullName;
  2798 		fullName[0] = 0;
  2799 		if(aTrace.iFlags&BTrace::EContextIdPresent)
  2800 			aTrace.iContextID->FullTraceName(fullName);
  2801 		printf("%-60s ",fullName);
  2802 		}
  2803 	else
  2804 		{
  2805 		Object::TraceNameBuf traceName;
  2806 		traceName[0] = 0;
  2807 		if(aTrace.iFlags&BTrace::EContextIdPresent)
  2808 			aTrace.iContextID->TraceName(traceName);
  2809 		printf("%-10s ",traceName);
  2810 		}
  2811 	// print trace categories...
  2812 	const char* catName = CategoryName(aTrace.iCategory);
  2813 	const char* subCatName = SubCategoryName(aTrace.iCategory,aTrace.iSubCategory);
  2814 	if(ReportLevel>2)
  2815 		printf("%18s %-24s ",catName,subCatName);
  2816 	else
  2817 		{
  2818 		if(subCatName[0])
  2819 			printf("%24s ",subCatName);
  2820 		else
  2821 			printf("%24s ",catName);
  2822 		};
  2823 
  2824 	// print trace data contents...
  2825 	TUint i;
  2826 	for(i=0; i<aTrace.iDataSize; i+=4)
  2827 		{
  2828 		TUint32 data = aTrace.iData[i/sizeof(TUint32)];
  2829 		if(i<16)
  2830 			{
  2831 			// first 4 words of data may have 'type' info set during pre-processing...
  2832 			switch(aTrace.iDataTypes[i/sizeof(TUint32)])
  2833 				{
  2834 			case EDataTypeObject:
  2835 				{
  2836 				// data is an object, print "full name"[traceID]...
  2837 				Object* object = (Object*)data;
  2838 				if(ReportLevel>2)
  2839 					{
  2840 					Object::FullTraceNameBuf name;
  2841 					object->FullTraceName(name);
  2842 					printf("%s ",name);
  2843 					}
  2844 				else
  2845 					{
  2846 					Object::TraceNameBuf name;
  2847 					object->TraceName(name);
  2848 					printf("%s ",name);
  2849 					}
  2850 				}
  2851 				continue;
  2852 
  2853 			case EDataTypeText:
  2854 				{
  2855 				// rest of trace is text...
  2856 				TUint8* text = (TUint8*)aTrace.iData+i;
  2857 				TUint8* textEnd = text+(aTrace.iDataSize-i);
  2858 				TUint8 buffer[256];
  2859 				TUint x=0;
  2860 				while(text<textEnd && x<sizeof(buffer)-2)
  2861 					{
  2862 					TUint8 c = *text++;
  2863 					TUint8 escape = 0;
  2864 					switch(c)
  2865 						{
  2866 					case 9: escape = 't'; break;
  2867 					case 10: escape = 'n'; break;
  2868 					case 13: escape = 'r'; break;
  2869 					default:
  2870 						if(c<' ') c = '?';
  2871 						break;
  2872 						}
  2873 					if(!escape)
  2874 						buffer[x++] = c;
  2875 					else
  2876 						{
  2877 						buffer[x++] = '\\';
  2878 						buffer[x++] = escape;
  2879 						}
  2880 					}
  2881 				buffer[x] = 0;
  2882 				printf("\"%s\" ",buffer);
  2883 				i = aTrace.iDataSize; // skip to end of data
  2884 				}
  2885 				continue;
  2886 
  2887 			default:
  2888 				break;
  2889 				}
  2890 			}
  2891 		// default to print data as hex value...
  2892 		printf("%08x ",(unsigned int)data);
  2893 		}
  2894 
  2895 	// print any extra data added by pre-processing...
  2896 	for(i=0; i<2; ++i)
  2897 		{
  2898 		if(aTrace.iCalculatedData[i])
  2899 			printf("{%u} ",(unsigned int)aTrace.iCalculatedData[i]);
  2900 		}
  2901 
  2902 	if (aTrace.iError)
  2903 		printf(" ***ERROR***");
  2904 
  2905 	// end-of-line finally!
  2906 	printf("\n");
  2907 	}
  2908 
  2909 
  2910 void DumpAllTraces()
  2911 	{
  2912 	printf("\nREPORT: Trace Dump\n\n");
  2913 	for(TUint i=0; i<NextTraceId; i++)
  2914 		DumpTrace(*TraceIndex[i]);
  2915 	printf("\n");
  2916 	}
  2917 
  2918 
  2919 void ReportErrors()
  2920 	{
  2921 	TBool errors = 	TraceFormatErrors || InterruptNestErrors || TraceFormatErrors 
  2922 		|| ChunkErrors || CodeSegErrors || FastMutexNestErrors || KernelMemoryErrors
  2923 		|| ProfilingSampleErrors;
  2924 
  2925 	if(!errors)
  2926 		return;
  2927 		
  2928 	printf("\nREPORT: Trace Analysis Errors\n\n");
  2929 	if(TraceFormatErrors)
  2930 		printf("\tTrace Format Errors = %d\n",TraceFormatErrors);
  2931 	if(InterruptNestErrors)
  2932 		printf("\tInterrupt Nest Errors = %d\n",InterruptNestErrors);
  2933 	if(FastMutexNestErrors)
  2934 		printf("\tFast Mutex Nest Errors = %d\n",FastMutexNestErrors);
  2935 	if(KernelMemoryErrors)
  2936 		printf("\tKernel Memory Errors = %d\n",KernelMemoryErrors);
  2937 	if(ChunkErrors)
  2938 		printf("\tChunk Errors = %d\n",ChunkErrors);
  2939 	if(CodeSegErrors)
  2940 		printf("\tCodeSeg Errors = %d\n",CodeSegErrors);
  2941 	if(ProfilingSampleErrors)
  2942 		printf("\tProfiling Errors = %d\n",ProfilingSampleErrors);
  2943 	printf("\n");
  2944 	}
  2945 
  2946 
  2947 /**
  2948 The last trace record created has been preporcessed.
  2949 */
  2950 void DoneTrace()
  2951 	{
  2952 	if(LastTrace)
  2953 		TraceIndex[NextTraceId++] = (TraceRecord*)realloc(LastTrace,sizeof(TraceHeader)+LastTrace->iDataSize);
  2954 	LastTrace = 0;
  2955 	}
  2956 
  2957 
  2958 /**
  2959 Create a new trace record.
  2960 */
  2961 TraceRecord* NewTrace()
  2962 	{
  2963 	if(NextTraceId>=TraceIndexSize)
  2964 		{
  2965 		TraceIndexSize += 1024;
  2966 		TraceIndex = (TraceRecord**)realloc(TraceIndex,TraceIndexSize*sizeof(TraceIndex[0]));
  2967 		ASSERT(TraceIndex);
  2968 		}
  2969 	DoneTrace();
  2970 	LastTrace = (TraceRecord*)malloc(sizeof(TraceRecord));
  2971 	return LastTrace;
  2972 	}
  2973 
  2974 
  2975 /**
  2976 Delete all processed traces records.
  2977 */
  2978 void ResetTrace()
  2979 	{
  2980 	DoneTrace();
  2981 	TUint i;
  2982 	for(i=0; i<NextTraceId; ++i)
  2983 		free(TraceIndex[i]);
  2984 	free(TraceIndex);
  2985 	TraceIndex = 0;
  2986 	TraceIndexSize = 0;
  2987 	LastTrace = 0;
  2988 	NextTraceId = 0;
  2989 	TraceRecordId = 0;
  2990 	}
  2991 
  2992 
  2993 void EndTrace()
  2994 	{
  2995 	DoneTrace();
  2996 	}
  2997 
  2998 
  2999 /**
  3000 Process an entire BTrace log capture.
  3001 
  3002 @param aInput		Pointer to function which will supply raw trace data.
  3003 					Function should place up to aMaxSize bytes of data at aBuffer and return
  3004 					the number of bytes stored. Return zero to indicate end of data.
  3005 @param aReportLevel	Level of detail required of trace alaysis.
  3006 					0 = brief summary, 1 = full summary, 2 = condensed trace dump, 3 = full trace dump.
  3007 */
  3008 void ProcessAllTrace(TUint (*aInput)(TAny* aBuffer, TUint aMaxSize),TInt aReportLevel)
  3009 	{
  3010 	ReportLevel = aReportLevel;
  3011 //	__UHEAP_MARK;
  3012 	printf("Btrace Analysis:\n");
  3013 	printf("\nTHIS TOOL IS UNOFFICIAL, UNSUPPORTED AND SUBJECT TO CHANGE WITHOUT NOTICE!\n");
  3014 
  3015 	StartTrace();
  3016 	StartCpuUsage();
  3017 	StartChunks();
  3018 	StartCodeSegs();
  3019 	StartFastMutex();
  3020 	StartKernelMemory();
  3021 	StartMetaTrace();
  3022 	StartProfilingSample();
  3023 
  3024 	for(; !TraceBufferFilled ;)
  3025 		{
  3026 		// read more data...
  3027 		TUint size = (*aInput)(TraceBuffer+TraceBufferSize, sizeof(TraceBuffer)-TraceBufferSize);
  3028 		if(!size)
  3029 			break;
  3030 		TraceBufferSize += size;
  3031 
  3032 		// process all the complete traces in buffer...
  3033 		const TUint8* data = TraceBuffer;
  3034 		TUint sizeRemaining = TraceBufferSize;
  3035 		while(sizeRemaining>BTrace::ESizeIndex)
  3036 			{
  3037 			TUint traceSize = (data[BTrace::ESizeIndex]+3)&~3;
  3038 			if(traceSize>sizeRemaining)
  3039 				break;
  3040 
  3041 			TraceRecord* trace = NewTrace();
  3042 			ASSERT(trace);
  3043 			if(!PreProcessTrace(*trace,data))
  3044 				{
  3045 				if (!TraceBufferFilled)
  3046 					{
  3047 					// bad trace, create dummy 1 byte trace record...
  3048 					memset(trace,0,sizeof(*trace));
  3049 					trace->iCategory = BTrace::EMetaTrace;
  3050 					trace->iSubCategory = KJunkTraceSubcategory;
  3051 					trace->iDataSize = 4;
  3052 					trace->iData[0] = *data;
  3053 					++TraceFormatErrors;
  3054 					ErrorOnThisTrace = true;
  3055 					traceSize = 1;
  3056 					}
  3057 				else // The buffer was filled so ignore the rest of the data
  3058 					break;
  3059 				}
  3060 
  3061 			data += traceSize;
  3062 			sizeRemaining -= traceSize;
  3063 			}
  3064 		
  3065 		if (!TraceBufferFilled)
  3066 			{
  3067 			memcpy(TraceBuffer,data,sizeRemaining);
  3068 			TraceBufferSize = sizeRemaining;
  3069 			}
  3070 		else
  3071 			{
  3072 			// The trace buffer was filled so ignore the rest of the data
  3073 			// and just read whatever is left to flush it from the btrace buffer.
  3074 			while ((*aInput)(TraceBuffer, sizeof(TraceBuffer))){};
  3075 			TraceBufferSize = 0;	// reset here so a format error isn't reported
  3076 			}
  3077 
  3078 		if(aReportLevel<2)
  3079 			ResetTrace(); // free up memory as we go along
  3080 		}
  3081 	EndTrace();
  3082 	EndCpuUsage();
  3083 
  3084 	if(TraceBufferSize)
  3085 		{
  3086 		++TraceFormatErrors;
  3087 		ErrorOnThisTrace = true;
  3088 		}
  3089 
  3090 	ReportTimeUnits();
  3091 	ReportErrors();
  3092 	if(aReportLevel>=2)
  3093 		DumpAllTraces();
  3094 	if(ReportLevel>=1 || CpuUsagePresent)
  3095 		{
  3096 		ReportProcesses();
  3097 		ReportThreads();
  3098 		}
  3099 	ReportChunks();
  3100 	ReportKernelMemory();
  3101 	ReportCodeSegs();
  3102 	ReportFastMutex();
  3103 	ReportSampleProfiling();
  3104 
  3105 	ResetTrace();
  3106 	ObjectContainer::Reset();
  3107 //	__UHEAP_MARKEND;
  3108 	}
  3109 
  3110