diff -r 8e12a575a9b5 -r 15296fd0af4a sysperfana/heapanalyser/Libraries/Engine/HeapLib/Output_HTML/HeapToHTMLPageEntireListing.cs --- /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( "" ); + + WriteHeadEnd(); + + WriteBodyBegin(); + + WriteDivisionBegin( AsyncHTMLFileWriter.TAlignment.EAlignCenter ); + + Writer.WriteLine( "" ); + WriteTableRowBegin(); + WriteTableColumnBegin(); + + Writer.WriteLine( "
" ); + + // Set up table columns. If we've got a debug version of EUSER then + // we can show the allocation numbers. + Writer.WriteLine( "" ); + + 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( " ", "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( "" ); + + // 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 + "
"; + body += "Header: " + entry.HeaderSize.ToString() + " bytes
"; + body += "Payload: " + entry.PayloadLength.ToString() + " bytes

"; + 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).

"; + 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.

"; + body += "This individual cell corresponds to " + instanceSizeAsPercentageOfTotal + " of the total " + typeProperName + " heap space.
"; + + 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( "
" ); + + int rawItemsCount = Math.Min( KDWordsPerLine * 2, aCell.RawItems.Count ); + for( int i=0; i" ); + + // 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( "" ); + } + else + { + ret.Append( "" ); + rawItem = null; + } + } + + ret.Append( "" ); + + // Second set of columns - characterised data + for( runIndex = i; runIndex < runExtent; runIndex++ ) + { + // Get the item + if ( runIndex < rawItemsCount ) + { + rawItem = aCell[ runIndex ]; + ret.Append( "" ); + } + else + { + ret.Append( "" ); + rawItem = null; + } + } + + ret.Append( "" ); + } + ret.Append( "
" + rawItem.OriginalData.ToString("x8") + " " + HTMLEntityUtility.Entitize( rawItem.OriginalCharacterisedData ) + "
" ); + // + 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( "" ); + line.Append( "0x" + fileName ); + line.Append( "" ); + 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 + } +}