diff -r 8e12a575a9b5 -r 15296fd0af4a sysperfana/heapanalyser/Libraries/Engine/MemAnalysisLib/MemAnalysisStatisticalCollection.cs --- /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 iItems = new List( 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 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 AllPriorOperations + { + get { return iAllItems; } + } + #endregion + + #region Data members + private MemOpBase iLastOperation = new MemOpFree(); + private List iAllItems = new List( 5000 ); + private List iCollections = new List( 100 ); + private MemObjStatisticalCollection iNullSymbolCollection = new MemObjStatisticalCollection(); + #endregion + } +}