--- /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
+ }
+}