sysperfana/heapanalyser/Libraries/Engine/MemAnalysisLib/MemAnalysisRegionalCollection.cs
author Matti Laitinen <matti.t.laitinen@nokia.com>
Tue, 15 Jun 2010 12:47:20 +0300
changeset 8 15296fd0af4a
permissions -rw-r--r--
HeapAnalyser 1.1.0

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