sysperfana/heapanalyser/Libraries/Engine/HeapLib/Output_HTML/HeapToHTMLPageEntireListing.cs
changeset 8 15296fd0af4a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sysperfana/heapanalyser/Libraries/Engine/HeapLib/Output_HTML/HeapToHTMLPageEntireListing.cs	Tue Jun 15 12:47:20 2010 +0300
@@ -0,0 +1,612 @@
+/*
+* 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.IO;
+using System.Text;
+using System.Collections;
+using SymbianUtils;
+using SymbianUtils.RawItems;
+using HeapLib.Cells;
+using HeapLib.Array;
+using HeapLib.Statistics.Tracking.Base;
+using HeapLib.Reconstructor;
+
+namespace HeapLib
+{
+	public class HeapToHTMLPageEntireListing : AsyncHTMLFileWriter
+	{
+		#region Enumerations
+		public enum TSortType
+		{
+			ESortTypeByAddress = 0,
+			ESortTypeByType,
+			ESortTypeByLength
+		}
+		#endregion
+
+		#region Constructors & destructor
+		public HeapToHTMLPageEntireListing( HeapReconstructor aReconstructor, TSortType aSortType, string aFileName )
+			:	base( aFileName )
+		{
+            iSortType = aSortType;
+            iReconstructor = aReconstructor;
+
+            // Make a new (but empty) array
+            iEntries = new HeapCellArray( aReconstructor.Data.Count + 1 );
+			
+            // Depending on the sort type, trigger the sort method
+            // in the array. Since the array is empty this won't
+            // do a lot, except set up the array to use our chosen
+            // comparison object...
+			switch( iSortType )
+			{
+			default:
+			case TSortType.ESortTypeByAddress:
+                iEntries.SortByAddress();
+				break;
+			case TSortType.ESortTypeByType:
+                iEntries.SortByType();
+				break;
+			case TSortType.ESortTypeByLength:
+                iEntries.SortByLength();
+				break;
+			}
+            
+            // Now copy the entries into the array
+            iEntries.Copy( aReconstructor.Data );
+        }
+		#endregion
+		
+		#region API
+		public static string PageFileName( TSortType aSortType )
+		{
+			string ret = "EntireHeapListing_";
+			//
+			switch( aSortType )
+			{
+			default:
+			case TSortType.ESortTypeByAddress:
+				ret += "ByAddress";
+				break;
+			case TSortType.ESortTypeByType:
+				ret += "ByType";
+				break;
+			case TSortType.ESortTypeByLength:
+				ret += "ByLength";
+				break;
+			}
+			//
+			ret += ".html";
+			//
+			return ret;
+		}
+
+		public static string HeapCellLinkIdentifierName( HeapCell aCell )
+		{
+			string ret = "Cell_" + aCell.Address.ToString("x8");
+			return ret;
+		}
+		#endregion
+
+		#region Internal state related
+		private enum TState
+		{
+			EStateHeader = 0,
+			EStateBody,
+			EStateFooter,
+			EStateDone
+		}
+
+		private TState State
+		{
+			get { return iState; }
+			set { iState = value; }
+		}
+
+		private void OnStateHeader()
+		{
+			WriteDocumentBegin();
+			WriteHeadBegin();
+			WriteTitle( "Heap Information" );
+
+			#region Styles
+			WriteStyleBegin();
+				WriteStyleName( "td, tr, p, li" );
+				WriteStyleBodyBegin();
+				WriteStyleBody( "font-family: Verdana, Arial, Helvetica, sans-serif;" );
+				WriteStyleBody( "font-size: 10pt;" );
+				WriteStyleBody( "white-space: nowrap;" );
+				WriteStyleBodyEnd();
+
+				WriteLine( "a:link { text-decoration: none; color:  #0000CC }" );
+				WriteLine( "a:visited { text-decoration: none; color:  #0000CC }" );
+				WriteLine( "a:active { text-decoration: none; color:  #0000CC }" );
+				WriteLine( "a:hover { text-decoration: underline; color:  #0000CC }" );
+
+				WriteStyleName( ".rawData" );
+				WriteStyleBodyBegin();
+				WriteStyleBody( "font-family: courier, courier new, monospace;" );
+				WriteStyleBody( "font-size: 10pt;" );
+				WriteStyleBody( "color: #000099;" );
+				WriteStyleBody( "white-space: nowrap;" );
+				WriteStyleBodyEnd();
+
+				WriteStyleName( ".tableHeaders" );
+				WriteStyleBodyBegin();
+				WriteStyleBody( "font-family: Verdana, Arial, Helvetica, sans-serif;" );
+				WriteStyleBody( "font-size: 12pt;" );
+				WriteStyleBody( "color: #000000; font-weight: bold;" );
+				WriteStyleBody( "white-space: nowrap;" );
+				WriteStyleBody(	"border-bottom: #000000 1px solid;" );
+				WriteStyleBodyEnd();
+
+				WriteStyleName( ".tableHeaderSelected" );
+				WriteStyleBodyBegin();
+				WriteStyleBody( "font-family: Verdana, Arial, Helvetica, sans-serif;" );
+				WriteStyleBody( "font-size: 12pt;" );
+				WriteStyleBody( "color: #FF0000; font-weight: bold;" );
+				WriteStyleBody( "white-space: nowrap;" );
+				WriteStyleBody(	"border-bottom: #000000 1px solid;" );
+				WriteStyleBodyEnd();
+
+				WriteStyleName( ".tableBorder" );
+				WriteStyleBodyBegin();
+				WriteStyleBody(	"border-width: 1px;" );
+				WriteStyleBody( "border-style: solid;" );
+				WriteStyleBody(	"border-color: #000000;" );
+				WriteStyleBodyEnd();
+
+				WriteStyleName( ".tableRowTitle" );
+				WriteStyleBodyBegin();
+				WriteStyleBody( "background-color: #DDDDDD;" );
+				WriteStyleBodyEnd();
+
+				WriteStyleName( ".tableRowBody1" );
+				WriteStyleBodyBegin();
+                WriteStyleBody( "background-color: #FFFFFF;" );
+				WriteStyleBodyEnd();
+
+				WriteStyleName( ".tableRowFreeCell" );
+				WriteStyleBodyBegin();
+                WriteStyleBody( "background-color: #C5F5F1;" );
+				WriteStyleBodyEnd();
+
+				WriteStyleName( ".tableRowBody2" );
+				WriteStyleBodyBegin();
+                WriteStyleBody( "background-color: #EEEEEE;" );
+				WriteStyleBodyEnd();
+
+				WriteStyleName( ".freeCell" );
+				WriteStyleBodyBegin();
+				WriteStyleBody( "font-family: courier, courier new, monospace;" );
+				WriteStyleBody( "font-size: 10pt;" );
+				WriteStyleBody( "color: #009900;" );
+				WriteStyleBody( "white-space: nowrap;" );
+				WriteStyleBodyEnd();
+			WriteStyleEnd();
+			#endregion
+
+			WriteLine( "<SCRIPT SRC=\"HeapData/" + HeapToHTMLPageJavaScriptManager.JavaScriptHelperFileName + "\"></SCRIPT>" );
+
+			WriteHeadEnd();
+
+			WriteBodyBegin();
+
+			WriteDivisionBegin( AsyncHTMLFileWriter.TAlignment.EAlignCenter );
+			
+			Writer.WriteLine( "<TABLE width=\"65%\" cellspacing=\"3\" cellpadding=\"3\">" );
+			WriteTableRowBegin();
+			WriteTableColumnBegin();
+
+				Writer.WriteLine( "<TABLE class=\"tableBorder\" width=\"100%\" cellspacing=\"0\" cellpadding=\"4\">" );
+
+				// Set up table columns. If we've got a debug version of EUSER then
+				// we can show the allocation numbers.
+				Writer.WriteLine( "<TR class=\"tableRowTitle\">" );
+
+					MakeColumnHeading( "Address", TAlignment.EAlignLeft, TSortType.ESortTypeByAddress );
+					MakeColumnHeading( "Type", TAlignment.EAlignCenter, TSortType.ESortTypeByType );
+
+					if	( iReconstructor.SourceData.MetaData.Heap.DebugAllocator )
+					{
+						WriteTableColumn( "Alloc #", TAlignment.EAlignCenter, "tableHeaders" );
+					}
+					MakeColumnHeading( "Length", TAlignment.EAlignCenter, TSortType.ESortTypeByLength );
+
+					WriteTableColumn( "&nbsp", "tableHeaders" );
+					WriteTableColumn( "Symbol", TAlignment.EAlignLeft, "tableHeaders" );
+					WriteTableColumn( "Object Name", TAlignment.EAlignLeft, "tableHeaders" );
+
+				WriteTableRowEnd();
+
+				#region Blank row
+				WriteTableRowBegin();
+					WriteTableColumnEmpty();
+					WriteTableColumnEmpty();
+                    if ( iReconstructor.SourceData.MetaData.Heap.DebugAllocator )
+					{
+						WriteTableColumnEmpty();
+					}
+					WriteTableColumnEmpty();
+					WriteTableColumnEmpty();
+					WriteTableColumnEmpty();
+					WriteTableColumnEmpty();
+				WriteTableRowEnd();
+				#endregion
+		}
+
+		private void OnStateBody()
+		{
+			HeapCell entry = iEntries[ iCurrentHeapCellIndex++ ];
+			string link;
+			string body = string.Empty;
+
+			string style = TableRowBodyStyleName;
+			if	( entry.Type == HeapCell.TType.EFree )
+			{
+				style = "tableRowFreeCell";
+			}
+			Writer.WriteLine( "<TR class=\"" + style + "\">" );
+
+			// Address
+			WriteTableColumnBegin();
+			WriteDivisionBeginWithId( HeapCellLinkIdentifierName( entry ) );
+			string cellAddress = "0x" + entry.Address.ToString("x8");
+			MakeAddressLink( entry );
+			WriteDivisionEnd();
+			WriteTableColumnEnd();
+		
+			// Type
+			string typeProperName = string.Empty;
+			if	( entry.Type == HeapCell.TType.EAllocated )
+			{
+				typeProperName = "Allocated";
+				body = CreateCellContentsQuickView( entry );
+			}
+			else if ( entry.Type == HeapCell.TType.EFree )
+			{
+				typeProperName = "Free";
+				body = CreateCellContentsQuickView( entry );
+			}
+
+			link = HeapToHTMLPageJavaScriptManager.MakeToolTipDiv( typeProperName + " Cell", body, typeProperName, KHeapDataPreviewLength );
+			WriteTableColumnBegin( TAlignment.EAlignCenter, string.Empty );
+			WriteLine( link );
+			WriteTableColumnEnd();
+
+			// Alloc number
+            if ( iReconstructor.SourceData.MetaData.Heap.DebugAllocator )
+			{
+				link = HeapToHTMLPageJavaScriptManager.MakeToolTipDiv( "Allocation Number", "Number " + entry.AllocationNumber.ToString() + " of " + iEntries.Count.ToString() + " cells.", entry.AllocationNumber.ToString() );
+				
+				WriteTableColumnBegin( TAlignment.EAlignRight, string.Empty );
+				WriteLine( link );
+				WriteTableColumnEnd();
+			}
+
+			// Cell length
+			body = string.Empty;
+			body += "Type:    " + typeProperName + "<BR>";
+			body += "Header:  " + entry.HeaderSize.ToString() + " bytes<BR>";
+			body += "Payload: " + entry.PayloadLength.ToString() + " bytes<BR><BR>";
+			if	( entry.Type == HeapCell.TType.EFree )
+			{
+                string instanceSizeAsPercentageOfTotal = iReconstructor.Statistics.CellLengthAsHeapPercentage( entry ).ToString("##0.000");
+				body += "This individual cell corresponds to " + instanceSizeAsPercentageOfTotal + " of the total free cells in this heap.";
+			}
+            link = HeapToHTMLPageJavaScriptManager.MakeToolTipDiv( "Cell Length", body, entry.Length.ToString() );
+			WriteTableColumnBegin( TAlignment.EAlignRight, string.Empty );
+			WriteLine( link );
+			WriteTableColumnEnd();
+
+			// Spacer
+			WriteTableColumnSpace();
+
+			// Symbol
+			if	( entry.Symbol != null )
+			{
+                // Get symbol tracking info.
+                TrackingInfo trackingInfo = iReconstructor.Statistics.StatsAllocated.TrackerSymbols[ entry.Symbol ];
+				System.Diagnostics.Debug.Assert( trackingInfo != null );
+                string instanceSizeAsPercentageOfTotal = iReconstructor.Statistics.CellLengthAsHeapPercentage( entry ).ToString("##0.000") + "%";
+                string totalSymbolicSizeAsPercentageOfTotal = NumberFormattingUtils.NumberAsPercentageThreeDP( trackingInfo.AssociatedMemory, iReconstructor.Statistics.SizeTotal ) + "%";
+
+				body = string.Empty;
+				if	( trackingInfo.Count > 1 )
+				{
+					body += "There are " + trackingInfo.Count.ToString() + " other instances of this symbol ";
+				}
+				else
+				{
+					body += "This is the only instance of this symbol ";
+				}
+				body += "and each instance is using " + trackingInfo.PayloadLength.ToString() + " bytes of memory (plus cell header overhead).<BR><BR>";
+				body += "Of the total allocated heap memory, cells associated with this symbolic are using a total of " + trackingInfo.AssociatedMemory.ToString() + " bytes (" + totalSymbolicSizeAsPercentageOfTotal + " of total heap) memory.<BR><BR>";
+				body += "This individual cell corresponds to " + instanceSizeAsPercentageOfTotal + " of the total " + typeProperName + " heap space.<BR>";
+
+                link = HeapToHTMLPageJavaScriptManager.MakeToolTipDiv( "Symbol Information", body, entry.Symbol.NameWithoutVTablePrefix );
+				WriteTableColumnBegin( TAlignment.EAlignLeft, string.Empty );
+				WriteLine( link );
+				WriteTableColumnEnd();
+			}
+			else
+			{
+				WriteTableColumnEmpty();
+			}
+
+			// Object name	
+			if	( entry.Symbol != null )
+			{
+				WriteTableColumn( entry.Symbol.ObjectWithoutSection, TAlignment.EAlignLeft ); 
+			}
+			else
+			{
+				WriteTableColumnEmpty();
+			}
+
+			WriteTableRowEnd();
+		}
+
+		private void OnStateFooter()
+		{
+			WriteTableEnd();
+
+			WriteTableColumnEnd();
+			WriteTableRowEnd();
+			WriteTableEnd();
+			WriteDivisionEnd();
+
+			WriteBodyEnd();
+
+			WriteDocumentEnd();
+		}
+		#endregion
+
+		#region From AsyncTextWriterBase
+		protected override bool ContinueProcessing()
+		{
+			return ( State != TState.EStateDone );
+		}
+
+        public override long Size
+		{
+			get
+			{
+				return (long) iEntries.Count + 2;
+			}
+		}
+
+        public override long Position
+		{
+			get
+			{
+				long pos = 0;
+				//
+				switch( State )
+				{
+				case TState.EStateHeader:
+					pos = 1;
+					break;
+				case TState.EStateBody:
+					pos = (long) (1 + iCurrentHeapCellIndex);
+					break;
+				case TState.EStateFooter:
+					pos = (long) (2 + iCurrentHeapCellIndex);
+					break;
+				default:
+					pos = (long) iEntries.Count + 2;
+					break;
+				}
+				//
+				return pos;
+			}
+		}
+
+        public override void ExportData()
+		{
+			switch( State )
+			{
+			case TState.EStateHeader:
+				OnStateHeader();
+				State = TState.EStateBody;
+				break;
+			case TState.EStateBody:
+				OnStateBody();
+				if	( iCurrentHeapCellIndex >= iEntries.Count )
+				{
+					State = TState.EStateFooter;
+				}
+				break;
+			case TState.EStateFooter:
+				OnStateFooter();
+				State = TState.EStateDone;
+				break;
+			}
+
+		}
+		#endregion
+
+		#region Internal methods
+		private string CreateCellContentsQuickView( HeapCell aCell )
+		{
+			const int KDWordsPerLine = 4;
+
+			StringBuilder ret = new StringBuilder();
+			//
+			ret.Append( "<table>" );
+
+			int rawItemsCount = Math.Min( KDWordsPerLine * 2, aCell.RawItems.Count );
+			for( int i=0; i<rawItemsCount; i += KDWordsPerLine )
+			{
+				ret.Append( "<tr>" );
+
+				// Work out how many items on this line
+				int runIndex;
+				int runExtent = i + KDWordsPerLine;
+				RawItem rawItem = null;
+				
+				// First set of columns - original data
+				for( runIndex = i; runIndex < runExtent; runIndex++ )
+				{
+					// Get the item
+					if	( runIndex < rawItemsCount )
+					{
+						rawItem = aCell[ runIndex ];
+						ret.Append( "<td align=center>" + rawItem.OriginalData.ToString("x8") + "</td>" );
+					}
+					else
+					{
+						ret.Append( "<td></td>" );
+						rawItem = null;
+					}
+				}
+				
+				ret.Append( "<td>&nbsp;</td>" );
+
+				// Second set of columns - characterised data
+				for( runIndex = i; runIndex < runExtent; runIndex++ )
+				{
+					// Get the item
+					if	( runIndex < rawItemsCount )
+					{
+						rawItem = aCell[ runIndex ];
+						ret.Append( "<td align=center>" + HTMLEntityUtility.Entitize( rawItem.OriginalCharacterisedData ) + "</td>" );
+					}
+					else
+					{
+						ret.Append( "<td></td>" );
+						rawItem = null;
+					}
+				}
+				
+				ret.Append( "</tr>" );
+			}
+			ret.Append( "</table>" );
+			//
+			return ret.ToString();
+		}
+
+		private string TableRowBodyStyleName
+		{
+			get
+			{
+				string ret = "tableRowBody";
+				ret += iTableBodyRowStyleAlternator.ToString("d1");
+				//
+				if	( iTableBodyRowStyleAlternator == 2 )
+				{
+					iTableBodyRowStyleAlternator = 1;
+				}
+				else
+				{
+					iTableBodyRowStyleAlternator = 2;
+				}
+				//
+				return ret;
+			}
+		}
+
+		private void MakeColumnHeading( string aTitle, TAlignment aAlignment, TSortType aSortType )
+		{
+			if	( iSortType != aSortType )
+			{
+				string toolTipBody = "Sort by ";
+				//
+				switch( aSortType )
+				{
+				default:
+				case TSortType.ESortTypeByAddress:
+					toolTipBody += "address";
+					break;
+				case TSortType.ESortTypeByType:
+					toolTipBody += "type";
+					break;
+				case TSortType.ESortTypeByLength:
+					toolTipBody += "length";
+					break;
+				}
+				//
+				string url = PageFileName( aSortType );
+				string linkWithToolTip = HeapToHTMLPageJavaScriptManager.MakeToolTipLink( "Sorting", toolTipBody, url, string.Empty, aTitle );
+				//
+				WriteTableColumnBegin( aAlignment, "tableHeaders" );
+				WriteLine( linkWithToolTip );
+				WriteTableColumnEnd();
+			}
+			else
+			{
+				WriteTableColumn( aTitle, aAlignment, "tableHeaderSelected" );
+			}
+		}
+
+		private void MakeAddressLink( HeapCell aCell )
+		{
+            string fileName = HeapToHTMLPageHeapCellManager.HeapCellFileName( aCell );
+            string subDir = HeapToHTMLPageHeapCellManager.HeapCellDirectory( aCell, string.Empty, '/' );
+
+            string heapCellDataPageUrl = "./HeapData" + subDir + "/" + fileName + ".html";
+            string heapCellLinkedCellPageUrl = "./HeapLinkInfo" + subDir + "/" + fileName + ".html";
+
+			StringBuilder line = new StringBuilder();
+			line.Append( "<A " );
+			line.Append( "TARGET=\"HeapCellData\" " );
+			line.Append( "HREF=\"" );
+			line.Append( heapCellDataPageUrl );
+			line.Append( "\" " );
+			line.Append( "onClick=\"parent.HeapLinkInfo.location=\'" + heapCellLinkedCellPageUrl + "\'\"" );
+			line.Append( ">" );
+            line.Append( "0x" + fileName );
+			line.Append( "</A>" );
+			Writer.Write( line.ToString() );
+		}
+    	#endregion
+
+		#region Internal constants
+		private const int KHeapDataPreviewLength = 500;
+		#endregion
+
+		#region Data members
+		private readonly HeapReconstructor iReconstructor;
+		private readonly HeapCellArray iEntries;
+		private readonly TSortType iSortType;
+		private int iCurrentHeapCellIndex = 0;
+		private TState iState;
+		private int iTableBodyRowStyleAlternator = 1;
+		#endregion
+	}
+}