|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * |
|
5 * Redistribution and use in source and binary forms, with or without |
|
6 * modification, are permitted provided that the following conditions are met: |
|
7 * |
|
8 * - Redistributions of source code must retain the above copyright notice, |
|
9 * this list of conditions and the following disclaimer. |
|
10 * - Redistributions in binary form must reproduce the above copyright notice, |
|
11 * this list of conditions and the following disclaimer in the documentation |
|
12 * and/or other materials provided with the distribution. |
|
13 * - Neither the name of Nokia Corporation nor the names of its contributors |
|
14 * may be used to endorse or promote products derived from this software |
|
15 * without specific prior written permission. |
|
16 * |
|
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 * POSSIBILITY OF SUCH DAMAGE. |
|
28 * |
|
29 * Initial Contributors: |
|
30 * Nokia Corporation - initial contribution. |
|
31 * |
|
32 * Contributors: |
|
33 * |
|
34 * Description: |
|
35 * |
|
36 */ |
|
37 |
|
38 using System; |
|
39 using System.Collections; |
|
40 using System.Collections.Generic; |
|
41 using MemAnalysisLib.MemoryOperations.Class; |
|
42 using MemAnalysisLib.MemoryOperations.Functions; |
|
43 using MemAnalysisLib.MemoryOperations.Operations; |
|
44 |
|
45 namespace MemAnalysisLib |
|
46 { |
|
47 public class MemObjRegionMarker |
|
48 { |
|
49 #region Properties |
|
50 public bool Initialised |
|
51 { |
|
52 get |
|
53 { |
|
54 return !( LineNumber == KUninitialisedLineNumber && RegionText == KUninitialisedRegionText ); |
|
55 } |
|
56 } |
|
57 |
|
58 public bool MatchedRegionText |
|
59 { |
|
60 get { return iMatchedRegionText; } |
|
61 set { iMatchedRegionText = value; } |
|
62 } |
|
63 |
|
64 public string RegionText |
|
65 { |
|
66 get { return iRegionText; } |
|
67 set { iRegionText = value; } |
|
68 } |
|
69 |
|
70 public long LineNumber |
|
71 { |
|
72 get { return iLineNumber; } |
|
73 set { iLineNumber = value; } |
|
74 } |
|
75 #endregion |
|
76 |
|
77 #region Internal constants |
|
78 const long KUninitialisedLineNumber = -1; |
|
79 const string KUninitialisedRegionText = "__!__!__!UNINIT!__!__!__"; |
|
80 #endregion |
|
81 |
|
82 #region Data members |
|
83 private bool iMatchedRegionText; |
|
84 private string iRegionText = KUninitialisedRegionText; |
|
85 private long iLineNumber = KUninitialisedLineNumber; |
|
86 #endregion |
|
87 } |
|
88 |
|
89 public class MemObjRegionalCollection |
|
90 { |
|
91 #region Constructor & destructor |
|
92 public MemObjRegionalCollection() |
|
93 { |
|
94 } |
|
95 #endregion |
|
96 |
|
97 #region API |
|
98 public void Add( MemOpBase aItem ) |
|
99 { |
|
100 iItems.Add( aItem ); |
|
101 } |
|
102 |
|
103 public MemOpBase ItemByAddress( long aCellAddress ) |
|
104 { |
|
105 int index; |
|
106 return ItemByAddress( aCellAddress, out index ); |
|
107 } |
|
108 |
|
109 public MemOpBase ItemByAddress( long aCellAddress, out int aIndex ) |
|
110 { |
|
111 aIndex = -1; |
|
112 MemOpBase ret = null; |
|
113 int count = iItems.Count; |
|
114 // |
|
115 for( int i = count-1; i>=0; i-- ) |
|
116 { |
|
117 MemOpBase item = (MemOpBase) iItems[ i ]; |
|
118 if ( item.CellAddress == aCellAddress ) |
|
119 { |
|
120 aIndex = i; |
|
121 ret = item; |
|
122 break; |
|
123 } |
|
124 } |
|
125 // |
|
126 return ret; |
|
127 } |
|
128 |
|
129 public MemOpBase ItemByAddress( long aCellAddress, TClass aClass ) |
|
130 { |
|
131 int index; |
|
132 return ItemByAddress( aCellAddress, aClass, out index ); |
|
133 } |
|
134 |
|
135 public MemOpBase ItemByAddress( long aCellAddress, TClass aClass, out int aIndex ) |
|
136 { |
|
137 aIndex = -1; |
|
138 MemOpBase ret = null; |
|
139 int count = iItems.Count; |
|
140 // |
|
141 for( int i = count-1; i>=0; i-- ) |
|
142 { |
|
143 MemOpBase item = (MemOpBase) iItems[ i ]; |
|
144 if ( item.CellAddress == aCellAddress ) |
|
145 { |
|
146 if ( aClass == TClass.ENotApplicable || item.Class == aClass ) |
|
147 { |
|
148 aIndex = i; |
|
149 ret = item; |
|
150 break; |
|
151 } |
|
152 } |
|
153 } |
|
154 // |
|
155 return ret; |
|
156 } |
|
157 |
|
158 public MemOpBase ItemByOperationIndex( long aOpIndex, TClass aClass, out int aIndex ) |
|
159 { |
|
160 aIndex = -1; |
|
161 MemOpBase ret = null; |
|
162 int count = iItems.Count; |
|
163 // |
|
164 for( int i = count-1; i>=0; i-- ) |
|
165 { |
|
166 MemOpBase item = (MemOpBase) iItems[ i ]; |
|
167 if ( item.OperationIndex == aOpIndex ) |
|
168 { |
|
169 if ( aClass == TClass.ENotApplicable || item.Class == aClass ) |
|
170 { |
|
171 aIndex = i; |
|
172 ret = item; |
|
173 break; |
|
174 } |
|
175 } |
|
176 } |
|
177 // |
|
178 return ret; |
|
179 } |
|
180 |
|
181 public bool RemoveByCellAddress( MemOpBase aItem ) |
|
182 { |
|
183 int index; |
|
184 bool ret = false; |
|
185 // |
|
186 if ( ItemByAddress( aItem.CellAddress, aItem.Class, out index ) != null ) |
|
187 { |
|
188 iItems.RemoveAt( index ); |
|
189 ret = true; |
|
190 } |
|
191 // |
|
192 return ret; |
|
193 } |
|
194 #endregion |
|
195 |
|
196 #region Properties |
|
197 public int Count |
|
198 { |
|
199 get { return iItems.Count; } |
|
200 } |
|
201 |
|
202 public MemOpBase this[int aIndex] |
|
203 { |
|
204 get |
|
205 { |
|
206 MemOpBase item = (MemOpBase) iItems[aIndex]; |
|
207 return item; |
|
208 } |
|
209 } |
|
210 |
|
211 public MemObjRegionMarker RegionStart |
|
212 { |
|
213 get { return iRegionStart; } |
|
214 set { iRegionStart = value; } |
|
215 } |
|
216 |
|
217 public MemObjRegionMarker RegionEnd |
|
218 { |
|
219 get { return iRegionEnd; } |
|
220 set { iRegionEnd = value; } |
|
221 } |
|
222 |
|
223 public long AllocationCount |
|
224 { |
|
225 get |
|
226 { |
|
227 long ret = 0; |
|
228 // |
|
229 int count = Count; |
|
230 for(int i=0; i<count; i++) |
|
231 { |
|
232 MemOpBase item = this[i]; |
|
233 if ( item is MemOpAllocation ) |
|
234 { |
|
235 ret++; |
|
236 } |
|
237 } |
|
238 // |
|
239 return ret; |
|
240 } |
|
241 } |
|
242 |
|
243 public long DeallocationCount |
|
244 { |
|
245 get |
|
246 { |
|
247 long ret = 0; |
|
248 // |
|
249 int count = Count; |
|
250 for(int i=0; i<count; i++) |
|
251 { |
|
252 MemOpBase item = this[i]; |
|
253 if ( item is MemOpFree ) |
|
254 { |
|
255 ret++; |
|
256 } |
|
257 } |
|
258 // |
|
259 return ret; |
|
260 } |
|
261 } |
|
262 |
|
263 public long TotalAmountOfAllocatedMemory |
|
264 { |
|
265 get |
|
266 { |
|
267 long ret = 0; |
|
268 // |
|
269 foreach ( MemOpBase op in iItems ) |
|
270 { |
|
271 if ( op.Class == TClass.EReallocation ) |
|
272 { |
|
273 #warning Fix me - TotalAmountOfAllocatedMemory is broken for reallocs |
|
274 } |
|
275 else if ( op.Class == TClass.EAllocation ) |
|
276 { |
|
277 MemOpAllocation allocItem = (MemOpAllocation) op; |
|
278 ret += allocItem.CellSize; |
|
279 } |
|
280 } |
|
281 // |
|
282 return ret; |
|
283 } |
|
284 } |
|
285 |
|
286 public long TotalAmountOfDeallocatedMemory |
|
287 { |
|
288 get |
|
289 { |
|
290 long ret = 0; |
|
291 // |
|
292 foreach ( MemOpBase op in iItems ) |
|
293 { |
|
294 if ( op.Class == TClass.EDeallocation && op.Link != null ) |
|
295 { |
|
296 MemOpAllocation allocItem = (MemOpAllocation) op.Link; |
|
297 ret += allocItem.CellSize; |
|
298 } |
|
299 } |
|
300 // |
|
301 return ret; |
|
302 } |
|
303 } |
|
304 |
|
305 public long TotalMemoryAllocatedButNotFreed |
|
306 { |
|
307 get |
|
308 { |
|
309 long ret = 0; |
|
310 // |
|
311 foreach ( MemOpBase op in iItems ) |
|
312 { |
|
313 // Allocated cells without links back to the deleted cells |
|
314 // must be orphans. |
|
315 if ( op.Link == null ) |
|
316 { |
|
317 if ( op.Class == TClass.EAllocation ) |
|
318 { |
|
319 MemOpAllocation allocItem = (MemOpAllocation) op; |
|
320 ret += allocItem.CellSize; |
|
321 } |
|
322 else if ( op.Class == TClass.EReallocation ) |
|
323 { |
|
324 #warning Fix me - TotalMemoryAllocatedButNotFreed is broken for reallocs |
|
325 MemOpReallocation allocItem = (MemOpReallocation) op; |
|
326 ret += allocItem.CellSize; |
|
327 } |
|
328 } |
|
329 } |
|
330 // |
|
331 return ret; |
|
332 } |
|
333 } |
|
334 #endregion |
|
335 |
|
336 #region Internal methods |
|
337 #endregion |
|
338 |
|
339 #region Data members |
|
340 private MemObjRegionMarker iRegionStart = new MemObjRegionMarker(); |
|
341 private MemObjRegionMarker iRegionEnd = new MemObjRegionMarker(); |
|
342 private ArrayList iItems = new ArrayList(50); |
|
343 #endregion |
|
344 } |
|
345 |
|
346 public class MemObjRegionalData |
|
347 { |
|
348 #region Constants |
|
349 const string KOperationOutsideOfRegionText = "Memory operation(s) took place outside of region markers"; |
|
350 #endregion |
|
351 |
|
352 #region Constructor & destructor |
|
353 public MemObjRegionalData() |
|
354 { |
|
355 } |
|
356 #endregion |
|
357 |
|
358 #region API |
|
359 public void MarkerStartIdentified( string aText, long aLineNumber ) |
|
360 { |
|
361 if ( iCurrentCollection != null ) |
|
362 { |
|
363 // We've just finished a collection. Normally this is handled |
|
364 // by the end item, but if the end item wasn't found, then |
|
365 // we must do it manually. |
|
366 CurrentCollectionComplete( KOperationOutsideOfRegionText, aLineNumber - 1, false ); |
|
367 } |
|
368 |
|
369 // Set the starting items |
|
370 iCurrentCollection = new MemObjRegionalCollection(); |
|
371 iCurrentCollection.RegionStart.RegionText = aText; |
|
372 iCurrentCollection.RegionStart.LineNumber = aLineNumber; |
|
373 iCurrentCollection.RegionStart.MatchedRegionText = true; |
|
374 } |
|
375 |
|
376 public void MarkerEndIdentified( string aText, long aLineNumber ) |
|
377 { |
|
378 CurrentCollectionComplete( aText, aLineNumber, true ); |
|
379 } |
|
380 |
|
381 public void AllItemsLocated( long aLastLineNumber ) |
|
382 { |
|
383 // Don't need these anymore |
|
384 if ( iCurrentCollection != null ) |
|
385 { |
|
386 iCurrentCollection.RegionEnd.RegionText = ""; |
|
387 iCurrentCollection.RegionEnd.LineNumber = aLastLineNumber; |
|
388 iCollections.Add( iCurrentCollection ); |
|
389 } |
|
390 iCurrentCollection = null; |
|
391 iAllItems.Clear(); |
|
392 } |
|
393 |
|
394 public void Add( MemOpBase aItem, bool aDiscardAllocAndFreedMatchingCells ) |
|
395 { |
|
396 #region When deallocating, search for original alloc and link items... |
|
397 // If the item is a de-allocation, hunt backwards through the allocation |
|
398 // list until we find the allocating cell. Then setup their two-way relationship |
|
399 bool throwAwayObject = false; |
|
400 |
|
401 if ( aItem.IsAllocationType == false ) |
|
402 { |
|
403 int count = iAllItems.Count; |
|
404 for(int i=count - 1; i>=0; i--) |
|
405 { |
|
406 MemOpBase item = (MemOpBase) iAllItems[i]; |
|
407 // |
|
408 if ( item.Link == null && item.CellAddress == aItem.CellAddress && item.IsAllocationType != aItem.IsAllocationType ) |
|
409 { |
|
410 // The item should be the allocation that this de-alloc is associated |
|
411 // with.. |
|
412 //System.Diagnostics.Debug.Assert( item.IsAllocationType == true ); - User::Realloc screwing things up? |
|
413 if ( aDiscardAllocAndFreedMatchingCells ) |
|
414 { |
|
415 // Can ignore both cells. First remove teh previous allocation cell. |
|
416 iAllItems.RemoveAt( i ); |
|
417 |
|
418 // We don't even add aItem to the 'all items' container. |
|
419 // However, we still need to remove the linked allocation from it's container. |
|
420 if ( item.Collection != null ) |
|
421 { |
|
422 MemObjRegionalCollection collectionForAllocation = (MemObjRegionalCollection) item.Collection; |
|
423 int colCount = collectionForAllocation.Count; |
|
424 collectionForAllocation.RemoveByCellAddress( item ); |
|
425 |
|
426 // Make sure we really removed it. |
|
427 System.Diagnostics.Debug.Assert( collectionForAllocation.Count == colCount - 1 ); |
|
428 |
|
429 // We don't want to log this 'free' operation since it perfectly |
|
430 // matched an allocation. |
|
431 throwAwayObject = true; |
|
432 } |
|
433 } |
|
434 else |
|
435 { |
|
436 item.Link = aItem; |
|
437 aItem.Link = item; |
|
438 } |
|
439 |
|
440 break; |
|
441 } |
|
442 } |
|
443 } |
|
444 #endregion |
|
445 |
|
446 // Add the item to our master list... |
|
447 if ( !throwAwayObject ) |
|
448 { |
|
449 AddToCollection( aItem ); |
|
450 } |
|
451 } |
|
452 |
|
453 public void Add( MemOpReallocation aItem ) |
|
454 { |
|
455 #warning THIS CODE IS TOTALLY BROKEN - RETEST AFTER COLLECING NEW TRACES |
|
456 |
|
457 /* |
|
458 * The main issue is that it doesn't store the full reallocation chain for repeated reallocations |
|
459 * |
|
460 // Locate the original allocation item... |
|
461 int itemIndex; |
|
462 int collectionIndex; |
|
463 MemOpBase item; |
|
464 MemObjRegionalCollection collection = CollectionByCellAddress( aItem.OriginalCellAddress, TClass.EAllocation, out item, out collectionIndex, out itemIndex ); |
|
465 // |
|
466 if ( collection != null && item != null ) |
|
467 { |
|
468 // It should be an allocation item |
|
469 System.Diagnostics.Debug.Assert( item is MemOpAllocation ); |
|
470 |
|
471 // Update it |
|
472 MemOpAllocation allocItem = (MemOpAllocation) item; |
|
473 allocItem.AllocationSize = aItem.AllocationSize; |
|
474 allocItem.HeapSize = aItem.HeapSize; |
|
475 allocItem.CellAddress = aItem.CellAddress; |
|
476 |
|
477 // Associate |
|
478 aItem.Link = item; |
|
479 |
|
480 AddToCollection( aItem ); |
|
481 } |
|
482 */ |
|
483 } |
|
484 |
|
485 public MemObjRegionalCollection CollectionByOperationIndex( long aOpIndex, TClass aClass, out MemOpBase aItem, out int aCollectionIndex, out int aItemIndex ) |
|
486 { |
|
487 aItem = null; |
|
488 aCollectionIndex = -1; |
|
489 aItemIndex = -1; |
|
490 MemObjRegionalCollection ret = null; |
|
491 |
|
492 // First check whether the item is in the current collection (if we have one) |
|
493 if ( iCurrentCollection != null ) |
|
494 { |
|
495 aItem = iCurrentCollection.ItemByOperationIndex( aOpIndex, aClass, out aItemIndex ); |
|
496 if ( aItem != null ) |
|
497 { |
|
498 // Yes, it resides in the current collection... |
|
499 ret = iCurrentCollection; |
|
500 } |
|
501 } |
|
502 else |
|
503 { |
|
504 // Need to search the remaining collections. Must search backwards! |
|
505 int count = iCollections.Count; |
|
506 for( int i = count-1; i>=0; i-- ) |
|
507 { |
|
508 MemObjRegionalCollection collection = (MemObjRegionalCollection) iCollections[ i ]; |
|
509 aItem = collection.ItemByOperationIndex( aOpIndex, aClass, out aItemIndex ); |
|
510 if ( aItem != null ) |
|
511 { |
|
512 // Yes, its in this collection |
|
513 ret = collection; |
|
514 aCollectionIndex = i; |
|
515 break; |
|
516 } |
|
517 } |
|
518 } |
|
519 |
|
520 return ret; |
|
521 } |
|
522 |
|
523 public MemObjRegionalCollection CollectionByCellAddress( long aCellAddress, TClass aClass ) |
|
524 { |
|
525 int index; |
|
526 return CollectionByCellAddress( aCellAddress, aClass, out index ); |
|
527 } |
|
528 |
|
529 public MemObjRegionalCollection CollectionByCellAddress( long aCellAddress, TClass aClass, out int aCollectionIndex ) |
|
530 { |
|
531 aCollectionIndex = -1; |
|
532 int itemIndex = -1; |
|
533 MemOpBase item = null; |
|
534 return CollectionByCellAddress( aCellAddress, aClass, out item, out aCollectionIndex, out itemIndex ); |
|
535 } |
|
536 |
|
537 public MemObjRegionalCollection CollectionByCellAddress( long aCellAddress, TClass aClass, out MemOpBase aItem, out int aCollectionIndex, out int aItemIndex ) |
|
538 { |
|
539 aItem = null; |
|
540 aCollectionIndex = -1; |
|
541 aItemIndex = -1; |
|
542 MemObjRegionalCollection ret = null; |
|
543 |
|
544 // First check whether the item is in the current collection (if we have one) |
|
545 if ( iCurrentCollection != null ) |
|
546 { |
|
547 aItem = iCurrentCollection.ItemByAddress( aCellAddress, aClass, out aItemIndex ); |
|
548 if ( aItem != null ) |
|
549 { |
|
550 // Yes, it resides in the current collection... |
|
551 ret = iCurrentCollection; |
|
552 } |
|
553 } |
|
554 else |
|
555 { |
|
556 // Need to search the remaining collections. Must search backwards! |
|
557 int count = iCollections.Count; |
|
558 for( int i = count-1; i>=0; i-- ) |
|
559 { |
|
560 MemObjRegionalCollection collection = (MemObjRegionalCollection) iCollections[ i ]; |
|
561 aItem = collection.ItemByAddress( aCellAddress, aClass, out aItemIndex ); |
|
562 if ( aItem != null ) |
|
563 { |
|
564 // Yes, its in this collection |
|
565 ret = collection; |
|
566 aCollectionIndex = i; |
|
567 break; |
|
568 } |
|
569 } |
|
570 } |
|
571 |
|
572 return ret; |
|
573 } |
|
574 #endregion |
|
575 |
|
576 #region Properties |
|
577 public int Count |
|
578 { |
|
579 get { return iCollections.Count; } |
|
580 } |
|
581 |
|
582 public MemObjRegionalCollection this[ int aIndex ] |
|
583 { |
|
584 get |
|
585 { |
|
586 MemObjRegionalCollection ret = (MemObjRegionalCollection) iCollections[ aIndex ]; |
|
587 return ret; |
|
588 } |
|
589 } |
|
590 #endregion |
|
591 |
|
592 #region Internal methods |
|
593 private void AddToCollection( MemOpBase aItem ) |
|
594 { |
|
595 // Add the item to our master list... |
|
596 iAllItems.Add( aItem ); |
|
597 aItem.OperationIndex = iAllItems.Count; |
|
598 |
|
599 // If the start region marker hasn't been initialised, it means |
|
600 // that the object operation took place outside of an allocation |
|
601 if ( iCurrentCollection == null || iCurrentCollection.RegionStart.Initialised == false ) |
|
602 { |
|
603 if ( iCurrentCollection == null ) |
|
604 iCurrentCollection = new MemObjRegionalCollection(); |
|
605 |
|
606 // In this case, we set the start line number to the line upon |
|
607 // which the operation took place. |
|
608 iCurrentCollection.RegionStart.LineNumber = aItem.LineNumber; |
|
609 iCurrentCollection.RegionStart.RegionText = KOperationOutsideOfRegionText; |
|
610 } |
|
611 |
|
612 // Associate the item with this collection |
|
613 aItem.Collection = iCurrentCollection; |
|
614 iCurrentCollection.Add( aItem ); |
|
615 } |
|
616 |
|
617 private void CurrentCollectionComplete( string aText, long aLineNumber, bool aMatchedRegionText ) |
|
618 { |
|
619 if ( iCurrentCollection != null ) |
|
620 { |
|
621 iCurrentCollection.RegionEnd.RegionText = aText; |
|
622 iCurrentCollection.RegionEnd.LineNumber = aLineNumber; |
|
623 iCurrentCollection.RegionEnd.MatchedRegionText = aMatchedRegionText; |
|
624 // |
|
625 iCollections.Add( iCurrentCollection ); |
|
626 iCurrentCollection = null; |
|
627 } |
|
628 } |
|
629 #endregion |
|
630 |
|
631 #region Data members |
|
632 private MemObjRegionalCollection iCurrentCollection; |
|
633 private ArrayList iAllItems = new ArrayList( 5000 ); |
|
634 private ArrayList iCollections = new ArrayList( 100 ); |
|
635 #endregion |
|
636 } |
|
637 } |