1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32utils/trace/btrace_analyse.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,3110 @@
1.4 +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#if defined(__EPOC32__) || defined(__WINS__)
1.20 +// compiling for Symbian OS...
1.21 +#include <e32std.h>
1.22 +#include <e32std_private.h>
1.23 +#include <e32svr.h>
1.24 +#include <e32def.h>
1.25 +#include <e32def_private.h>
1.26 +#include <d32btrace.h>
1.27 +#include "e32btrace.h"
1.28 +
1.29 +inline void* malloc(TInt aSize) { return User::Alloc(aSize); }
1.30 +inline void* realloc(void* aPtr,TInt aSize) { return User::ReAlloc(aPtr,aSize); }
1.31 +inline void free(void* aPtr) { User::Free(aPtr); }
1.32 +
1.33 +TUint8 PrintfBuffer[256];
1.34 +TUint PrintfBufferWidth = 0;
1.35 +
1.36 +static void printf(const char* aFormat,...)
1.37 + {
1.38 + VA_LIST list;
1.39 + VA_START(list,aFormat);
1.40 + TPtrC8 format((const TUint8*)aFormat);
1.41 + TPtr8 buf(PrintfBuffer+PrintfBufferWidth,sizeof(PrintfBuffer)-PrintfBufferWidth);
1.42 + buf.AppendFormatList(format,list);
1.43 + PrintfBufferWidth += buf.Size();
1.44 + for(;;)
1.45 + {
1.46 + TUint width = 0;
1.47 + for(;;)
1.48 + {
1.49 + if(width>=PrintfBufferWidth)
1.50 + return;
1.51 + if(PrintfBuffer[width]=='\n')
1.52 + break;
1.53 + ++width;
1.54 + }
1.55 + TPtrC8 line(PrintfBuffer,width);
1.56 + ++width;
1.57 + RDebug::RawPrint(line);
1.58 + _LIT(KLineEnd,"\r\n");
1.59 + RDebug::RawPrint(KLineEnd);
1.60 + memcpy(PrintfBuffer,PrintfBuffer+width,PrintfBufferWidth-width);
1.61 + PrintfBufferWidth -= width;
1.62 + }
1.63 + }
1.64 +
1.65 +typedef TUint uintptr_t;
1.66 +
1.67 +#ifndef ASSERT
1.68 +#define ASSERT(c) (void)((c)||(AssertFailed(__LINE__)))
1.69 +TInt AssertFailed(TInt aLine)
1.70 + {
1.71 + _LIT(KPanicCategory,"BTRACE-ANALYSE");
1.72 + User::Panic(KPanicCategory,aLine);
1.73 + return 0;
1.74 + }
1.75 +#endif // ASSERT
1.76 +
1.77 +
1.78 +//
1.79 +// Trace buffer helper functions - for use on target only
1.80 +//
1.81 +RBTrace Trace;
1.82 +TUint8* AnalyseData;
1.83 +TUint AnalyseDataRemain = 0;
1.84 +
1.85 +void RePrime()
1.86 + {
1.87 + for(TInt i=0; i<256; ++i)
1.88 + {
1.89 + if(Trace.Filter(i))
1.90 + {
1.91 + // toggle filter to force a prime
1.92 + Trace.SetFilter(i,0);
1.93 + Trace.SetFilter(i,1);
1.94 + }
1.95 + }
1.96 + }
1.97 +
1.98 +TUint AnalyseStream(TAny* aBuffer, TUint aMaxSize)
1.99 + {
1.100 + TUint size = AnalyseDataRemain;
1.101 + if(!size)
1.102 + {
1.103 + Trace.DataUsed();
1.104 + AnalyseDataRemain = Trace.GetData(AnalyseData);
1.105 + size = AnalyseDataRemain;
1.106 + }
1.107 + if(size>aMaxSize)
1.108 + size = aMaxSize;
1.109 + memcpy(aBuffer,AnalyseData,size);
1.110 + AnalyseData += size;
1.111 + AnalyseDataRemain -= size;
1.112 + return size;
1.113 + }
1.114 +
1.115 +void ProcessAllTrace(TUint (*aInput)(TAny* aBuffer, TUint aMaxSize),TInt aReportLevel);
1.116 +
1.117 +void DoAnalyse(TInt aAnalysisLevel)
1.118 + {
1.119 + AnalyseDataRemain = 0;
1.120 + TUint oldMode = Trace.Mode();
1.121 + Trace.SetMode(0); // turn off trace capture while we dump
1.122 + ProcessAllTrace(AnalyseStream, aAnalysisLevel);
1.123 + Trace.SetMode(oldMode);
1.124 + RePrime();
1.125 + }
1.126 +
1.127 +TInt BTraceAnalyseSetup()
1.128 + {
1.129 + TInt r = Trace.Open();
1.130 + if (r != KErrNone)
1.131 + {
1.132 + return r;
1.133 + }
1.134 + // Stop tracing
1.135 + TUint oldMode = Trace.Mode();
1.136 + Trace.SetMode(0);
1.137 +
1.138 + // empty btrace buffer and reprime it
1.139 + Trace.Empty();
1.140 + Trace.SetMode(oldMode);
1.141 + RePrime();
1.142 + return KErrNone;
1.143 + }
1.144 +
1.145 +void BTraceAnalyseEnd()
1.146 + {
1.147 + Trace.Close();
1.148 + }
1.149 +
1.150 +void BTraceAnalyse(TInt aAnalysisLevel)
1.151 + {
1.152 + // Stop tracing
1.153 + TUint oldMode = Trace.Mode();
1.154 + Trace.SetMode(0);
1.155 +
1.156 + AnalyseDataRemain = 0;
1.157 + ProcessAllTrace(AnalyseStream, aAnalysisLevel);
1.158 +
1.159 + // empty btrace buffer and reprime it
1.160 + Trace.Empty();
1.161 + Trace.SetMode(oldMode);
1.162 + RePrime();
1.163 + }
1.164 +
1.165 +#else
1.166 +// compiling for host...
1.167 +
1.168 +#include <stdio.h>
1.169 +#include <string.h>
1.170 +#include <malloc.h>
1.171 +
1.172 +#if defined(_MSC_VER)
1.173 +typedef __int64 longlong;
1.174 +typedef unsigned __int64 ulonglong;
1.175 +#define BREAKPOINT { _asm int 3 } /**< Invoke debugger */
1.176 +#else
1.177 +typedef long long longlong;
1.178 +typedef long long ulonglong;
1.179 +#define BREAKPOINT
1.180 +#endif
1.181 +
1.182 +typedef signed char TInt8;
1.183 +typedef unsigned char TUint8;
1.184 +typedef unsigned short TUint16;
1.185 +typedef unsigned int TUint32;
1.186 +typedef ulonglong TUint64;
1.187 +typedef unsigned int uintptr_t;
1.188 +typedef int TInt;
1.189 +typedef unsigned TUint;
1.190 +typedef int TBool;
1.191 +typedef void TAny;
1.192 +typedef float TReal;
1.193 +#define IMPORT_C
1.194 +#include "e32btrace.h"
1.195 +
1.196 +#define ASSERT(c) (void)((c)||(AssertFailed(__LINE__)))
1.197 +extern "C" void exit(int);
1.198 +TInt AssertFailed(TInt aLine)
1.199 + {
1.200 + fprintf(stderr,"Panic: BTRACE-ANALYSE %d",aLine);
1.201 + BREAKPOINT;
1.202 + exit(2);
1.203 + return 0;
1.204 + }
1.205 +
1.206 +#define __UHEAP_MARK
1.207 +#define __UHEAP_MARKEND
1.208 +
1.209 +TAny* operator new(size_t, TAny* p) {return p;}
1.210 +
1.211 +#endif // SYMBIAN_OS
1.212 +
1.213 +
1.214 +
1.215 +//
1.216 +// Global data
1.217 +//
1.218 +
1.219 +TInt ReportLevel = 0;
1.220 +TUint8 TraceBuffer[0x10000];
1.221 +TUint TraceBufferSize = 0;
1.222 +TUint64 Timestamp = 0;
1.223 +TUint64 TimestampBase = 0;
1.224 +TUint32 TraceRecordId = 0;
1.225 +TUint32 TimestampPeriod = 0;
1.226 +TUint32 Timestamp2Period = 0;
1.227 +TBool Timestamp64Bit = 0;
1.228 +TUint TraceFormatErrors = 0;
1.229 +TBool TraceBufferFilled = false;
1.230 +TBool SMP = true;
1.231 +TBool ErrorOnThisTrace = false;
1.232 +
1.233 +const TUint8 KJunkTraceSubcategory = 255; // Dummy sub-category for EMetaTrace
1.234 +
1.235 +const TInt KMaxCpus = 8;
1.236 +
1.237 +//
1.238 +// Utilities
1.239 +//
1.240 +
1.241 +void ToHex(TUint8* aString,TUint32 aValue)
1.242 + {
1.243 + TUint i=32;
1.244 + do
1.245 + {
1.246 + i -= 4;
1.247 + TUint8 c = (TUint8)((aValue>>i)&0xf);
1.248 + if(c>=10)
1.249 + c += 'a'-10;
1.250 + else
1.251 + c += '0';
1.252 + *aString++ = c;
1.253 + }
1.254 + while(i);
1.255 + }
1.256 +
1.257 +
1.258 +TUint MakeName(TUint8* aString,const char* aName,TUint32 aHexValue)
1.259 + {
1.260 + TUint8* start = aString;
1.261 + for(;;)
1.262 + {
1.263 + TUint8 c = *aName++;
1.264 + if(!c)
1.265 + break;
1.266 + *aString++ = c;
1.267 + }
1.268 + ToHex(aString,aHexValue);
1.269 + aString[8] = 0;
1.270 + return aString-start+8;
1.271 + }
1.272 +
1.273 +
1.274 +/**
1.275 +Convert a timestamp into real time units (micro-seconds)
1.276 +*/
1.277 +TUint32 Time(TUint64 aTimestamp)
1.278 + {
1.279 + if(!TimestampPeriod)
1.280 + return (TUint32)aTimestamp;
1.281 + TInt exponent = (TInt8)(TimestampPeriod>>24);
1.282 + TUint64 mantissa = TimestampPeriod&0xffffff;
1.283 + aTimestamp *= mantissa;
1.284 + exponent += 32;
1.285 + if(exponent<0)
1.286 + aTimestamp >>= -exponent;
1.287 + else
1.288 + aTimestamp <<= exponent;
1.289 + TUint64 timeLo = (aTimestamp&0xffffffffu)*1000000;
1.290 + TUint64 timeHi = (aTimestamp>>32)*1000000;
1.291 + TUint64 us = timeHi+(timeLo>>32)+((timeLo>>31)&1);
1.292 + return TUint32(us);
1.293 + }
1.294 +
1.295 +
1.296 +void ReportTimeUnits()
1.297 + {
1.298 + if(!TimestampPeriod)
1.299 + printf("\nAll times are given in BTrace Timestamp1 units.\n\n");
1.300 + else
1.301 + {
1.302 + TInt exponent = (TInt8)(TimestampPeriod>>24);
1.303 + TUint64 mantissa = TimestampPeriod&0xffffff;
1.304 + TUint64 period = 1000000;
1.305 + period *= mantissa;
1.306 + exponent += 32;
1.307 + if(exponent<0)
1.308 + period >>= -exponent;
1.309 + else
1.310 + period <<= exponent;
1.311 + printf("\nAll times are given in microseconds, resolution %d.%03dus\n\n",(int)TUint32(period>>32),(int)TUint32((((period&0xffffffffu)*1000)+0x80000000u)>>32));
1.312 + }
1.313 + }
1.314 +
1.315 +
1.316 +TUint SetBits(TUint8* aData, TUint aOffset, TUint aSize)
1.317 + {
1.318 + TUint mask = 1<<(aOffset&7);
1.319 + TUint8* data = aData+(aOffset>>3);
1.320 + TUint errors = 0;
1.321 + while(aSize)
1.322 + {
1.323 + if(*data&mask)
1.324 + ++errors;
1.325 + *data |= (TUint8)mask;
1.326 + mask <<= 1;
1.327 + if(mask>0xFF)
1.328 + {
1.329 + mask = 0x01;
1.330 + ++data;
1.331 + }
1.332 + --aSize;
1.333 + }
1.334 + return errors;
1.335 + }
1.336 +
1.337 +
1.338 +TUint ClearBits(TUint8* aData, TUint aOffset, TUint aSize)
1.339 + {
1.340 + TUint mask = 1<<(aOffset&7);
1.341 + TUint8* data = aData+(aOffset>>3);
1.342 + TUint errors = 0;
1.343 + while(aSize)
1.344 + {
1.345 + if(!(*data&mask))
1.346 + ++errors;
1.347 + *data &= (TUint8)~mask;
1.348 + mask <<= 1;
1.349 + if(mask>0xFF)
1.350 + {
1.351 + mask = 0x01;
1.352 + ++data;
1.353 + }
1.354 + --aSize;
1.355 + }
1.356 + return errors;
1.357 + }
1.358 +
1.359 +
1.360 +void WarnIfError(TUint aErrorCount)
1.361 + {
1.362 + if (TraceBufferFilled)
1.363 + printf("WARNING - BTRACE BUFFER IS FULL SO TRACE DATA MAY BE INCOMPLETE\n");
1.364 +
1.365 + if(aErrorCount==0 && TraceFormatErrors==0)
1.366 + return;
1.367 + printf("CONSISTENCY ERRORS FOUND DURING TRACE ANALYSIS, RESULTS ARE UNRELIABLE!\n");
1.368 + }
1.369 +
1.370 +
1.371 +#define CHECK_TRACE_DATA_WORDS(numWords) \
1.372 + if(aTrace.iDataSize<numWords*4 && ++TraceFormatErrors) return
1.373 +
1.374 +
1.375 +//
1.376 +// Category naming
1.377 +//
1.378 +
1.379 +const char* const UnknownNames[256] =
1.380 + {
1.381 + "?00","?01","?02","?03","?04","?05","?06","?07","?08","?09",
1.382 + "?10","?11","?12","?13","?14","?15","?16","?17","?18","?19",
1.383 + "?20","?21","?22","?23","?24","?25","?26","?27","?28","?29",
1.384 + "?30","?31","?32","?33","?34","?35","?36","?37","?38","?39",
1.385 + "?40","?41","?42","?43","?44","?45","?46","?47","?48","?49",
1.386 + "?50","?51","?52","?53","?54","?55","?56","?57","?58","?59",
1.387 + "?60","?61","?62","?63","?64","?65","?66","?67","?68","?69",
1.388 + "?70","?71","?72","?73","?74","?75","?76","?77","?78","?79",
1.389 + "?80","?81","?82","?83","?84","?85","?86","?87","?88","?89",
1.390 + "?90","?91","?92","?93","?94","?95","?96","?97","?98","?99",
1.391 + "?100","?101","?102","?103","?104","?105","?106","?107","?108","?109",
1.392 + "?110","?111","?112","?113","?114","?115","?116","?117","?118","?119",
1.393 + "?120","?121","?122","?123","?124","?125","?126","?127","?128","?129",
1.394 + "?130","?131","?132","?133","?134","?135","?136","?137","?138","?139",
1.395 + "?140","?141","?142","?143","?144","?145","?146","?147","?148","?149",
1.396 + "?150","?151","?152","?153","?154","?155","?156","?157","?158","?159",
1.397 + "?160","?161","?162","?163","?164","?165","?166","?167","?168","?169",
1.398 + "?170","?171","?172","?173","?174","?175","?176","?177","?178","?179",
1.399 + "?180","?181","?182","?183","?184","?185","?186","?187","?188","?189",
1.400 + "?190","?191","?192","?193","?194","?195","?196","?197","?198","?199",
1.401 + "?200","?201","?202","?203","?204","?205","?206","?207","?208","?209",
1.402 + "?210","?211","?212","?213","?214","?215","?216","?217","?218","?219",
1.403 + "?220","?221","?222","?223","?224","?225","?226","?227","?228","?229",
1.404 + "?230","?231","?232","?233","?234","?235","?236","?237","?238","?239",
1.405 + "?240","?241","?242","?243","?244","?245","?246","?247","?248","?249",
1.406 + "?250","?251","?252","?253","?254","?255"
1.407 + };
1.408 +
1.409 +
1.410 +#define STRINGIFY2(a) #a /**< Helper for #STRINGIFY */
1.411 +#define STRINGIFY(a) STRINGIFY2(a) /**< Convert \a a into a quoted string */
1.412 +#define CASE_CAT_NAME(name) case BTrace::name: return STRINGIFY(name)
1.413 +
1.414 +const char* CategoryName(TUint8 aCategory)
1.415 + {
1.416 + switch((BTrace::TCategory)aCategory)
1.417 + {
1.418 + CASE_CAT_NAME(ERDebugPrintf);
1.419 + CASE_CAT_NAME(EKernPrintf);
1.420 + CASE_CAT_NAME(EPlatsecPrintf);
1.421 + case BTrace::EThreadIdentification: return "EThreadId"; // CASE_CAT_NAME(EThreadIdentification)
1.422 + CASE_CAT_NAME(ECpuUsage);
1.423 + CASE_CAT_NAME(EKernPerfLog);
1.424 + CASE_CAT_NAME(EClientServer);
1.425 + CASE_CAT_NAME(ERequests);
1.426 + CASE_CAT_NAME(EChunks);
1.427 + CASE_CAT_NAME(ECodeSegs);
1.428 + CASE_CAT_NAME(EPaging);
1.429 + CASE_CAT_NAME(EThreadPriority);
1.430 + CASE_CAT_NAME(EPagingMedia);
1.431 + CASE_CAT_NAME(EKernelMemory);
1.432 + CASE_CAT_NAME(EHeap);
1.433 + CASE_CAT_NAME(EMetaTrace);
1.434 +
1.435 + CASE_CAT_NAME(EFastMutex);
1.436 + CASE_CAT_NAME(EProfiling);
1.437 + CASE_CAT_NAME(ESymbianKernelSync);
1.438 + CASE_CAT_NAME(EFlexibleMemModel);
1.439 + CASE_CAT_NAME(ETest1);
1.440 + CASE_CAT_NAME(ETest2);
1.441 + default:
1.442 + break;
1.443 + }
1.444 + return UnknownNames[aCategory];
1.445 + }
1.446 +
1.447 +const char* SubCategoryName(TUint8 aCategory, TUint8 aSubCategory)
1.448 + {
1.449 + switch(aCategory)
1.450 + {
1.451 + case BTrace::ERDebugPrintf:
1.452 + case BTrace::EKernPrintf:
1.453 + case BTrace::EPlatsecPrintf:
1.454 + return ""; // no subcategories for these
1.455 +
1.456 + case BTrace::EThreadIdentification:
1.457 + switch((BTrace::TThreadIdentification)aSubCategory)
1.458 + {
1.459 + CASE_CAT_NAME(ENanoThreadCreate);
1.460 + CASE_CAT_NAME(ENanoThreadDestroy);
1.461 + CASE_CAT_NAME(EThreadCreate);
1.462 + CASE_CAT_NAME(EThreadDestroy);
1.463 + CASE_CAT_NAME(EThreadName);
1.464 + CASE_CAT_NAME(EProcessName);
1.465 + CASE_CAT_NAME(EThreadId);
1.466 + CASE_CAT_NAME(EProcessCreate);
1.467 + CASE_CAT_NAME(EProcessDestroy);
1.468 + }
1.469 + break;
1.470 +
1.471 + case BTrace::ECpuUsage:
1.472 + switch((BTrace::TCpuUsage)aSubCategory)
1.473 + {
1.474 + CASE_CAT_NAME(EIrqStart);
1.475 + CASE_CAT_NAME(EIrqEnd);
1.476 + CASE_CAT_NAME(EFiqStart);
1.477 + CASE_CAT_NAME(EFiqEnd);
1.478 + CASE_CAT_NAME(EIDFCStart);
1.479 + CASE_CAT_NAME(EIDFCEnd);
1.480 + CASE_CAT_NAME(ENewThreadContext);
1.481 + }
1.482 + break;
1.483 +
1.484 + case BTrace::EChunks:
1.485 + switch((BTrace::TChunks)aSubCategory)
1.486 + {
1.487 + CASE_CAT_NAME(EChunkCreated);
1.488 + CASE_CAT_NAME(EChunkInfo);
1.489 + CASE_CAT_NAME(EChunkDestroyed);
1.490 + CASE_CAT_NAME(EChunkMemoryAllocated);
1.491 + CASE_CAT_NAME(EChunkMemoryDeallocated);
1.492 + CASE_CAT_NAME(EChunkMemoryAdded);
1.493 + CASE_CAT_NAME(EChunkMemoryRemoved);
1.494 + CASE_CAT_NAME(EChunkOwner);
1.495 + }
1.496 + break;
1.497 +
1.498 + case BTrace::ECodeSegs:
1.499 + switch((BTrace::TCodeSegs)aSubCategory)
1.500 + {
1.501 + CASE_CAT_NAME(ECodeSegCreated);
1.502 + CASE_CAT_NAME(ECodeSegInfo);
1.503 + CASE_CAT_NAME(ECodeSegDestroyed);
1.504 + CASE_CAT_NAME(ECodeSegMapped);
1.505 + CASE_CAT_NAME(ECodeSegUnmapped);
1.506 + CASE_CAT_NAME(ECodeSegMemoryAllocated);
1.507 + CASE_CAT_NAME(ECodeSegMemoryDeallocated);
1.508 + }
1.509 + break;
1.510 +
1.511 + case BTrace::EPaging:
1.512 + switch((BTrace::TPaging)aSubCategory)
1.513 + {
1.514 + CASE_CAT_NAME(EPagingPageInBegin);
1.515 + CASE_CAT_NAME(EPagingPageInUnneeded);
1.516 + CASE_CAT_NAME(EPagingPageInROM);
1.517 + CASE_CAT_NAME(EPagingPageOutROM);
1.518 + CASE_CAT_NAME(EPagingPageInFree);
1.519 + CASE_CAT_NAME(EPagingPageOutFree);
1.520 + CASE_CAT_NAME(EPagingRejuvenate);
1.521 + CASE_CAT_NAME(EPagingPageNop);
1.522 + CASE_CAT_NAME(EPagingPageLock);
1.523 + CASE_CAT_NAME(EPagingPageUnlock);
1.524 + CASE_CAT_NAME(EPagingPageOutCache);
1.525 + CASE_CAT_NAME(EPagingPageInCode);
1.526 + CASE_CAT_NAME(EPagingPageOutCode);
1.527 + CASE_CAT_NAME(EPagingMapCode);
1.528 + CASE_CAT_NAME(EPagingAged);
1.529 + CASE_CAT_NAME(EPagingDecompressStart);
1.530 + CASE_CAT_NAME(EPagingDecompressEnd);
1.531 + CASE_CAT_NAME(EPagingMemoryModel);
1.532 + CASE_CAT_NAME(EPagingChunkDonatePage);
1.533 + CASE_CAT_NAME(EPagingChunkReclaimPage);
1.534 + CASE_CAT_NAME(EPagingPageIn);
1.535 + CASE_CAT_NAME(EPagingPageOut);
1.536 + CASE_CAT_NAME(EPagingMapPage);
1.537 + CASE_CAT_NAME(EPagingDonatePage);
1.538 + CASE_CAT_NAME(EPagingReclaimPage);
1.539 + CASE_CAT_NAME(EPagingAgedClean);
1.540 + CASE_CAT_NAME(EPagingAgedDirty);
1.541 + CASE_CAT_NAME(EPagingPageTableAlloc);
1.542 + }
1.543 + break;
1.544 +
1.545 + case BTrace::EKernelMemory:
1.546 + switch((BTrace::TKernelMemory)aSubCategory)
1.547 + {
1.548 + CASE_CAT_NAME(EKernelMemoryInitialFree);
1.549 + CASE_CAT_NAME(EKernelMemoryCurrentFree);
1.550 + CASE_CAT_NAME(EKernelMemoryMiscAlloc);
1.551 + CASE_CAT_NAME(EKernelMemoryMiscFree);
1.552 + CASE_CAT_NAME(EKernelMemoryDemandPagingCache);
1.553 + CASE_CAT_NAME(EKernelMemoryDrvPhysAlloc);
1.554 + CASE_CAT_NAME(EKernelMemoryDrvPhysFree);
1.555 + }
1.556 + break;
1.557 +
1.558 + case BTrace::EMetaTrace:
1.559 + {
1.560 + if(aSubCategory==KJunkTraceSubcategory)
1.561 + return "*JUNK*";
1.562 + else
1.563 + {
1.564 + switch((BTrace::TMetaTrace)aSubCategory)
1.565 + {
1.566 + CASE_CAT_NAME(EMetaTraceTimestampsInfo);
1.567 + CASE_CAT_NAME(EMetaTraceMeasurementStart);
1.568 + CASE_CAT_NAME(EMetaTraceMeasurementEnd);
1.569 + CASE_CAT_NAME(EMetaTraceFilterChange);
1.570 + }
1.571 + }
1.572 + }
1.573 + break;
1.574 +
1.575 + case BTrace::EFastMutex:
1.576 + switch((BTrace::TFastMutex)aSubCategory)
1.577 + {
1.578 + CASE_CAT_NAME(EFastMutexWait);
1.579 + CASE_CAT_NAME(EFastMutexSignal);
1.580 + CASE_CAT_NAME(EFastMutexFlash);
1.581 + CASE_CAT_NAME(EFastMutexName);
1.582 + CASE_CAT_NAME(EFastMutexBlock);
1.583 + }
1.584 + break;
1.585 +
1.586 + case BTrace::EProfiling:
1.587 + switch((BTrace::TProfiling)aSubCategory)
1.588 + {
1.589 + CASE_CAT_NAME(ECpuFullSample);
1.590 + CASE_CAT_NAME(ECpuOptimisedSample);
1.591 + CASE_CAT_NAME(ECpuIdfcSample);
1.592 + CASE_CAT_NAME(ECpuNonSymbianThreadSample);
1.593 + }
1.594 + break;
1.595 +
1.596 + case BTrace::ESymbianKernelSync:
1.597 + switch((BTrace::TSymbianKernelSync)aSubCategory)
1.598 + {
1.599 + CASE_CAT_NAME(ESemaphoreCreate);
1.600 + CASE_CAT_NAME(ESemaphoreDestroy);
1.601 + CASE_CAT_NAME(ESemaphoreAcquire);
1.602 + CASE_CAT_NAME(ESemaphoreRelease);
1.603 + CASE_CAT_NAME(ESemaphoreBlock);
1.604 + CASE_CAT_NAME(EMutexCreate);
1.605 + CASE_CAT_NAME(EMutexDestroy);
1.606 + CASE_CAT_NAME(EMutexAcquire);
1.607 + CASE_CAT_NAME(EMutexRelease);
1.608 + CASE_CAT_NAME(EMutexBlock);
1.609 + CASE_CAT_NAME(ECondVarCreate);
1.610 + CASE_CAT_NAME(ECondVarDestroy);
1.611 + CASE_CAT_NAME(ECondVarBlock);
1.612 + CASE_CAT_NAME(ECondVarWakeUp);
1.613 + CASE_CAT_NAME(ECondVarSignal);
1.614 + CASE_CAT_NAME(ECondVarBroadcast);
1.615 + }
1.616 + break;
1.617 +
1.618 + case BTrace::EFlexibleMemModel:
1.619 + switch((BTrace::TFlexibleMemModel)aSubCategory)
1.620 + {
1.621 + CASE_CAT_NAME(EMemoryObjectCreate);
1.622 + CASE_CAT_NAME(EMemoryObjectDestroy);
1.623 + CASE_CAT_NAME(EMemoryMappingCreate);
1.624 + CASE_CAT_NAME(EMemoryMappingDestroy);
1.625 + CASE_CAT_NAME(EMemoryObjectIsChunk);
1.626 + CASE_CAT_NAME(EMemoryObjectIsCodeSeg);
1.627 + CASE_CAT_NAME(EMemoryObjectIsProcessStaticData);
1.628 + CASE_CAT_NAME(EMemoryObjectIsDllStaticData);
1.629 + CASE_CAT_NAME(EMemoryObjectIsSupervisorStack);
1.630 + CASE_CAT_NAME(EMemoryObjectIsUserStack);
1.631 + CASE_CAT_NAME(EAddressSpaceId);
1.632 + }
1.633 + break;
1.634 +
1.635 + }
1.636 + return UnknownNames[aSubCategory];
1.637 + }
1.638 +
1.639 +
1.640 +
1.641 +//
1.642 +// Data structures
1.643 +//
1.644 +
1.645 +enum TDataType
1.646 + {
1.647 + EDataTypeNone = 0,
1.648 + EDataTypeText,
1.649 + EDataTypeObject,
1.650 + };
1.651 +
1.652 +class Thread;
1.653 +class Cpu;
1.654 +
1.655 +struct TraceHeader
1.656 + {
1.657 + TUint8 iCpuNum;
1.658 + TUint8 iCategory;
1.659 + TUint8 iSubCategory;
1.660 + TUint8 iFlags;
1.661 + TUint32 iHeader2;
1.662 + TUint64 iTimestamp;
1.663 + TUint32 iTimestamp2;
1.664 + Thread* iContextID;
1.665 + TUint32 iPC;
1.666 + TUint32 iExtra;
1.667 + TUint8 iDataTypes[4];
1.668 + TUint32 iCalculatedData[2];
1.669 + TUint iDataSize;
1.670 + Cpu* iCpu;
1.671 + TUint32 iError;
1.672 + };
1.673 +
1.674 +
1.675 +struct TraceRecord : public TraceHeader
1.676 + {
1.677 + TUint32 iData[(8+KMaxBTraceDataArray)/4];
1.678 + };
1.679 +
1.680 +
1.681 +
1.682 +//
1.683 +// ECpuUsage traces
1.684 +//
1.685 +
1.686 +enum TContext
1.687 + {
1.688 + EContextThread,
1.689 + EContextFiq,
1.690 + EContextIrq,
1.691 + EContextIDFC,
1.692 + EContextUnknown
1.693 + };
1.694 +
1.695 +class Cpu
1.696 + {
1.697 +public:
1.698 + Cpu();
1.699 + void ChangeContext(TContext aType, Thread* aThread=0);
1.700 + void Reset();
1.701 +
1.702 + TContext iCurrentContext;
1.703 + TInt iFiqNest;
1.704 + TInt iIrqNest;
1.705 + TInt iIDFCNest;
1.706 + TUint64 iFiqTime;
1.707 + TUint64 iIrqTime;
1.708 + TUint64 iIDFCTime;
1.709 + Thread* iCurrentThread;
1.710 + TUint64 iBaseTimestamp;
1.711 + };
1.712 +
1.713 +//
1.714 +// Objects
1.715 +//
1.716 +
1.717 +const TUint KMaxTraceNameLength = 10;
1.718 +
1.719 +class Object
1.720 + {
1.721 +public:
1.722 + Object(TUint32 aTraceId, const char* aTraceNamePrefix)
1.723 + : iTraceId(aTraceId), iIndex(~0u), iOwner(0), iOwnerTraceId(0), iAlive(1), iNameSet(false), iNameLength(0),
1.724 + iTraceNamePrefix(aTraceNamePrefix)
1.725 + {
1.726 + iName[0] = 0;
1.727 + }
1.728 +
1.729 + void Destroy()
1.730 + {
1.731 + if(iAlive)
1.732 + --iAlive;
1.733 + if(iOwnerTraceId && !iOwner)
1.734 + --UnknownOwners;
1.735 + }
1.736 +
1.737 + virtual ~Object()
1.738 + {}
1.739 +
1.740 + void SetName(void* aName, TUint aLength)
1.741 + {
1.742 + ASSERT(aLength<sizeof(iName));
1.743 + iNameLength = (TUint8)aLength;
1.744 + memcpy(iName,aName,aLength);
1.745 + iName[aLength] = 0;
1.746 + iNameSet = true;
1.747 + }
1.748 +
1.749 + void SetName(TraceRecord& aTrace, TUint aIndex)
1.750 + {
1.751 + SetName(aTrace.iData+aIndex,aTrace.iDataSize-aIndex*4);
1.752 + aTrace.iDataTypes[aIndex] = EDataTypeText;
1.753 + }
1.754 +
1.755 + TBool IsName(void* aName, TUint aLength)
1.756 + {
1.757 + if(aLength!=iNameLength)
1.758 + return false;
1.759 + while(aLength--)
1.760 + if(iName[aLength]!=((TUint8*)aName)[aLength])
1.761 + return false;
1.762 + return true;
1.763 + }
1.764 +
1.765 + typedef TUint8 TraceNameBuf[KMaxTraceNameLength+1];
1.766 + typedef TUint8 FullNameBuf[KMaxBTraceDataArray+2+KMaxBTraceDataArray+2+KMaxBTraceDataArray+1]; // space for name1::name2::name3[tracename]
1.767 + typedef TUint8 FullTraceNameBuf[KMaxBTraceDataArray+1+KMaxBTraceDataArray+2+KMaxBTraceDataArray+KMaxTraceNameLength+1+1]; // space for [tracename]'name1::name2::name3'
1.768 +
1.769 + TUint FullName(FullNameBuf& aName)
1.770 + {
1.771 + TUint length = 0;
1.772 + if(iOwner)
1.773 + {
1.774 + if(iOwner->iOwner)
1.775 + {
1.776 + memcpy(aName+length,iOwner->iOwner->iName,iOwner->iOwner->iNameLength);
1.777 + length += iOwner->iOwner->iNameLength;
1.778 + aName[length++] = ':';
1.779 + aName[length++] = ':';
1.780 + }
1.781 + memcpy(aName+length,iOwner->iName,iOwner->iNameLength);
1.782 + length += iOwner->iNameLength;
1.783 + aName[length++] = ':';
1.784 + aName[length++] = ':';
1.785 + }
1.786 + memcpy(aName+length,iName,iNameLength);
1.787 + length += iNameLength;
1.788 + aName[length] = 0;
1.789 + return length;
1.790 + }
1.791 +
1.792 + TUint TraceName(TraceNameBuf& aName)
1.793 + {
1.794 + TInt i = 0;
1.795 + const TUint KNumDigits = KMaxTraceNameLength-4;
1.796 + aName[i++] = '<';
1.797 + const char* prefix = iTraceNamePrefix;
1.798 + if(prefix[0])
1.799 + aName[i++] = *prefix++;
1.800 + if(prefix[0])
1.801 + aName[i++] = *prefix++;
1.802 + TUint n = iIndex;
1.803 + for(TUint d=KNumDigits; d>0; --d)
1.804 + {
1.805 + aName[i+d-1] = TUint8('0'+(n%10));
1.806 + n /= 10;
1.807 + }
1.808 + i += KNumDigits;
1.809 + aName[i++] = '>';
1.810 + aName[i] = 0;
1.811 + return i;
1.812 + }
1.813 +
1.814 + TUint FullTraceName(FullTraceNameBuf& aName)
1.815 + {
1.816 + TUint l1 = TraceName(*(TraceNameBuf*)aName);
1.817 + aName[l1++] = '\'';
1.818 + TUint l2 = FullName(*(FullNameBuf*)(aName+l1));
1.819 + aName[l1+l2++] = '\'';
1.820 + aName[l1+l2] = 0;
1.821 + return l1+l2;
1.822 + }
1.823 +
1.824 +public:
1.825 + TUint32 iTraceId; ///< ID for object as found in raw trace data.
1.826 + TUint iIndex; ///< Index into container for this object.
1.827 + Object* iOwner; ///< Object which 'owns' this one, e.g. process which owns a thread.
1.828 + TUint32 iOwnerTraceId; ///< Trace ID for owner if owner object as yet unknown
1.829 + TUint8 iAlive; ///< True if object destroyed trace not yet parsed.
1.830 + TUint8 iNameSet; ///< True if name has been set.
1.831 + TUint8 iNameLength;
1.832 + TUint8 iName[KMaxBTraceDataArray+1];
1.833 + const char* iTraceNamePrefix;
1.834 +public:
1.835 + static TUint32 UnknownOwners;
1.836 + };
1.837 +TUint32 Object::UnknownOwners = 0;
1.838 +
1.839 +
1.840 +class ObjectContainer
1.841 + {
1.842 +public:
1.843 + ObjectContainer()
1.844 + : iNumEntries(0), iEntriesLength(0) , iEntries(0)
1.845 + {
1.846 + iLink = iAllContainers;
1.847 + iAllContainers = this;
1.848 + }
1.849 +
1.850 + static void Reset()
1.851 + {
1.852 + ObjectContainer* container = iAllContainers;
1.853 + while(container)
1.854 + {
1.855 + TUint i = container->iNumEntries;
1.856 + while(i--)
1.857 + free(container->iEntries[i].iItem);
1.858 + free(container->iEntries);
1.859 + container->iEntries = 0;
1.860 + container->iNumEntries = 0;
1.861 + container->iEntriesLength = 0;
1.862 + container = container->iLink;
1.863 + }
1.864 + }
1.865 +
1.866 + void Add(Object* aObject)
1.867 + {
1.868 + if(iNumEntries>=iEntriesLength)
1.869 + {
1.870 + iEntriesLength += 128;
1.871 + iEntries = (Entry*)realloc(iEntries,iEntriesLength*sizeof(Entry));
1.872 + ASSERT(iEntries);
1.873 + }
1.874 + aObject->iIndex = iNumEntries;
1.875 + Entry& entry = iEntries[iNumEntries++];
1.876 + entry.iTraceId = aObject->iTraceId;
1.877 + entry.iItem = aObject;
1.878 + }
1.879 +
1.880 + TUint Count()
1.881 + {
1.882 + return iNumEntries;
1.883 + }
1.884 +
1.885 + Object* operator[](TInt aIndex)
1.886 + {
1.887 + if(TUint(aIndex)<iNumEntries)
1.888 + return iEntries[aIndex].iItem;
1.889 + ASSERT(0);
1.890 + return 0;
1.891 + }
1.892 +
1.893 + Object* Find(TUint32 aTraceId)
1.894 + {
1.895 + Entry* ptr = iEntries+iNumEntries;
1.896 + Entry* end = iEntries;
1.897 + while(ptr>end)
1.898 + {
1.899 + --ptr;
1.900 + if(ptr->iTraceId==aTraceId)
1.901 + {
1.902 + if(ptr->iItem->iAlive)
1.903 + return ptr->iItem;
1.904 + else
1.905 + break;
1.906 + }
1.907 + }
1.908 + return 0;
1.909 + }
1.910 +private:
1.911 + struct Entry
1.912 + {
1.913 + TUint32 iTraceId;
1.914 + Object* iItem;
1.915 + };
1.916 + TUint iNumEntries;
1.917 + TUint iEntriesLength;
1.918 + Entry* iEntries;
1.919 + ObjectContainer* iLink;
1.920 +
1.921 + static ObjectContainer* iAllContainers;
1.922 + };
1.923 +ObjectContainer* ObjectContainer::iAllContainers = 0;
1.924 +
1.925 +
1.926 +#define GENERIC_OBJECT_DEFINITIONS(C) \
1.927 + \
1.928 + static C* Find(TUint32 aTraceId) \
1.929 + { \
1.930 + return (C*)iContainer.Find(aTraceId); \
1.931 + } \
1.932 + \
1.933 + static C* Create(TraceRecord& aTrace, TUint aIndex) \
1.934 + { \
1.935 + TUint32 traceId = aTrace.iData[aIndex]; \
1.936 + C* object = new C(traceId); \
1.937 + aTrace.iDataTypes[aIndex] = EDataTypeObject; \
1.938 + aTrace.iData[aIndex] = (uintptr_t)object; \
1.939 + return object; \
1.940 + } \
1.941 + \
1.942 + static C* Find(TraceRecord& aTrace, TUint aIndex) \
1.943 + { \
1.944 + TUint32 traceId = aTrace.iData[aIndex]; \
1.945 + C* object = Find(traceId); \
1.946 + if(!object) \
1.947 + return 0; \
1.948 + aTrace.iDataTypes[aIndex] = EDataTypeObject; \
1.949 + aTrace.iData[aIndex] = (uintptr_t)object; \
1.950 + return object; \
1.951 + } \
1.952 + \
1.953 + static C* FindOrCreate(TraceRecord& aTrace, TUint aIndex) \
1.954 + { \
1.955 + C* object = Find(aTrace,aIndex); \
1.956 + if(!object) \
1.957 + object = Create(aTrace,aIndex); \
1.958 + return object; \
1.959 + }
1.960 +
1.961 +
1.962 +
1.963 +//
1.964 +// Process
1.965 +//
1.966 +
1.967 +class Process : public Object
1.968 + {
1.969 +public:
1.970 + Process(TUint32 aTraceId)
1.971 + : Object(aTraceId,"P"), iThreadCount(0), iMaxThreadCount(0)
1.972 + {
1.973 + iContainer.Add(this);
1.974 + }
1.975 +
1.976 + GENERIC_OBJECT_DEFINITIONS(Process);
1.977 +
1.978 +public:
1.979 + TUint iThreadCount;
1.980 + TUint iMaxThreadCount;
1.981 +
1.982 + static ObjectContainer iContainer;
1.983 + };
1.984 +ObjectContainer Process::iContainer;
1.985 +
1.986 +
1.987 +
1.988 +//
1.989 +// Thread
1.990 +//
1.991 +class FastMutex;
1.992 +class Thread : public Object
1.993 + {
1.994 +public:
1.995 + Thread(TUint32 aTraceId)
1.996 + : Object(aTraceId,"T"), iId(~0u), iCpuTime(0), iSamples(0)
1.997 + {
1.998 + iContainer.Add(this);
1.999 + iNameLength = (TUint8)MakeName(iName,"NThread-",aTraceId);
1.1000 + }
1.1001 +
1.1002 + TUint64 CpuTime()
1.1003 + {
1.1004 + if(!iLastCpu || !iLastCpu->iBaseTimestamp)
1.1005 + return 0;
1.1006 + if(iLastCpu->iCurrentThread==this)
1.1007 + return iCpuTime + Timestamp - iLastCpu->iBaseTimestamp;
1.1008 + return iCpuTime;
1.1009 + }
1.1010 +
1.1011 + void Sampled()
1.1012 + {
1.1013 + if( iSamples+1 != 0xFFFFFFFF)
1.1014 + {
1.1015 + iSamples++;
1.1016 + }
1.1017 + }
1.1018 +
1.1019 + GENERIC_OBJECT_DEFINITIONS(Thread);
1.1020 +
1.1021 + static Object* FindThreadOrProcess(TraceRecord& aTrace, TUint aIndex)
1.1022 + {
1.1023 + if (!aTrace.iData[aIndex])
1.1024 + return 0;
1.1025 + Object* p = Find(aTrace, aIndex);
1.1026 + if (!p)
1.1027 + p = Process::Find(aTrace, aIndex);
1.1028 + return p;
1.1029 + }
1.1030 +public:
1.1031 + TUint32 iId;
1.1032 + Cpu* iLastCpu;
1.1033 + TUint64 iCpuTime;
1.1034 + TUint64 iFMBlockStartTime;
1.1035 + FastMutex* iWaitFastMutex;
1.1036 +
1.1037 + // Number of profiling samples
1.1038 + TUint32 iSamples;
1.1039 +
1.1040 + static ObjectContainer iContainer;
1.1041 + };
1.1042 +
1.1043 +ObjectContainer Thread::iContainer;
1.1044 +
1.1045 +
1.1046 +
1.1047 +//
1.1048 +// Chunk
1.1049 +//
1.1050 +
1.1051 +TUint ChunkErrors = 0;
1.1052 +
1.1053 +const TUint KPageShift = 12; // chunk memory is allocated in 4kB pages
1.1054 +
1.1055 +class Chunk : public Object
1.1056 + {
1.1057 +public:
1.1058 + Chunk(TUint32 aTraceId)
1.1059 + : Object(aTraceId,"C"), iCurrentSize(0), iPeakSize(0), iMaxSize(0), iPageMap(0), iTraceErrors(0)
1.1060 + {
1.1061 + iContainer.Add(this);
1.1062 + }
1.1063 +
1.1064 + ~Chunk()
1.1065 + {
1.1066 + free(iPageMap);
1.1067 + }
1.1068 +
1.1069 + void SetMaxSize(TUint32 aMaxSize)
1.1070 + {
1.1071 + ASSERT(!iMaxSize);
1.1072 + iMaxSize = aMaxSize;
1.1073 + TUint mapSize = ((aMaxSize>>KPageShift)+7)>>3;
1.1074 + iPageMap = (TUint8*)malloc(mapSize);
1.1075 + ASSERT(iPageMap);
1.1076 + memset(iPageMap,0,mapSize);
1.1077 + iCurrentSize = 0;
1.1078 + }
1.1079 +
1.1080 + void Commit(TUint32 aStart,TUint32 aSize)
1.1081 + {
1.1082 + if(!iPageMap) // we havent been intialised yet
1.1083 + return;
1.1084 +
1.1085 + if(aStart+aSize<aStart || aStart+aSize>iMaxSize)
1.1086 + {
1.1087 + ++iTraceErrors;
1.1088 + ++ChunkErrors;
1.1089 + return;
1.1090 + }
1.1091 + if(SetBits(iPageMap,aStart>>KPageShift,aSize>>KPageShift))
1.1092 + {
1.1093 + ++iTraceErrors;
1.1094 + ++ChunkErrors;
1.1095 + ErrorOnThisTrace = true;
1.1096 + }
1.1097 + }
1.1098 +
1.1099 + void Decommit(TUint32 aStart,TUint32 aSize)
1.1100 + {
1.1101 + if(!iPageMap) // we havent been intialised yet
1.1102 + return;
1.1103 +
1.1104 + // Decommit is complicated by the fact that aSize is the number of pages
1.1105 + // actually decommited, which may be less than the region of the original
1.1106 + // chunk decommit operation. E.g. if pages 1 and 3 were originally decommited
1.1107 + // and the decommit operation was for pages 0-3, then the trace has a size of
1.1108 + // 2 pages, even though the operation was on 4 pages.
1.1109 + // We handle this, repeatedly decommiting from our iPageMap, until we have
1.1110 + // freed aSize bytes worth of pages...
1.1111 + while(aSize)
1.1112 + {
1.1113 + if(aStart+aSize<aStart || aStart+aSize>iMaxSize)
1.1114 + {
1.1115 + // we haven't found enough memory to decommit
1.1116 + ++iTraceErrors;
1.1117 + ++ChunkErrors;
1.1118 + ErrorOnThisTrace = true;
1.1119 + return;
1.1120 + }
1.1121 + TUint notDecommitted = ClearBits(iPageMap,aStart>>KPageShift,aSize>>KPageShift);
1.1122 + aStart += aSize;
1.1123 + aSize = notDecommitted<<KPageShift;
1.1124 + }
1.1125 + }
1.1126 +
1.1127 + void ResetMemory()
1.1128 + {
1.1129 + }
1.1130 +
1.1131 + GENERIC_OBJECT_DEFINITIONS(Chunk);
1.1132 +
1.1133 +public:
1.1134 + TUint32 iCurrentSize;
1.1135 + TUint32 iPeakSize;
1.1136 + TUint32 iMaxSize;
1.1137 + TUint8* iPageMap;
1.1138 + TUint iTraceErrors;
1.1139 +
1.1140 + static ObjectContainer iContainer;
1.1141 + };
1.1142 +ObjectContainer Chunk::iContainer;
1.1143 +
1.1144 +
1.1145 +
1.1146 +//
1.1147 +// Semaphore, Mutex, CondVar
1.1148 +//
1.1149 +class Semaphore : public Object
1.1150 + {
1.1151 +public:
1.1152 + Semaphore(TUint32 aTraceId)
1.1153 + : Object(aTraceId,"S")
1.1154 + {
1.1155 + iContainer.Add(this);
1.1156 + }
1.1157 +
1.1158 + ~Semaphore()
1.1159 + {
1.1160 + }
1.1161 +
1.1162 + GENERIC_OBJECT_DEFINITIONS(Semaphore);
1.1163 +public:
1.1164 +
1.1165 + static ObjectContainer iContainer;
1.1166 + };
1.1167 +ObjectContainer Semaphore::iContainer;
1.1168 +
1.1169 +
1.1170 +class Mutex : public Object
1.1171 + {
1.1172 +public:
1.1173 + Mutex(TUint32 aTraceId)
1.1174 + : Object(aTraceId,"M")
1.1175 + {
1.1176 + iContainer.Add(this);
1.1177 + }
1.1178 +
1.1179 + ~Mutex()
1.1180 + {
1.1181 + }
1.1182 +
1.1183 + GENERIC_OBJECT_DEFINITIONS(Mutex);
1.1184 +public:
1.1185 +
1.1186 + static ObjectContainer iContainer;
1.1187 + };
1.1188 +ObjectContainer Mutex::iContainer;
1.1189 +
1.1190 +
1.1191 +class CondVar : public Object
1.1192 + {
1.1193 +public:
1.1194 + CondVar(TUint32 aTraceId)
1.1195 + : Object(aTraceId,"V")
1.1196 + {
1.1197 + iContainer.Add(this);
1.1198 + }
1.1199 +
1.1200 + ~CondVar()
1.1201 + {
1.1202 + }
1.1203 +
1.1204 + GENERIC_OBJECT_DEFINITIONS(CondVar);
1.1205 +public:
1.1206 +
1.1207 + static ObjectContainer iContainer;
1.1208 + };
1.1209 +ObjectContainer CondVar::iContainer;
1.1210 +
1.1211 +
1.1212 +
1.1213 +
1.1214 +//
1.1215 +// CodeSeg
1.1216 +//
1.1217 +
1.1218 +TUint CodeSegErrors = 0;
1.1219 +
1.1220 +class CodeSeg : public Object
1.1221 + {
1.1222 +public:
1.1223 + CodeSeg(TUint32 aTraceId)
1.1224 + : Object(aTraceId,"CS"), iAllocatedMemory(0)
1.1225 + {
1.1226 + iContainer.Add(this);
1.1227 + }
1.1228 +
1.1229 + GENERIC_OBJECT_DEFINITIONS(CodeSeg);
1.1230 +
1.1231 + TUint iAllocatedMemory;
1.1232 +public:
1.1233 + static ObjectContainer iContainer;
1.1234 + };
1.1235 +ObjectContainer CodeSeg::iContainer;
1.1236 +
1.1237 +
1.1238 +
1.1239 +//
1.1240 +// FastMutex
1.1241 +//
1.1242 +
1.1243 +TUint FastMutexNestErrors = 0;
1.1244 +
1.1245 +class FastMutex : public Object
1.1246 + {
1.1247 +public:
1.1248 + FastMutex(TUint32 aTraceId)
1.1249 + : Object(aTraceId,"FM"), iHoldingThread(0), iHeldCount(0), iTotalHeldTime(0),
1.1250 + iMaxHeldTime(0), iMaxHeldTimestamp(0), iMaxHeldPc(0), iBlockCount(0)
1.1251 + {
1.1252 + iContainer.Add(this);
1.1253 + iNameLength = (TUint8)MakeName(iName,"NFastMutex-",aTraceId);
1.1254 + iNameLength = 19;
1.1255 + }
1.1256 +
1.1257 + TUint32 Wait(Thread* aThread)
1.1258 + {
1.1259 + TUint32 time = 0;
1.1260 + if(iHoldingThread)
1.1261 + {
1.1262 + ++FastMutexNestErrors;
1.1263 + ErrorOnThisTrace = true;
1.1264 + }
1.1265 + iHoldingThread = aThread;
1.1266 + iWaitCpuTimeBase = aThread->CpuTime();
1.1267 + if (aThread->iWaitFastMutex == this)
1.1268 + {
1.1269 + time = (TUint32)(Timestamp - aThread->iFMBlockStartTime);
1.1270 + }
1.1271 + aThread->iWaitFastMutex = 0;
1.1272 + return time;
1.1273 + }
1.1274 +
1.1275 + void Block(Thread* aThread)
1.1276 + {
1.1277 + if (aThread->iWaitFastMutex != this)
1.1278 + {
1.1279 + aThread->iFMBlockStartTime = Timestamp;
1.1280 + aThread->iWaitFastMutex = this;
1.1281 + ++iBlockCount;
1.1282 + }
1.1283 + };
1.1284 +
1.1285 + TUint32 Signal(Thread* aThread, TUint32 aPc)
1.1286 + {
1.1287 + if (!iHoldingThread) // First record for this mutex so ignore it as don't
1.1288 + return 0; // have waiting thread details
1.1289 +
1.1290 + if(iHoldingThread!=aThread)
1.1291 + {
1.1292 + ++FastMutexNestErrors;
1.1293 + ErrorOnThisTrace = true;
1.1294 + iHoldingThread = 0;
1.1295 + return 0;
1.1296 + }
1.1297 + iHoldingThread = 0;
1.1298 + TUint64 time = aThread->CpuTime()-iWaitCpuTimeBase;
1.1299 + ++iHeldCount;
1.1300 + iTotalHeldTime += time;
1.1301 + if(time>iMaxHeldTime)
1.1302 + {
1.1303 + iMaxHeldTime = time;
1.1304 + iMaxHeldPc = aPc;
1.1305 + iMaxHeldTimestamp = Timestamp;
1.1306 + }
1.1307 + return (TUint32)time;
1.1308 + }
1.1309 +
1.1310 + GENERIC_OBJECT_DEFINITIONS(FastMutex);
1.1311 +
1.1312 +public:
1.1313 + Thread* iHoldingThread;
1.1314 + TUint32 iHeldCount; // number of times mutex acquired
1.1315 + TUint64 iTotalHeldTime;
1.1316 + TUint64 iWaitCpuTimeBase;
1.1317 + TUint64 iMaxHeldTime;
1.1318 + TUint64 iMaxHeldTimestamp;
1.1319 + TUint32 iMaxHeldPc;
1.1320 + TUint32 iBlockCount; // number of times mutex caused a thread to wait
1.1321 +
1.1322 + static ObjectContainer iContainer;
1.1323 + };
1.1324 +ObjectContainer FastMutex::iContainer;
1.1325 +
1.1326 +
1.1327 +
1.1328 +
1.1329 +//
1.1330 +// ProfilingSample
1.1331 +//
1.1332 +
1.1333 +TUint ProfilingSampleErrors = 0;
1.1334 +
1.1335 +class ProfilingSample : public Object
1.1336 + {
1.1337 +public:
1.1338 + ProfilingSample(TUint32 aTraceId)
1.1339 + : Object(aTraceId,"PS")
1.1340 + {
1.1341 + iContainer.Add(this);
1.1342 + iNameLength = (TUint8)MakeName(iName,"ProfilingSample-",aTraceId);
1.1343 + }
1.1344 +
1.1345 + void SetPC( TUint32 aPC )
1.1346 + {
1.1347 + iPC = aPC;
1.1348 + }
1.1349 +
1.1350 + void SetThread( TUint32 aThread )
1.1351 + {
1.1352 + if( 0 != aThread )
1.1353 + iThread = aThread;
1.1354 + }
1.1355 +
1.1356 + void SetType(const BTrace::TProfiling aType)
1.1357 + {
1.1358 + iType = aType;
1.1359 + }
1.1360 +
1.1361 + GENERIC_OBJECT_DEFINITIONS(ProfilingSample);
1.1362 +
1.1363 +
1.1364 +public:
1.1365 +
1.1366 + static ObjectContainer iContainer;
1.1367 + static Thread* iTopTen[10];
1.1368 + static TUint32 iSamples;
1.1369 + static TUint32 iLastThread;
1.1370 +
1.1371 + TUint32 iPC;
1.1372 + TUint32 iThread;
1.1373 + BTrace::TProfiling iType;
1.1374 +
1.1375 + };
1.1376 +
1.1377 +TUint32 ProfilingSample::iSamples = 0;
1.1378 +TUint32 ProfilingSample::iLastThread = 0;
1.1379 +
1.1380 +ObjectContainer ProfilingSample::iContainer;
1.1381 +
1.1382 +
1.1383 +//
1.1384 +// EThreadIdentification traces
1.1385 +//
1.1386 +
1.1387 +void PreProcessThreadIdentification(TraceRecord& aTrace)
1.1388 + {
1.1389 + Thread* thread;
1.1390 + Process* process;
1.1391 +
1.1392 + switch((BTrace::TThreadIdentification)aTrace.iSubCategory)
1.1393 + {
1.1394 + case BTrace::ENanoThreadCreate:
1.1395 + CHECK_TRACE_DATA_WORDS(1);
1.1396 + thread = Thread::FindOrCreate(aTrace,0);
1.1397 + break;
1.1398 +
1.1399 + case BTrace::ENanoThreadDestroy:
1.1400 + CHECK_TRACE_DATA_WORDS(1);
1.1401 + thread = Thread::Find(aTrace,0);
1.1402 + if(thread)
1.1403 + thread->Destroy();
1.1404 + break;
1.1405 +
1.1406 + case BTrace::EThreadCreate:
1.1407 + case BTrace::EThreadName:
1.1408 + CHECK_TRACE_DATA_WORDS(2);
1.1409 + thread = Thread::FindOrCreate(aTrace,0);
1.1410 + if(aTrace.iSubCategory==BTrace::EThreadCreate)
1.1411 + ++thread->iAlive; // thread needs destroying twice (ENanoThreadDestroy+EThreadDestroy)
1.1412 + process = Process::FindOrCreate(aTrace,1);
1.1413 + thread->iOwner = process;
1.1414 + ++process->iThreadCount;
1.1415 + if(process->iThreadCount>process->iMaxThreadCount)
1.1416 + process->iMaxThreadCount = process->iThreadCount;
1.1417 + thread->SetName(aTrace,2);
1.1418 + break;
1.1419 +
1.1420 + case BTrace::EThreadDestroy:
1.1421 + CHECK_TRACE_DATA_WORDS(1);
1.1422 + thread = Thread::Find(aTrace,0);
1.1423 + if(thread)
1.1424 + {
1.1425 + thread->Destroy();
1.1426 + process = (Process*)thread->iOwner;
1.1427 + if(process && process->iThreadCount)
1.1428 + --process->iThreadCount;
1.1429 + }
1.1430 + break;
1.1431 +
1.1432 + case BTrace::EProcessName:
1.1433 + CHECK_TRACE_DATA_WORDS(2);
1.1434 + if(aTrace.iData[0])
1.1435 + {
1.1436 + thread = Thread::FindOrCreate(aTrace,0);
1.1437 + process = Process::Find(aTrace.iData[1]);
1.1438 + if(!process || (process->iNameLength && !process->IsName(aTrace.iData+2,aTrace.iDataSize-2*4)))
1.1439 + {
1.1440 + if(process)
1.1441 + process->Destroy();
1.1442 + process = Process::Create(aTrace,1); // no existing process, or name different
1.1443 + }
1.1444 + else
1.1445 + process = Process::Find(aTrace,1); // find again (this will update trace data[1])
1.1446 + }
1.1447 + else
1.1448 + process = Process::Find(aTrace,1);
1.1449 + if(process)
1.1450 + process->SetName(aTrace,2);
1.1451 + break;
1.1452 +
1.1453 + case BTrace::EThreadId:
1.1454 + CHECK_TRACE_DATA_WORDS(2);
1.1455 + thread = Thread::FindOrCreate(aTrace,0);
1.1456 + process = Process::FindOrCreate(aTrace,1);
1.1457 + thread->iId = aTrace.iData[2];
1.1458 + break;
1.1459 +
1.1460 + case BTrace::EProcessCreate:
1.1461 + CHECK_TRACE_DATA_WORDS(1);
1.1462 + process = Process::FindOrCreate(aTrace,0);
1.1463 + break;
1.1464 +
1.1465 + case BTrace::EProcessDestroy:
1.1466 + CHECK_TRACE_DATA_WORDS(1);
1.1467 + process = Process::FindOrCreate(aTrace,0);
1.1468 + if(process)
1.1469 + process->Destroy();
1.1470 + break;
1.1471 +
1.1472 + default:
1.1473 + break;
1.1474 + }
1.1475 + }
1.1476 +
1.1477 +
1.1478 +//
1.1479 +// ECpuUsage traces
1.1480 +//
1.1481 +
1.1482 +Cpu TheCpus[KMaxCpus];
1.1483 +TUint InterruptNestErrors = 0;
1.1484 +TUint CpuUsagePresent = 0;
1.1485 +
1.1486 +Cpu::Cpu()
1.1487 + : iCurrentContext(EContextUnknown),
1.1488 + iFiqNest(0),
1.1489 + iIrqNest(0),
1.1490 + iIDFCNest(0),
1.1491 + iFiqTime(0),
1.1492 + iIrqTime(0),
1.1493 + iIDFCTime(0),
1.1494 + iCurrentThread(0),
1.1495 + iBaseTimestamp(0)
1.1496 + {
1.1497 + }
1.1498 +
1.1499 +void Cpu::Reset()
1.1500 + {
1.1501 + iCurrentContext = EContextUnknown;
1.1502 + iFiqNest = 0;
1.1503 + iIrqNest = 0;
1.1504 + iIDFCNest = 0;
1.1505 + iCurrentThread = 0;
1.1506 + iBaseTimestamp = 0;
1.1507 + }
1.1508 +
1.1509 +void ResetCpuUsage()
1.1510 + {
1.1511 + TInt i;
1.1512 + for (i=0; i<KMaxCpus; ++i)
1.1513 + TheCpus[i].Reset();
1.1514 + }
1.1515 +
1.1516 +
1.1517 +void StartCpuUsage()
1.1518 + {
1.1519 + TInt i;
1.1520 + for (i=0; i<KMaxCpus; ++i)
1.1521 + new (&TheCpus[i]) Cpu;
1.1522 + InterruptNestErrors = 0;
1.1523 + }
1.1524 +
1.1525 +
1.1526 +void Cpu::ChangeContext(TContext aType, Thread* aThread)
1.1527 + {
1.1528 + TUint64 delta = Timestamp-iBaseTimestamp;
1.1529 + switch(iCurrentContext)
1.1530 + {
1.1531 + case EContextThread:
1.1532 + iCurrentThread->iCpuTime += delta;
1.1533 + break;
1.1534 + case EContextFiq:
1.1535 + iFiqTime += delta;
1.1536 + break;
1.1537 + case EContextIrq:
1.1538 + iIrqTime += delta;
1.1539 + break;
1.1540 + case EContextIDFC:
1.1541 + iIDFCTime += delta;
1.1542 + break;
1.1543 + default:
1.1544 + break;
1.1545 + }
1.1546 +
1.1547 + if(aType==EContextUnknown)
1.1548 + {
1.1549 + if(iFiqNest)
1.1550 + aType = EContextFiq;
1.1551 + else if(iIrqNest)
1.1552 + aType = EContextIrq;
1.1553 + else if(iIDFCNest)
1.1554 + aType = EContextIDFC;
1.1555 + else
1.1556 + {
1.1557 + aType = EContextThread;
1.1558 + aThread = iCurrentThread;
1.1559 + }
1.1560 + }
1.1561 +
1.1562 + if(aType==EContextThread && !aThread)
1.1563 + {
1.1564 + iCurrentContext = EContextUnknown;
1.1565 + iBaseTimestamp = 0;
1.1566 + return;
1.1567 + }
1.1568 +
1.1569 + iCurrentContext = aType;
1.1570 + if(aType==EContextThread)
1.1571 + {
1.1572 + iCurrentThread = aThread;
1.1573 + aThread->iLastCpu = this;
1.1574 + }
1.1575 +
1.1576 + iBaseTimestamp = Timestamp;
1.1577 + }
1.1578 +
1.1579 +
1.1580 +void PreProcessCpuUsage(TraceRecord& aTrace)
1.1581 + {
1.1582 + CpuUsagePresent = true;
1.1583 + Cpu& cpu = *aTrace.iCpu;
1.1584 +
1.1585 + switch((BTrace::TCpuUsage)aTrace.iSubCategory)
1.1586 + {
1.1587 + case BTrace::EIrqStart:
1.1588 + ++cpu.iIrqNest;
1.1589 + cpu.ChangeContext(EContextIrq);
1.1590 + break;
1.1591 +
1.1592 + case BTrace::EFiqStart:
1.1593 + ++cpu.iFiqNest;
1.1594 + cpu.ChangeContext(EContextFiq);
1.1595 + break;
1.1596 +
1.1597 + case BTrace::EIDFCStart:
1.1598 + if(cpu.iIrqNest+cpu.iFiqNest>1 || cpu.iIDFCNest!=0)
1.1599 + {
1.1600 + ++InterruptNestErrors;
1.1601 + ErrorOnThisTrace = true;
1.1602 + }
1.1603 + cpu.iIrqNest = 0;
1.1604 + cpu.iFiqNest = 0;
1.1605 + cpu.iIDFCNest = 1;
1.1606 + cpu.ChangeContext(EContextIDFC);
1.1607 + break;
1.1608 +
1.1609 + case BTrace::EIrqEnd:
1.1610 + if(cpu.iIrqNest)
1.1611 + --cpu.iIrqNest;
1.1612 + else
1.1613 + {
1.1614 + ++InterruptNestErrors;
1.1615 + ErrorOnThisTrace = true;
1.1616 + }
1.1617 + cpu.ChangeContext(EContextUnknown);
1.1618 + break;
1.1619 +
1.1620 + case BTrace::EFiqEnd:
1.1621 + if(cpu.iFiqNest)
1.1622 + --cpu.iFiqNest;
1.1623 + else
1.1624 + {
1.1625 + ++InterruptNestErrors;
1.1626 + ErrorOnThisTrace = true;
1.1627 + }
1.1628 + cpu.ChangeContext(EContextUnknown);
1.1629 + break;
1.1630 +
1.1631 + case BTrace::EIDFCEnd:
1.1632 + if(cpu.iIDFCNest!=1)
1.1633 + {
1.1634 + ++InterruptNestErrors;
1.1635 + ErrorOnThisTrace = true;
1.1636 + }
1.1637 + cpu.iIDFCNest = 0;
1.1638 + cpu.ChangeContext(EContextUnknown);
1.1639 + break;
1.1640 +
1.1641 + case BTrace::ENewThreadContext:
1.1642 + if(cpu.iIrqNest+cpu.iFiqNest>1 || cpu.iIDFCNest!=0)
1.1643 + {
1.1644 + ++InterruptNestErrors;
1.1645 + ErrorOnThisTrace = true;
1.1646 + }
1.1647 + cpu.iIrqNest = 0;
1.1648 + cpu.iFiqNest = 0;
1.1649 + cpu.iIDFCNest = 0;
1.1650 + cpu.ChangeContext(EContextThread,aTrace.iContextID);
1.1651 + break;
1.1652 + }
1.1653 + }
1.1654 +
1.1655 +
1.1656 +void ReportThreads()
1.1657 + {
1.1658 + TUint numThreads = Thread::iContainer.Count();
1.1659 + if(!numThreads)
1.1660 + return;
1.1661 +
1.1662 + TUint64 totalTime = 0;
1.1663 + printf("\nREPORT: Threads\n\n");
1.1664 + WarnIfError(0);
1.1665 + printf("%-10s %5s %10s %8s %s\n","","State","CPUTime","TraceId","Name");
1.1666 + TUint i;
1.1667 + for(i=0; i<numThreads; ++i)
1.1668 + {
1.1669 + Thread* thread = (Thread*)Thread::iContainer[i];
1.1670 + Object::FullNameBuf fullName;
1.1671 + thread->FullName(fullName);
1.1672 + Object::TraceNameBuf name;
1.1673 + thread->TraceName(name);
1.1674 + printf("%-10s %5s %10d %08x '%s'\n",name,
1.1675 + thread->iAlive?(const char*)"Alive":(const char*)"Dead",
1.1676 + (int)Time(thread->iCpuTime),(int)thread->iTraceId,fullName);
1.1677 + totalTime += thread->iCpuTime;
1.1678 + }
1.1679 + for (i=0; i<(TUint)KMaxCpus; ++i)
1.1680 + {
1.1681 + printf("CPU %1d\n", i);
1.1682 + Cpu& cpu = TheCpus[i];
1.1683 + printf("%-10s %5s %10d %s\n","FIQ","",(int)Time(cpu.iFiqTime),"");
1.1684 + printf("%-10s %5s %10d %s\n","IRQ","",(int)Time(cpu.iIrqTime),"");
1.1685 + printf("%-10s %5s %10d %s\n","IDFC","",(int)Time(cpu.iIDFCTime),"");
1.1686 + totalTime += cpu.iFiqTime + cpu.iIrqTime + cpu.iIDFCTime;
1.1687 + }
1.1688 + printf("%-10s %5s ----------\n","","");
1.1689 + printf("%-10s %5s %10d\n","","",(int)Time(totalTime));
1.1690 + printf("\n");
1.1691 + }
1.1692 +
1.1693 +
1.1694 +void ReportProcesses()
1.1695 + {
1.1696 + TUint numProcesses = Process::iContainer.Count();
1.1697 + if(!numProcesses)
1.1698 + return;
1.1699 +
1.1700 + printf("\nREPORT: Processes\n\n");
1.1701 + WarnIfError(0);
1.1702 + printf("%-10s %5s %7s %8s %s\n","","State","Threads","TraceId","Name");
1.1703 + TUint i;
1.1704 + for(i=0; i<numProcesses; ++i)
1.1705 + {
1.1706 + Process* process = (Process*)Process::iContainer[i];
1.1707 + Object::FullNameBuf fullName;
1.1708 + process->FullName(fullName);
1.1709 + Object::TraceNameBuf name;
1.1710 + process->TraceName(name);
1.1711 + printf("%-10s %5s %3u/%-3u %08x '%s'\n",name,
1.1712 + process->iAlive?(const char*)"Alive":(const char*)"Dead",
1.1713 + (unsigned int)process->iThreadCount,(unsigned int)process->iMaxThreadCount,
1.1714 + (unsigned int)process->iTraceId,fullName);
1.1715 + }
1.1716 + printf("\n");
1.1717 + }
1.1718 +
1.1719 +
1.1720 +void EndCpuUsage()
1.1721 + {
1.1722 + TInt i;
1.1723 + for (i=0; i<KMaxCpus; ++i)
1.1724 + TheCpus[i].ChangeContext(EContextUnknown);
1.1725 + }
1.1726 +
1.1727 +
1.1728 +//
1.1729 +// EChunks traces
1.1730 +//
1.1731 +
1.1732 +void StartChunks()
1.1733 + {
1.1734 + ChunkErrors = 0;
1.1735 + }
1.1736 +
1.1737 +
1.1738 +void PreProcessChunks(TraceRecord& aTrace)
1.1739 + {
1.1740 + CHECK_TRACE_DATA_WORDS(1);
1.1741 + Chunk* chunk = Chunk::FindOrCreate(aTrace,0);
1.1742 +
1.1743 + switch((BTrace::TChunks)aTrace.iSubCategory)
1.1744 + {
1.1745 + case BTrace::EChunkCreated:
1.1746 + CHECK_TRACE_DATA_WORDS(2);
1.1747 + chunk->SetName(aTrace,2);
1.1748 + chunk->SetMaxSize(aTrace.iData[1]);
1.1749 + // start by assuming thread is 'owned' by the thread which created it...
1.1750 + chunk->iOwner = aTrace.iContextID;
1.1751 + break;
1.1752 +
1.1753 + case BTrace::EChunkInfo:
1.1754 + CHECK_TRACE_DATA_WORDS(3);
1.1755 + break; // ignore
1.1756 +
1.1757 + case BTrace::EChunkDestroyed:
1.1758 + chunk->Destroy();
1.1759 + break;
1.1760 +
1.1761 + case BTrace::EChunkMemoryAllocated:
1.1762 + {
1.1763 + CHECK_TRACE_DATA_WORDS(3);
1.1764 + chunk->Commit(aTrace.iData[1],aTrace.iData[2]);
1.1765 + TUint32 size = chunk->iCurrentSize+aTrace.iData[2];
1.1766 + if(size<chunk->iCurrentSize || size>chunk->iMaxSize)
1.1767 + size = chunk->iMaxSize;
1.1768 + chunk->iCurrentSize = size;
1.1769 + if(size>chunk->iPeakSize)
1.1770 + chunk->iPeakSize = size;
1.1771 + aTrace.iCalculatedData[0] = size/1024;
1.1772 + }
1.1773 + break;
1.1774 +
1.1775 + case BTrace::EChunkMemoryDeallocated:
1.1776 + {
1.1777 + CHECK_TRACE_DATA_WORDS(3);
1.1778 + chunk->Decommit(aTrace.iData[1],aTrace.iData[2]);
1.1779 + TUint32 size = chunk->iCurrentSize-aTrace.iData[2];
1.1780 + if(size>chunk->iCurrentSize)
1.1781 + size = 0;
1.1782 + chunk->iCurrentSize = size;
1.1783 + aTrace.iCalculatedData[0] = size/1024;
1.1784 + }
1.1785 + break;
1.1786 +
1.1787 + case BTrace::EChunkMemoryAdded:
1.1788 + CHECK_TRACE_DATA_WORDS(3);
1.1789 + chunk->Commit(aTrace.iData[1],aTrace.iData[2]);
1.1790 + break;
1.1791 +
1.1792 + case BTrace::EChunkMemoryRemoved:
1.1793 + CHECK_TRACE_DATA_WORDS(3);
1.1794 + chunk->Decommit(aTrace.iData[1],aTrace.iData[2]);
1.1795 + break;
1.1796 +
1.1797 + case BTrace::EChunkOwner:
1.1798 + {
1.1799 + CHECK_TRACE_DATA_WORDS(2);
1.1800 + Process* process = Process::FindOrCreate(aTrace,1);
1.1801 + // set owner, unless current owner is owned by the same process
1.1802 + // (this preserves creating thread names in ownership list which is more useful)
1.1803 + if(!chunk->iOwner || chunk->iOwner->iOwner!=process)
1.1804 + chunk->iOwner = process;
1.1805 + }
1.1806 + break;
1.1807 +
1.1808 + }
1.1809 + }
1.1810 +
1.1811 +
1.1812 +void ReportChunks()
1.1813 + {
1.1814 + TUint numChunks = Chunk::iContainer.Count();
1.1815 + if(!numChunks)
1.1816 + return;
1.1817 +
1.1818 + if(!ReportLevel)
1.1819 + printf("\nREPORT: Chunks (Named objects only)\n\n");
1.1820 + else
1.1821 + printf("\nREPORT: Chunks\n\n");
1.1822 + WarnIfError(ChunkErrors);
1.1823 + printf("%-10s %5s %8s %8s %8s %8s %s\n",
1.1824 + "","State","Size","Peak","Max","TraceId","Name");
1.1825 + TUint totalSize = 0;
1.1826 + TUint i;
1.1827 + for(i=0; i<numChunks; ++i)
1.1828 + {
1.1829 + Chunk* chunk = (Chunk*)Chunk::iContainer[i];
1.1830 + if(ReportLevel==0 && !chunk->iNameSet)
1.1831 + continue; // only report explicitly named mutexes at report level 0
1.1832 + Object::FullNameBuf fullName;
1.1833 + chunk->FullName(fullName);
1.1834 + Object::TraceNameBuf name;
1.1835 + chunk->TraceName(name);
1.1836 + printf("%-10s %5s %7uk %7uk %7uk %08x '%s'\n",
1.1837 + name,chunk->iAlive?(const char*)"Alive":(const char*)"Dead",
1.1838 + (unsigned int)chunk->iCurrentSize/1024,(unsigned int)chunk->iPeakSize/1024,(unsigned int)chunk->iMaxSize/1024,
1.1839 + (unsigned int)chunk->iTraceId,fullName);
1.1840 + totalSize += chunk->iCurrentSize/1024;
1.1841 + }
1.1842 + printf("%-10s %5s --------\n","","");
1.1843 + printf("%-10s %5s %7uk\n","","",totalSize);
1.1844 + printf("\n");
1.1845 + }
1.1846 +
1.1847 +
1.1848 +
1.1849 +//
1.1850 +// CodeSeg
1.1851 +//
1.1852 +
1.1853 +void StartCodeSegs()
1.1854 + {
1.1855 + CodeSegErrors = 0;
1.1856 + }
1.1857 +
1.1858 +
1.1859 +void PreProcessCodeSegs(TraceRecord& aTrace)
1.1860 + {
1.1861 + CHECK_TRACE_DATA_WORDS(1);
1.1862 + CodeSeg* codeseg;
1.1863 +
1.1864 + switch((BTrace::TCodeSegs)aTrace.iSubCategory)
1.1865 + {
1.1866 + case BTrace::ECodeSegCreated:
1.1867 + codeseg = CodeSeg::FindOrCreate(aTrace,0);
1.1868 + codeseg->SetName(aTrace,1);
1.1869 + break;
1.1870 +
1.1871 + case BTrace::ECodeSegInfo:
1.1872 + CHECK_TRACE_DATA_WORDS(10);
1.1873 + CodeSeg::FindOrCreate(aTrace,0);
1.1874 +/* - 4 bytes containing the attributes.
1.1875 + - 4 bytes containing the code base address (.text).
1.1876 + - 4 bytes containing the size of the code section (.text).
1.1877 + - 4 bytes containing the base address of the constant data section (.radata).
1.1878 + - 4 bytes containing the size of the constant data section (.radata).
1.1879 + - 4 bytes containing the base address of the initialised data section (.data).
1.1880 + - 4 bytes containing the size of the initialised data section (.data).
1.1881 + - 4 bytes containing the base address of the uninitialised data section (.bss).
1.1882 + - 4 bytes containing the size of the uninitialised data section (.bss).
1.1883 +*/ break;
1.1884 +
1.1885 + case BTrace::ECodeSegDestroyed:
1.1886 + codeseg = CodeSeg::FindOrCreate(aTrace,0);
1.1887 + codeseg->Destroy();
1.1888 + codeseg->iAllocatedMemory = 0; // clear this now because ECodeSegMemoryDeallocated comes after codeseg destroy
1.1889 + break;
1.1890 +
1.1891 + case BTrace::ECodeSegMapped:
1.1892 + CHECK_TRACE_DATA_WORDS(2);
1.1893 + codeseg = CodeSeg::FindOrCreate(aTrace,0);
1.1894 + Process::FindOrCreate(aTrace,1);
1.1895 + break;
1.1896 +
1.1897 + case BTrace::ECodeSegUnmapped:
1.1898 + CHECK_TRACE_DATA_WORDS(2);
1.1899 + CodeSeg::FindOrCreate(aTrace,0);
1.1900 + Process::FindOrCreate(aTrace,1);
1.1901 + break;
1.1902 +
1.1903 + case BTrace::ECodeSegMemoryAllocated:
1.1904 + CHECK_TRACE_DATA_WORDS(2);
1.1905 + codeseg = CodeSeg::FindOrCreate(aTrace,0);
1.1906 + codeseg->iAllocatedMemory += aTrace.iData[1];
1.1907 + if(codeseg->iAllocatedMemory<aTrace.iData[1])
1.1908 + {
1.1909 + codeseg->iAllocatedMemory = ~0u; // overflowed!
1.1910 + ++CodeSegErrors;
1.1911 + ErrorOnThisTrace = true;
1.1912 + }
1.1913 + break;
1.1914 +
1.1915 + case BTrace::ECodeSegMemoryDeallocated:
1.1916 + {
1.1917 + CHECK_TRACE_DATA_WORDS(2);
1.1918 + codeseg = CodeSeg::Find(aTrace,0);
1.1919 + if(codeseg)
1.1920 + {
1.1921 + TUint32 memory = codeseg->iAllocatedMemory-aTrace.iData[1];
1.1922 + if(memory>codeseg->iAllocatedMemory)
1.1923 + {
1.1924 + memory = 0; // underflowed
1.1925 + ++CodeSegErrors;
1.1926 + ErrorOnThisTrace = true;
1.1927 + }
1.1928 + codeseg->iAllocatedMemory = memory;
1.1929 + }
1.1930 + }
1.1931 + break;
1.1932 +
1.1933 + }
1.1934 + }
1.1935 +
1.1936 +
1.1937 +void ReportCodeSegs()
1.1938 + {
1.1939 + TUint numCodeSegs = CodeSeg::iContainer.Count();
1.1940 + if(!numCodeSegs)
1.1941 + return;
1.1942 +
1.1943 + if(!ReportLevel)
1.1944 + printf("\nREPORT: CodeSegs (Named objects only)\n\n");
1.1945 + else
1.1946 + printf("\nREPORT: CodeSegs\n\n");
1.1947 + WarnIfError(CodeSegErrors);
1.1948 + printf("%-10s %5s %8s %8s %s\n",
1.1949 + "","State","Memory","TraceId","Name");
1.1950 + TUint totalSize = 0;
1.1951 + TUint i;
1.1952 + for(i=0; i<numCodeSegs; ++i)
1.1953 + {
1.1954 + CodeSeg* codeseg = (CodeSeg*)CodeSeg::iContainer[i];
1.1955 + if(ReportLevel==0 && !codeseg->iNameSet)
1.1956 + continue; // only report explicitly named mutexes at report level 0
1.1957 + Object::FullNameBuf fullName;
1.1958 + codeseg->FullName(fullName);
1.1959 + Object::TraceNameBuf name;
1.1960 + codeseg->TraceName(name);
1.1961 + printf("%-10s %5s %7uk %08x '%s'\n",
1.1962 + name,codeseg->iAlive?(const char*)"Alive":(const char*)"Dead",
1.1963 + (unsigned int)codeseg->iAllocatedMemory/1024,(unsigned int)codeseg->iTraceId,fullName);
1.1964 + totalSize += codeseg->iAllocatedMemory/1024;
1.1965 + }
1.1966 + printf("%-10s %5s --------\n","","");
1.1967 + printf("%-10s %5s %7uk\n","","",totalSize);
1.1968 + printf("\n");
1.1969 + }
1.1970 +
1.1971 +
1.1972 +
1.1973 +//
1.1974 +// MetaTrace
1.1975 +//
1.1976 +
1.1977 +TUint KernelMemoryInitialFree = 0;
1.1978 +TUint KernelMemoryCurrentFree = 0;
1.1979 +TUint KernelMemoryMisc = 0;
1.1980 +TUint KernelMemoryDrvPhys = 0;
1.1981 +TUint KernelMemoryDemandPagingCache = 0;
1.1982 +TUint KernelMemoryErrors = 0;
1.1983 +TBool KernelMemoryTracesPresent = false;
1.1984 +
1.1985 +void StartKernelMemory()
1.1986 + {
1.1987 + KernelMemoryInitialFree = 0;
1.1988 + KernelMemoryCurrentFree = 0;
1.1989 + KernelMemoryMisc = 0;
1.1990 + KernelMemoryDrvPhys = 0;
1.1991 + KernelMemoryErrors = 0;
1.1992 + KernelMemoryTracesPresent = false;
1.1993 + }
1.1994 +
1.1995 +
1.1996 +void PreProcessKernelMemory(TraceRecord& aTrace)
1.1997 + {
1.1998 + CHECK_TRACE_DATA_WORDS(1);
1.1999 + KernelMemoryTracesPresent = true;
1.2000 + switch((BTrace::TKernelMemory)aTrace.iSubCategory)
1.2001 + {
1.2002 + case BTrace::EKernelMemoryInitialFree:
1.2003 + KernelMemoryInitialFree = aTrace.iData[0];
1.2004 + aTrace.iCalculatedData[0] = KernelMemoryInitialFree/1024;
1.2005 + break;
1.2006 +
1.2007 + case BTrace::EKernelMemoryCurrentFree:
1.2008 + KernelMemoryCurrentFree = aTrace.iData[0];
1.2009 + aTrace.iCalculatedData[0] = KernelMemoryCurrentFree/1024;
1.2010 + break;
1.2011 +
1.2012 + case BTrace::EKernelMemoryMiscAlloc:
1.2013 + KernelMemoryMisc += aTrace.iData[0];
1.2014 + if(KernelMemoryMisc < aTrace.iData[0])
1.2015 + {
1.2016 + KernelMemoryMisc = 0xffffffffu;
1.2017 + ++KernelMemoryErrors;
1.2018 + ErrorOnThisTrace = true;
1.2019 + }
1.2020 + aTrace.iCalculatedData[0] = KernelMemoryMisc/1024;
1.2021 + break;
1.2022 +
1.2023 + case BTrace::EKernelMemoryMiscFree:
1.2024 + if(KernelMemoryMisc >= aTrace.iData[0])
1.2025 + KernelMemoryMisc -= aTrace.iData[0];
1.2026 + else
1.2027 + {
1.2028 + KernelMemoryMisc = 0;
1.2029 + ++KernelMemoryErrors;
1.2030 + ErrorOnThisTrace = true;
1.2031 + }
1.2032 + aTrace.iCalculatedData[0] = KernelMemoryMisc/1024;
1.2033 + break;
1.2034 +
1.2035 + case BTrace::EKernelMemoryDemandPagingCache:
1.2036 + KernelMemoryDemandPagingCache = aTrace.iData[0];
1.2037 + break;
1.2038 +
1.2039 + case BTrace::EKernelMemoryDrvPhysAlloc:
1.2040 + KernelMemoryDrvPhys += aTrace.iData[0];
1.2041 + if(KernelMemoryDrvPhys < aTrace.iData[0])
1.2042 + {
1.2043 + KernelMemoryDrvPhys = 0xffffffffu;
1.2044 + ++KernelMemoryErrors;
1.2045 + ErrorOnThisTrace = true;
1.2046 + }
1.2047 + aTrace.iCalculatedData[0] = KernelMemoryDrvPhys/1024;
1.2048 + break;
1.2049 +
1.2050 + case BTrace::EKernelMemoryDrvPhysFree:
1.2051 + if(KernelMemoryDrvPhys >= aTrace.iData[0])
1.2052 + KernelMemoryDrvPhys -= aTrace.iData[0];
1.2053 + else
1.2054 + {
1.2055 + KernelMemoryDrvPhys = 0;
1.2056 + ++KernelMemoryErrors;
1.2057 + ErrorOnThisTrace = true;
1.2058 + }
1.2059 + aTrace.iCalculatedData[0] = KernelMemoryDrvPhys/1024;
1.2060 + break;
1.2061 + }
1.2062 + }
1.2063 +
1.2064 +void ReportKernelMemory()
1.2065 + {
1.2066 + if(!KernelMemoryTracesPresent)
1.2067 + return;
1.2068 +
1.2069 + printf("\nREPORT: Kernel Memory\n\n");
1.2070 + WarnIfError(KernelMemoryErrors);
1.2071 + printf("Total RAM size............................. %dk\n",KernelMemoryInitialFree/1024);
1.2072 + printf("Miscelaneous RAM used by kernel............ %dk\n",KernelMemoryMisc/1024);
1.2073 + printf("Physical RAM allocated by device drivers... %dk\n",KernelMemoryDrvPhys/1024);
1.2074 + printf("Demand paging cache reserve................ %dk\n",KernelMemoryDemandPagingCache/1024);
1.2075 + if(ReportLevel>1)
1.2076 + printf("Last 'current free RAM' value seen......... %dk\n",KernelMemoryCurrentFree/1024);
1.2077 +
1.2078 + printf("\n");
1.2079 + }
1.2080 +
1.2081 +//
1.2082 +// MetaTrace
1.2083 +//
1.2084 +
1.2085 +void StartMetaTrace()
1.2086 + {
1.2087 + TimestampPeriod = 0;
1.2088 + Timestamp2Period = 0;
1.2089 + }
1.2090 +
1.2091 +
1.2092 +void PreProcessMetaTrace(TraceRecord& aTrace)
1.2093 + {
1.2094 + switch((BTrace::TMetaTrace)aTrace.iSubCategory)
1.2095 + {
1.2096 + case BTrace::EMetaTraceTimestampsInfo:
1.2097 + CHECK_TRACE_DATA_WORDS(3);
1.2098 + TimestampPeriod = aTrace.iData[0];
1.2099 + Timestamp2Period = aTrace.iData[1];
1.2100 + Timestamp64Bit = aTrace.iData[2]&1;
1.2101 + break;
1.2102 +
1.2103 + case BTrace::EMetaTraceMeasurementStart:
1.2104 + case BTrace::EMetaTraceMeasurementEnd:
1.2105 + CHECK_TRACE_DATA_WORDS(2);
1.2106 + aTrace.iDataTypes[2] = EDataTypeText;
1.2107 + break;
1.2108 +
1.2109 + case BTrace::EMetaTraceFilterChange:
1.2110 + CHECK_TRACE_DATA_WORDS(1);
1.2111 + break;
1.2112 + }
1.2113 + }
1.2114 +
1.2115 +//
1.2116 +// EFastMutex traces
1.2117 +//
1.2118 +
1.2119 +void StartFastMutex()
1.2120 + {
1.2121 + FastMutexNestErrors = 0;
1.2122 + }
1.2123 +
1.2124 +
1.2125 +void PreProcessFastMutex(TraceRecord& aTrace)
1.2126 + {
1.2127 + CHECK_TRACE_DATA_WORDS(1);
1.2128 + FastMutex* mutex = FastMutex::FindOrCreate(aTrace,0);
1.2129 + Thread* thread = aTrace.iContextID;
1.2130 +
1.2131 + switch((BTrace::TFastMutex)aTrace.iSubCategory)
1.2132 + {
1.2133 + case BTrace::EFastMutexWait:
1.2134 + aTrace.iCalculatedData[0] = Time(mutex->Wait(thread));
1.2135 + break;
1.2136 +
1.2137 + case BTrace::EFastMutexSignal:
1.2138 + aTrace.iCalculatedData[0] = Time(mutex->Signal(thread,aTrace.iPC));
1.2139 + break;
1.2140 +
1.2141 + case BTrace::EFastMutexFlash:
1.2142 + aTrace.iCalculatedData[0] = Time(mutex->Signal(thread,aTrace.iPC));
1.2143 + mutex->Wait(thread);
1.2144 + break;
1.2145 +
1.2146 + case BTrace::EFastMutexName:
1.2147 + CHECK_TRACE_DATA_WORDS(2);
1.2148 + mutex->SetName(aTrace,2);
1.2149 + break;
1.2150 +
1.2151 + case BTrace::EFastMutexBlock:
1.2152 + mutex->Block(thread);
1.2153 + break;
1.2154 +
1.2155 + }
1.2156 + }
1.2157 +
1.2158 +
1.2159 +void PreProcessSymbianKernelSync(TraceRecord& aTrace)
1.2160 + {
1.2161 + switch((BTrace::TSymbianKernelSync)aTrace.iSubCategory)
1.2162 + {
1.2163 + case BTrace::ESemaphoreCreate:
1.2164 + {
1.2165 + CHECK_TRACE_DATA_WORDS(2);
1.2166 + TUint32 ownerid = aTrace.iData[1];
1.2167 + Semaphore* sem = Semaphore::FindOrCreate(aTrace,0);
1.2168 + Object* owner = Thread::FindThreadOrProcess(aTrace,1);
1.2169 + sem->iOwner = owner;
1.2170 + if (!owner && ownerid)
1.2171 + sem->iOwnerTraceId = ownerid, ++Object::UnknownOwners;
1.2172 + sem->SetName(aTrace,2);
1.2173 + break;
1.2174 + }
1.2175 +
1.2176 + case BTrace::ESemaphoreDestroy:
1.2177 + {
1.2178 + CHECK_TRACE_DATA_WORDS(1);
1.2179 + Semaphore* sem = Semaphore::Find(aTrace,0);
1.2180 + if (sem)
1.2181 + sem->Destroy();
1.2182 + break;
1.2183 + }
1.2184 +
1.2185 + case BTrace::ESemaphoreAcquire:
1.2186 + case BTrace::ESemaphoreRelease:
1.2187 + case BTrace::ESemaphoreBlock:
1.2188 + {
1.2189 + CHECK_TRACE_DATA_WORDS(1);
1.2190 + Semaphore::FindOrCreate(aTrace,0);
1.2191 + break;
1.2192 + }
1.2193 +
1.2194 +
1.2195 + case BTrace::EMutexCreate:
1.2196 + {
1.2197 + CHECK_TRACE_DATA_WORDS(2);
1.2198 + TUint32 ownerid = aTrace.iData[1];
1.2199 + Mutex* m = Mutex::FindOrCreate(aTrace,0);
1.2200 + Object* owner = Thread::FindThreadOrProcess(aTrace,1);
1.2201 + m->iOwner = owner;
1.2202 + if (!owner && ownerid)
1.2203 + m->iOwnerTraceId = ownerid, ++Object::UnknownOwners;
1.2204 + m->SetName(aTrace,2);
1.2205 + break;
1.2206 + }
1.2207 +
1.2208 + case BTrace::EMutexDestroy:
1.2209 + {
1.2210 + CHECK_TRACE_DATA_WORDS(1);
1.2211 + Mutex* m = Mutex::Find(aTrace,0);
1.2212 + if (m)
1.2213 + m->Destroy();
1.2214 + break;
1.2215 + }
1.2216 +
1.2217 + case BTrace::EMutexAcquire:
1.2218 + case BTrace::EMutexRelease:
1.2219 + case BTrace::EMutexBlock:
1.2220 + {
1.2221 + CHECK_TRACE_DATA_WORDS(1);
1.2222 + Mutex::FindOrCreate(aTrace,0);
1.2223 + break;
1.2224 + }
1.2225 +
1.2226 +
1.2227 + case BTrace::ECondVarCreate:
1.2228 + {
1.2229 + CHECK_TRACE_DATA_WORDS(2);
1.2230 + TUint32 ownerid = aTrace.iData[1];
1.2231 + CondVar* cv = CondVar::FindOrCreate(aTrace,0);
1.2232 + Object* owner = Thread::FindThreadOrProcess(aTrace,1);
1.2233 + cv->iOwner = owner;
1.2234 + if (!owner && ownerid)
1.2235 + cv->iOwnerTraceId = ownerid, ++Object::UnknownOwners;
1.2236 + cv->SetName(aTrace,2);
1.2237 + break;
1.2238 + }
1.2239 +
1.2240 + case BTrace::ECondVarDestroy:
1.2241 + {
1.2242 + CHECK_TRACE_DATA_WORDS(1);
1.2243 + CondVar* cv = CondVar::Find(aTrace,0);
1.2244 + if (cv)
1.2245 + cv->Destroy();
1.2246 + break;
1.2247 + }
1.2248 +
1.2249 + case BTrace::ECondVarBlock:
1.2250 + case BTrace::ECondVarWakeUp:
1.2251 + case BTrace::ECondVarSignal:
1.2252 + case BTrace::ECondVarBroadcast:
1.2253 + {
1.2254 + CHECK_TRACE_DATA_WORDS(1);
1.2255 + CondVar::FindOrCreate(aTrace,0);
1.2256 + break;
1.2257 + }
1.2258 +
1.2259 +
1.2260 + default:
1.2261 + break;
1.2262 + }
1.2263 + }
1.2264 +
1.2265 +
1.2266 +void ReportFastMutex()
1.2267 + {
1.2268 + TUint numMutexes = FastMutex::iContainer.Count();
1.2269 + if(!numMutexes)
1.2270 + return;
1.2271 +
1.2272 + if(!ReportLevel)
1.2273 + printf("\nREPORT: FastMutexes (Named objects only)\n\n");
1.2274 + else
1.2275 + printf("\nREPORT: FastMutexes\n\n");
1.2276 + WarnIfError(0);
1.2277 + printf("%-10s %8s %8s %10s %10s %-8s %12s %8s %s\n",
1.2278 + "","MaxTime","AveTime","HeldCount","BlockCount","MaxPC","MaxTimestamp","TraceId","Name");
1.2279 + TUint i;
1.2280 + for(i=0; i<numMutexes; ++i)
1.2281 + {
1.2282 + FastMutex* mutex = (FastMutex*)FastMutex::iContainer[i];
1.2283 + if(ReportLevel==0 && !mutex->iNameSet)
1.2284 + continue; // only report explicitly named mutexes at report level 0
1.2285 + Object::FullNameBuf fullName;
1.2286 + mutex->FullName(fullName);
1.2287 + Object::TraceNameBuf name;
1.2288 + mutex->TraceName(name);
1.2289 + TUint32 averageHeldTime = mutex->iHeldCount ? Time(mutex->iTotalHeldTime/mutex->iHeldCount) : 0;
1.2290 + printf("%-10s %8u %8u %10u %10u %08x %12u %08x '%s'\n",
1.2291 + name,(unsigned int)Time(mutex->iMaxHeldTime),(unsigned int)averageHeldTime,(unsigned int)mutex->iHeldCount,(unsigned int)mutex->iBlockCount,
1.2292 + (unsigned int)mutex->iMaxHeldPc,(unsigned int)Time(mutex->iMaxHeldTimestamp-TimestampBase),(unsigned int)mutex->iTraceId,fullName);
1.2293 + }
1.2294 + printf("\n");
1.2295 + }
1.2296 +
1.2297 +
1.2298 +//
1.2299 +// ProfilingSample
1.2300 +//
1.2301 +
1.2302 +void StartProfilingSample()
1.2303 + {
1.2304 + ProfilingSampleErrors = 0;
1.2305 + }
1.2306 +
1.2307 +
1.2308 +/**
1.2309 + Index 0 of TraceRecord is the program counter
1.2310 + The only one not having it are ECpuNonSymbianThreadSample samples.
1.2311 + Index 1 of TraceRecord is the NThread pointer.
1.2312 + The only one that has it is ECpuFullSample.
1.2313 + The samples are identified by their index, which is maintained by
1.2314 + ProfilingSample::iSamples. Thus to create a ProfilingSample object we
1.2315 + need to put this value in the data at index 0 after copying the PC
1.2316 + and Thread id (if present).
1.2317 + The reasoning is that all samples need to be represented and thus we
1.2318 + need to create a ProfilingSample object, even when they are on the same
1.2319 + PC and or thread. Each sample important and should not be discarded.
1.2320 +*/
1.2321 +void PreProcessProfiling(TraceRecord& aTrace)
1.2322 + {
1.2323 +
1.2324 + ProfilingSample* sample;
1.2325 + Thread* thread;
1.2326 +
1.2327 + switch((BTrace::TProfiling)aTrace.iSubCategory)
1.2328 + {
1.2329 +
1.2330 + case BTrace::ECpuFullSample:
1.2331 + {
1.2332 + CHECK_TRACE_DATA_WORDS(2);
1.2333 +
1.2334 + TUint32 aThread = aTrace.iData[1];
1.2335 + // The thread id is aTrace.iData[1], so find or create it
1.2336 + // This action can modify aTrace.iData[1], that is why we took a copy above
1.2337 + thread = Thread::FindOrCreate(aTrace,1);
1.2338 + if( thread )
1.2339 + thread->Sampled();
1.2340 +
1.2341 + TUint32 aPC = aTrace.iData[0];
1.2342 +
1.2343 + // Always create a sample identified by the running counter ProfilingSample::iSamples
1.2344 + aTrace.iData[0] = ProfilingSample::iSamples;
1.2345 + sample = ProfilingSample::Create(aTrace,0);
1.2346 + if( sample )
1.2347 + {
1.2348 + sample->SetPC( aPC );
1.2349 + sample->SetThread( aThread );
1.2350 + sample->SetType(BTrace::ECpuFullSample);
1.2351 + }
1.2352 +
1.2353 + ProfilingSample::iLastThread = aThread;
1.2354 + }
1.2355 + break;
1.2356 +
1.2357 + case BTrace::ECpuOptimisedSample:
1.2358 + {
1.2359 + CHECK_TRACE_DATA_WORDS(1);
1.2360 + TUint32 aPC = aTrace.iData[0];
1.2361 +
1.2362 + aTrace.iData[0] = ProfilingSample::iSamples;
1.2363 + sample = ProfilingSample::Create(aTrace,0);
1.2364 + if( sample )
1.2365 + {
1.2366 + sample->SetPC( aPC );
1.2367 + sample->SetType( BTrace::ECpuOptimisedSample );
1.2368 + sample->SetThread(ProfilingSample::iLastThread);
1.2369 + }
1.2370 +
1.2371 + if( 0 != ProfilingSample::iLastThread )
1.2372 + {
1.2373 + thread = Thread::Find(ProfilingSample::iLastThread);
1.2374 + if( thread )
1.2375 + {
1.2376 + thread->Sampled();
1.2377 + }
1.2378 + }
1.2379 +
1.2380 + }
1.2381 + break;
1.2382 +
1.2383 + case BTrace::ECpuIdfcSample:
1.2384 + {
1.2385 + CHECK_TRACE_DATA_WORDS(1);
1.2386 + TUint32 aPC = aTrace.iData[0];
1.2387 +
1.2388 + aTrace.iData[0] = ProfilingSample::iSamples;
1.2389 + sample = ProfilingSample::Create(aTrace,0);
1.2390 +
1.2391 + sample->SetPC( aPC );
1.2392 + sample->SetType(BTrace::ECpuIdfcSample);
1.2393 +
1.2394 + }
1.2395 + break;
1.2396 +
1.2397 + case BTrace::ECpuNonSymbianThreadSample:
1.2398 + {
1.2399 + // No data
1.2400 + aTrace.iData[0] = ProfilingSample::iSamples;
1.2401 + sample = ProfilingSample::Create(aTrace,0);
1.2402 + sample->SetType(BTrace::ECpuNonSymbianThreadSample);
1.2403 +
1.2404 + }
1.2405 + break;
1.2406 +
1.2407 + default:
1.2408 + ProfilingSampleErrors++;
1.2409 + ErrorOnThisTrace = true;
1.2410 + }
1.2411 +
1.2412 + ProfilingSample::iSamples++;
1.2413 +
1.2414 + }
1.2415 +
1.2416 +
1.2417 +void ReportSampleProfiling()
1.2418 + {
1.2419 + printf("\nREPORT: Profiling\n\n");
1.2420 +
1.2421 + TUint numSamples = ProfilingSample::iContainer.Count();
1.2422 + if(!numSamples)
1.2423 + {
1.2424 + printf("\n No Samples\n\n");
1.2425 + return;
1.2426 + }
1.2427 +
1.2428 + WarnIfError(0);
1.2429 +
1.2430 +
1.2431 + // Print thread samples
1.2432 + TUint numThreads = Thread::iContainer.Count();
1.2433 + if(numThreads)
1.2434 + {
1.2435 + printf(" Samples by Thread\n\n");
1.2436 + printf("%-11s %-8s %-8s\t%-12s\t%s\n\n", "", "TraceId", "Samples", "%", "Name");
1.2437 + TUint i;
1.2438 + TReal threadPercentage;
1.2439 + for(i=0; i<numThreads; ++i)
1.2440 + {
1.2441 + Thread* thread = (Thread*)Thread::iContainer[i];
1.2442 +
1.2443 + if( thread && thread->iSamples )
1.2444 + {
1.2445 + Object::FullNameBuf fullName;
1.2446 + thread->FullName(fullName);
1.2447 + Object::TraceNameBuf name;
1.2448 + thread->TraceName(name);
1.2449 +
1.2450 + threadPercentage = thread->iSamples*100.0/numSamples;
1.2451 +
1.2452 + printf("%-10s %08x %8d\t%02.2f\t'%s'\n",
1.2453 + name,
1.2454 + (unsigned int)thread->iTraceId,
1.2455 + (unsigned int)(thread->iSamples),
1.2456 + threadPercentage,
1.2457 + fullName );
1.2458 +
1.2459 + }//if samples
1.2460 + }//for numThreads
1.2461 + }//if threads
1.2462 +
1.2463 +
1.2464 + if(ReportLevel>0)
1.2465 + {
1.2466 +
1.2467 + printf("\nAll samples\n\n%-21s %-8s %-8s\n\n", "Type", "ThreadId", "PC");
1.2468 +
1.2469 + TUint i;
1.2470 + TUint fullSamples = 0;
1.2471 + TUint optSamples = 0;
1.2472 + TUint dfcSamples = 0;
1.2473 + TUint nonSymbSamples = 0;
1.2474 +
1.2475 + for(i=0; i<numSamples; ++i)
1.2476 + {
1.2477 + ProfilingSample* sample = (ProfilingSample*)ProfilingSample::iContainer[i];
1.2478 + switch((BTrace::TProfiling)sample->iType)
1.2479 + {
1.2480 + case BTrace::ECpuFullSample:
1.2481 + {
1.2482 + if( ReportLevel>1)
1.2483 + printf("ECpuFull %08x %08x\n",
1.2484 + (unsigned int)(sample->iThread), (unsigned int)(sample->iPC) );
1.2485 +
1.2486 + fullSamples++;
1.2487 + }
1.2488 + break;
1.2489 + case BTrace::ECpuOptimisedSample:
1.2490 + {
1.2491 + if( ReportLevel>1)
1.2492 + printf("ECpuOptimised %08x %08x\n",
1.2493 + (unsigned int)(sample->iThread), (unsigned int)(sample->iPC) );
1.2494 +
1.2495 + optSamples++;
1.2496 + }
1.2497 + break;
1.2498 + case BTrace::ECpuIdfcSample:
1.2499 + {
1.2500 + if( ReportLevel>1)
1.2501 + printf("ECpuIdfc %08x\n", (unsigned int)(sample->iPC) );
1.2502 +
1.2503 + dfcSamples++;
1.2504 + }
1.2505 + break;
1.2506 + case BTrace::ECpuNonSymbianThreadSample:
1.2507 + {
1.2508 + if( ReportLevel>1)
1.2509 + printf("ECpuNonSymbianThread\n");
1.2510 +
1.2511 + nonSymbSamples++;
1.2512 + }
1.2513 + break;
1.2514 + }//switch
1.2515 + }//for
1.2516 +
1.2517 +
1.2518 + TReal typePercentage;
1.2519 +
1.2520 + printf("\nSamples by type\n");
1.2521 +
1.2522 + typePercentage = fullSamples * 100.0 / numSamples;
1.2523 + printf(" Samples of type ECpuFullSample :\t\t%-10d\t%02.2f %%\n", fullSamples, typePercentage );
1.2524 +
1.2525 + typePercentage = optSamples * 100.0 / numSamples;
1.2526 + printf(" Samples of type ECpuOptimisedSample :\t\t%-10d\t%02.2f %%\n", optSamples, typePercentage );
1.2527 +
1.2528 + typePercentage = dfcSamples * 100.0 / numSamples;
1.2529 + printf(" Samples of type ECpuIdfcSample :\t\t%-10d\t%02.2f %%\n", dfcSamples, typePercentage );
1.2530 +
1.2531 + typePercentage = nonSymbSamples * 100.0 / numSamples;
1.2532 + printf(" Samples of type ECpuNonSymbianThreadSample :\t%-10d\t%02.2f %%\n", nonSymbSamples, typePercentage );
1.2533 +
1.2534 + printf(" Total Samples : \t\t\t\t%d\n", numSamples );
1.2535 +
1.2536 + }//report level
1.2537 +
1.2538 + printf("\n");
1.2539 + }
1.2540 +
1.2541 +//
1.2542 +// Trace processing
1.2543 +//
1.2544 +
1.2545 +TraceRecord** TraceIndex = 0;
1.2546 +TUint TraceIndexSize = 0;
1.2547 +TUint32 NextTraceId = 0;
1.2548 +TraceRecord* LastTrace = 0;
1.2549 +TBool Timestamp2Present = 0;
1.2550 +TBool TraceDumpStarted = false;
1.2551 +
1.2552 +
1.2553 +void StartTrace()
1.2554 + {
1.2555 + TraceDumpStarted = false;
1.2556 + TraceFormatErrors = 0;
1.2557 + TraceBufferFilled = false;
1.2558 + Timestamp2Present = false;
1.2559 + }
1.2560 +
1.2561 +
1.2562 +TUint32 ReadTraceWord(const TUint8*& header)
1.2563 + {
1.2564 + TUint32 word;
1.2565 + memcpy(&word, header, sizeof(TUint32));
1.2566 + header += sizeof(TUint32);
1.2567 + return word;
1.2568 + }
1.2569 +
1.2570 +
1.2571 +TBool PreProcessTrace(TraceRecord& aTrace, const TUint8* aData)
1.2572 + {
1.2573 + ErrorOnThisTrace = false;
1.2574 + aTrace.iError = 0;
1.2575 +
1.2576 + aTrace.iDataSize = 0; // initialise to safe value
1.2577 +
1.2578 + // process aTrace header...
1.2579 + TUint traceSize = aData[BTrace::ESizeIndex];
1.2580 + if(traceSize<4u || traceSize>(TUint)KMaxBTraceRecordSize)
1.2581 + {
1.2582 + aTrace.iError = 1;
1.2583 + return false; // bad size
1.2584 + }
1.2585 + aTrace.iCpuNum = 0;
1.2586 +
1.2587 + TUint8 flags = aData[BTrace::EFlagsIndex];
1.2588 + if(!TraceRecordId) // first trace record...?
1.2589 + flags &= ~BTrace::EMissingRecord; // ignore missing traces before log start
1.2590 + aTrace.iFlags = flags;
1.2591 +
1.2592 + TUint8 category = aData[BTrace::ECategoryIndex];
1.2593 + aTrace.iCategory = category;
1.2594 +
1.2595 + TUint8 subCategory = aData[BTrace::ESubCategoryIndex];
1.2596 + aTrace.iSubCategory = subCategory;
1.2597 +
1.2598 + const TUint8* header = aData+4;
1.2599 +
1.2600 + TUint32 header2 = 0;
1.2601 + if(flags&BTrace::EHeader2Present)
1.2602 + {
1.2603 + header2 = ReadTraceWord(header);
1.2604 + aTrace.iCpuNum = (TUint8)(header2>>20);
1.2605 + }
1.2606 + aTrace.iHeader2 = header2;
1.2607 + aTrace.iCpu = TheCpus + aTrace.iCpuNum;
1.2608 +
1.2609 + // process timestamp and timestamp2...
1.2610 + TUint32 ts1 = 0;
1.2611 + TUint32 ts2 = 0;
1.2612 + TUint64 timestamp = 0;
1.2613 + if(flags&BTrace::ETimestampPresent)
1.2614 + ts1 = ReadTraceWord(header);
1.2615 + if(flags&BTrace::ETimestamp2Present)
1.2616 + {
1.2617 + Timestamp2Present = true;
1.2618 + ts2 = ReadTraceWord(header);
1.2619 + }
1.2620 + aTrace.iTimestamp2 = ts2;
1.2621 + if(flags&BTrace::ETimestampPresent)
1.2622 + {
1.2623 + if (Timestamp64Bit)
1.2624 + {
1.2625 + timestamp = ts2;
1.2626 + timestamp <<= 32;
1.2627 + timestamp |= ts1;
1.2628 + Timestamp = timestamp;
1.2629 + }
1.2630 + else
1.2631 + {
1.2632 + timestamp = ts1;
1.2633 + if(timestamp<(Timestamp&0xffffffffu))
1.2634 + Timestamp += TUint64(1)<<32;
1.2635 + Timestamp &= TUint64(0xffffffff)<<32;
1.2636 + Timestamp |= timestamp;
1.2637 + timestamp = Timestamp;
1.2638 + }
1.2639 + if(!TraceRecordId)
1.2640 + TimestampBase = timestamp; // record timestamp of first trace
1.2641 + }
1.2642 + aTrace.iTimestamp = timestamp;
1.2643 +
1.2644 + // process context...
1.2645 + // coverity[assign_zero]
1.2646 + aTrace.iContextID = 0;
1.2647 + if(flags&BTrace::EContextIdPresent)
1.2648 + {
1.2649 + TUint32 contextId = ReadTraceWord(header);
1.2650 + Thread* thread = Thread::Find(contextId);
1.2651 + if(!thread)
1.2652 + thread = new Thread(contextId);
1.2653 + aTrace.iContextID = thread;
1.2654 + }
1.2655 +
1.2656 + // process pc...
1.2657 + TUint32 pc = 0;
1.2658 + if(flags&BTrace::EPcPresent)
1.2659 + pc = ReadTraceWord(header);
1.2660 + aTrace.iPC = pc;
1.2661 +
1.2662 + // process extra...
1.2663 + TUint32 extra = 0;
1.2664 + if(flags&BTrace::EExtraPresent)
1.2665 + extra = ReadTraceWord(header);
1.2666 + aTrace.iExtra = extra;
1.2667 +
1.2668 + // process payload data...
1.2669 + TUint headerSize = header-aData;
1.2670 + aData = (TUint8*)header;
1.2671 + if(headerSize>traceSize)
1.2672 + {
1.2673 + aTrace.iError = 1;
1.2674 + return false; // bad trace record
1.2675 + }
1.2676 + TUint dataSize = traceSize-headerSize;
1.2677 + if(dataSize>sizeof(aTrace.iData))
1.2678 + {
1.2679 + aTrace.iError = 1;
1.2680 + return false; // bad trace record
1.2681 + }
1.2682 + aTrace.iDataSize = dataSize;
1.2683 + memcpy(&aTrace.iData,aData,dataSize);
1.2684 +
1.2685 + // clear pre-processor specific data...
1.2686 + aTrace.iDataTypes[0] = 0;
1.2687 + aTrace.iDataTypes[1] = 0;
1.2688 + aTrace.iDataTypes[2] = 0;
1.2689 + aTrace.iDataTypes[3] = 0;
1.2690 + aTrace.iCalculatedData[0] = 0;
1.2691 + aTrace.iCalculatedData[1] = 0;
1.2692 +
1.2693 + // check for missing.
1.2694 + if(flags & BTrace::EMissingRecord)
1.2695 + {// Some trace was missing as the btrace buffer must have been filled.
1.2696 + TraceBufferFilled = true;
1.2697 + aTrace.iError = 1;
1.2698 + return false;
1.2699 + }
1.2700 +
1.2701 + // category specific processing...
1.2702 + switch(aTrace.iCategory)
1.2703 + {
1.2704 + case BTrace::ERDebugPrintf:
1.2705 + case BTrace::EKernPrintf:
1.2706 + case BTrace::EPlatsecPrintf:
1.2707 + if((flags&BTrace::EHeader2Present) && (header2&BTrace::EMultipartFlagMask))
1.2708 + aTrace.iDataTypes[2] = EDataTypeText;
1.2709 + else
1.2710 + aTrace.iDataTypes[1] = EDataTypeText;
1.2711 + break;
1.2712 + case BTrace::EThreadIdentification:
1.2713 + PreProcessThreadIdentification(aTrace); break;
1.2714 + case BTrace::ECpuUsage:
1.2715 + PreProcessCpuUsage(aTrace); break;
1.2716 + case BTrace::EChunks:
1.2717 + PreProcessChunks(aTrace); break;
1.2718 + case BTrace::ECodeSegs:
1.2719 + PreProcessCodeSegs(aTrace); break;
1.2720 + case BTrace::EKernelMemory:
1.2721 + PreProcessKernelMemory(aTrace); break;
1.2722 + case BTrace::EMetaTrace:
1.2723 + PreProcessMetaTrace(aTrace); break;
1.2724 + case BTrace::EFastMutex:
1.2725 + PreProcessFastMutex(aTrace); break;
1.2726 + case BTrace::EProfiling:
1.2727 + PreProcessProfiling(aTrace); break;
1.2728 + case BTrace::ESymbianKernelSync:
1.2729 + PreProcessSymbianKernelSync(aTrace); break;
1.2730 + default:
1.2731 + break;
1.2732 + }
1.2733 +
1.2734 + // update trace ID...
1.2735 + ++TraceRecordId;
1.2736 + if (ErrorOnThisTrace)
1.2737 + aTrace.iError = 1;
1.2738 + return true;
1.2739 + }
1.2740 +
1.2741 +
1.2742 +void DumpTrace(TraceRecord& aTrace)
1.2743 + {
1.2744 + if(!TraceDumpStarted)
1.2745 + {
1.2746 + // print heading...
1.2747 + if(SMP)
1.2748 + printf("C ");
1.2749 + if(Timestamp2Present)
1.2750 + printf("%10s ","TimeStamp2");
1.2751 + printf("%10s ","Time");
1.2752 + printf("%-8s ","PC");
1.2753 + if(ReportLevel>2)
1.2754 + {
1.2755 + printf("%-60s ","Context");
1.2756 + printf("%18s ","Category");
1.2757 + printf("%24s ","SubCategory");
1.2758 + }
1.2759 + else
1.2760 + {
1.2761 + printf("%-10s ","Context");
1.2762 + printf("%24s ","SubCategory");
1.2763 + }
1.2764 + printf("Data...\n");
1.2765 + TraceDumpStarted = true;
1.2766 + }
1.2767 +
1.2768 + if(aTrace.iFlags&BTrace::EMissingRecord)
1.2769 + printf("MISSING TRACE RECORD(S)\n");
1.2770 +
1.2771 + // print CPU number
1.2772 + if (SMP)
1.2773 + {
1.2774 + printf("%1d ", aTrace.iCpuNum);
1.2775 + }
1.2776 +
1.2777 + // print timestamp...
1.2778 + if(Timestamp2Present)
1.2779 + {
1.2780 + if(aTrace.iFlags&BTrace::ETimestamp2Present)
1.2781 + printf("%10u ",(unsigned int)aTrace.iTimestamp2);
1.2782 + else
1.2783 + printf(" ");
1.2784 + }
1.2785 +
1.2786 + if(aTrace.iFlags&BTrace::ETimestampPresent)
1.2787 + printf("%10u ",(unsigned int)Time(aTrace.iTimestamp-TimestampBase));
1.2788 + else
1.2789 + printf(" ");
1.2790 +
1.2791 + // print PC...
1.2792 + if(aTrace.iFlags&BTrace::EPcPresent)
1.2793 + printf("%08x ",(unsigned int)aTrace.iPC);
1.2794 + else
1.2795 + printf(" ");
1.2796 +
1.2797 + // print context...
1.2798 + if(ReportLevel>2)
1.2799 + {
1.2800 + Object::FullTraceNameBuf fullName;
1.2801 + fullName[0] = 0;
1.2802 + if(aTrace.iFlags&BTrace::EContextIdPresent)
1.2803 + aTrace.iContextID->FullTraceName(fullName);
1.2804 + printf("%-60s ",fullName);
1.2805 + }
1.2806 + else
1.2807 + {
1.2808 + Object::TraceNameBuf traceName;
1.2809 + traceName[0] = 0;
1.2810 + if(aTrace.iFlags&BTrace::EContextIdPresent)
1.2811 + aTrace.iContextID->TraceName(traceName);
1.2812 + printf("%-10s ",traceName);
1.2813 + }
1.2814 + // print trace categories...
1.2815 + const char* catName = CategoryName(aTrace.iCategory);
1.2816 + const char* subCatName = SubCategoryName(aTrace.iCategory,aTrace.iSubCategory);
1.2817 + if(ReportLevel>2)
1.2818 + printf("%18s %-24s ",catName,subCatName);
1.2819 + else
1.2820 + {
1.2821 + if(subCatName[0])
1.2822 + printf("%24s ",subCatName);
1.2823 + else
1.2824 + printf("%24s ",catName);
1.2825 + };
1.2826 +
1.2827 + // print trace data contents...
1.2828 + TUint i;
1.2829 + for(i=0; i<aTrace.iDataSize; i+=4)
1.2830 + {
1.2831 + TUint32 data = aTrace.iData[i/sizeof(TUint32)];
1.2832 + if(i<16)
1.2833 + {
1.2834 + // first 4 words of data may have 'type' info set during pre-processing...
1.2835 + switch(aTrace.iDataTypes[i/sizeof(TUint32)])
1.2836 + {
1.2837 + case EDataTypeObject:
1.2838 + {
1.2839 + // data is an object, print "full name"[traceID]...
1.2840 + Object* object = (Object*)data;
1.2841 + if(ReportLevel>2)
1.2842 + {
1.2843 + Object::FullTraceNameBuf name;
1.2844 + object->FullTraceName(name);
1.2845 + printf("%s ",name);
1.2846 + }
1.2847 + else
1.2848 + {
1.2849 + Object::TraceNameBuf name;
1.2850 + object->TraceName(name);
1.2851 + printf("%s ",name);
1.2852 + }
1.2853 + }
1.2854 + continue;
1.2855 +
1.2856 + case EDataTypeText:
1.2857 + {
1.2858 + // rest of trace is text...
1.2859 + TUint8* text = (TUint8*)aTrace.iData+i;
1.2860 + TUint8* textEnd = text+(aTrace.iDataSize-i);
1.2861 + TUint8 buffer[256];
1.2862 + TUint x=0;
1.2863 + while(text<textEnd && x<sizeof(buffer)-2)
1.2864 + {
1.2865 + TUint8 c = *text++;
1.2866 + TUint8 escape = 0;
1.2867 + switch(c)
1.2868 + {
1.2869 + case 9: escape = 't'; break;
1.2870 + case 10: escape = 'n'; break;
1.2871 + case 13: escape = 'r'; break;
1.2872 + default:
1.2873 + if(c<' ') c = '?';
1.2874 + break;
1.2875 + }
1.2876 + if(!escape)
1.2877 + buffer[x++] = c;
1.2878 + else
1.2879 + {
1.2880 + buffer[x++] = '\\';
1.2881 + buffer[x++] = escape;
1.2882 + }
1.2883 + }
1.2884 + buffer[x] = 0;
1.2885 + printf("\"%s\" ",buffer);
1.2886 + i = aTrace.iDataSize; // skip to end of data
1.2887 + }
1.2888 + continue;
1.2889 +
1.2890 + default:
1.2891 + break;
1.2892 + }
1.2893 + }
1.2894 + // default to print data as hex value...
1.2895 + printf("%08x ",(unsigned int)data);
1.2896 + }
1.2897 +
1.2898 + // print any extra data added by pre-processing...
1.2899 + for(i=0; i<2; ++i)
1.2900 + {
1.2901 + if(aTrace.iCalculatedData[i])
1.2902 + printf("{%u} ",(unsigned int)aTrace.iCalculatedData[i]);
1.2903 + }
1.2904 +
1.2905 + if (aTrace.iError)
1.2906 + printf(" ***ERROR***");
1.2907 +
1.2908 + // end-of-line finally!
1.2909 + printf("\n");
1.2910 + }
1.2911 +
1.2912 +
1.2913 +void DumpAllTraces()
1.2914 + {
1.2915 + printf("\nREPORT: Trace Dump\n\n");
1.2916 + for(TUint i=0; i<NextTraceId; i++)
1.2917 + DumpTrace(*TraceIndex[i]);
1.2918 + printf("\n");
1.2919 + }
1.2920 +
1.2921 +
1.2922 +void ReportErrors()
1.2923 + {
1.2924 + TBool errors = TraceFormatErrors || InterruptNestErrors || TraceFormatErrors
1.2925 + || ChunkErrors || CodeSegErrors || FastMutexNestErrors || KernelMemoryErrors
1.2926 + || ProfilingSampleErrors;
1.2927 +
1.2928 + if(!errors)
1.2929 + return;
1.2930 +
1.2931 + printf("\nREPORT: Trace Analysis Errors\n\n");
1.2932 + if(TraceFormatErrors)
1.2933 + printf("\tTrace Format Errors = %d\n",TraceFormatErrors);
1.2934 + if(InterruptNestErrors)
1.2935 + printf("\tInterrupt Nest Errors = %d\n",InterruptNestErrors);
1.2936 + if(FastMutexNestErrors)
1.2937 + printf("\tFast Mutex Nest Errors = %d\n",FastMutexNestErrors);
1.2938 + if(KernelMemoryErrors)
1.2939 + printf("\tKernel Memory Errors = %d\n",KernelMemoryErrors);
1.2940 + if(ChunkErrors)
1.2941 + printf("\tChunk Errors = %d\n",ChunkErrors);
1.2942 + if(CodeSegErrors)
1.2943 + printf("\tCodeSeg Errors = %d\n",CodeSegErrors);
1.2944 + if(ProfilingSampleErrors)
1.2945 + printf("\tProfiling Errors = %d\n",ProfilingSampleErrors);
1.2946 + printf("\n");
1.2947 + }
1.2948 +
1.2949 +
1.2950 +/**
1.2951 +The last trace record created has been preporcessed.
1.2952 +*/
1.2953 +void DoneTrace()
1.2954 + {
1.2955 + if(LastTrace)
1.2956 + TraceIndex[NextTraceId++] = (TraceRecord*)realloc(LastTrace,sizeof(TraceHeader)+LastTrace->iDataSize);
1.2957 + LastTrace = 0;
1.2958 + }
1.2959 +
1.2960 +
1.2961 +/**
1.2962 +Create a new trace record.
1.2963 +*/
1.2964 +TraceRecord* NewTrace()
1.2965 + {
1.2966 + if(NextTraceId>=TraceIndexSize)
1.2967 + {
1.2968 + TraceIndexSize += 1024;
1.2969 + TraceIndex = (TraceRecord**)realloc(TraceIndex,TraceIndexSize*sizeof(TraceIndex[0]));
1.2970 + ASSERT(TraceIndex);
1.2971 + }
1.2972 + DoneTrace();
1.2973 + LastTrace = (TraceRecord*)malloc(sizeof(TraceRecord));
1.2974 + return LastTrace;
1.2975 + }
1.2976 +
1.2977 +
1.2978 +/**
1.2979 +Delete all processed traces records.
1.2980 +*/
1.2981 +void ResetTrace()
1.2982 + {
1.2983 + DoneTrace();
1.2984 + TUint i;
1.2985 + for(i=0; i<NextTraceId; ++i)
1.2986 + free(TraceIndex[i]);
1.2987 + free(TraceIndex);
1.2988 + TraceIndex = 0;
1.2989 + TraceIndexSize = 0;
1.2990 + LastTrace = 0;
1.2991 + NextTraceId = 0;
1.2992 + TraceRecordId = 0;
1.2993 + }
1.2994 +
1.2995 +
1.2996 +void EndTrace()
1.2997 + {
1.2998 + DoneTrace();
1.2999 + }
1.3000 +
1.3001 +
1.3002 +/**
1.3003 +Process an entire BTrace log capture.
1.3004 +
1.3005 +@param aInput Pointer to function which will supply raw trace data.
1.3006 + Function should place up to aMaxSize bytes of data at aBuffer and return
1.3007 + the number of bytes stored. Return zero to indicate end of data.
1.3008 +@param aReportLevel Level of detail required of trace alaysis.
1.3009 + 0 = brief summary, 1 = full summary, 2 = condensed trace dump, 3 = full trace dump.
1.3010 +*/
1.3011 +void ProcessAllTrace(TUint (*aInput)(TAny* aBuffer, TUint aMaxSize),TInt aReportLevel)
1.3012 + {
1.3013 + ReportLevel = aReportLevel;
1.3014 +// __UHEAP_MARK;
1.3015 + printf("Btrace Analysis:\n");
1.3016 + printf("\nTHIS TOOL IS UNOFFICIAL, UNSUPPORTED AND SUBJECT TO CHANGE WITHOUT NOTICE!\n");
1.3017 +
1.3018 + StartTrace();
1.3019 + StartCpuUsage();
1.3020 + StartChunks();
1.3021 + StartCodeSegs();
1.3022 + StartFastMutex();
1.3023 + StartKernelMemory();
1.3024 + StartMetaTrace();
1.3025 + StartProfilingSample();
1.3026 +
1.3027 + for(; !TraceBufferFilled ;)
1.3028 + {
1.3029 + // read more data...
1.3030 + TUint size = (*aInput)(TraceBuffer+TraceBufferSize, sizeof(TraceBuffer)-TraceBufferSize);
1.3031 + if(!size)
1.3032 + break;
1.3033 + TraceBufferSize += size;
1.3034 +
1.3035 + // process all the complete traces in buffer...
1.3036 + const TUint8* data = TraceBuffer;
1.3037 + TUint sizeRemaining = TraceBufferSize;
1.3038 + while(sizeRemaining>BTrace::ESizeIndex)
1.3039 + {
1.3040 + TUint traceSize = (data[BTrace::ESizeIndex]+3)&~3;
1.3041 + if(traceSize>sizeRemaining)
1.3042 + break;
1.3043 +
1.3044 + TraceRecord* trace = NewTrace();
1.3045 + ASSERT(trace);
1.3046 + if(!PreProcessTrace(*trace,data))
1.3047 + {
1.3048 + if (!TraceBufferFilled)
1.3049 + {
1.3050 + // bad trace, create dummy 1 byte trace record...
1.3051 + memset(trace,0,sizeof(*trace));
1.3052 + trace->iCategory = BTrace::EMetaTrace;
1.3053 + trace->iSubCategory = KJunkTraceSubcategory;
1.3054 + trace->iDataSize = 4;
1.3055 + trace->iData[0] = *data;
1.3056 + ++TraceFormatErrors;
1.3057 + ErrorOnThisTrace = true;
1.3058 + traceSize = 1;
1.3059 + }
1.3060 + else // The buffer was filled so ignore the rest of the data
1.3061 + break;
1.3062 + }
1.3063 +
1.3064 + data += traceSize;
1.3065 + sizeRemaining -= traceSize;
1.3066 + }
1.3067 +
1.3068 + if (!TraceBufferFilled)
1.3069 + {
1.3070 + memcpy(TraceBuffer,data,sizeRemaining);
1.3071 + TraceBufferSize = sizeRemaining;
1.3072 + }
1.3073 + else
1.3074 + {
1.3075 + // The trace buffer was filled so ignore the rest of the data
1.3076 + // and just read whatever is left to flush it from the btrace buffer.
1.3077 + while ((*aInput)(TraceBuffer, sizeof(TraceBuffer))){};
1.3078 + TraceBufferSize = 0; // reset here so a format error isn't reported
1.3079 + }
1.3080 +
1.3081 + if(aReportLevel<2)
1.3082 + ResetTrace(); // free up memory as we go along
1.3083 + }
1.3084 + EndTrace();
1.3085 + EndCpuUsage();
1.3086 +
1.3087 + if(TraceBufferSize)
1.3088 + {
1.3089 + ++TraceFormatErrors;
1.3090 + ErrorOnThisTrace = true;
1.3091 + }
1.3092 +
1.3093 + ReportTimeUnits();
1.3094 + ReportErrors();
1.3095 + if(aReportLevel>=2)
1.3096 + DumpAllTraces();
1.3097 + if(ReportLevel>=1 || CpuUsagePresent)
1.3098 + {
1.3099 + ReportProcesses();
1.3100 + ReportThreads();
1.3101 + }
1.3102 + ReportChunks();
1.3103 + ReportKernelMemory();
1.3104 + ReportCodeSegs();
1.3105 + ReportFastMutex();
1.3106 + ReportSampleProfiling();
1.3107 +
1.3108 + ResetTrace();
1.3109 + ObjectContainer::Reset();
1.3110 +// __UHEAP_MARKEND;
1.3111 + }
1.3112 +
1.3113 +