First public contribution.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 #if defined(__EPOC32__) || defined(__WINS__)
17 // compiling for Symbian OS...
19 #include <e32std_private.h>
22 #include <e32def_private.h>
23 #include <d32btrace.h>
24 #include "e32btrace.h"
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); }
30 TUint8 PrintfBuffer[256];
31 TUint PrintfBufferWidth = 0;
33 static void printf(const char* aFormat,...)
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();
46 if(width>=PrintfBufferWidth)
48 if(PrintfBuffer[width]=='\n')
52 TPtrC8 line(PrintfBuffer,width);
54 RDebug::RawPrint(line);
55 _LIT(KLineEnd,"\r\n");
56 RDebug::RawPrint(KLineEnd);
57 memcpy(PrintfBuffer,PrintfBuffer+width,PrintfBufferWidth-width);
58 PrintfBufferWidth -= width;
62 typedef TUint uintptr_t;
65 #define ASSERT(c) (void)((c)||(AssertFailed(__LINE__)))
66 TInt AssertFailed(TInt aLine)
68 _LIT(KPanicCategory,"BTRACE-ANALYSE");
69 User::Panic(KPanicCategory,aLine);
76 // Trace buffer helper functions - for use on target only
80 TUint AnalyseDataRemain = 0;
84 for(TInt i=0; i<256; ++i)
88 // toggle filter to force a prime
95 TUint AnalyseStream(TAny* aBuffer, TUint aMaxSize)
97 TUint size = AnalyseDataRemain;
101 AnalyseDataRemain = Trace.GetData(AnalyseData);
102 size = AnalyseDataRemain;
106 memcpy(aBuffer,AnalyseData,size);
108 AnalyseDataRemain -= size;
112 void ProcessAllTrace(TUint (*aInput)(TAny* aBuffer, TUint aMaxSize),TInt aReportLevel);
114 void DoAnalyse(TInt aAnalysisLevel)
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);
124 TInt BTraceAnalyseSetup()
126 TInt r = Trace.Open();
132 TUint oldMode = Trace.Mode();
135 // empty btrace buffer and reprime it
137 Trace.SetMode(oldMode);
142 void BTraceAnalyseEnd()
147 void BTraceAnalyse(TInt aAnalysisLevel)
150 TUint oldMode = Trace.Mode();
153 AnalyseDataRemain = 0;
154 ProcessAllTrace(AnalyseStream, aAnalysisLevel);
156 // empty btrace buffer and reprime it
158 Trace.SetMode(oldMode);
163 // compiling for host...
169 #if defined(_MSC_VER)
170 typedef __int64 longlong;
171 typedef unsigned __int64 ulonglong;
172 #define BREAKPOINT { _asm int 3 } /**< Invoke debugger */
174 typedef long long longlong;
175 typedef long long ulonglong;
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;
186 typedef unsigned TUint;
191 #include "e32btrace.h"
193 #define ASSERT(c) (void)((c)||(AssertFailed(__LINE__)))
194 extern "C" void exit(int);
195 TInt AssertFailed(TInt aLine)
197 fprintf(stderr,"Panic: BTRACE-ANALYSE %d",aLine);
204 #define __UHEAP_MARKEND
206 TAny* operator new(size_t, TAny* p) {return p;}
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;
228 TBool ErrorOnThisTrace = false;
230 const TUint8 KJunkTraceSubcategory = 255; // Dummy sub-category for EMetaTrace
232 const TInt KMaxCpus = 8;
238 void ToHex(TUint8* aString,TUint32 aValue)
244 TUint8 c = (TUint8)((aValue>>i)&0xf);
255 TUint MakeName(TUint8* aString,const char* aName,TUint32 aHexValue)
257 TUint8* start = aString;
265 ToHex(aString,aHexValue);
267 return aString-start+8;
272 Convert a timestamp into real time units (micro-seconds)
274 TUint32 Time(TUint64 aTimestamp)
277 return (TUint32)aTimestamp;
278 TInt exponent = (TInt8)(TimestampPeriod>>24);
279 TUint64 mantissa = TimestampPeriod&0xffffff;
280 aTimestamp *= mantissa;
283 aTimestamp >>= -exponent;
285 aTimestamp <<= exponent;
286 TUint64 timeLo = (aTimestamp&0xffffffffu)*1000000;
287 TUint64 timeHi = (aTimestamp>>32)*1000000;
288 TUint64 us = timeHi+(timeLo>>32)+((timeLo>>31)&1);
293 void ReportTimeUnits()
296 printf("\nAll times are given in BTrace Timestamp1 units.\n\n");
299 TInt exponent = (TInt8)(TimestampPeriod>>24);
300 TUint64 mantissa = TimestampPeriod&0xffffff;
301 TUint64 period = 1000000;
305 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));
313 TUint SetBits(TUint8* aData, TUint aOffset, TUint aSize)
315 TUint mask = 1<<(aOffset&7);
316 TUint8* data = aData+(aOffset>>3);
322 *data |= (TUint8)mask;
335 TUint ClearBits(TUint8* aData, TUint aOffset, TUint aSize)
337 TUint mask = 1<<(aOffset&7);
338 TUint8* data = aData+(aOffset>>3);
344 *data &= (TUint8)~mask;
357 void WarnIfError(TUint aErrorCount)
359 if (TraceBufferFilled)
360 printf("WARNING - BTRACE BUFFER IS FULL SO TRACE DATA MAY BE INCOMPLETE\n");
362 if(aErrorCount==0 && TraceFormatErrors==0)
364 printf("CONSISTENCY ERRORS FOUND DURING TRACE ANALYSIS, RESULTS ARE UNRELIABLE!\n");
368 #define CHECK_TRACE_DATA_WORDS(numWords) \
369 if(aTrace.iDataSize<numWords*4 && ++TraceFormatErrors) return
376 const char* const UnknownNames[256] =
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"
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)
411 const char* CategoryName(TUint8 aCategory)
413 switch((BTrace::TCategory)aCategory)
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);
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);
441 return UnknownNames[aCategory];
444 const char* SubCategoryName(TUint8 aCategory, TUint8 aSubCategory)
448 case BTrace::ERDebugPrintf:
449 case BTrace::EKernPrintf:
450 case BTrace::EPlatsecPrintf:
451 return ""; // no subcategories for these
453 case BTrace::EThreadIdentification:
454 switch((BTrace::TThreadIdentification)aSubCategory)
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);
468 case BTrace::ECpuUsage:
469 switch((BTrace::TCpuUsage)aSubCategory)
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);
481 case BTrace::EChunks:
482 switch((BTrace::TChunks)aSubCategory)
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);
495 case BTrace::ECodeSegs:
496 switch((BTrace::TCodeSegs)aSubCategory)
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);
508 case BTrace::EPaging:
509 switch((BTrace::TPaging)aSubCategory)
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);
542 case BTrace::EKernelMemory:
543 switch((BTrace::TKernelMemory)aSubCategory)
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);
555 case BTrace::EMetaTrace:
557 if(aSubCategory==KJunkTraceSubcategory)
561 switch((BTrace::TMetaTrace)aSubCategory)
563 CASE_CAT_NAME(EMetaTraceTimestampsInfo);
564 CASE_CAT_NAME(EMetaTraceMeasurementStart);
565 CASE_CAT_NAME(EMetaTraceMeasurementEnd);
566 CASE_CAT_NAME(EMetaTraceFilterChange);
572 case BTrace::EFastMutex:
573 switch((BTrace::TFastMutex)aSubCategory)
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);
583 case BTrace::EProfiling:
584 switch((BTrace::TProfiling)aSubCategory)
586 CASE_CAT_NAME(ECpuFullSample);
587 CASE_CAT_NAME(ECpuOptimisedSample);
588 CASE_CAT_NAME(ECpuIdfcSample);
589 CASE_CAT_NAME(ECpuNonSymbianThreadSample);
593 case BTrace::ESymbianKernelSync:
594 switch((BTrace::TSymbianKernelSync)aSubCategory)
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);
615 case BTrace::EFlexibleMemModel:
616 switch((BTrace::TFlexibleMemModel)aSubCategory)
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);
633 return UnknownNames[aSubCategory];
664 TUint8 iDataTypes[4];
665 TUint32 iCalculatedData[2];
672 struct TraceRecord : public TraceHeader
674 TUint32 iData[(8+KMaxBTraceDataArray)/4];
696 void ChangeContext(TContext aType, Thread* aThread=0);
699 TContext iCurrentContext;
706 Thread* iCurrentThread;
707 TUint64 iBaseTimestamp;
714 const TUint KMaxTraceNameLength = 10;
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)
730 if(iOwnerTraceId && !iOwner)
737 void SetName(void* aName, TUint aLength)
739 ASSERT(aLength<sizeof(iName));
740 iNameLength = (TUint8)aLength;
741 memcpy(iName,aName,aLength);
746 void SetName(TraceRecord& aTrace, TUint aIndex)
748 SetName(aTrace.iData+aIndex,aTrace.iDataSize-aIndex*4);
749 aTrace.iDataTypes[aIndex] = EDataTypeText;
752 TBool IsName(void* aName, TUint aLength)
754 if(aLength!=iNameLength)
757 if(iName[aLength]!=((TUint8*)aName)[aLength])
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'
766 TUint FullName(FullNameBuf& aName)
773 memcpy(aName+length,iOwner->iOwner->iName,iOwner->iOwner->iNameLength);
774 length += iOwner->iOwner->iNameLength;
775 aName[length++] = ':';
776 aName[length++] = ':';
778 memcpy(aName+length,iOwner->iName,iOwner->iNameLength);
779 length += iOwner->iNameLength;
780 aName[length++] = ':';
781 aName[length++] = ':';
783 memcpy(aName+length,iName,iNameLength);
784 length += iNameLength;
789 TUint TraceName(TraceNameBuf& aName)
792 const TUint KNumDigits = KMaxTraceNameLength-4;
794 const char* prefix = iTraceNamePrefix;
796 aName[i++] = *prefix++;
798 aName[i++] = *prefix++;
800 for(TUint d=KNumDigits; d>0; --d)
802 aName[i+d-1] = TUint8('0'+(n%10));
811 TUint FullTraceName(FullTraceNameBuf& aName)
813 TUint l1 = TraceName(*(TraceNameBuf*)aName);
815 TUint l2 = FullName(*(FullNameBuf*)(aName+l1));
816 aName[l1+l2++] = '\'';
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.
829 TUint8 iName[KMaxBTraceDataArray+1];
830 const char* iTraceNamePrefix;
832 static TUint32 UnknownOwners;
834 TUint32 Object::UnknownOwners = 0;
837 class ObjectContainer
841 : iNumEntries(0), iEntriesLength(0) , iEntries(0)
843 iLink = iAllContainers;
844 iAllContainers = this;
849 ObjectContainer* container = iAllContainers;
852 TUint i = container->iNumEntries;
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;
863 void Add(Object* aObject)
865 if(iNumEntries>=iEntriesLength)
867 iEntriesLength += 128;
868 iEntries = (Entry*)realloc(iEntries,iEntriesLength*sizeof(Entry));
871 aObject->iIndex = iNumEntries;
872 Entry& entry = iEntries[iNumEntries++];
873 entry.iTraceId = aObject->iTraceId;
874 entry.iItem = aObject;
882 Object* operator[](TInt aIndex)
884 if(TUint(aIndex)<iNumEntries)
885 return iEntries[aIndex].iItem;
890 Object* Find(TUint32 aTraceId)
892 Entry* ptr = iEntries+iNumEntries;
893 Entry* end = iEntries;
897 if(ptr->iTraceId==aTraceId)
899 if(ptr->iItem->iAlive)
914 TUint iEntriesLength;
916 ObjectContainer* iLink;
918 static ObjectContainer* iAllContainers;
920 ObjectContainer* ObjectContainer::iAllContainers = 0;
923 #define GENERIC_OBJECT_DEFINITIONS(C) \
925 static C* Find(TUint32 aTraceId) \
927 return (C*)iContainer.Find(aTraceId); \
930 static C* Create(TraceRecord& aTrace, TUint aIndex) \
932 TUint32 traceId = aTrace.iData[aIndex]; \
933 C* object = new C(traceId); \
934 aTrace.iDataTypes[aIndex] = EDataTypeObject; \
935 aTrace.iData[aIndex] = (uintptr_t)object; \
939 static C* Find(TraceRecord& aTrace, TUint aIndex) \
941 TUint32 traceId = aTrace.iData[aIndex]; \
942 C* object = Find(traceId); \
945 aTrace.iDataTypes[aIndex] = EDataTypeObject; \
946 aTrace.iData[aIndex] = (uintptr_t)object; \
950 static C* FindOrCreate(TraceRecord& aTrace, TUint aIndex) \
952 C* object = Find(aTrace,aIndex); \
954 object = Create(aTrace,aIndex); \
964 class Process : public Object
967 Process(TUint32 aTraceId)
968 : Object(aTraceId,"P"), iThreadCount(0), iMaxThreadCount(0)
970 iContainer.Add(this);
973 GENERIC_OBJECT_DEFINITIONS(Process);
977 TUint iMaxThreadCount;
979 static ObjectContainer iContainer;
981 ObjectContainer Process::iContainer;
989 class Thread : public Object
992 Thread(TUint32 aTraceId)
993 : Object(aTraceId,"T"), iId(~0u), iCpuTime(0), iSamples(0)
995 iContainer.Add(this);
996 iNameLength = (TUint8)MakeName(iName,"NThread-",aTraceId);
1001 if(!iLastCpu || !iLastCpu->iBaseTimestamp)
1003 if(iLastCpu->iCurrentThread==this)
1004 return iCpuTime + Timestamp - iLastCpu->iBaseTimestamp;
1010 if( iSamples+1 != 0xFFFFFFFF)
1016 GENERIC_OBJECT_DEFINITIONS(Thread);
1018 static Object* FindThreadOrProcess(TraceRecord& aTrace, TUint aIndex)
1020 if (!aTrace.iData[aIndex])
1022 Object* p = Find(aTrace, aIndex);
1024 p = Process::Find(aTrace, aIndex);
1031 TUint64 iFMBlockStartTime;
1032 FastMutex* iWaitFastMutex;
1034 // Number of profiling samples
1037 static ObjectContainer iContainer;
1040 ObjectContainer Thread::iContainer;
1048 TUint ChunkErrors = 0;
1050 const TUint KPageShift = 12; // chunk memory is allocated in 4kB pages
1052 class Chunk : public Object
1055 Chunk(TUint32 aTraceId)
1056 : Object(aTraceId,"C"), iCurrentSize(0), iPeakSize(0), iMaxSize(0), iPageMap(0), iTraceErrors(0)
1058 iContainer.Add(this);
1066 void SetMaxSize(TUint32 aMaxSize)
1069 iMaxSize = aMaxSize;
1070 TUint mapSize = ((aMaxSize>>KPageShift)+7)>>3;
1071 iPageMap = (TUint8*)malloc(mapSize);
1073 memset(iPageMap,0,mapSize);
1077 void Commit(TUint32 aStart,TUint32 aSize)
1079 if(!iPageMap) // we havent been intialised yet
1082 if(aStart+aSize<aStart || aStart+aSize>iMaxSize)
1088 if(SetBits(iPageMap,aStart>>KPageShift,aSize>>KPageShift))
1092 ErrorOnThisTrace = true;
1096 void Decommit(TUint32 aStart,TUint32 aSize)
1098 if(!iPageMap) // we havent been intialised yet
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...
1110 if(aStart+aSize<aStart || aStart+aSize>iMaxSize)
1112 // we haven't found enough memory to decommit
1115 ErrorOnThisTrace = true;
1118 TUint notDecommitted = ClearBits(iPageMap,aStart>>KPageShift,aSize>>KPageShift);
1120 aSize = notDecommitted<<KPageShift;
1128 GENERIC_OBJECT_DEFINITIONS(Chunk);
1131 TUint32 iCurrentSize;
1137 static ObjectContainer iContainer;
1139 ObjectContainer Chunk::iContainer;
1144 // Semaphore, Mutex, CondVar
1146 class Semaphore : public Object
1149 Semaphore(TUint32 aTraceId)
1150 : Object(aTraceId,"S")
1152 iContainer.Add(this);
1159 GENERIC_OBJECT_DEFINITIONS(Semaphore);
1162 static ObjectContainer iContainer;
1164 ObjectContainer Semaphore::iContainer;
1167 class Mutex : public Object
1170 Mutex(TUint32 aTraceId)
1171 : Object(aTraceId,"M")
1173 iContainer.Add(this);
1180 GENERIC_OBJECT_DEFINITIONS(Mutex);
1183 static ObjectContainer iContainer;
1185 ObjectContainer Mutex::iContainer;
1188 class CondVar : public Object
1191 CondVar(TUint32 aTraceId)
1192 : Object(aTraceId,"V")
1194 iContainer.Add(this);
1201 GENERIC_OBJECT_DEFINITIONS(CondVar);
1204 static ObjectContainer iContainer;
1206 ObjectContainer CondVar::iContainer;
1215 TUint CodeSegErrors = 0;
1217 class CodeSeg : public Object
1220 CodeSeg(TUint32 aTraceId)
1221 : Object(aTraceId,"CS"), iAllocatedMemory(0)
1223 iContainer.Add(this);
1226 GENERIC_OBJECT_DEFINITIONS(CodeSeg);
1228 TUint iAllocatedMemory;
1230 static ObjectContainer iContainer;
1232 ObjectContainer CodeSeg::iContainer;
1240 TUint FastMutexNestErrors = 0;
1242 class FastMutex : public Object
1245 FastMutex(TUint32 aTraceId)
1246 : Object(aTraceId,"FM"), iHoldingThread(0), iHeldCount(0), iTotalHeldTime(0),
1247 iMaxHeldTime(0), iMaxHeldTimestamp(0), iMaxHeldPc(0), iBlockCount(0)
1249 iContainer.Add(this);
1250 iNameLength = (TUint8)MakeName(iName,"NFastMutex-",aTraceId);
1254 TUint32 Wait(Thread* aThread)
1259 ++FastMutexNestErrors;
1260 ErrorOnThisTrace = true;
1262 iHoldingThread = aThread;
1263 iWaitCpuTimeBase = aThread->CpuTime();
1264 if (aThread->iWaitFastMutex == this)
1266 time = (TUint32)(Timestamp - aThread->iFMBlockStartTime);
1268 aThread->iWaitFastMutex = 0;
1272 void Block(Thread* aThread)
1274 if (aThread->iWaitFastMutex != this)
1276 aThread->iFMBlockStartTime = Timestamp;
1277 aThread->iWaitFastMutex = this;
1282 TUint32 Signal(Thread* aThread, TUint32 aPc)
1284 if (!iHoldingThread) // First record for this mutex so ignore it as don't
1285 return 0; // have waiting thread details
1287 if(iHoldingThread!=aThread)
1289 ++FastMutexNestErrors;
1290 ErrorOnThisTrace = true;
1295 TUint64 time = aThread->CpuTime()-iWaitCpuTimeBase;
1297 iTotalHeldTime += time;
1298 if(time>iMaxHeldTime)
1300 iMaxHeldTime = time;
1302 iMaxHeldTimestamp = Timestamp;
1304 return (TUint32)time;
1307 GENERIC_OBJECT_DEFINITIONS(FastMutex);
1310 Thread* iHoldingThread;
1311 TUint32 iHeldCount; // number of times mutex acquired
1312 TUint64 iTotalHeldTime;
1313 TUint64 iWaitCpuTimeBase;
1314 TUint64 iMaxHeldTime;
1315 TUint64 iMaxHeldTimestamp;
1317 TUint32 iBlockCount; // number of times mutex caused a thread to wait
1319 static ObjectContainer iContainer;
1321 ObjectContainer FastMutex::iContainer;
1330 TUint ProfilingSampleErrors = 0;
1332 class ProfilingSample : public Object
1335 ProfilingSample(TUint32 aTraceId)
1336 : Object(aTraceId,"PS")
1338 iContainer.Add(this);
1339 iNameLength = (TUint8)MakeName(iName,"ProfilingSample-",aTraceId);
1342 void SetPC( TUint32 aPC )
1347 void SetThread( TUint32 aThread )
1353 void SetType(const BTrace::TProfiling aType)
1358 GENERIC_OBJECT_DEFINITIONS(ProfilingSample);
1363 static ObjectContainer iContainer;
1364 static Thread* iTopTen[10];
1365 static TUint32 iSamples;
1366 static TUint32 iLastThread;
1370 BTrace::TProfiling iType;
1374 TUint32 ProfilingSample::iSamples = 0;
1375 TUint32 ProfilingSample::iLastThread = 0;
1377 ObjectContainer ProfilingSample::iContainer;
1381 // EThreadIdentification traces
1384 void PreProcessThreadIdentification(TraceRecord& aTrace)
1389 switch((BTrace::TThreadIdentification)aTrace.iSubCategory)
1391 case BTrace::ENanoThreadCreate:
1392 CHECK_TRACE_DATA_WORDS(1);
1393 thread = Thread::FindOrCreate(aTrace,0);
1396 case BTrace::ENanoThreadDestroy:
1397 CHECK_TRACE_DATA_WORDS(1);
1398 thread = Thread::Find(aTrace,0);
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);
1417 case BTrace::EThreadDestroy:
1418 CHECK_TRACE_DATA_WORDS(1);
1419 thread = Thread::Find(aTrace,0);
1423 process = (Process*)thread->iOwner;
1424 if(process && process->iThreadCount)
1425 --process->iThreadCount;
1429 case BTrace::EProcessName:
1430 CHECK_TRACE_DATA_WORDS(2);
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)))
1439 process = Process::Create(aTrace,1); // no existing process, or name different
1442 process = Process::Find(aTrace,1); // find again (this will update trace data[1])
1445 process = Process::Find(aTrace,1);
1447 process->SetName(aTrace,2);
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];
1457 case BTrace::EProcessCreate:
1458 CHECK_TRACE_DATA_WORDS(1);
1459 process = Process::FindOrCreate(aTrace,0);
1462 case BTrace::EProcessDestroy:
1463 CHECK_TRACE_DATA_WORDS(1);
1464 process = Process::FindOrCreate(aTrace,0);
1479 Cpu TheCpus[KMaxCpus];
1480 TUint InterruptNestErrors = 0;
1481 TUint CpuUsagePresent = 0;
1484 : iCurrentContext(EContextUnknown),
1498 iCurrentContext = EContextUnknown;
1506 void ResetCpuUsage()
1509 for (i=0; i<KMaxCpus; ++i)
1514 void StartCpuUsage()
1517 for (i=0; i<KMaxCpus; ++i)
1518 new (&TheCpus[i]) Cpu;
1519 InterruptNestErrors = 0;
1523 void Cpu::ChangeContext(TContext aType, Thread* aThread)
1525 TUint64 delta = Timestamp-iBaseTimestamp;
1526 switch(iCurrentContext)
1528 case EContextThread:
1529 iCurrentThread->iCpuTime += delta;
1544 if(aType==EContextUnknown)
1547 aType = EContextFiq;
1549 aType = EContextIrq;
1551 aType = EContextIDFC;
1554 aType = EContextThread;
1555 aThread = iCurrentThread;
1559 if(aType==EContextThread && !aThread)
1561 iCurrentContext = EContextUnknown;
1566 iCurrentContext = aType;
1567 if(aType==EContextThread)
1569 iCurrentThread = aThread;
1570 aThread->iLastCpu = this;
1573 iBaseTimestamp = Timestamp;
1577 void PreProcessCpuUsage(TraceRecord& aTrace)
1579 CpuUsagePresent = true;
1580 Cpu& cpu = *aTrace.iCpu;
1582 switch((BTrace::TCpuUsage)aTrace.iSubCategory)
1584 case BTrace::EIrqStart:
1586 cpu.ChangeContext(EContextIrq);
1589 case BTrace::EFiqStart:
1591 cpu.ChangeContext(EContextFiq);
1594 case BTrace::EIDFCStart:
1595 if(cpu.iIrqNest+cpu.iFiqNest>1 || cpu.iIDFCNest!=0)
1597 ++InterruptNestErrors;
1598 ErrorOnThisTrace = true;
1603 cpu.ChangeContext(EContextIDFC);
1606 case BTrace::EIrqEnd:
1611 ++InterruptNestErrors;
1612 ErrorOnThisTrace = true;
1614 cpu.ChangeContext(EContextUnknown);
1617 case BTrace::EFiqEnd:
1622 ++InterruptNestErrors;
1623 ErrorOnThisTrace = true;
1625 cpu.ChangeContext(EContextUnknown);
1628 case BTrace::EIDFCEnd:
1629 if(cpu.iIDFCNest!=1)
1631 ++InterruptNestErrors;
1632 ErrorOnThisTrace = true;
1635 cpu.ChangeContext(EContextUnknown);
1638 case BTrace::ENewThreadContext:
1639 if(cpu.iIrqNest+cpu.iFiqNest>1 || cpu.iIDFCNest!=0)
1641 ++InterruptNestErrors;
1642 ErrorOnThisTrace = true;
1647 cpu.ChangeContext(EContextThread,aTrace.iContextID);
1653 void ReportThreads()
1655 TUint numThreads = Thread::iContainer.Count();
1659 TUint64 totalTime = 0;
1660 printf("\nREPORT: Threads\n\n");
1662 printf("%-10s %5s %10s %8s %s\n","","State","CPUTime","TraceId","Name");
1664 for(i=0; i<numThreads; ++i)
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;
1676 for (i=0; i<(TUint)KMaxCpus; ++i)
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;
1685 printf("%-10s %5s ----------\n","","");
1686 printf("%-10s %5s %10d\n","","",(int)Time(totalTime));
1691 void ReportProcesses()
1693 TUint numProcesses = Process::iContainer.Count();
1697 printf("\nREPORT: Processes\n\n");
1699 printf("%-10s %5s %7s %8s %s\n","","State","Threads","TraceId","Name");
1701 for(i=0; i<numProcesses; ++i)
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);
1720 for (i=0; i<KMaxCpus; ++i)
1721 TheCpus[i].ChangeContext(EContextUnknown);
1735 void PreProcessChunks(TraceRecord& aTrace)
1737 CHECK_TRACE_DATA_WORDS(1);
1738 Chunk* chunk = Chunk::FindOrCreate(aTrace,0);
1740 switch((BTrace::TChunks)aTrace.iSubCategory)
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;
1750 case BTrace::EChunkInfo:
1751 CHECK_TRACE_DATA_WORDS(3);
1754 case BTrace::EChunkDestroyed:
1758 case BTrace::EChunkMemoryAllocated:
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;
1772 case BTrace::EChunkMemoryDeallocated:
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)
1779 chunk->iCurrentSize = size;
1780 aTrace.iCalculatedData[0] = size/1024;
1784 case BTrace::EChunkMemoryAdded:
1785 CHECK_TRACE_DATA_WORDS(3);
1786 chunk->Commit(aTrace.iData[1],aTrace.iData[2]);
1789 case BTrace::EChunkMemoryRemoved:
1790 CHECK_TRACE_DATA_WORDS(3);
1791 chunk->Decommit(aTrace.iData[1],aTrace.iData[2]);
1794 case BTrace::EChunkOwner:
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;
1811 TUint numChunks = Chunk::iContainer.Count();
1816 printf("\nREPORT: Chunks (Named objects only)\n\n");
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;
1824 for(i=0; i<numChunks; ++i)
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;
1839 printf("%-10s %5s --------\n","","");
1840 printf("%-10s %5s %7uk\n","","",totalSize);
1850 void StartCodeSegs()
1856 void PreProcessCodeSegs(TraceRecord& aTrace)
1858 CHECK_TRACE_DATA_WORDS(1);
1861 switch((BTrace::TCodeSegs)aTrace.iSubCategory)
1863 case BTrace::ECodeSegCreated:
1864 codeseg = CodeSeg::FindOrCreate(aTrace,0);
1865 codeseg->SetName(aTrace,1);
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).
1882 case BTrace::ECodeSegDestroyed:
1883 codeseg = CodeSeg::FindOrCreate(aTrace,0);
1885 codeseg->iAllocatedMemory = 0; // clear this now because ECodeSegMemoryDeallocated comes after codeseg destroy
1888 case BTrace::ECodeSegMapped:
1889 CHECK_TRACE_DATA_WORDS(2);
1890 codeseg = CodeSeg::FindOrCreate(aTrace,0);
1891 Process::FindOrCreate(aTrace,1);
1894 case BTrace::ECodeSegUnmapped:
1895 CHECK_TRACE_DATA_WORDS(2);
1896 CodeSeg::FindOrCreate(aTrace,0);
1897 Process::FindOrCreate(aTrace,1);
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])
1906 codeseg->iAllocatedMemory = ~0u; // overflowed!
1908 ErrorOnThisTrace = true;
1912 case BTrace::ECodeSegMemoryDeallocated:
1914 CHECK_TRACE_DATA_WORDS(2);
1915 codeseg = CodeSeg::Find(aTrace,0);
1918 TUint32 memory = codeseg->iAllocatedMemory-aTrace.iData[1];
1919 if(memory>codeseg->iAllocatedMemory)
1921 memory = 0; // underflowed
1923 ErrorOnThisTrace = true;
1925 codeseg->iAllocatedMemory = memory;
1934 void ReportCodeSegs()
1936 TUint numCodeSegs = CodeSeg::iContainer.Count();
1941 printf("\nREPORT: CodeSegs (Named objects only)\n\n");
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;
1949 for(i=0; i<numCodeSegs; ++i)
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;
1963 printf("%-10s %5s --------\n","","");
1964 printf("%-10s %5s %7uk\n","","",totalSize);
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;
1982 void StartKernelMemory()
1984 KernelMemoryInitialFree = 0;
1985 KernelMemoryCurrentFree = 0;
1986 KernelMemoryMisc = 0;
1987 KernelMemoryDrvPhys = 0;
1988 KernelMemoryErrors = 0;
1989 KernelMemoryTracesPresent = false;
1993 void PreProcessKernelMemory(TraceRecord& aTrace)
1995 CHECK_TRACE_DATA_WORDS(1);
1996 KernelMemoryTracesPresent = true;
1997 switch((BTrace::TKernelMemory)aTrace.iSubCategory)
1999 case BTrace::EKernelMemoryInitialFree:
2000 KernelMemoryInitialFree = aTrace.iData[0];
2001 aTrace.iCalculatedData[0] = KernelMemoryInitialFree/1024;
2004 case BTrace::EKernelMemoryCurrentFree:
2005 KernelMemoryCurrentFree = aTrace.iData[0];
2006 aTrace.iCalculatedData[0] = KernelMemoryCurrentFree/1024;
2009 case BTrace::EKernelMemoryMiscAlloc:
2010 KernelMemoryMisc += aTrace.iData[0];
2011 if(KernelMemoryMisc < aTrace.iData[0])
2013 KernelMemoryMisc = 0xffffffffu;
2014 ++KernelMemoryErrors;
2015 ErrorOnThisTrace = true;
2017 aTrace.iCalculatedData[0] = KernelMemoryMisc/1024;
2020 case BTrace::EKernelMemoryMiscFree:
2021 if(KernelMemoryMisc >= aTrace.iData[0])
2022 KernelMemoryMisc -= aTrace.iData[0];
2025 KernelMemoryMisc = 0;
2026 ++KernelMemoryErrors;
2027 ErrorOnThisTrace = true;
2029 aTrace.iCalculatedData[0] = KernelMemoryMisc/1024;
2032 case BTrace::EKernelMemoryDemandPagingCache:
2033 KernelMemoryDemandPagingCache = aTrace.iData[0];
2036 case BTrace::EKernelMemoryDrvPhysAlloc:
2037 KernelMemoryDrvPhys += aTrace.iData[0];
2038 if(KernelMemoryDrvPhys < aTrace.iData[0])
2040 KernelMemoryDrvPhys = 0xffffffffu;
2041 ++KernelMemoryErrors;
2042 ErrorOnThisTrace = true;
2044 aTrace.iCalculatedData[0] = KernelMemoryDrvPhys/1024;
2047 case BTrace::EKernelMemoryDrvPhysFree:
2048 if(KernelMemoryDrvPhys >= aTrace.iData[0])
2049 KernelMemoryDrvPhys -= aTrace.iData[0];
2052 KernelMemoryDrvPhys = 0;
2053 ++KernelMemoryErrors;
2054 ErrorOnThisTrace = true;
2056 aTrace.iCalculatedData[0] = KernelMemoryDrvPhys/1024;
2061 void ReportKernelMemory()
2063 if(!KernelMemoryTracesPresent)
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);
2073 printf("Last 'current free RAM' value seen......... %dk\n",KernelMemoryCurrentFree/1024);
2082 void StartMetaTrace()
2084 TimestampPeriod = 0;
2085 Timestamp2Period = 0;
2089 void PreProcessMetaTrace(TraceRecord& aTrace)
2091 switch((BTrace::TMetaTrace)aTrace.iSubCategory)
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;
2100 case BTrace::EMetaTraceMeasurementStart:
2101 case BTrace::EMetaTraceMeasurementEnd:
2102 CHECK_TRACE_DATA_WORDS(2);
2103 aTrace.iDataTypes[2] = EDataTypeText;
2106 case BTrace::EMetaTraceFilterChange:
2107 CHECK_TRACE_DATA_WORDS(1);
2113 // EFastMutex traces
2116 void StartFastMutex()
2118 FastMutexNestErrors = 0;
2122 void PreProcessFastMutex(TraceRecord& aTrace)
2124 CHECK_TRACE_DATA_WORDS(1);
2125 FastMutex* mutex = FastMutex::FindOrCreate(aTrace,0);
2126 Thread* thread = aTrace.iContextID;
2128 switch((BTrace::TFastMutex)aTrace.iSubCategory)
2130 case BTrace::EFastMutexWait:
2131 aTrace.iCalculatedData[0] = Time(mutex->Wait(thread));
2134 case BTrace::EFastMutexSignal:
2135 aTrace.iCalculatedData[0] = Time(mutex->Signal(thread,aTrace.iPC));
2138 case BTrace::EFastMutexFlash:
2139 aTrace.iCalculatedData[0] = Time(mutex->Signal(thread,aTrace.iPC));
2140 mutex->Wait(thread);
2143 case BTrace::EFastMutexName:
2144 CHECK_TRACE_DATA_WORDS(2);
2145 mutex->SetName(aTrace,2);
2148 case BTrace::EFastMutexBlock:
2149 mutex->Block(thread);
2156 void PreProcessSymbianKernelSync(TraceRecord& aTrace)
2158 switch((BTrace::TSymbianKernelSync)aTrace.iSubCategory)
2160 case BTrace::ESemaphoreCreate:
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);
2173 case BTrace::ESemaphoreDestroy:
2175 CHECK_TRACE_DATA_WORDS(1);
2176 Semaphore* sem = Semaphore::Find(aTrace,0);
2182 case BTrace::ESemaphoreAcquire:
2183 case BTrace::ESemaphoreRelease:
2184 case BTrace::ESemaphoreBlock:
2186 CHECK_TRACE_DATA_WORDS(1);
2187 Semaphore::FindOrCreate(aTrace,0);
2192 case BTrace::EMutexCreate:
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);
2199 if (!owner && ownerid)
2200 m->iOwnerTraceId = ownerid, ++Object::UnknownOwners;
2201 m->SetName(aTrace,2);
2205 case BTrace::EMutexDestroy:
2207 CHECK_TRACE_DATA_WORDS(1);
2208 Mutex* m = Mutex::Find(aTrace,0);
2214 case BTrace::EMutexAcquire:
2215 case BTrace::EMutexRelease:
2216 case BTrace::EMutexBlock:
2218 CHECK_TRACE_DATA_WORDS(1);
2219 Mutex::FindOrCreate(aTrace,0);
2224 case BTrace::ECondVarCreate:
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);
2231 if (!owner && ownerid)
2232 cv->iOwnerTraceId = ownerid, ++Object::UnknownOwners;
2233 cv->SetName(aTrace,2);
2237 case BTrace::ECondVarDestroy:
2239 CHECK_TRACE_DATA_WORDS(1);
2240 CondVar* cv = CondVar::Find(aTrace,0);
2246 case BTrace::ECondVarBlock:
2247 case BTrace::ECondVarWakeUp:
2248 case BTrace::ECondVarSignal:
2249 case BTrace::ECondVarBroadcast:
2251 CHECK_TRACE_DATA_WORDS(1);
2252 CondVar::FindOrCreate(aTrace,0);
2263 void ReportFastMutex()
2265 TUint numMutexes = FastMutex::iContainer.Count();
2270 printf("\nREPORT: FastMutexes (Named objects only)\n\n");
2272 printf("\nREPORT: FastMutexes\n\n");
2274 printf("%-10s %8s %8s %10s %10s %-8s %12s %8s %s\n",
2275 "","MaxTime","AveTime","HeldCount","BlockCount","MaxPC","MaxTimestamp","TraceId","Name");
2277 for(i=0; i<numMutexes; ++i)
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);
2299 void StartProfilingSample()
2301 ProfilingSampleErrors = 0;
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.
2318 void PreProcessProfiling(TraceRecord& aTrace)
2321 ProfilingSample* sample;
2324 switch((BTrace::TProfiling)aTrace.iSubCategory)
2327 case BTrace::ECpuFullSample:
2329 CHECK_TRACE_DATA_WORDS(2);
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);
2338 TUint32 aPC = aTrace.iData[0];
2340 // Always create a sample identified by the running counter ProfilingSample::iSamples
2341 aTrace.iData[0] = ProfilingSample::iSamples;
2342 sample = ProfilingSample::Create(aTrace,0);
2345 sample->SetPC( aPC );
2346 sample->SetThread( aThread );
2347 sample->SetType(BTrace::ECpuFullSample);
2350 ProfilingSample::iLastThread = aThread;
2354 case BTrace::ECpuOptimisedSample:
2356 CHECK_TRACE_DATA_WORDS(1);
2357 TUint32 aPC = aTrace.iData[0];
2359 aTrace.iData[0] = ProfilingSample::iSamples;
2360 sample = ProfilingSample::Create(aTrace,0);
2363 sample->SetPC( aPC );
2364 sample->SetType( BTrace::ECpuOptimisedSample );
2365 sample->SetThread(ProfilingSample::iLastThread);
2368 if( 0 != ProfilingSample::iLastThread )
2370 thread = Thread::Find(ProfilingSample::iLastThread);
2380 case BTrace::ECpuIdfcSample:
2382 CHECK_TRACE_DATA_WORDS(1);
2383 TUint32 aPC = aTrace.iData[0];
2385 aTrace.iData[0] = ProfilingSample::iSamples;
2386 sample = ProfilingSample::Create(aTrace,0);
2388 sample->SetPC( aPC );
2389 sample->SetType(BTrace::ECpuIdfcSample);
2394 case BTrace::ECpuNonSymbianThreadSample:
2397 aTrace.iData[0] = ProfilingSample::iSamples;
2398 sample = ProfilingSample::Create(aTrace,0);
2399 sample->SetType(BTrace::ECpuNonSymbianThreadSample);
2405 ProfilingSampleErrors++;
2406 ErrorOnThisTrace = true;
2409 ProfilingSample::iSamples++;
2414 void ReportSampleProfiling()
2416 printf("\nREPORT: Profiling\n\n");
2418 TUint numSamples = ProfilingSample::iContainer.Count();
2421 printf("\n No Samples\n\n");
2428 // Print thread samples
2429 TUint numThreads = Thread::iContainer.Count();
2432 printf(" Samples by Thread\n\n");
2433 printf("%-11s %-8s %-8s\t%-12s\t%s\n\n", "", "TraceId", "Samples", "%", "Name");
2435 TReal threadPercentage;
2436 for(i=0; i<numThreads; ++i)
2438 Thread* thread = (Thread*)Thread::iContainer[i];
2440 if( thread && thread->iSamples )
2442 Object::FullNameBuf fullName;
2443 thread->FullName(fullName);
2444 Object::TraceNameBuf name;
2445 thread->TraceName(name);
2447 threadPercentage = thread->iSamples*100.0/numSamples;
2449 printf("%-10s %08x %8d\t%02.2f\t'%s'\n",
2451 (unsigned int)thread->iTraceId,
2452 (unsigned int)(thread->iSamples),
2464 printf("\nAll samples\n\n%-21s %-8s %-8s\n\n", "Type", "ThreadId", "PC");
2467 TUint fullSamples = 0;
2468 TUint optSamples = 0;
2469 TUint dfcSamples = 0;
2470 TUint nonSymbSamples = 0;
2472 for(i=0; i<numSamples; ++i)
2474 ProfilingSample* sample = (ProfilingSample*)ProfilingSample::iContainer[i];
2475 switch((BTrace::TProfiling)sample->iType)
2477 case BTrace::ECpuFullSample:
2480 printf("ECpuFull %08x %08x\n",
2481 (unsigned int)(sample->iThread), (unsigned int)(sample->iPC) );
2486 case BTrace::ECpuOptimisedSample:
2489 printf("ECpuOptimised %08x %08x\n",
2490 (unsigned int)(sample->iThread), (unsigned int)(sample->iPC) );
2495 case BTrace::ECpuIdfcSample:
2498 printf("ECpuIdfc %08x\n", (unsigned int)(sample->iPC) );
2503 case BTrace::ECpuNonSymbianThreadSample:
2506 printf("ECpuNonSymbianThread\n");
2515 TReal typePercentage;
2517 printf("\nSamples by type\n");
2519 typePercentage = fullSamples * 100.0 / numSamples;
2520 printf(" Samples of type ECpuFullSample :\t\t%-10d\t%02.2f %%\n", fullSamples, typePercentage );
2522 typePercentage = optSamples * 100.0 / numSamples;
2523 printf(" Samples of type ECpuOptimisedSample :\t\t%-10d\t%02.2f %%\n", optSamples, typePercentage );
2525 typePercentage = dfcSamples * 100.0 / numSamples;
2526 printf(" Samples of type ECpuIdfcSample :\t\t%-10d\t%02.2f %%\n", dfcSamples, typePercentage );
2528 typePercentage = nonSymbSamples * 100.0 / numSamples;
2529 printf(" Samples of type ECpuNonSymbianThreadSample :\t%-10d\t%02.2f %%\n", nonSymbSamples, typePercentage );
2531 printf(" Total Samples : \t\t\t\t%d\n", numSamples );
2542 TraceRecord** TraceIndex = 0;
2543 TUint TraceIndexSize = 0;
2544 TUint32 NextTraceId = 0;
2545 TraceRecord* LastTrace = 0;
2546 TBool Timestamp2Present = 0;
2547 TBool TraceDumpStarted = false;
2552 TraceDumpStarted = false;
2553 TraceFormatErrors = 0;
2554 TraceBufferFilled = false;
2555 Timestamp2Present = false;
2559 TUint32 ReadTraceWord(const TUint8*& header)
2562 memcpy(&word, header, sizeof(TUint32));
2563 header += sizeof(TUint32);
2568 TBool PreProcessTrace(TraceRecord& aTrace, const TUint8* aData)
2570 ErrorOnThisTrace = false;
2573 aTrace.iDataSize = 0; // initialise to safe value
2575 // process aTrace header...
2576 TUint traceSize = aData[BTrace::ESizeIndex];
2577 if(traceSize<4u || traceSize>(TUint)KMaxBTraceRecordSize)
2580 return false; // bad size
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;
2589 TUint8 category = aData[BTrace::ECategoryIndex];
2590 aTrace.iCategory = category;
2592 TUint8 subCategory = aData[BTrace::ESubCategoryIndex];
2593 aTrace.iSubCategory = subCategory;
2595 const TUint8* header = aData+4;
2597 TUint32 header2 = 0;
2598 if(flags&BTrace::EHeader2Present)
2600 header2 = ReadTraceWord(header);
2601 aTrace.iCpuNum = (TUint8)(header2>>20);
2603 aTrace.iHeader2 = header2;
2604 aTrace.iCpu = TheCpus + aTrace.iCpuNum;
2606 // process timestamp and timestamp2...
2609 TUint64 timestamp = 0;
2610 if(flags&BTrace::ETimestampPresent)
2611 ts1 = ReadTraceWord(header);
2612 if(flags&BTrace::ETimestamp2Present)
2614 Timestamp2Present = true;
2615 ts2 = ReadTraceWord(header);
2617 aTrace.iTimestamp2 = ts2;
2618 if(flags&BTrace::ETimestampPresent)
2625 Timestamp = timestamp;
2630 if(timestamp<(Timestamp&0xffffffffu))
2631 Timestamp += TUint64(1)<<32;
2632 Timestamp &= TUint64(0xffffffff)<<32;
2633 Timestamp |= timestamp;
2634 timestamp = Timestamp;
2637 TimestampBase = timestamp; // record timestamp of first trace
2639 aTrace.iTimestamp = timestamp;
2641 // process context...
2642 // coverity[assign_zero]
2643 aTrace.iContextID = 0;
2644 if(flags&BTrace::EContextIdPresent)
2646 TUint32 contextId = ReadTraceWord(header);
2647 Thread* thread = Thread::Find(contextId);
2649 thread = new Thread(contextId);
2650 aTrace.iContextID = thread;
2655 if(flags&BTrace::EPcPresent)
2656 pc = ReadTraceWord(header);
2661 if(flags&BTrace::EExtraPresent)
2662 extra = ReadTraceWord(header);
2663 aTrace.iExtra = extra;
2665 // process payload data...
2666 TUint headerSize = header-aData;
2667 aData = (TUint8*)header;
2668 if(headerSize>traceSize)
2671 return false; // bad trace record
2673 TUint dataSize = traceSize-headerSize;
2674 if(dataSize>sizeof(aTrace.iData))
2677 return false; // bad trace record
2679 aTrace.iDataSize = dataSize;
2680 memcpy(&aTrace.iData,aData,dataSize);
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;
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;
2698 // category specific processing...
2699 switch(aTrace.iCategory)
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;
2707 aTrace.iDataTypes[1] = EDataTypeText;
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;
2731 // update trace ID...
2733 if (ErrorOnThisTrace)
2739 void DumpTrace(TraceRecord& aTrace)
2741 if(!TraceDumpStarted)
2746 if(Timestamp2Present)
2747 printf("%10s ","TimeStamp2");
2748 printf("%10s ","Time");
2749 printf("%-8s ","PC");
2752 printf("%-60s ","Context");
2753 printf("%18s ","Category");
2754 printf("%24s ","SubCategory");
2758 printf("%-10s ","Context");
2759 printf("%24s ","SubCategory");
2761 printf("Data...\n");
2762 TraceDumpStarted = true;
2765 if(aTrace.iFlags&BTrace::EMissingRecord)
2766 printf("MISSING TRACE RECORD(S)\n");
2771 printf("%1d ", aTrace.iCpuNum);
2774 // print timestamp...
2775 if(Timestamp2Present)
2777 if(aTrace.iFlags&BTrace::ETimestamp2Present)
2778 printf("%10u ",(unsigned int)aTrace.iTimestamp2);
2783 if(aTrace.iFlags&BTrace::ETimestampPresent)
2784 printf("%10u ",(unsigned int)Time(aTrace.iTimestamp-TimestampBase));
2789 if(aTrace.iFlags&BTrace::EPcPresent)
2790 printf("%08x ",(unsigned int)aTrace.iPC);
2797 Object::FullTraceNameBuf fullName;
2799 if(aTrace.iFlags&BTrace::EContextIdPresent)
2800 aTrace.iContextID->FullTraceName(fullName);
2801 printf("%-60s ",fullName);
2805 Object::TraceNameBuf traceName;
2807 if(aTrace.iFlags&BTrace::EContextIdPresent)
2808 aTrace.iContextID->TraceName(traceName);
2809 printf("%-10s ",traceName);
2811 // print trace categories...
2812 const char* catName = CategoryName(aTrace.iCategory);
2813 const char* subCatName = SubCategoryName(aTrace.iCategory,aTrace.iSubCategory);
2815 printf("%18s %-24s ",catName,subCatName);
2819 printf("%24s ",subCatName);
2821 printf("%24s ",catName);
2824 // print trace data contents...
2826 for(i=0; i<aTrace.iDataSize; i+=4)
2828 TUint32 data = aTrace.iData[i/sizeof(TUint32)];
2831 // first 4 words of data may have 'type' info set during pre-processing...
2832 switch(aTrace.iDataTypes[i/sizeof(TUint32)])
2834 case EDataTypeObject:
2836 // data is an object, print "full name"[traceID]...
2837 Object* object = (Object*)data;
2840 Object::FullTraceNameBuf name;
2841 object->FullTraceName(name);
2846 Object::TraceNameBuf name;
2847 object->TraceName(name);
2855 // rest of trace is text...
2856 TUint8* text = (TUint8*)aTrace.iData+i;
2857 TUint8* textEnd = text+(aTrace.iDataSize-i);
2860 while(text<textEnd && x<sizeof(buffer)-2)
2866 case 9: escape = 't'; break;
2867 case 10: escape = 'n'; break;
2868 case 13: escape = 'r'; break;
2878 buffer[x++] = escape;
2882 printf("\"%s\" ",buffer);
2883 i = aTrace.iDataSize; // skip to end of data
2891 // default to print data as hex value...
2892 printf("%08x ",(unsigned int)data);
2895 // print any extra data added by pre-processing...
2898 if(aTrace.iCalculatedData[i])
2899 printf("{%u} ",(unsigned int)aTrace.iCalculatedData[i]);
2903 printf(" ***ERROR***");
2905 // end-of-line finally!
2910 void DumpAllTraces()
2912 printf("\nREPORT: Trace Dump\n\n");
2913 for(TUint i=0; i<NextTraceId; i++)
2914 DumpTrace(*TraceIndex[i]);
2921 TBool errors = TraceFormatErrors || InterruptNestErrors || TraceFormatErrors
2922 || ChunkErrors || CodeSegErrors || FastMutexNestErrors || KernelMemoryErrors
2923 || ProfilingSampleErrors;
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);
2938 printf("\tChunk Errors = %d\n",ChunkErrors);
2940 printf("\tCodeSeg Errors = %d\n",CodeSegErrors);
2941 if(ProfilingSampleErrors)
2942 printf("\tProfiling Errors = %d\n",ProfilingSampleErrors);
2948 The last trace record created has been preporcessed.
2953 TraceIndex[NextTraceId++] = (TraceRecord*)realloc(LastTrace,sizeof(TraceHeader)+LastTrace->iDataSize);
2959 Create a new trace record.
2961 TraceRecord* NewTrace()
2963 if(NextTraceId>=TraceIndexSize)
2965 TraceIndexSize += 1024;
2966 TraceIndex = (TraceRecord**)realloc(TraceIndex,TraceIndexSize*sizeof(TraceIndex[0]));
2970 LastTrace = (TraceRecord*)malloc(sizeof(TraceRecord));
2976 Delete all processed traces records.
2982 for(i=0; i<NextTraceId; ++i)
2983 free(TraceIndex[i]);
3000 Process an entire BTrace log capture.
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.
3008 void ProcessAllTrace(TUint (*aInput)(TAny* aBuffer, TUint aMaxSize),TInt aReportLevel)
3010 ReportLevel = aReportLevel;
3012 printf("Btrace Analysis:\n");
3013 printf("\nTHIS TOOL IS UNOFFICIAL, UNSUPPORTED AND SUBJECT TO CHANGE WITHOUT NOTICE!\n");
3020 StartKernelMemory();
3022 StartProfilingSample();
3024 for(; !TraceBufferFilled ;)
3026 // read more data...
3027 TUint size = (*aInput)(TraceBuffer+TraceBufferSize, sizeof(TraceBuffer)-TraceBufferSize);
3030 TraceBufferSize += size;
3032 // process all the complete traces in buffer...
3033 const TUint8* data = TraceBuffer;
3034 TUint sizeRemaining = TraceBufferSize;
3035 while(sizeRemaining>BTrace::ESizeIndex)
3037 TUint traceSize = (data[BTrace::ESizeIndex]+3)&~3;
3038 if(traceSize>sizeRemaining)
3041 TraceRecord* trace = NewTrace();
3043 if(!PreProcessTrace(*trace,data))
3045 if (!TraceBufferFilled)
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;
3057 else // The buffer was filled so ignore the rest of the data
3062 sizeRemaining -= traceSize;
3065 if (!TraceBufferFilled)
3067 memcpy(TraceBuffer,data,sizeRemaining);
3068 TraceBufferSize = sizeRemaining;
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
3079 ResetTrace(); // free up memory as we go along
3086 ++TraceFormatErrors;
3087 ErrorOnThisTrace = true;
3094 if(ReportLevel>=1 || CpuUsagePresent)
3100 ReportKernelMemory();
3103 ReportSampleProfiling();
3106 ObjectContainer::Reset();