|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <piprofiler/ProfilerVersion.h> |
|
20 #include <piprofiler/ProfilerTraces.h> |
|
21 |
|
22 #include <kern_priv.h> |
|
23 #include <plat_priv.h> |
|
24 |
|
25 #include "MemSamplerImpl.h" |
|
26 |
|
27 // for testing precise stack utilization tracing... |
|
28 // crashes at the moment |
|
29 |
|
30 #include <nk_cpu.h> |
|
31 |
|
32 #if !defined(__NKERN_H__) |
|
33 #include <nkern.h> |
|
34 #endif |
|
35 |
|
36 #define TAG(obj) (*(TUint32*)&(obj->iAsyncDeleteNext)) |
|
37 #define PROFILER_CHUNK_MARK ((TUint32)0x00001000) |
|
38 #define PROFILER_MEM_THREAD_MARK ((TUint32)0x00000001) |
|
39 #define PROFILER_LIBRARY_MARK ((TUint32)0x10000000) |
|
40 #define PROFILER_MEM_THREAD_UNMARK ~PROFILER_MEM_THREAD_MARK |
|
41 |
|
42 #ifdef MEM_EVENT_HANDLER |
|
43 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS |
|
44 _LIT8(KMemVersion,"2.03"); |
|
45 #else |
|
46 _LIT8(KMemVersion, "2.02"); |
|
47 #endif |
|
48 #else |
|
49 _LIT8(KMemVersion, "1.56"); |
|
50 #endif |
|
51 |
|
52 DMemSamplerImpl::DMemSamplerImpl() : |
|
53 sampleDescriptor(&(this->sample[1]),0,256) |
|
54 { |
|
55 LOGSTRING("MemSamplerImpl::MemSamplerImpl() - konstruktori"); |
|
56 |
|
57 iCount = 0; |
|
58 |
|
59 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS |
|
60 iSampleType = ESampleThreads; |
|
61 #else |
|
62 iSampleThreads = true; |
|
63 #endif |
|
64 iTimeToSample = false; |
|
65 |
|
66 iTotalMemoryOk = false; |
|
67 iTotalMemoryNameOk = false; |
|
68 |
|
69 iNewChunkCount = 0; |
|
70 iChunkCount = 0; |
|
71 iChunksProcessing = ENothingToProcess; |
|
72 iThreadsProcessing = ENothingToProcess; |
|
73 |
|
74 iNewThreadCount = 0; |
|
75 iThreadCount = 0; |
|
76 |
|
77 // reset data structures |
|
78 for(TInt i(0);i<KProfilerMaxChunksAmount;i++) |
|
79 { |
|
80 // heap chunks |
|
81 this->heapChunksToSample[i] = 0; |
|
82 this->heapChunkNamesToReport[i] = 0; |
|
83 } |
|
84 |
|
85 for(TInt i(0);i<KProfilerMaxThreadsAmount;i++) |
|
86 { |
|
87 // threads |
|
88 this->threadsToSample[i] = 0; |
|
89 this->threadNamesToReport[i] = 0; |
|
90 } |
|
91 |
|
92 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS |
|
93 iLibrariesProcessing = ENothingToProcess; |
|
94 iNewLibraryCount = 0; |
|
95 iLibraryCount = 0; |
|
96 |
|
97 for(TInt i(0); i<KProfilerMaxLibrariesAmount; i++) |
|
98 { |
|
99 // libraries |
|
100 this->librariesToSample[i] = 0; |
|
101 this->libraryNamesToReport[i] = 0; |
|
102 } |
|
103 #endif |
|
104 |
|
105 } |
|
106 |
|
107 DMemSamplerImpl::~DMemSamplerImpl() |
|
108 { |
|
109 |
|
110 } |
|
111 |
|
112 TInt DMemSamplerImpl::CreateFirstSample() |
|
113 { |
|
114 LOGSTRING("MemSamplerImpl::CreateFirstSample - entry"); |
|
115 |
|
116 this->sampleDescriptor.Zero(); |
|
117 this->sampleDescriptor.Append(_L8("Bappea_V")); |
|
118 this->sampleDescriptor.Append(KMemVersion); |
|
119 this->sampleDescriptor.Append(_L8("_MEM")); |
|
120 |
|
121 sample[0] = this->sampleDescriptor.Size(); |
|
122 |
|
123 LOGSTRING("MemSamplerImpl::CreateFirstSample - exit"); |
|
124 |
|
125 return (TInt)(sample[0]+1); |
|
126 } |
|
127 |
|
128 TBool DMemSamplerImpl::SampleNeeded() |
|
129 { |
|
130 iCount++; |
|
131 #ifdef MEM_EVENT_HANDLER |
|
132 // make the collection of chunks/threads only once, rest will be collected with mem event handler |
|
133 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS |
|
134 if (iCount <= iMemSamplingPeriod && ((iCount % iMemSamplingPeriod) == 0 || (iCount % iMemSamplingPeriodDiv3) == 0)) |
|
135 #else |
|
136 if (iCount <= iMemSamplingPeriod && ((iCount % iMemSamplingPeriod) == 0 || (iCount % iMemSamplingPeriodDiv2) == 0)) |
|
137 #endif |
|
138 #else |
|
139 if ((iCount % iMemSamplingPeriod) == 0 || (iCount % iMemSamplingPeriodDiv2) == 0) |
|
140 #endif |
|
141 { |
|
142 LOGSTRING2("MemSamplerImpl::SampleNeeded - time: %d", iCount); |
|
143 iTimeToSample = true; |
|
144 return true; |
|
145 } |
|
146 else |
|
147 { |
|
148 return false; |
|
149 } |
|
150 |
|
151 } |
|
152 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS |
|
153 TInt DMemSamplerImpl::SampleImpl() |
|
154 { |
|
155 // Sample threads: |
|
156 if( iSampleType == ESampleThreads ) |
|
157 { |
|
158 if(this->iThreadsProcessing == ENothingToProcess ) |
|
159 { |
|
160 if(!iTimeToSample) |
|
161 { |
|
162 return 0; |
|
163 } |
|
164 else |
|
165 { |
|
166 iTimeToSample = false; |
|
167 // gather first all thread stacks |
|
168 return GatherThreads(); |
|
169 } |
|
170 } |
|
171 else |
|
172 { |
|
173 // process now thread stack list |
|
174 TInt length = this->ProcessThreads(); |
|
175 |
|
176 if(length == 0) |
|
177 { |
|
178 this->iThreadsProcessing = ENothingToProcess; |
|
179 // switch to collect chunk data |
|
180 iSampleType = ESampleChunks; |
|
181 } |
|
182 return length; |
|
183 } |
|
184 } |
|
185 |
|
186 // Sample chunks: |
|
187 if( iSampleType == ESampleChunks ) |
|
188 { |
|
189 if(this->iChunksProcessing == ENothingToProcess) |
|
190 { |
|
191 if(!iTimeToSample) |
|
192 { |
|
193 return 0; |
|
194 } |
|
195 else |
|
196 { |
|
197 iTimeToSample = false; |
|
198 // gather first all chunks |
|
199 return GatherChunks(); |
|
200 } |
|
201 } |
|
202 else |
|
203 { |
|
204 // still something to go through in lists |
|
205 TInt length = this->ProcessChunks(); |
|
206 |
|
207 if(length == 0) |
|
208 { |
|
209 this->iChunksProcessing = ENothingToProcess; |
|
210 // switch to collect library data |
|
211 iSampleType = ESampleLibraries; |
|
212 //iSampleThreads = true; |
|
213 } |
|
214 return length; |
|
215 } |
|
216 } |
|
217 |
|
218 // Sample libraries: |
|
219 if( iSampleType == ESampleLibraries ) |
|
220 { |
|
221 if(this->iLibrariesProcessing == ENothingToProcess ) |
|
222 { |
|
223 if(!iTimeToSample) |
|
224 { |
|
225 return 0; |
|
226 } |
|
227 else |
|
228 { |
|
229 iTimeToSample = false; |
|
230 // gather libraries |
|
231 return GatherLibraries(); |
|
232 } |
|
233 } |
|
234 else |
|
235 { |
|
236 // process now thread stack list |
|
237 TInt length = this->ProcessLibraries(); |
|
238 if(length == 0) |
|
239 { |
|
240 this->iLibrariesProcessing = ENothingToProcess; |
|
241 // switch to collect chunk data |
|
242 iSampleType = ESampleThreads; |
|
243 } |
|
244 return length; |
|
245 } |
|
246 } |
|
247 |
|
248 // should not reach this point... |
|
249 return 0; |
|
250 } |
|
251 #else |
|
252 TInt DMemSamplerImpl::SampleImpl() |
|
253 { |
|
254 // check if either chunk or thread lists have unprocessed items |
|
255 if(this->iChunksProcessing == ENothingToProcess && !iSampleThreads) |
|
256 { |
|
257 if(!iTimeToSample) |
|
258 { |
|
259 return 0; |
|
260 } |
|
261 else |
|
262 { |
|
263 iTimeToSample = false; |
|
264 // gather first all chunks |
|
265 return GatherChunks(); |
|
266 } |
|
267 } |
|
268 else if(!iSampleThreads) |
|
269 { |
|
270 // still something to go through in lists |
|
271 TInt length = this->ProcessChunks(); |
|
272 |
|
273 if(length == 0) |
|
274 { |
|
275 this->iChunksProcessing = ENothingToProcess; |
|
276 // switch to collect thread data |
|
277 iSampleThreads = true; |
|
278 } |
|
279 return length; |
|
280 } |
|
281 |
|
282 if(this->iThreadsProcessing == ENothingToProcess && iSampleThreads) |
|
283 { |
|
284 if(!iTimeToSample) |
|
285 { |
|
286 return 0; |
|
287 } |
|
288 else |
|
289 { |
|
290 iTimeToSample = false; |
|
291 // gather first all thread stacks |
|
292 return GatherThreads(); |
|
293 } |
|
294 } |
|
295 |
|
296 else if(iSampleThreads) |
|
297 { |
|
298 // process now thread stack list |
|
299 TInt length = this->ProcessThreads(); |
|
300 |
|
301 if(length == 0) |
|
302 { |
|
303 this->iThreadsProcessing = ENothingToProcess; |
|
304 // switch to collect chunk data |
|
305 iSampleThreads = false; |
|
306 } |
|
307 return length; |
|
308 } |
|
309 |
|
310 // should not reach this point... |
|
311 return 0; |
|
312 } |
|
313 #endif |
|
314 |
|
315 inline TInt DMemSamplerImpl::GatherChunks() |
|
316 { |
|
317 // encode a process binary |
|
318 name.Zero(); |
|
319 |
|
320 NKern::ThreadEnterCS(); // Prevent us from dying or suspending whilst holding a DMutex |
|
321 DObjectCon& chunks = *Kern::Containers()[EChunk]; |
|
322 chunks.Wait(); // Obtain the container mutex so the list does get changed under us |
|
323 |
|
324 this->iChunkCount = 0; |
|
325 this->iNewChunkCount = 0; |
|
326 this->iTotalMemoryOk = false; |
|
327 TInt totalChunkCount(chunks.Count()); |
|
328 DChunk* c; |
|
329 |
|
330 for(TInt i(0);i<totalChunkCount;i++) |
|
331 { |
|
332 c = (DChunk*)(chunks)[i]; |
|
333 |
|
334 LOGSTRING3("Processing chunk %d, tag: 0x%x",i,TAG(c)); |
|
335 |
|
336 if( (TAG(c) & 0x0000ffff) != PROFILER_CHUNK_MARK) |
|
337 { |
|
338 LOGSTRING4("Marking chunk %d/%d, old tag 0x%x",i,(totalChunkCount-1), TAG(c)); |
|
339 // this chunk has not been tagged yet |
|
340 name.Zero(); |
|
341 c->TraceAppendName(name,false); |
|
342 const TUint8* ptr = name.Ptr(); |
|
343 |
|
344 TAG(c) = (PROFILER_CHUNK_MARK); |
|
345 this->heapChunkNamesToReport[iNewChunkCount] = c; |
|
346 iNewChunkCount++; |
|
347 } |
|
348 |
|
349 // the chunk has been tagged, add heap chunks to the list |
|
350 this->heapChunksToSample[this->iChunkCount] = c; |
|
351 this->iChunkCount++; |
|
352 LOGSTRING2("Added chunk %d to Chunks",i); |
|
353 } |
|
354 |
|
355 if(this->iChunkCount > 0 || this->iNewChunkCount > 0) |
|
356 { |
|
357 this->iChunksProcessing = EStartingToProcess; |
|
358 |
|
359 // process the first sample |
|
360 TInt length = this->ProcessChunks(); |
|
361 |
|
362 if(length == 0) |
|
363 { |
|
364 this->iChunksProcessing = ENothingToProcess; |
|
365 } |
|
366 |
|
367 chunks.Signal(); // Release the container mutex |
|
368 NKern::ThreadLeaveCS(); // End of critical section |
|
369 return length; |
|
370 } |
|
371 |
|
372 LOGTEXT("MemSamplerImpl::SampleImpl - Error, no threads"); |
|
373 chunks.Signal(); // Release the container mutex |
|
374 NKern::ThreadLeaveCS(); // End of critical section |
|
375 return 0; |
|
376 } |
|
377 |
|
378 inline TInt DMemSamplerImpl::GatherThreads() |
|
379 { |
|
380 // The thread memory consumption |
|
381 |
|
382 NKern::ThreadEnterCS(); // Prevent us from dying or suspending whilst holding a DMutex |
|
383 DObjectCon& threads = *Kern::Containers()[EThread]; |
|
384 threads.Wait(); // Obtain the container mutex so the list does get changed under us |
|
385 |
|
386 this->iThreadCount = 0; |
|
387 this->iNewThreadCount = 0; |
|
388 this->iTotalMemoryOk = false; |
|
389 |
|
390 TInt totalThreadCount = threads.Count(); |
|
391 |
|
392 for(TInt i(0);i<totalThreadCount;i++) |
|
393 { |
|
394 DThread* t = (DThread*)(threads)[i]; |
|
395 |
|
396 LOGSTRING3("Processing thread %d, tag: 0x%x",i,TAG(t)); |
|
397 |
|
398 if( (TAG(t) & PROFILER_MEM_THREAD_MARK) == 0) |
|
399 { |
|
400 LOGSTRING4("Marking thread %d/%d, old tag 0x%x",i,(totalThreadCount-1), TAG(t)); |
|
401 // this thread's chunk has not been reported yet |
|
402 this->threadNamesToReport[iNewThreadCount] = t; |
|
403 iNewThreadCount++; |
|
404 // tag the thread |
|
405 TAG(t) |= PROFILER_MEM_THREAD_MARK; |
|
406 } |
|
407 |
|
408 // the chunk has been tagged, add heap chunks to the list |
|
409 this->threadsToSample[this->iThreadCount] = t; |
|
410 this->iThreadCount++; |
|
411 LOGSTRING2("Added thread %d to threads to sample",i); |
|
412 } |
|
413 |
|
414 if(this->iThreadCount > 0 || this->iNewThreadCount > 0) |
|
415 { |
|
416 this->iThreadsProcessing = EStartingToProcess; |
|
417 |
|
418 // process the first sample |
|
419 TInt length = this->ProcessThreads(); |
|
420 |
|
421 if(length == 0) |
|
422 { |
|
423 this->iThreadsProcessing = ENothingToProcess; |
|
424 } |
|
425 threads.Signal(); // Release the container mutex |
|
426 NKern::ThreadLeaveCS(); // End of critical section |
|
427 return length; |
|
428 } |
|
429 |
|
430 LOGTEXT("MemSamplerImpl::SampleImpl - Error, no threads"); |
|
431 threads.Signal(); // Release the container mutex |
|
432 NKern::ThreadLeaveCS(); // End of critical section |
|
433 return 0; |
|
434 } |
|
435 |
|
436 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS |
|
437 |
|
438 inline TInt DMemSamplerImpl::GatherLibraries() |
|
439 { |
|
440 LOGTEXT("MemSamplerImpl::GatherLibraries() - entry"); |
|
441 // encode a process binary |
|
442 name.Zero(); |
|
443 |
|
444 NKern::ThreadEnterCS(); // Prevent us from dying or suspending whilst holding a DMutex |
|
445 DObjectCon& libs = *Kern::Containers()[ELibrary]; |
|
446 libs.Wait(); // Obtain the container mutex so the list does get changed under us |
|
447 |
|
448 this->iLibraryCount = 0; |
|
449 this->iNewLibraryCount = 0; |
|
450 this->iTotalMemoryOk = false; |
|
451 TInt totalLibCount(libs.Count()); |
|
452 DLibrary* l; |
|
453 |
|
454 for(TInt i(0);i<totalLibCount;i++) |
|
455 { |
|
456 l = (DLibrary*)(libs)[i]; |
|
457 |
|
458 LOGSTRING3("Processing library %d, tag: 0x%x",i,TAG(l)); |
|
459 |
|
460 if( (TAG(l) & 0xffffffff) != PROFILER_LIBRARY_MARK) |
|
461 { |
|
462 LOGSTRING4("Marking library %d/%d, old tag 0x%x",i,(totalLibCount-1), TAG(l)); |
|
463 // this library has not been tagged yet |
|
464 name.Zero(); |
|
465 l->TraceAppendName(name,false); |
|
466 const TUint8* ptr = name.Ptr(); |
|
467 |
|
468 TAG(l) = (PROFILER_LIBRARY_MARK); |
|
469 this->libraryNamesToReport[iNewLibraryCount] = l; |
|
470 iNewLibraryCount++; |
|
471 } |
|
472 |
|
473 // the library has been tagged, add library to the list |
|
474 this->librariesToSample[this->iLibraryCount] = l; |
|
475 this->iLibraryCount++; |
|
476 LOGSTRING2("Added library %d to Libraries",i); |
|
477 } |
|
478 |
|
479 if(this->iLibraryCount > 0 || this->iNewLibraryCount > 0) |
|
480 { |
|
481 this->iLibrariesProcessing = EStartingToProcess; |
|
482 |
|
483 // process the first sample |
|
484 TInt length = this->ProcessLibraries(); |
|
485 |
|
486 if(length == 0) |
|
487 { |
|
488 this->iLibrariesProcessing = ENothingToProcess; |
|
489 } |
|
490 |
|
491 libs.Signal(); // Release the container mutex |
|
492 NKern::ThreadLeaveCS(); // End of critical section |
|
493 return length; |
|
494 } |
|
495 |
|
496 LOGTEXT("MemSamplerImpl::SampleImpl - Error, no libraries"); |
|
497 libs.Signal(); // Release the container mutex |
|
498 NKern::ThreadLeaveCS(); // End of critical section |
|
499 return 0; |
|
500 } |
|
501 #endif |
|
502 |
|
503 inline TInt DMemSamplerImpl::ProcessChunks() |
|
504 { |
|
505 if(iNewChunkCount > 0) |
|
506 { |
|
507 if(this->iChunksProcessing == EStartingToProcess) |
|
508 { |
|
509 // this is the first sample, encode a code for names |
|
510 this->iChunksProcessing = EProcessingNames; |
|
511 return EncodeNameCode(); |
|
512 } |
|
513 |
|
514 if(iTotalMemoryNameOk == false) |
|
515 { |
|
516 return EncodeTotalMemoryName(); |
|
517 } |
|
518 |
|
519 // there are new chunk names to report |
|
520 iNewChunkCount--; |
|
521 DChunk* c = this->heapChunkNamesToReport[iNewChunkCount]; |
|
522 return EncodeChunkName(*c); |
|
523 |
|
524 } |
|
525 else if(iChunkCount > 0) |
|
526 { |
|
527 if(this->iChunksProcessing == EProcessingNames || this->iChunksProcessing == EStartingToProcess) |
|
528 { |
|
529 // this is the first data sample, encode a code for data |
|
530 this->iChunksProcessing = EProcessingData; |
|
531 return EncodeDataCode(); |
|
532 } |
|
533 |
|
534 if(this->iTotalMemoryOk == false) |
|
535 { |
|
536 return EncodeTotalMemory(); |
|
537 } |
|
538 |
|
539 // there are no new chunks to report |
|
540 // thus generate the real report |
|
541 iChunkCount--; |
|
542 DChunk* c = this->heapChunksToSample[iChunkCount]; |
|
543 return EncodeChunkData(*c); |
|
544 } |
|
545 else |
|
546 { |
|
547 // everything is processed |
|
548 LOGSTRING2(" Chunks processed! Chunk count = %d", iChunkCount); |
|
549 #ifdef MEM_EVENT_HANDLER |
|
550 this->iChunksGathered = true; |
|
551 Kern::Printf("MemSamplerImpl::ProcessChunks() - chunks gathered! Time: %d",iCount); |
|
552 #endif |
|
553 return 0; |
|
554 } |
|
555 } |
|
556 |
|
557 inline TInt DMemSamplerImpl::ProcessThreads() |
|
558 { |
|
559 |
|
560 if(iNewThreadCount > 0) |
|
561 { |
|
562 if(this->iThreadsProcessing == EStartingToProcess) |
|
563 { |
|
564 // this is the first sample, encode a code for names |
|
565 this->iThreadsProcessing = EProcessingNames; |
|
566 return EncodeNameCode(); |
|
567 } |
|
568 |
|
569 if(iTotalMemoryNameOk == false) |
|
570 { |
|
571 return EncodeTotalMemoryName(); |
|
572 } |
|
573 |
|
574 iNewThreadCount--; |
|
575 DThread* t = this->threadNamesToReport[iNewThreadCount]; |
|
576 return EncodeChunkName(*t); |
|
577 } |
|
578 else if(iThreadCount > 0) |
|
579 { |
|
580 if(this->iThreadsProcessing == EProcessingNames || this->iThreadsProcessing == EStartingToProcess) |
|
581 { |
|
582 // this is the first data sample, encode a code for data |
|
583 this->iThreadsProcessing = EProcessingData; |
|
584 return EncodeDataCode(); |
|
585 } |
|
586 |
|
587 if(this->iTotalMemoryOk == false) |
|
588 { |
|
589 return EncodeTotalMemory(); |
|
590 } |
|
591 |
|
592 // there are no new threads to report |
|
593 // thus generate the real report |
|
594 iThreadCount--; |
|
595 DThread* t = this->threadsToSample[iThreadCount]; |
|
596 return EncodeChunkData(*t); |
|
597 } |
|
598 else |
|
599 { |
|
600 // everything is processed |
|
601 LOGSTRING2(" Threads processed! Thread count = %d", iThreadCount); |
|
602 #ifdef MEM_EVENT_HANDLER |
|
603 this->iThreadsGathered = true; |
|
604 Kern::Printf("MemSamplerImpl::ProcessThreads() - threads gathered! Time: %d", iCount); |
|
605 #endif |
|
606 return 0; |
|
607 } |
|
608 } |
|
609 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS |
|
610 inline TInt DMemSamplerImpl::ProcessLibraries() |
|
611 { |
|
612 LOGTEXT("ProcessLibraries - entry"); |
|
613 if(iNewLibraryCount > 0) |
|
614 { |
|
615 if(this->iLibrariesProcessing == EStartingToProcess) |
|
616 { |
|
617 // this is the first sample, encode a code for names |
|
618 this->iLibrariesProcessing = EProcessingNames; |
|
619 return EncodeNameCode(); |
|
620 } |
|
621 |
|
622 if(iTotalMemoryNameOk == false) |
|
623 { |
|
624 return EncodeTotalMemoryName(); |
|
625 } |
|
626 |
|
627 // there are new library names to report |
|
628 iNewLibraryCount--; |
|
629 DLibrary* l = this->libraryNamesToReport[iNewLibraryCount]; |
|
630 return EncodeChunkName(*l); |
|
631 |
|
632 } |
|
633 else if(iLibraryCount > 0) |
|
634 { |
|
635 if(this->iLibrariesProcessing == EProcessingNames || this->iLibrariesProcessing == EStartingToProcess) |
|
636 { |
|
637 // this is the first data sample, encode a code for data |
|
638 this->iLibrariesProcessing = EProcessingData; |
|
639 return EncodeDataCode(); |
|
640 } |
|
641 |
|
642 if(this->iTotalMemoryOk == false) |
|
643 { |
|
644 return EncodeTotalMemory(); |
|
645 } |
|
646 |
|
647 // there are no new libraries to report |
|
648 // thus generate the real report |
|
649 iLibraryCount--; |
|
650 DLibrary* l = this->librariesToSample[iLibraryCount]; |
|
651 return EncodeChunkData(*l); |
|
652 } |
|
653 else |
|
654 { |
|
655 // everything is processed |
|
656 LOGSTRING2(" Libraries processed! Library count = %d", iLibraryCount); |
|
657 |
|
658 this->iLibrariesGathered = true; |
|
659 Kern::Printf("MemSamplerImpl::ProcessLibraries() - libraries gathered! Time: %d",iCount); |
|
660 |
|
661 return 0; |
|
662 } |
|
663 } |
|
664 #endif |
|
665 inline TInt DMemSamplerImpl::EncodeNameCode() |
|
666 { |
|
667 sample[0] = 1; |
|
668 sample[1] = 0xaa; |
|
669 return 2; |
|
670 } |
|
671 |
|
672 inline TInt DMemSamplerImpl::EncodeDataCode() |
|
673 { |
|
674 sample[0] = 1; |
|
675 sample[1] = 0xdd; |
|
676 return 2; |
|
677 } |
|
678 |
|
679 inline TInt DMemSamplerImpl::EncodeTotalMemoryName() |
|
680 { |
|
681 this->iTotalMemoryNameOk = true; |
|
682 |
|
683 TUint8* size = &sample[0]; |
|
684 *size = 0; |
|
685 |
|
686 // encode name |
|
687 this->sampleDescriptor.Zero(); |
|
688 this->sampleDescriptor.Append(_L("TOTAL_MEMORY")); |
|
689 *size += this->sampleDescriptor.Size(); |
|
690 |
|
691 // add id here |
|
692 TUint32 id(0xbabbeaaa); |
|
693 this->sampleDescriptor.Append((TUint8*)&(id),sizeof(TUint32)); |
|
694 *size += sizeof(TUint32); |
|
695 |
|
696 // the size is the descriptor length + the size field |
|
697 return ((TInt)(*size))+1; |
|
698 } |
|
699 |
|
700 inline TInt DMemSamplerImpl::EncodeTotalMemory() |
|
701 { |
|
702 |
|
703 TUint8* size = &sample[0]; |
|
704 *size = 0; |
|
705 |
|
706 NKern::LockSystem(); |
|
707 TInt freeRam = Kern::FreeRamInBytes(); |
|
708 TInt totalRam = Kern::SuperPage().iTotalRamSize; |
|
709 NKern::UnlockSystem(); |
|
710 |
|
711 this->sampleDescriptor.Zero(); |
|
712 |
|
713 TUint32 id(0xbabbeaaa); |
|
714 TInt zero(0); |
|
715 |
|
716 this->sampleDescriptor.Append((TUint8*)&(id),sizeof(TUint32)); |
|
717 *size += sizeof(TUint); |
|
718 |
|
719 this->sampleDescriptor.Append((TUint8*)&(totalRam),sizeof(TInt)); |
|
720 *size += sizeof(TInt); |
|
721 |
|
722 // append the cell amount allocated |
|
723 this->sampleDescriptor.Append((TUint8*)&(zero),sizeof(TInt)); |
|
724 *size += sizeof(TInt); |
|
725 |
|
726 // append the chunk size |
|
727 this->sampleDescriptor.Append((TUint8*)&(freeRam),sizeof(TInt)); |
|
728 *size += sizeof(TInt); |
|
729 |
|
730 // append the thread user stack size |
|
731 this->sampleDescriptor.Append((TUint8*)&(zero),sizeof(TInt)); |
|
732 *size += sizeof(TInt); |
|
733 |
|
734 this->iTotalMemoryOk = true; |
|
735 |
|
736 return ((TInt)(*size))+1; |
|
737 } |
|
738 |
|
739 inline TInt DMemSamplerImpl::EncodeChunkName(DChunk& c) |
|
740 { |
|
741 // the size of the following name is in the first byte |
|
742 TUint8* size = &sample[0]; |
|
743 *size = 0; |
|
744 |
|
745 // encode chunk name |
|
746 this->sampleDescriptor.Zero(); |
|
747 this->sampleDescriptor.Append(_L("C_")); |
|
748 c.TraceAppendFullName(this->sampleDescriptor,false); |
|
749 *size += this->sampleDescriptor.Size(); |
|
750 |
|
751 // add chunk object address here |
|
752 TUint32 chunkAddr((TUint32)&c); |
|
753 this->sampleDescriptor.Append((TUint8*)&(chunkAddr),sizeof(TUint32)); |
|
754 *size += sizeof(TUint32); |
|
755 |
|
756 // the size is the descriptor length + the size field |
|
757 LOGSTRING2("Non-Heap Chunk Name - %d",*size); |
|
758 return ((TInt)(*size))+1; |
|
759 } |
|
760 |
|
761 inline TInt DMemSamplerImpl::EncodeChunkName(DThread& t) |
|
762 { |
|
763 // the size of the following name is in the first byte |
|
764 TUint8* size = &sample[0]; |
|
765 *size = 0; |
|
766 this->sampleDescriptor.Zero(); |
|
767 |
|
768 this->sampleDescriptor.Append(_L("T_")); |
|
769 t.TraceAppendFullName(this->sampleDescriptor,false); |
|
770 *size += this->sampleDescriptor.Size(); |
|
771 |
|
772 // copy the 4 bytes from the thread id field |
|
773 this->sampleDescriptor.Append((TUint8*)&(t.iId),sizeof(TUint)); |
|
774 *size += sizeof(TUint); |
|
775 |
|
776 // the size is the descriptor length + the size field |
|
777 LOGSTRING2("Name - %d",*size); |
|
778 return ((TInt)(*size))+1; |
|
779 } |
|
780 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS |
|
781 inline TInt DMemSamplerImpl::EncodeChunkName(DLibrary& l) |
|
782 { |
|
783 // the size of the following name is in the first byte |
|
784 TUint8* size = &sample[0]; |
|
785 *size = 0; |
|
786 |
|
787 // encode library name |
|
788 this->sampleDescriptor.Zero(); |
|
789 this->sampleDescriptor.Append(_L("L_")); |
|
790 l.TraceAppendFullName(this->sampleDescriptor,false); |
|
791 *size += this->sampleDescriptor.Size(); |
|
792 |
|
793 // add chunk object address here |
|
794 TUint32 libAddr((TUint32)&l); |
|
795 this->sampleDescriptor.Append((TUint8*)&(libAddr),sizeof(TUint32)); |
|
796 *size += sizeof(TUint32); |
|
797 |
|
798 // the size is the descriptor length + the size field |
|
799 LOGSTRING2("Name - %d",*size); |
|
800 return ((TInt)(*size))+1; |
|
801 } |
|
802 #endif |
|
803 inline TInt DMemSamplerImpl::EncodeChunkData(DChunk& c) |
|
804 { |
|
805 // the size of the following name is in the first byte |
|
806 TUint8* size = &sample[0]; |
|
807 *size = 0; |
|
808 this->sampleDescriptor.Zero(); |
|
809 TInt zero(0); |
|
810 |
|
811 TUint32 address((TUint32)&c); |
|
812 |
|
813 this->sampleDescriptor.Append((TUint8*)&address,sizeof(TUint32)); |
|
814 *size += sizeof(TUint); |
|
815 |
|
816 // copy the total amount of memory allocated |
|
817 this->sampleDescriptor.Append((TUint8*)&(c.iSize),sizeof(TInt)); |
|
818 *size += sizeof(TInt); |
|
819 |
|
820 // append the cell amount allocated |
|
821 this->sampleDescriptor.Append((TUint8*)&(zero),sizeof(TInt)); |
|
822 *size += sizeof(TInt); |
|
823 |
|
824 // append the chunk size |
|
825 this->sampleDescriptor.Append((TUint8*)&(c.iSize),sizeof(TUint)); |
|
826 *size += sizeof(TUint); |
|
827 |
|
828 // append the thread user stack size |
|
829 this->sampleDescriptor.Append((TUint8*)&(zero),sizeof(TInt)); |
|
830 *size += sizeof(TInt); |
|
831 |
|
832 LOGSTRING2("Data - %d",*size); |
|
833 return ((TInt)(*size))+1; |
|
834 |
|
835 } |
|
836 |
|
837 inline TInt DMemSamplerImpl::EncodeChunkData(DThread& t) |
|
838 { |
|
839 LOGTEXT("MemSamplerImpl::EncodeChunkData - entry"); |
|
840 //LOGSTRING2("MemSamplerImpl::EncodeChunkData - processing thread 0x%x ",&t); |
|
841 |
|
842 // the size of the following name is in the first byte |
|
843 TUint8* size = &sample[0]; |
|
844 *size = 0; |
|
845 this->sampleDescriptor.Zero(); |
|
846 |
|
847 LOGTEXT("MemSamplerImpl::EncodeChunkData - cleared"); |
|
848 |
|
849 this->sampleDescriptor.Append((TUint8*)&(t.iId),sizeof(TUint)); |
|
850 *size += sizeof(TUint); |
|
851 |
|
852 // copy the total amount of memory allocated for user side stack |
|
853 this->sampleDescriptor.Append((TUint8*)&(t.iUserStackSize),sizeof(TInt)); |
|
854 *size += sizeof(TInt); |
|
855 |
|
856 TInt zero(0); |
|
857 // append the cell amount allocated (zero, not in use here) |
|
858 this->sampleDescriptor.Append((TUint8*)&zero,sizeof(TInt)); |
|
859 *size += sizeof(TInt); |
|
860 |
|
861 // append the chunk size (this is not a chunk) |
|
862 this->sampleDescriptor.Append((TUint8*)&(zero),sizeof(TUint)); |
|
863 *size += sizeof(TUint); |
|
864 |
|
865 // append user stack (max) size |
|
866 this->sampleDescriptor.Append((TUint8*)&(t.iUserStackSize),sizeof(TInt)); |
|
867 *size += sizeof(TInt); |
|
868 |
|
869 LOGSTRING2("Data -> %d",*size); |
|
870 return ((TInt)(*size))+1; |
|
871 } |
|
872 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS |
|
873 inline TInt DMemSamplerImpl::EncodeChunkData(DLibrary& l) |
|
874 { |
|
875 LOGTEXT("MemSamplerImpl::EncodeChunkData (Library) - entry"); |
|
876 // the size of the following name is in the first byte |
|
877 TUint8* size = &sample[0]; |
|
878 *size = 0; |
|
879 this->sampleDescriptor.Zero(); |
|
880 |
|
881 TUint32 address((TUint32)&l); |
|
882 |
|
883 this->sampleDescriptor.Append((TUint8*)&address,sizeof(TUint32)); |
|
884 *size += sizeof(TUint); |
|
885 |
|
886 this->sampleDescriptor.Append((TUint8*)&(l.iCodeSeg->iSize),sizeof(TUint32)); |
|
887 *size += sizeof(TInt); |
|
888 |
|
889 this->sampleDescriptor.Append((TUint8*)&(l.iMapCount),sizeof(TInt)); |
|
890 *size += sizeof(TInt); |
|
891 |
|
892 TInt zero(0); |
|
893 this->sampleDescriptor.Append((TUint8*)&(zero),sizeof(TInt)); |
|
894 *size += sizeof(TInt); |
|
895 |
|
896 this->sampleDescriptor.Append((TUint8*)&(zero),sizeof(TInt)); |
|
897 *size += sizeof(TInt); |
|
898 |
|
899 LOGSTRING2("LData - %d",*size); |
|
900 return ((TInt)(*size))+1; |
|
901 |
|
902 } |
|
903 #endif |
|
904 void DMemSamplerImpl::Reset() |
|
905 { |
|
906 Kern::Printf("MemSamplerImpl::Reset"); |
|
907 iCount = 0; // sample threads 1 cycle after actual MEM sample time... |
|
908 this->iTimeToSample = false; |
|
909 this->iChunkCount = 0; |
|
910 this->iNewChunkCount = 0; |
|
911 |
|
912 this->iTotalMemoryOk = false; |
|
913 this->iTotalMemoryNameOk = false; |
|
914 |
|
915 this->iChunksProcessing = ENothingToProcess; |
|
916 this->iThreadsProcessing = ENothingToProcess; |
|
917 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS |
|
918 this->iLibrariesProcessing = ENothingToProcess; |
|
919 this->iSampleType = ESampleThreads; |
|
920 #else |
|
921 this->iSampleThreads = true; |
|
922 #endif |
|
923 |
|
924 this->sampleDescriptor.Zero(); |
|
925 |
|
926 // clear all chunk tags |
|
927 NKern::ThreadEnterCS(); // Prevent us from dying or suspending whilst holding a DMutex |
|
928 DObjectCon* chunks = Kern::Containers()[EChunk]; |
|
929 chunks->Wait(); // Obtain the container mutex so the list does get changed under us |
|
930 |
|
931 TInt totalChunkCount = chunks->Count(); |
|
932 for(TInt i=0;i<totalChunkCount;i++) |
|
933 { |
|
934 DChunk* c = (DChunk*)(*chunks)[i]; |
|
935 TAG(c) = 0; |
|
936 } |
|
937 chunks->Signal(); // Release the container mutex |
|
938 |
|
939 Kern::Printf("MemSamplerImpl::Reset"); |
|
940 this->iThreadCount = 0; |
|
941 this->iNewThreadCount = 0; |
|
942 this->sampleDescriptor.Zero(); |
|
943 |
|
944 // clear all chunk tags |
|
945 DObjectCon* threads = Kern::Containers()[EThread]; |
|
946 threads->Wait(); // Obtain the container mutex so the list does get changed under us |
|
947 |
|
948 TInt totalThreadCount = threads->Count(); |
|
949 for(TInt i=0;i<totalThreadCount;i++) |
|
950 { |
|
951 DThread* t = (DThread*)(*threads)[i]; |
|
952 TAG(t) = (TAG(t) & 0xfffffffe); |
|
953 } |
|
954 threads->Signal(); // Release the container mutex |
|
955 |
|
956 #ifdef MEM_EVENT_HANDLER_LIBRARY_EVENTS |
|
957 this->iLibraryCount = 0; |
|
958 this->iNewLibraryCount = 0; |
|
959 this->sampleDescriptor.Zero(); |
|
960 |
|
961 // clear all library tags |
|
962 DObjectCon* libs = Kern::Containers()[ELibrary]; |
|
963 libs->Wait(); // Obtain the container mutex so the list does get changed under us |
|
964 |
|
965 TInt totalLibraryCount = libs->Count(); |
|
966 for(TInt i=0; i<totalLibraryCount; i++) |
|
967 { |
|
968 DLibrary* l = (DLibrary*)(*libs)[i]; |
|
969 TAG(l) = (TAG(l) & 0xefffffff); |
|
970 } |
|
971 libs->Signal(); // Release the container mutex |
|
972 #endif |
|
973 |
|
974 NKern::ThreadLeaveCS(); // End of critical section |
|
975 } |
|
976 |