sysperfana/heapanalyser/Libraries/Engine/MemAnalysisLib/MemAnalysisStatisticalCollection.cs
changeset 8 15296fd0af4a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sysperfana/heapanalyser/Libraries/Engine/MemAnalysisLib/MemAnalysisStatisticalCollection.cs	Tue Jun 15 12:47:20 2010 +0300
@@ -0,0 +1,719 @@
+/*
+* 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;
+using MemAnalysisLib.Interfaces;
+
+namespace MemAnalysisLib
+{
+	public class MemObjStatisticalCollection
+	{
+		#region Constructor & destructor
+		public MemObjStatisticalCollection()
+		{
+		}
+		#endregion
+
+		#region API
+		public void Add( MemOpBase aItem )
+		{
+			iItems.Add( aItem );
+		}
+
+		public bool Remove( MemOpBase aItem )
+		{
+			int index;
+			bool ret = false;
+			//
+            if ( ItemByAddressAndOperationIndex( aItem.CellAddress, aItem.OperationIndex, 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 = iItems[aIndex];
+				return item;
+			}
+		}
+
+		public long AllocationCount
+		{
+			get
+			{
+				long ret = 0;
+				//
+                foreach( MemOpBase op in iItems )
+                {
+                    if ( op.IsAllocationType )
+                    {
+                        ++ret;
+                    }
+				}
+				//
+				return ret;
+			}
+		}
+
+		public long DeallocationCount
+		{
+			get
+			{
+				long ret = 0;
+				//
+                foreach ( MemOpBase op in iItems )
+                {
+                    if ( op.Class == TClass.EDeallocation )
+                    {
+                        ret++;
+                    }
+                }
+                //
+				return ret;
+			}
+		}
+
+        public long TotalAmountOfAllocatedMemory
+		{
+			get
+			{
+				long ret = 0;
+				//
+                foreach ( MemOpBase op in iItems )
+                {
+                    if ( op.IsAllocationType )
+                    {
+                        ret += op.CellSize;
+                    }
+                }
+				//
+				return ret;
+			}
+		}
+
+        public long TotalAmountOfDeallocatedMemory
+		{
+			get
+			{
+                long ret = 0;
+                //
+                foreach ( MemOpBase op in iItems )
+                {
+                    if ( op.IsDeallocationType )
+                    {
+                        ret += op.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 )
+                        {
+                            ret += op.CellSize;
+                        }
+                        else if ( op.Class == TClass.EReallocation )
+                        {
+                            ret += op.CellSize;
+                        }
+                    }
+                }
+                //
+                return ret;
+			}
+		}
+		#endregion
+
+		#region Internal methods
+		public MemOpBase ItemByAddressAndOperationIndex( uint aCellAddress, int aOperationIndex, TClass aClass, out int aIndex )
+		{
+            aIndex = -1;
+            MemOpBase ret = null;
+            //
+			for( int i = iItems.Count-1; i>=0; i-- )
+			{
+				MemOpBase item = iItems[ i ];
+                //
+				if	( item.CellAddress == aCellAddress && item.OperationIndex == aOperationIndex )
+				{
+                    if ( aClass == TClass.ENotApplicable )
+                    {
+                        aIndex = i;
+                        ret = item;
+                        break;
+                    }
+                    else if ( item.Class == aClass )
+                    {
+                        aIndex = i;
+                        ret = item;
+                        break;
+                    }
+				}
+			}
+			//
+			return ret;
+		}
+		#endregion
+
+		#region Data members
+        private List<MemOpBase> iItems = new List<MemOpBase>( 50 );
+		#endregion
+	}
+
+    public class MemObjStatisticalData : CollectionManager
+	{
+		#region Constructor & destructor
+		public MemObjStatisticalData()
+		{
+			iCollections.Add( iNullSymbolCollection );
+		}
+		#endregion
+
+		#region API
+		public void Add( MemOpBase aItem, bool aDiscardAllocAndFreedMatchingCells )
+		{
+            /*
+            if ( aItem.CellAddress == 0xc8036684 )
+            {
+                int x = 0;
+                x++;
+                MemOpAllocation ob = (MemOpAllocation) aItem;
+                if	( ob.LinkRegisterAddress == 0x80874729 )
+                {
+                    int x = 0;
+                    x++;
+                }
+            }
+            */
+
+            
+            int allItemCount = iAllItems.Count;
+
+            // Check for chained operations - we just treat it as a high level op in that case.
+            if  ( aItem.Function.ChainedFunction != null && allItemCount > 0 )
+            {
+                MemOpBase lastOp = PriorOperationByAllocationNumber( aItem.AllocationNumber );
+                if ( lastOp != null &&
+                     lastOp.AllocationNumber == aItem.AllocationNumber &&
+                     lastOp.CellAddress == aItem.CellAddress && 
+                     lastOp.Class == aItem.Class &&
+                     lastOp.Function.ToString() == aItem.Function.ChainedFunction.ToString() )
+                {
+                    // The current operation, replaces the prior one.
+                    RemoveFromCollection( lastOp );
+                    RemovePriorOperation( lastOp );
+                    allItemCount = iAllItems.Count;
+
+                    // Also, we must reset any linkage that the prior operation may have
+                    // created when it was added.
+                    if ( lastOp.Link != null )
+                    {
+                        lastOp.Link.Link = null;
+                    }
+                }
+            }
+
+			// 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 saveItem = true;
+            if ( aItem.IsDeallocationType )
+			{
+                MemOpBase lastOp = PriorOperationByAllocationNumber( aItem.AllocationNumber );
+                if ( aItem.Function.ChainedFunction != null && lastOp != null && lastOp.Class == TClass.EDeallocation )
+                {
+                    if ( lastOp.CellAddress == aItem.CellAddress &&
+                         lastOp.Function.ToString() == aItem.Function.ChainedFunction.ToString() )
+                    {
+                        if ( aDiscardAllocAndFreedMatchingCells )
+                        {
+                            // This is a chained delete operation, e.g:
+                            //
+                            // [KMEM] OKF     - C: 0xc802776c, HS:    80064, HCS:    85896, LR: 0x800c98c4, AS:      316, AN:      314, VT: 0x800d09c8
+                            // [KMEM] OD      - C: 0xc802776c, HS:    80064, HCS:    85896, LR: 0x800a2ea8, AS:      316, AN:      314, VT: 0x800d09c8
+                            // [KMEM] ODBD    - C: 0xc802776c, HS:    80064, HCS:    85896, LR: 0x800adec8, AS:      316, AN:      314, VT: 0x800d0000
+                            //
+                            // and we're handling OD or ODBD after already having processed OKF. In that case, we've already thrown away the original
+                            // alloc, and there's nothing left for us to do here.
+                            saveItem = false;
+                        }
+                        else
+                        {
+                            // We need to replace the OKF/OD operation with the OD/ODBD respectively. In order
+                            // for the loop below to process the item, we must re-nullify the link
+                            MemOpBase originalAllocationOp = lastOp.Link;
+                            originalAllocationOp.Link = null;
+                        }
+                    }
+                }
+
+                // If the item is a deallocation, but we can't find any matching alloc
+                // then just ignore the deallocation entirely.
+                //
+                // We'll assume that its an isolated dealloc, but if we find a matching
+                // alloc we'll toggle this back again to preseve the item.
+                saveItem = false;
+                //
+                for ( int i = allItemCount - 1; i >= 0; i-- )
+				{
+					MemOpBase item = 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..
+						if	( aDiscardAllocAndFreedMatchingCells )
+						{
+							// Can ignore both the allocation and deallocation.
+							RemoveFromCollection( item );
+							iAllItems.RemoveAt( i );
+							
+                            // Don't save the delete - we are ignoring matching alloc & frees
+                            break;
+						}
+						else
+						{
+							item.Link = aItem;
+							aItem.Link = item;
+                            saveItem = true;
+							break;
+						}
+					}
+				}
+			}
+	
+			// Add the item to our master list...
+            if ( saveItem )
+            {
+
+                // Locate the corresponding collection and also add the item there too
+                MemOpAllocation searchObject = null;
+                if ( aItem.IsAllocationType )
+                {
+                    searchObject = (MemOpAllocation) aItem;
+                }
+                else
+                {
+                    // Try to base the search object on the link item (if we have one..)
+                    if ( aItem.Link != null )
+                    {
+                        searchObject = (MemOpAllocation) aItem.Link;
+                    }
+                }
+
+                if ( searchObject != null )
+                {
+                    if ( searchObject.LinkRegisterSymbol != null )
+                    {
+                        MemObjStatisticalCollection collection = CollectionBySymbol( searchObject );
+                        if ( collection == null )
+                        {
+                            // Make a new collection
+                            collection = new MemObjStatisticalCollection();
+                            iCollections.Add( collection );
+                        }
+                        collection.Add( aItem );
+                    }
+                    else
+                    {
+                        // Use the null symbol collection
+                        iNullSymbolCollection.Add( aItem );
+                    }
+                }
+
+                AddNewPriorOperation( aItem );
+            }
+		}
+
+		public void Add( MemOpReallocation aItem )
+		{
+            aItem.Function.Process( aItem, this );
+
+#warning This code is broken (but is disabled)
+           
+			/*
+             * The main issue is that it doesn't store the full reallocation chain for repeated reallocations
+             * 
+			if	( aItem.CellAddress == 0x00607ddc )
+			{
+				int x = 0;
+				x++;
+			}
+
+			// Locate the original allocation item...
+			MemObjStatisticalCollection collection = CollectionByCellAddress( aItem.OriginalCellAddress, TClass.EAllocation );
+			if	( collection != null )
+			{
+				// Find the item
+				MemOpBase item = collection.ItemByAddress( aItem.OriginalCellAddress, TClass.EAllocation );
+
+				// 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;
+			}
+			else
+			{
+				// Its permissable to call Realloc to allocate first-time memory
+				// so its entirely possible that there wasn't any prior call to any of
+				// the 'pure' alloc functions.
+
+				// Add the item to our master list...
+				iAllItems.Add( aItem );
+                aItem.OperationIndex = iAllItems.Count;
+
+				// Locate the corresponding collection and also add the item there too
+                if ( aItem.LinkRegisterSymbol != null )
+				{
+					collection = CollectionBySymbol( aItem );
+					if	( collection == null )
+					{
+						// Make a new collection
+						collection = new MemObjStatisticalCollection();
+						iCollections.Add( collection );
+					}
+					collection.Add( aItem );
+				}
+			}
+			*/
+        }
+
+		public void AllItemsLocated()
+		{
+			// Sort the collection by number of items per sub-item
+			MemAnalysisStatisticalComparerByAllocationCount comparer = new MemAnalysisStatisticalComparerByAllocationCount();
+			iCollections.Sort( comparer );
+		}
+
+		public MemOpBase AllItemAt( int aIndex )
+		{
+			MemOpBase item = (MemOpBase) iAllItems[ aIndex ];
+			return item;
+		}
+
+		public MemObjStatisticalCollection CollectionAt( int aIndex )
+		{
+			MemObjStatisticalCollection ret = (MemObjStatisticalCollection) iCollections[ aIndex ];
+			return ret;
+		}
+
+		public MemObjStatisticalCollection CollectionByCellAddress( uint aCellAddress, TClass aClass )
+		{
+            MemObjStatisticalCollection ret = null;
+            //
+			int count = iAllItems.Count;
+			for( int i = count-1; i>=0; i-- )
+			{
+				MemOpBase item = (MemOpBase) iAllItems[ i ];
+                //
+                if ( item.CellAddress == aCellAddress )
+                {
+                    if ( aClass == TClass.ENotApplicable )
+                    {
+                        // Found the item, now locate its collection...
+                        ret = CollectionBySymbol( item );
+                        break;
+                    }
+                    else if ( aClass == item.Class )
+                    {
+                        // Found the item, now locate its collection...
+                        ret = CollectionBySymbol( item );
+                        break;
+                    }
+                }
+			}
+            //
+            return ret;
+		}
+
+        public MemObjStatisticalCollection CollectionByCellAddressSearchForwards( uint aCellAddress, TClass aClass )
+		{
+            MemObjStatisticalCollection ret = null;
+            //
+            int count = iAllItems.Count;
+			for( int i = 0; i<count; i++ )
+			{
+                MemOpBase item = (MemOpBase) iAllItems[ i ];
+                //
+                if ( item.CellAddress == aCellAddress )
+                {
+                    if ( aClass == TClass.ENotApplicable )
+                    {
+                        // Found the item, now locate its collection...
+                        ret = CollectionBySymbol( item );
+                        break;
+                    }
+                    else if ( aClass == item.Class )
+                    {
+                        // Found the item, now locate its collection...
+                        ret = CollectionBySymbol( item );
+                        break;
+                    }
+                }
+            }
+            //
+            return ret;
+        }
+
+        public MemObjStatisticalCollection CollectionBySymbol( MemOpBase aItem )
+        {
+			System.Diagnostics.Debug.Assert( aItem.IsAllocationType || aItem.IsReallocationType );
+            //
+			MemOpAllocation allocObject = (MemOpAllocation) aItem;
+            MemObjStatisticalCollection ret = CollectionBySymbol( allocObject.LinkRegisterSymbol, allocObject.LinkRegisterAddress );
+            //
+            return ret;
+        }
+
+		public MemObjStatisticalCollection CollectionBySymbol( SymbolLib.Generics.GenericSymbol aSymbol, uint aAddress )
+		{
+			// We also need a symbol...
+			MemObjStatisticalCollection ret = null;
+			//
+            if ( aSymbol != null )
+			{
+				int count = iCollections.Count;
+				for( int i=0; i<count; i++ )
+				{
+					MemObjStatisticalCollection collection = (MemObjStatisticalCollection) iCollections[ i ];
+					if	( collection != iNullSymbolCollection )
+					{
+						System.Diagnostics.Debug.Assert( collection.Count > 0 );
+						MemOpAllocation compareToObject = (MemOpAllocation) collection[0];
+
+						// Comparing the link register address is a very specific match - therefore we
+						// prefer the slightly slower comparison against the symbol name. This prevents
+						// multiple entries in the list that come from the same symbol (but different 
+						// instruction address).. i.e. the allocation occurs within the same function,
+						// but a slightly different location.
+                        if ( compareToObject.LinkRegisterSymbol != null )
+						{
+                            if ( compareToObject.LinkRegisterSymbol.Symbol == aSymbol.Symbol )
+							{
+								ret = collection;
+								break;
+							}
+						}
+                        else if ( compareToObject.LinkRegisterAddress == aAddress )
+						{
+							// Symbols match, add it to this container
+							ret = collection;
+							break;
+						}
+					}
+				}
+			}
+			else
+			{
+				// Must be from the null symbol collection then.
+				ret = iNullSymbolCollection;
+			}
+			//
+			return ret;
+		}
+
+		public MemOpBase ItemByLineNumber( long aLineNumber )
+		{
+			int count = iAllItems.Count;
+			for( int i = count-1; i>=0; i-- )
+			{
+				MemOpBase item = (MemOpBase) iAllItems[ i ];
+				if	( item.LineNumber == aLineNumber )
+				{
+					return item;
+				}
+			}
+
+			return null;
+		}
+		#endregion
+
+		#region Properties
+		public int CollectionCount
+		{
+			get { return iCollections.Count; }
+		}
+		#endregion
+
+        #region CollectionManager Members
+        public void RemoveLastOperation()
+        {
+            int count = AllPriorOperationsCount;
+            if ( count > 0 )
+            {
+                AllPriorOperations.RemoveAt( count - 1 );
+                iLastOperation = LastOperation;
+            }
+        }
+
+        public void RemovePriorOperation( MemOpBase aItem )
+        {
+            /*
+            if ( aItem.CellAddress == 0xc8036684 )
+            {
+                int x = 0;
+                x++;
+            }
+            */
+            iAllItems.Remove( aItem );
+        }
+
+        public void AddNewPriorOperation( MemOpBase aItem )
+        {
+            iLastOperation = aItem;
+            AllPriorOperations.Add( aItem );
+            aItem.OperationIndex = AllPriorOperationsCount;
+        }
+
+        public void RemoveFromCollection( MemOpBase aItem )
+        {
+            int count = iCollections.Count;
+            for ( int i = count - 1; i >= 0; i-- )
+            {
+                MemObjStatisticalCollection collection = (MemObjStatisticalCollection) iCollections[ i ];
+                System.Diagnostics.Debug.Assert( collection.Count > 0 || collection == iNullSymbolCollection );
+                if ( collection.Remove( aItem ) )
+                {
+                    // Remove the collection as well (if its empty)
+                    if ( collection.Count == 0 )
+                    {
+                        iCollections.RemoveAt( i );
+                    }
+                    break;
+                }
+            }
+        }
+
+        public void AddToCollection( MemOpBase aItem, SymbolLib.Generics.GenericSymbol aSymbol, uint aLinkRegisterAddress )
+        {
+            MemObjStatisticalCollection collection = CollectionBySymbol( aSymbol, aLinkRegisterAddress );
+            if ( collection == null )
+            {
+                // Make a new collection
+                collection = new MemObjStatisticalCollection();
+                iCollections.Add( collection );
+            }
+
+            collection.Add( aItem );
+        }
+
+        public MemOpBase PriorOperationByAllocationNumber( uint aAllocNumber )
+        {
+            MemOpBase ret = null;
+            //
+            for ( int i = AllPriorOperationsCount - 1; i >= 0; i-- )
+            {
+                MemOpBase op = AllPriorOperations[ i ];
+                //
+                if ( op.AllocationNumber == aAllocNumber )
+                {
+                    ret = op;
+                    break;
+                }
+            }
+            //
+            return ret;
+        }
+
+        public MemOpBase LastOperation
+        {
+            get
+            {
+                MemOpBase ret = null;
+                //
+                if ( AllPriorOperationsCount > 0 )
+                {
+                    ret = AllPriorOperations[ AllPriorOperationsCount - 1 ];
+                }
+                //
+                return ret;
+            }
+        }
+
+        public int AllPriorOperationsCount
+        {
+            get { return iAllItems.Count; }
+        }
+
+        public List<MemOpBase> AllPriorOperations
+        {
+            get { return iAllItems; }
+        }
+        #endregion
+
+		#region Data members
+        private MemOpBase iLastOperation = new MemOpFree();
+        private List<MemOpBase> iAllItems = new List<MemOpBase>( 5000 );
+		private List<MemObjStatisticalCollection> iCollections = new List<MemObjStatisticalCollection>( 100 );
+		private MemObjStatisticalCollection iNullSymbolCollection = new MemObjStatisticalCollection();
+		#endregion
+    }
+}