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