sysperfana/heapanalyser/Libraries/Engine/HeapComparisonLib/CSV/Excel/CSVExcelExporterAllDataSets.cs
changeset 8 15296fd0af4a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sysperfana/heapanalyser/Libraries/Engine/HeapComparisonLib/CSV/Excel/CSVExcelExporterAllDataSets.cs	Tue Jun 15 12:47:20 2010 +0300
@@ -0,0 +1,495 @@
+/*
+* 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.Threading;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using Excel = Microsoft.Office.Interop.Excel;
+using System.Reflection; 
+using SymbianExcelUtils;
+using SymbianUtils;
+using SymbianUtils.Range;
+
+namespace HeapComparisonLib.CSV
+{
+    internal class CSVExcelExporterAllDataSets : DisposableObject
+    {
+        #region Constructors & destructor
+        public CSVExcelExporterAllDataSets( string aOutputFileName, SortedDictionary<long, string> aThreadMap, int aDataSetCount )
+        {
+            iDataSetCount = aDataSetCount;
+            iFileName = aOutputFileName;
+
+            // Sort the aThreadMap list by thread name, rather than id.
+            SortedDictionary<string, TThreadMapEntry> temp = new SortedDictionary<string, TThreadMapEntry>();
+            foreach ( KeyValuePair<long, string> kvp in aThreadMap )
+            {
+                TThreadMapEntry entry = new TThreadMapEntry();
+                entry.iThreadName = kvp.Value;
+                entry.iThreadId = kvp.Key;
+                //
+                string mungedName = string.Format( "{1} [{0:d5}]", kvp.Key, kvp.Value );
+                temp.Add( mungedName, entry );
+            }
+
+            // Now build new list, in the right order
+            iThreadMap = new Dictionary<long, TThreadMapEntry>( temp.Count + 1 );
+            foreach ( KeyValuePair<string, TThreadMapEntry> kvp in temp )
+            {
+                iThreadMap.Add( kvp.Value.iThreadId, kvp.Value );
+            }
+  
+            // Open up excel
+            iExcelApp = new Excel.Application();
+            if ( iExcelApp != null )
+            {
+                iExcelApp.Visible = false;
+                iExcelApp.DisplayAlerts = false;
+
+                // Prepare sheets
+                PrepareWorksheetReadyForData();
+            }
+            else
+            {
+                throw new Exception( "Microsoft Excel not available" );
+            }
+        }
+        #endregion
+
+        #region API
+        public void Export( CSVDataSet aSet )
+        {
+            int count = aSet.Count;
+            for ( int i = 0; i < count; i++ )
+            {
+                CSVThread thread = aSet[ i ];
+
+                // find row
+                if ( iThreadMap.ContainsKey( thread.ThreadId ) )
+                {
+                    TThreadMapEntry entry = iThreadMap[ thread.ThreadId ];
+
+                    Utils.SetValue( entry.iRowIndex, iColumnCounter, iSheetChunkSize, thread.SizeCurrent.ToString() );
+                    Utils.SetValue( entry.iRowIndex, iColumnCounter, iSheetAlloc, thread.AllocSpaceTotal.ToString() );
+                    Utils.SetValue( entry.iRowIndex, iColumnCounter, iSheetFree, thread.FreeSpaceTotal.ToString() );
+
+                    // Update stats
+                    ++entry.iNumberOfMatchingDataSets;
+                    
+                    // Min & max for each type
+                    entry.iRangeChunk.UpdateMin( thread.SizeCurrent );
+                    entry.iRangeChunk.UpdateMax( thread.SizeCurrent );
+                    entry.iRangeAlloc.UpdateMin( thread.AllocSpaceTotal );
+                    entry.iRangeAlloc.UpdateMax( thread.AllocSpaceTotal );
+                    entry.iRangeFree.UpdateMin( thread.FreeSpaceTotal );
+                    entry.iRangeFree.UpdateMax( thread.FreeSpaceTotal );
+
+                    // Delta for each type
+                    long deltaChunk = entry.iLastChunk > 0 ? ( thread.SizeCurrent - entry.iLastChunk ) : 0;
+                    long deltaAlloc = entry.iLastAlloc > 0 ? ( thread.AllocSpaceTotal - entry.iLastAlloc ) : 0;
+                    long deltaFree = entry.iLastFree > 0 ? ( thread.FreeSpaceTotal - entry.iLastFree ) : 0;
+                    entry.iDeltaChunk += deltaChunk;
+                    entry.iDeltaAlloc += deltaAlloc;
+                    entry.iDeltaFree += deltaFree;
+
+                    // Net effect
+                    entry.iNetEffectChunk += CSVExcelExporterAllDataSets.NetEffectForDelta( deltaChunk );
+                    entry.iNetEffectAlloc += CSVExcelExporterAllDataSets.NetEffectForDelta( deltaAlloc );
+                    entry.iNetEffectFree += CSVExcelExporterAllDataSets.NetEffectForDelta( deltaFree );
+
+                    // Update last values
+                    entry.iLastChunk = thread.SizeCurrent;
+                    entry.iLastAlloc = thread.AllocSpaceTotal;
+                    entry.iLastFree = thread.FreeSpaceTotal;
+                }
+                else
+                {
+                    throw new Exception( "Cannot find thread entry for thread named: " + thread.ThreadName );
+                }
+            }
+
+            ++iColumnCounter;
+        }
+        #endregion
+
+        #region From DisposableObject
+        protected override void CleanupManagedResources()
+        {
+            try
+            {
+                if ( iExcelApp != null )
+                {
+                    // We're finished
+                    PrepareWorsheetForSaving();
+
+                    // Save excel workbook
+                    SaveWorkbook();
+
+                    // Close app
+                    Utils.CloseExcel( iExcelApp );
+                }
+
+                iExcelApp = null;
+            }
+            finally
+            {
+                base.CleanupManagedResources();
+            }
+        }
+        #endregion
+
+        #region Internal methods
+        private void PrepareWorksheetReadyForData( )
+        {
+            Excel.Workbooks workbooks = iExcelApp.Workbooks;
+            workbooks.Add(Excel.XlWBATemplate.xlWBATWorksheet);
+            Excel.Workbook workbook = workbooks.get_Item(workbooks.Count);
+            Excel.Sheets sheets = workbook.Worksheets;
+
+            iSheetChunkSize = (Excel.Worksheet) sheets.get_Item( 1 );
+            CreateSheet( iSheetChunkSize, "Chunk Size" );
+
+            iSheetFree = (Excel.Worksheet) sheets.Add( Type.Missing, sheets.get_Item( sheets.Count ), 1, Excel.XlSheetType.xlWorksheet );
+            CreateSheet( iSheetFree, "Free Size" );
+
+            iSheetAlloc = (Excel.Worksheet) sheets.Add( Type.Missing, sheets.get_Item( sheets.Count ), 1, Excel.XlSheetType.xlWorksheet );
+            CreateSheet( iSheetAlloc, "Alloc Size" );
+        }
+
+        private void PrepareWorsheetForSaving()
+        {
+            // Update all sheets change factors...
+            CalculateChangeFactor( iSheetChunkSize, TThreadMapEntry.TType.ETypeChunk );
+            CalculateChangeFactor( iSheetAlloc, TThreadMapEntry.TType.ETypeAlloc );
+            CalculateChangeFactor( iSheetFree, TThreadMapEntry.TType.ETypeFree );
+
+            // Deltas
+            CalculateDelta( iSheetChunkSize, TThreadMapEntry.TType.ETypeChunk );
+            CalculateDelta( iSheetAlloc, TThreadMapEntry.TType.ETypeAlloc );
+            CalculateDelta( iSheetFree, TThreadMapEntry.TType.ETypeFree );
+ 
+            // Sort
+            SortByChangeFactor( iSheetChunkSize );
+            SortByChangeFactor( iSheetAlloc );
+            SortByChangeFactor( iSheetFree );
+
+            iSheetAlloc.Activate();
+        }
+
+        private void CreateSheet( Excel.Worksheet aSheet, string aTitle )
+        {
+            aSheet.Name = aTitle;
+            
+            // Create standard columns
+            Utils.SetValue( 1, KColumnNumberThreadName, aSheet, "Thread Name" );
+            Utils.SetValue( 1, KColumnNumberChangeFactor, aSheet, "Change Factor" );
+            Utils.SetValue( 1, KColumnNumberDelta, aSheet, "Overall Delta" );
+
+            // Set up column formatting
+            Utils.FormatColumn( KColumnNumberChangeFactor, aSheet, KColumnNumberFormatChangeFactor );
+            Utils.FormatColumn( KColumnNumberDelta, aSheet, KColumnNumberFormatDelta );
+
+            for ( int i = 0; i < iDataSetCount; i++ )
+            {
+                int col = i + KColumnNumberCycleFirst;
+                Utils.SetValue( 1, col, aSheet, string.Format( "Cycle {0:d}", i + 1 ) );
+                Utils.FormatColumn( col, aSheet, KColumnNumberFormatCycle );
+            }
+
+            Utils.MakeBoxedTitleRow( 1, KColumnNumberCycleFirst + iDataSetCount, aSheet, 0xFF0000 );
+
+            // Add thread names & ids
+            int row = 2;
+            foreach ( KeyValuePair<long, TThreadMapEntry> kvp in iThreadMap )
+            {
+                TThreadMapEntry entry = kvp.Value;
+                Utils.SetValue( row, KColumnNumberThreadName, aSheet, string.Format( "[{0:d5}] {1}", kvp.Key, kvp.Value.iThreadName ) );
+                if ( entry.iRowIndex == 0 )
+                {
+                    entry.iRowIndex = row;
+                }
+                ++row;
+            }
+
+            // Size columns
+            Utils.AutoFitColumn( KColumnNumberThreadName, aSheet );
+            Utils.SetColumnWidth( KColumnNumberChangeFactor, aSheet, 15 );
+            Utils.SetColumnWidth( KColumnNumberDelta, aSheet, 15 );
+        }
+
+        private void SaveWorkbook()
+        {
+            string path = Path.GetDirectoryName( iFileName );
+            System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo( path );
+            if ( !dirInfo.Exists )
+            {
+                dirInfo.Create();
+            }
+
+            System.IO.FileInfo fileInfo = new System.IO.FileInfo( iFileName );
+            if ( fileInfo.Exists )
+            {
+                try
+                {
+                    fileInfo.Delete();
+                }
+                catch ( Exception )
+                {
+                }
+            }
+
+            Microsoft.Office.Interop.Excel.Workbooks workbooks = iExcelApp.Workbooks;
+            Microsoft.Office.Interop.Excel.Workbook workbook = workbooks.get_Item( workbooks.Count );
+
+            try
+            {
+                workbook.SaveAs( iFileName,
+                                    Excel.XlFileFormat.xlExcel9795,
+                                    Type.Missing,
+                                    Type.Missing,
+                                    Type.Missing,
+                                    Type.Missing,
+                                    Excel.XlSaveAsAccessMode.xlNoChange,
+                                    Type.Missing,
+                                    Type.Missing,
+                                    Type.Missing,
+                                    Type.Missing,
+                                    Type.Missing );
+            }
+            catch ( System.IO.IOException )
+            {
+            }
+
+            workbook.Close( false, Type.Missing, Type.Missing );
+        }
+
+        private void SortByChangeFactor( Excel.Worksheet aSheet )
+        {
+            int colCount = KColumnNumberCycleFirst + iDataSetCount;
+            
+            Excel.Range masterSortCell = (Excel.Range) aSheet.Cells[ 1, KColumnNumberChangeFactor ];
+            Excel.Range range = Utils.GetRangeByColumnAndRow( 1, KColumnNumberThreadName, 1 + iThreadMap.Count, colCount, aSheet );
+            range.Sort( masterSortCell.Columns[ 1, Type.Missing ], Microsoft.Office.Interop.Excel.XlSortOrder.xlDescending,
+                        Type.Missing, Type.Missing, Microsoft.Office.Interop.Excel.XlSortOrder.xlAscending, 
+                        Type.Missing, Microsoft.Office.Interop.Excel.XlSortOrder.xlAscending, Microsoft.Office.Interop.Excel.XlYesNoGuess.xlYes,
+                        Type.Missing, Type.Missing,
+                        Microsoft.Office.Interop.Excel.XlSortOrientation.xlSortColumns,
+                        Microsoft.Office.Interop.Excel.XlSortMethod.xlPinYin,
+                        Microsoft.Office.Interop.Excel.XlSortDataOption.xlSortNormal,
+                        Microsoft.Office.Interop.Excel.XlSortDataOption.xlSortNormal,
+                        Microsoft.Office.Interop.Excel.XlSortDataOption.xlSortNormal );
+        }
+
+        private void CalculateChangeFactor( Excel.Worksheet aSheet, TThreadMapEntry.TType aType )
+        {
+            aSheet.Activate();
+
+            foreach ( KeyValuePair<long, TThreadMapEntry> kvp in iThreadMap )
+            {
+                TThreadMapEntry entry = kvp.Value;
+                //
+                string formula = entry.ChangeFactor( aType );
+                Utils.SetValue( entry.iRowIndex, KColumnNumberChangeFactor, aSheet, formula );
+            }
+        }
+
+        private void CalculateDelta( Excel.Worksheet aSheet, TThreadMapEntry.TType aType )
+        {
+            aSheet.Activate();
+
+            foreach ( KeyValuePair<long, TThreadMapEntry> kvp in iThreadMap )
+            {
+                TThreadMapEntry entry = kvp.Value;
+                //
+                string formula = entry.Delta( aType );
+                Utils.SetValue( entry.iRowIndex, KColumnNumberDelta, aSheet, formula );
+            }
+        }
+
+        private static int NetEffectForDelta( long aDelta )
+        {
+            int ret = -1;
+            //
+            if ( aDelta > 0 )
+            {
+                ret = 1;
+            }
+            else if ( aDelta == 0 )
+            {
+                ret = 0;
+            }
+            //
+            return ret;
+        }
+        #endregion
+
+        #region Internal constants
+        private const int KColumnNumberThreadName = 1;
+        private const int KColumnNumberChangeFactor = 2;
+        private const int KColumnNumberDelta = 3;
+
+        private const int KColumnNumberCycleFirst = 5;
+
+        private const string KColumnNumberFormatDelta = "[Red]###,###,##0;[Blue]-###,###,##0";
+        private const string KColumnNumberFormatCycle = "###,###,##0";
+        private const string KColumnNumberFormatChangeFactor = "[Red]#,##0.000000;[Blue]-#,##0.000000";
+        #endregion
+
+        #region Data members
+        private readonly string iFileName;
+        private readonly int iDataSetCount;
+        private readonly Dictionary<long, TThreadMapEntry> iThreadMap;
+        private Excel.Worksheet iSheetFree;
+        private Excel.Worksheet iSheetAlloc;
+        private Excel.Worksheet iSheetChunkSize;
+        private Excel.Application iExcelApp;
+        private int iColumnCounter = KColumnNumberCycleFirst;
+        #endregion
+    }
+
+    #region Internal class
+    internal class TThreadMapEntry
+    {
+        #region Enumerations
+        public enum TType
+        {
+            ETypeChunk = 0,
+            ETypeAlloc,
+            ETypeFree
+        }
+        #endregion
+
+        #region API
+        public string ChangeFactor( TType aType )
+        {
+            string ret = string.Empty;
+            //
+            if ( aType == TType.ETypeChunk )
+            {
+                ret = ChangeFactor( iNetEffectChunk, iDeltaChunk, iRangeChunk );
+            }
+            else if ( aType == TType.ETypeAlloc )
+            {
+                ret = ChangeFactor( iNetEffectAlloc, iDeltaAlloc, iRangeAlloc );
+            }
+            else if ( aType == TType.ETypeFree )
+            {
+                ret = ChangeFactor( iNetEffectFree, iDeltaFree, iRangeFree );
+            }
+            //
+            return ret;
+        }
+
+        public string Delta( TType aType )
+        {
+            string ret = string.Empty;
+            //
+            if ( aType == TType.ETypeChunk )
+            {
+                ret = ( iDeltaChunk != 0 ) ? "=" + iDeltaChunk.ToString() : string.Empty;
+            }
+            else if ( aType == TType.ETypeAlloc )
+            {
+                ret = ( iDeltaAlloc != 0 ) ? "=" + iDeltaAlloc.ToString() : string.Empty;
+            }
+            else if ( aType == TType.ETypeFree )
+            {
+                ret = ( iDeltaFree != 0 ) ? "=" + iDeltaFree.ToString() : string.Empty;
+            }
+            //
+            return ret;
+        }
+        #endregion
+
+        #region Internal methods
+        private string ChangeFactor( int aNetEffect, long aDelta, AddressRange aRange )
+        {
+            StringBuilder ret = new StringBuilder();
+
+            //      ( Total net effect * Total delta )
+            // --------------------------------------------
+            // (Max - Min) * (Number of Matching Data Sets)
+            // 
+            if ( aRange.Max - aRange.Min == 0 )
+            {
+                // Avoid divide by zero when there has been no change
+            }
+            else if ( aDelta == 0 )
+            {
+                // Overall change delta was zero
+            }
+            else
+            {
+                ret.Append( "=" );
+                ret.AppendFormat( "( {0} * ABS({1}) )", aNetEffect, aDelta );
+                ret.Append( " / " );
+                ret.AppendFormat( "( ({0} - {1}) * {2} )", aRange.Max, aRange.Min, iNumberOfMatchingDataSets );
+            }
+
+            //
+            return ret.ToString();
+        }
+        #endregion
+
+        #region Data members
+        public string iThreadName = string.Empty;
+        public long iThreadId = 0;
+        public int iRowIndex = 0;
+        public int iNumberOfMatchingDataSets = 0;
+
+        public AddressRange iRangeChunk = new AddressRange();
+        public AddressRange iRangeAlloc = new AddressRange();
+        public AddressRange iRangeFree = new AddressRange();
+
+        public long iLastChunk = 0;
+        public long iLastAlloc = 0;
+        public long iLastFree = 0;
+
+        public long iDeltaChunk = 0;
+        public long iDeltaAlloc = 0;
+        public long iDeltaFree = 0;
+
+        public int iNetEffectChunk = 0;
+        public int iNetEffectAlloc = 0;
+        public int iNetEffectFree = 0;
+        #endregion
+    }
+    #endregion
+}