sysperfana/heapanalyser/Libraries/Engine/MemAnalysisLib/MemAnalysisRegionalCollection.cs
changeset 8 15296fd0af4a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sysperfana/heapanalyser/Libraries/Engine/MemAnalysisLib/MemAnalysisRegionalCollection.cs	Tue Jun 15 12:47:20 2010 +0300
@@ -0,0 +1,637 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* - Redistributions of source code must retain the above copyright notice,
+*   this list of conditions and the following disclaimer.
+* - Redistributions in binary form must reproduce the above copyright notice,
+*   this list of conditions and the following disclaimer in the documentation
+*   and/or other materials provided with the distribution.
+* - Neither the name of Nokia Corporation nor the names of its contributors
+*   may be used to endorse or promote products derived from this software
+*   without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+* 
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using MemAnalysisLib.MemoryOperations.Class;
+using MemAnalysisLib.MemoryOperations.Functions;
+using MemAnalysisLib.MemoryOperations.Operations;
+
+namespace MemAnalysisLib
+{
+	public class MemObjRegionMarker
+	{
+		#region Properties
+		public bool Initialised
+		{
+			get
+			{
+				return !( LineNumber == KUninitialisedLineNumber && RegionText == KUninitialisedRegionText );
+			}
+		}
+		
+		public bool MatchedRegionText
+		{
+			get { return iMatchedRegionText; }
+			set { iMatchedRegionText = value; }
+		}
+
+		public string RegionText
+		{
+			get { return iRegionText; }
+			set { iRegionText = value; }
+		}
+
+		public long LineNumber
+		{
+			get { return iLineNumber; }
+			set { iLineNumber = value; }
+		}
+		#endregion
+
+		#region Internal constants
+		const long KUninitialisedLineNumber = -1;
+		const string KUninitialisedRegionText = "__!__!__!UNINIT!__!__!__";
+		#endregion
+
+		#region Data members
+		private bool iMatchedRegionText;
+		private string iRegionText = KUninitialisedRegionText;
+		private long iLineNumber = KUninitialisedLineNumber;
+		#endregion
+	}
+
+	public class MemObjRegionalCollection
+	{
+		#region Constructor & destructor
+		public MemObjRegionalCollection()
+		{
+		}
+		#endregion
+
+		#region API
+		public void Add( MemOpBase aItem )
+		{
+			iItems.Add( aItem );
+		}
+
+		public MemOpBase ItemByAddress( long aCellAddress )
+		{
+			int index;
+			return ItemByAddress( aCellAddress, out index );
+		}
+
+		public MemOpBase ItemByAddress( long aCellAddress, out int aIndex )
+		{
+			aIndex = -1;
+			MemOpBase ret = null;
+			int count = iItems.Count;
+			//
+			for( int i = count-1; i>=0; i-- )
+			{
+				MemOpBase item = (MemOpBase) iItems[ i ];
+				if	( item.CellAddress == aCellAddress )
+				{
+					aIndex = i;
+					ret = item;
+					break;
+				}
+			}
+			//
+			return ret;
+		}
+
+		public MemOpBase ItemByAddress( long aCellAddress, TClass aClass )
+		{
+			int index;
+			return ItemByAddress( aCellAddress, aClass, out index );
+		}
+
+		public MemOpBase ItemByAddress( long aCellAddress, TClass aClass, out int aIndex )
+		{
+			aIndex = -1;
+			MemOpBase ret = null;
+			int count = iItems.Count;
+			//
+			for( int i = count-1; i>=0; i-- )
+			{
+				MemOpBase item = (MemOpBase) iItems[ i ];
+				if	( item.CellAddress == aCellAddress )
+				{
+					if	( aClass == TClass.ENotApplicable || item.Class == aClass )
+					{
+						aIndex = i;
+						ret = item;
+						break;
+					}
+				}
+			}
+			//
+			return ret;
+		}
+
+		public MemOpBase ItemByOperationIndex( long aOpIndex, TClass aClass, out int aIndex )
+		{
+			aIndex = -1;
+			MemOpBase ret = null;
+			int count = iItems.Count;
+			//
+			for( int i = count-1; i>=0; i-- )
+			{
+				MemOpBase item = (MemOpBase) iItems[ i ];
+				if	( item.OperationIndex == aOpIndex )
+				{
+					if	( aClass == TClass.ENotApplicable || item.Class == aClass )
+					{
+						aIndex = i;
+						ret = item;
+						break;
+					}
+				}
+			}
+			//
+			return ret;
+		}
+
+		public bool RemoveByCellAddress( MemOpBase aItem )
+		{
+			int index;
+			bool ret = false;
+			//
+			if	( ItemByAddress( aItem.CellAddress, aItem.Class, out index ) != null )
+			{
+				iItems.RemoveAt( index );
+				ret = true;
+			}
+			//
+			return ret;
+		}
+		#endregion
+
+		#region Properties
+		public int Count
+		{
+			get { return iItems.Count; }
+		}
+
+		public MemOpBase this[int aIndex]
+		{
+			get
+			{
+				MemOpBase item = (MemOpBase) iItems[aIndex];
+				return item;
+			}
+		}
+
+		public MemObjRegionMarker RegionStart
+		{
+			get { return iRegionStart; }
+			set { iRegionStart = value; }
+		}
+
+		public MemObjRegionMarker RegionEnd
+		{
+			get { return iRegionEnd; }
+			set { iRegionEnd = value; }
+		}
+
+		public long AllocationCount
+		{
+			get
+			{
+				long ret = 0;
+				//
+				int count = Count;
+				for(int i=0; i<count; i++)
+				{
+					MemOpBase item = this[i];
+					if	( item is MemOpAllocation )
+					{
+						ret++;
+					}
+				}
+				//
+				return ret;
+			}
+		}
+
+		public long DeallocationCount
+		{
+			get
+			{
+				long ret = 0;
+				//
+				int count = Count;
+				for(int i=0; i<count; i++)
+				{
+					MemOpBase item = this[i];
+					if	( item is MemOpFree )
+					{
+						ret++;
+					}
+				}
+				//
+				return ret;
+			}
+		}
+
+        public long TotalAmountOfAllocatedMemory
+		{
+			get
+			{
+                long ret = 0;
+                //
+                foreach ( MemOpBase op in iItems )
+                {
+                    if ( op.Class == TClass.EReallocation )
+                    {
+                        #warning Fix me - TotalAmountOfAllocatedMemory is broken for reallocs
+                    }
+                    else if ( op.Class == TClass.EAllocation )
+                    {
+                        MemOpAllocation allocItem = (MemOpAllocation) op;
+                        ret += allocItem.CellSize;
+                    }
+                }
+                //
+                return ret;
+            }
+		}
+
+        public long TotalAmountOfDeallocatedMemory
+		{
+			get
+			{
+                long ret = 0;
+                //
+                foreach ( MemOpBase op in iItems )
+                {
+                    if ( op.Class == TClass.EDeallocation && op.Link != null )
+                    {
+                        MemOpAllocation allocItem = (MemOpAllocation) op.Link;
+                        ret += allocItem.CellSize;
+                    }
+                }
+                //
+                return ret;
+            }
+		}
+
+        public long TotalMemoryAllocatedButNotFreed
+		{
+			get
+			{
+                long ret = 0;
+                //
+                foreach ( MemOpBase op in iItems )
+                {
+                    // Allocated cells without links back to the deleted cells
+                    // must be orphans.
+                    if ( op.Link == null )
+                    {
+                        if ( op.Class == TClass.EAllocation )
+                        {
+                            MemOpAllocation allocItem = (MemOpAllocation) op;
+                            ret += allocItem.CellSize;
+                        }
+                        else if ( op.Class == TClass.EReallocation )
+                        {
+                            #warning Fix me - TotalMemoryAllocatedButNotFreed is broken for reallocs
+                            MemOpReallocation allocItem = (MemOpReallocation) op;
+                            ret += allocItem.CellSize;
+                        }
+                    }
+                }
+                //
+                return ret;
+            }
+		}
+		#endregion
+
+		#region Internal methods
+		#endregion
+
+		#region Data members
+		private MemObjRegionMarker iRegionStart = new MemObjRegionMarker();
+		private MemObjRegionMarker iRegionEnd = new MemObjRegionMarker();
+		private ArrayList iItems = new ArrayList(50);
+		#endregion
+	}
+
+	public class MemObjRegionalData
+	{
+		#region Constants
+		const string KOperationOutsideOfRegionText = "Memory operation(s) took place outside of region markers";
+		#endregion
+
+		#region Constructor & destructor
+		public MemObjRegionalData()
+		{
+		}
+		#endregion
+
+		#region API
+		public void MarkerStartIdentified( string aText, long aLineNumber )
+		{
+			if	( iCurrentCollection != null )
+			{
+				// We've just finished a collection. Normally this is handled
+				// by the end item, but if the end item wasn't found, then
+				// we must do it manually.
+				CurrentCollectionComplete( KOperationOutsideOfRegionText, aLineNumber - 1, false );
+			}
+
+			// Set the starting items
+			iCurrentCollection = new MemObjRegionalCollection();
+			iCurrentCollection.RegionStart.RegionText = aText;
+			iCurrentCollection.RegionStart.LineNumber = aLineNumber;
+			iCurrentCollection.RegionStart.MatchedRegionText = true;
+		}
+
+		public void MarkerEndIdentified( string aText, long aLineNumber )
+		{
+			CurrentCollectionComplete( aText, aLineNumber, true );
+		}
+
+		public void AllItemsLocated( long aLastLineNumber )
+		{
+			// Don't need these anymore
+			if	( iCurrentCollection != null )
+			{
+				iCurrentCollection.RegionEnd.RegionText = "";
+				iCurrentCollection.RegionEnd.LineNumber = aLastLineNumber;
+				iCollections.Add( iCurrentCollection );
+			}
+			iCurrentCollection = null;
+			iAllItems.Clear();
+		}
+
+		public void Add( MemOpBase aItem, bool aDiscardAllocAndFreedMatchingCells )
+		{
+			#region When deallocating, search for original alloc and link items...
+			// If the item is a de-allocation, hunt backwards through the allocation
+			// list until we find the allocating cell. Then setup their two-way relationship
+			bool throwAwayObject = false;
+
+			if	( aItem.IsAllocationType == false )
+			{
+				int count = iAllItems.Count;
+				for(int i=count - 1; i>=0; i--)
+				{
+					MemOpBase item = (MemOpBase) iAllItems[i];
+					//
+					if	( item.Link == null && item.CellAddress == aItem.CellAddress && item.IsAllocationType != aItem.IsAllocationType )
+					{
+						// The item should be the allocation that this de-alloc is associated
+						// with..
+						//System.Diagnostics.Debug.Assert( item.IsAllocationType == true ); - User::Realloc screwing things up?
+						if	( aDiscardAllocAndFreedMatchingCells )
+						{
+							// Can ignore both cells. First remove teh previous allocation cell.
+							iAllItems.RemoveAt( i );
+
+							// We don't even add aItem to the 'all items' container.
+							// However, we still need to remove the linked allocation from it's container.
+							if	( item.Collection != null )
+							{
+								MemObjRegionalCollection collectionForAllocation = (MemObjRegionalCollection) item.Collection;
+								int colCount = collectionForAllocation.Count;
+								collectionForAllocation.RemoveByCellAddress( item );
+
+								// Make sure we really removed it.
+								System.Diagnostics.Debug.Assert( collectionForAllocation.Count == colCount - 1 );
+
+								// We don't want to log this 'free' operation since it perfectly 
+								// matched an allocation.
+								throwAwayObject = true;
+							}
+						}
+						else
+						{
+							item.Link = aItem;
+							aItem.Link = item;
+						}
+
+						break;
+					}
+				}
+			}
+			#endregion
+	
+			// Add the item to our master list...
+			if	( !throwAwayObject )
+			{
+				AddToCollection( aItem );
+			}
+		}
+
+		public void Add( MemOpReallocation aItem )
+		{
+#warning THIS CODE IS TOTALLY BROKEN - RETEST AFTER COLLECING NEW TRACES
+
+			/*
+             * The main issue is that it doesn't store the full reallocation chain for repeated reallocations
+             * 
+			// Locate the original allocation item...
+			int itemIndex;
+			int collectionIndex;
+			MemOpBase item;
+			MemObjRegionalCollection collection = CollectionByCellAddress( aItem.OriginalCellAddress, TClass.EAllocation, out item, out collectionIndex, out itemIndex );
+			//
+			if	( collection != null && item != null )
+			{
+				// It should be an allocation item
+				System.Diagnostics.Debug.Assert( item is MemOpAllocation );
+
+				// Update it
+				MemOpAllocation allocItem = (MemOpAllocation) item;
+				allocItem.AllocationSize = aItem.AllocationSize;
+				allocItem.HeapSize = aItem.HeapSize;
+				allocItem.CellAddress = aItem.CellAddress;
+
+				// Associate
+				aItem.Link = item;
+
+				AddToCollection( aItem );
+			}
+             */
+		}
+
+		public MemObjRegionalCollection CollectionByOperationIndex( long aOpIndex, TClass aClass, out MemOpBase aItem, out int aCollectionIndex, out int aItemIndex )
+		{
+			aItem = null;
+			aCollectionIndex = -1;
+			aItemIndex = -1;
+			MemObjRegionalCollection ret = null;
+
+			// First check whether the item is in the current collection (if we have one)
+			if	( iCurrentCollection != null )
+			{
+				aItem = iCurrentCollection.ItemByOperationIndex( aOpIndex, aClass, out aItemIndex );
+				if	( aItem != null )
+				{
+					// Yes, it resides in the current collection...
+					ret = iCurrentCollection;
+				}
+			}
+			else
+			{
+				// Need to search the remaining collections. Must search backwards!
+				int count = iCollections.Count;
+				for( int i = count-1; i>=0; i-- )
+				{
+					MemObjRegionalCollection collection = (MemObjRegionalCollection) iCollections[ i ];
+					aItem = collection.ItemByOperationIndex( aOpIndex, aClass, out aItemIndex );
+					if	( aItem != null )
+					{
+						// Yes, its in this collection 
+						ret = collection;
+						aCollectionIndex = i;
+						break;
+					}
+				}
+			}
+
+			return ret;
+		}
+
+        public MemObjRegionalCollection CollectionByCellAddress( long aCellAddress, TClass aClass )
+		{
+			int index;
+			return CollectionByCellAddress( aCellAddress, aClass, out index );
+		}
+
+		public MemObjRegionalCollection CollectionByCellAddress( long aCellAddress, TClass aClass, out int aCollectionIndex )
+		{
+			aCollectionIndex = -1;
+			int itemIndex = -1;
+			MemOpBase item = null;
+			return CollectionByCellAddress( aCellAddress, aClass, out item, out aCollectionIndex, out itemIndex );
+		}
+		
+		public MemObjRegionalCollection CollectionByCellAddress( long aCellAddress, TClass aClass, out MemOpBase aItem, out int aCollectionIndex, out int aItemIndex )
+		{
+			aItem = null;
+			aCollectionIndex = -1;
+			aItemIndex = -1;
+			MemObjRegionalCollection ret = null;
+
+			// First check whether the item is in the current collection (if we have one)
+			if	( iCurrentCollection != null )
+			{
+				aItem = iCurrentCollection.ItemByAddress( aCellAddress, aClass, out aItemIndex );
+				if	( aItem != null )
+				{
+					// Yes, it resides in the current collection...
+					ret = iCurrentCollection;
+				}
+			}
+			else
+			{
+				// Need to search the remaining collections. Must search backwards!
+				int count = iCollections.Count;
+				for( int i = count-1; i>=0; i-- )
+				{
+					MemObjRegionalCollection collection = (MemObjRegionalCollection) iCollections[ i ];
+					aItem = collection.ItemByAddress( aCellAddress, aClass, out aItemIndex );
+					if	( aItem != null )
+					{
+						// Yes, its in this collection 
+						ret = collection;
+						aCollectionIndex = i;
+						break;
+					}
+				}
+			}
+
+			return ret;
+		}
+		#endregion
+
+		#region Properties
+		public int Count
+		{
+			get { return iCollections.Count; }
+		}
+
+		public MemObjRegionalCollection this[ int aIndex ]
+		{
+			get
+			{
+				MemObjRegionalCollection ret = (MemObjRegionalCollection) iCollections[ aIndex ];
+				return ret;
+			}
+		}
+		#endregion
+
+		#region Internal methods
+		private void AddToCollection( MemOpBase aItem )
+		{
+			// Add the item to our master list...
+			iAllItems.Add( aItem );
+			aItem.OperationIndex = iAllItems.Count;
+
+			// If the start region marker hasn't been initialised, it means
+			// that the object operation took place outside of an allocation
+			if	( iCurrentCollection == null || iCurrentCollection.RegionStart.Initialised == false )
+			{
+				if	( iCurrentCollection == null )
+					iCurrentCollection = new MemObjRegionalCollection();
+
+				// In this case, we set the start line number to the line upon
+				// which the operation took place.
+				iCurrentCollection.RegionStart.LineNumber = aItem.LineNumber;
+				iCurrentCollection.RegionStart.RegionText = KOperationOutsideOfRegionText;
+			}
+
+			// Associate the item with this collection
+			aItem.Collection = iCurrentCollection;
+			iCurrentCollection.Add( aItem );
+		}
+		
+		private void CurrentCollectionComplete( string aText, long aLineNumber, bool aMatchedRegionText )
+		{
+			if	( iCurrentCollection != null )
+			{
+				iCurrentCollection.RegionEnd.RegionText = aText;
+				iCurrentCollection.RegionEnd.LineNumber = aLineNumber;
+				iCurrentCollection.RegionEnd.MatchedRegionText = aMatchedRegionText;
+				//
+				iCollections.Add( iCurrentCollection );
+				iCurrentCollection = null;
+			}
+		}
+		#endregion
+
+		#region Data members
+		private MemObjRegionalCollection iCurrentCollection;
+		private ArrayList iAllItems = new ArrayList( 5000 );
+		private ArrayList iCollections = new ArrayList( 100 );
+		#endregion
+	}
+}