sysperfana/heapanalyser/Libraries/Engine/HeapComparisonLib/CSV/Excel/CSVExcelExporterAllDataSets.cs
changeset 8 15296fd0af4a
equal deleted inserted replaced
7:8e12a575a9b5 8:15296fd0af4a
       
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 *
       
     5 * Redistribution and use in source and binary forms, with or without
       
     6 * modification, are permitted provided that the following conditions are met:
       
     7 *
       
     8 * - Redistributions of source code must retain the above copyright notice,
       
     9 *   this list of conditions and the following disclaimer.
       
    10 * - Redistributions in binary form must reproduce the above copyright notice,
       
    11 *   this list of conditions and the following disclaimer in the documentation
       
    12 *   and/or other materials provided with the distribution.
       
    13 * - Neither the name of Nokia Corporation nor the names of its contributors
       
    14 *   may be used to endorse or promote products derived from this software
       
    15 *   without specific prior written permission.
       
    16 *
       
    17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
       
    18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
       
    20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
       
    21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
       
    22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
       
    23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
       
    24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
       
    25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
       
    26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
       
    27 * POSSIBILITY OF SUCH DAMAGE.
       
    28 * 
       
    29 * Initial Contributors:
       
    30 * Nokia Corporation - initial contribution.
       
    31 *
       
    32 * Contributors:
       
    33 *
       
    34 * Description: 
       
    35 *
       
    36 */
       
    37 
       
    38 using System;
       
    39 using System.IO;
       
    40 using System.Text;
       
    41 using System.Threading;
       
    42 using System.Collections.Generic;
       
    43 using System.Runtime.InteropServices;
       
    44 using Excel = Microsoft.Office.Interop.Excel;
       
    45 using System.Reflection; 
       
    46 using SymbianExcelUtils;
       
    47 using SymbianUtils;
       
    48 using SymbianUtils.Range;
       
    49 
       
    50 namespace HeapComparisonLib.CSV
       
    51 {
       
    52     internal class CSVExcelExporterAllDataSets : DisposableObject
       
    53     {
       
    54         #region Constructors & destructor
       
    55         public CSVExcelExporterAllDataSets( string aOutputFileName, SortedDictionary<long, string> aThreadMap, int aDataSetCount )
       
    56         {
       
    57             iDataSetCount = aDataSetCount;
       
    58             iFileName = aOutputFileName;
       
    59 
       
    60             // Sort the aThreadMap list by thread name, rather than id.
       
    61             SortedDictionary<string, TThreadMapEntry> temp = new SortedDictionary<string, TThreadMapEntry>();
       
    62             foreach ( KeyValuePair<long, string> kvp in aThreadMap )
       
    63             {
       
    64                 TThreadMapEntry entry = new TThreadMapEntry();
       
    65                 entry.iThreadName = kvp.Value;
       
    66                 entry.iThreadId = kvp.Key;
       
    67                 //
       
    68                 string mungedName = string.Format( "{1} [{0:d5}]", kvp.Key, kvp.Value );
       
    69                 temp.Add( mungedName, entry );
       
    70             }
       
    71 
       
    72             // Now build new list, in the right order
       
    73             iThreadMap = new Dictionary<long, TThreadMapEntry>( temp.Count + 1 );
       
    74             foreach ( KeyValuePair<string, TThreadMapEntry> kvp in temp )
       
    75             {
       
    76                 iThreadMap.Add( kvp.Value.iThreadId, kvp.Value );
       
    77             }
       
    78   
       
    79             // Open up excel
       
    80             iExcelApp = new Excel.Application();
       
    81             if ( iExcelApp != null )
       
    82             {
       
    83                 iExcelApp.Visible = false;
       
    84                 iExcelApp.DisplayAlerts = false;
       
    85 
       
    86                 // Prepare sheets
       
    87                 PrepareWorksheetReadyForData();
       
    88             }
       
    89             else
       
    90             {
       
    91                 throw new Exception( "Microsoft Excel not available" );
       
    92             }
       
    93         }
       
    94         #endregion
       
    95 
       
    96         #region API
       
    97         public void Export( CSVDataSet aSet )
       
    98         {
       
    99             int count = aSet.Count;
       
   100             for ( int i = 0; i < count; i++ )
       
   101             {
       
   102                 CSVThread thread = aSet[ i ];
       
   103 
       
   104                 // find row
       
   105                 if ( iThreadMap.ContainsKey( thread.ThreadId ) )
       
   106                 {
       
   107                     TThreadMapEntry entry = iThreadMap[ thread.ThreadId ];
       
   108 
       
   109                     Utils.SetValue( entry.iRowIndex, iColumnCounter, iSheetChunkSize, thread.SizeCurrent.ToString() );
       
   110                     Utils.SetValue( entry.iRowIndex, iColumnCounter, iSheetAlloc, thread.AllocSpaceTotal.ToString() );
       
   111                     Utils.SetValue( entry.iRowIndex, iColumnCounter, iSheetFree, thread.FreeSpaceTotal.ToString() );
       
   112 
       
   113                     // Update stats
       
   114                     ++entry.iNumberOfMatchingDataSets;
       
   115                     
       
   116                     // Min & max for each type
       
   117                     entry.iRangeChunk.UpdateMin( thread.SizeCurrent );
       
   118                     entry.iRangeChunk.UpdateMax( thread.SizeCurrent );
       
   119                     entry.iRangeAlloc.UpdateMin( thread.AllocSpaceTotal );
       
   120                     entry.iRangeAlloc.UpdateMax( thread.AllocSpaceTotal );
       
   121                     entry.iRangeFree.UpdateMin( thread.FreeSpaceTotal );
       
   122                     entry.iRangeFree.UpdateMax( thread.FreeSpaceTotal );
       
   123 
       
   124                     // Delta for each type
       
   125                     long deltaChunk = entry.iLastChunk > 0 ? ( thread.SizeCurrent - entry.iLastChunk ) : 0;
       
   126                     long deltaAlloc = entry.iLastAlloc > 0 ? ( thread.AllocSpaceTotal - entry.iLastAlloc ) : 0;
       
   127                     long deltaFree = entry.iLastFree > 0 ? ( thread.FreeSpaceTotal - entry.iLastFree ) : 0;
       
   128                     entry.iDeltaChunk += deltaChunk;
       
   129                     entry.iDeltaAlloc += deltaAlloc;
       
   130                     entry.iDeltaFree += deltaFree;
       
   131 
       
   132                     // Net effect
       
   133                     entry.iNetEffectChunk += CSVExcelExporterAllDataSets.NetEffectForDelta( deltaChunk );
       
   134                     entry.iNetEffectAlloc += CSVExcelExporterAllDataSets.NetEffectForDelta( deltaAlloc );
       
   135                     entry.iNetEffectFree += CSVExcelExporterAllDataSets.NetEffectForDelta( deltaFree );
       
   136 
       
   137                     // Update last values
       
   138                     entry.iLastChunk = thread.SizeCurrent;
       
   139                     entry.iLastAlloc = thread.AllocSpaceTotal;
       
   140                     entry.iLastFree = thread.FreeSpaceTotal;
       
   141                 }
       
   142                 else
       
   143                 {
       
   144                     throw new Exception( "Cannot find thread entry for thread named: " + thread.ThreadName );
       
   145                 }
       
   146             }
       
   147 
       
   148             ++iColumnCounter;
       
   149         }
       
   150         #endregion
       
   151 
       
   152         #region From DisposableObject
       
   153         protected override void CleanupManagedResources()
       
   154         {
       
   155             try
       
   156             {
       
   157                 if ( iExcelApp != null )
       
   158                 {
       
   159                     // We're finished
       
   160                     PrepareWorsheetForSaving();
       
   161 
       
   162                     // Save excel workbook
       
   163                     SaveWorkbook();
       
   164 
       
   165                     // Close app
       
   166                     Utils.CloseExcel( iExcelApp );
       
   167                 }
       
   168 
       
   169                 iExcelApp = null;
       
   170             }
       
   171             finally
       
   172             {
       
   173                 base.CleanupManagedResources();
       
   174             }
       
   175         }
       
   176         #endregion
       
   177 
       
   178         #region Internal methods
       
   179         private void PrepareWorksheetReadyForData( )
       
   180         {
       
   181             Excel.Workbooks workbooks = iExcelApp.Workbooks;
       
   182             workbooks.Add(Excel.XlWBATemplate.xlWBATWorksheet);
       
   183             Excel.Workbook workbook = workbooks.get_Item(workbooks.Count);
       
   184             Excel.Sheets sheets = workbook.Worksheets;
       
   185 
       
   186             iSheetChunkSize = (Excel.Worksheet) sheets.get_Item( 1 );
       
   187             CreateSheet( iSheetChunkSize, "Chunk Size" );
       
   188 
       
   189             iSheetFree = (Excel.Worksheet) sheets.Add( Type.Missing, sheets.get_Item( sheets.Count ), 1, Excel.XlSheetType.xlWorksheet );
       
   190             CreateSheet( iSheetFree, "Free Size" );
       
   191 
       
   192             iSheetAlloc = (Excel.Worksheet) sheets.Add( Type.Missing, sheets.get_Item( sheets.Count ), 1, Excel.XlSheetType.xlWorksheet );
       
   193             CreateSheet( iSheetAlloc, "Alloc Size" );
       
   194         }
       
   195 
       
   196         private void PrepareWorsheetForSaving()
       
   197         {
       
   198             // Update all sheets change factors...
       
   199             CalculateChangeFactor( iSheetChunkSize, TThreadMapEntry.TType.ETypeChunk );
       
   200             CalculateChangeFactor( iSheetAlloc, TThreadMapEntry.TType.ETypeAlloc );
       
   201             CalculateChangeFactor( iSheetFree, TThreadMapEntry.TType.ETypeFree );
       
   202 
       
   203             // Deltas
       
   204             CalculateDelta( iSheetChunkSize, TThreadMapEntry.TType.ETypeChunk );
       
   205             CalculateDelta( iSheetAlloc, TThreadMapEntry.TType.ETypeAlloc );
       
   206             CalculateDelta( iSheetFree, TThreadMapEntry.TType.ETypeFree );
       
   207  
       
   208             // Sort
       
   209             SortByChangeFactor( iSheetChunkSize );
       
   210             SortByChangeFactor( iSheetAlloc );
       
   211             SortByChangeFactor( iSheetFree );
       
   212 
       
   213             iSheetAlloc.Activate();
       
   214         }
       
   215 
       
   216         private void CreateSheet( Excel.Worksheet aSheet, string aTitle )
       
   217         {
       
   218             aSheet.Name = aTitle;
       
   219             
       
   220             // Create standard columns
       
   221             Utils.SetValue( 1, KColumnNumberThreadName, aSheet, "Thread Name" );
       
   222             Utils.SetValue( 1, KColumnNumberChangeFactor, aSheet, "Change Factor" );
       
   223             Utils.SetValue( 1, KColumnNumberDelta, aSheet, "Overall Delta" );
       
   224 
       
   225             // Set up column formatting
       
   226             Utils.FormatColumn( KColumnNumberChangeFactor, aSheet, KColumnNumberFormatChangeFactor );
       
   227             Utils.FormatColumn( KColumnNumberDelta, aSheet, KColumnNumberFormatDelta );
       
   228 
       
   229             for ( int i = 0; i < iDataSetCount; i++ )
       
   230             {
       
   231                 int col = i + KColumnNumberCycleFirst;
       
   232                 Utils.SetValue( 1, col, aSheet, string.Format( "Cycle {0:d}", i + 1 ) );
       
   233                 Utils.FormatColumn( col, aSheet, KColumnNumberFormatCycle );
       
   234             }
       
   235 
       
   236             Utils.MakeBoxedTitleRow( 1, KColumnNumberCycleFirst + iDataSetCount, aSheet, 0xFF0000 );
       
   237 
       
   238             // Add thread names & ids
       
   239             int row = 2;
       
   240             foreach ( KeyValuePair<long, TThreadMapEntry> kvp in iThreadMap )
       
   241             {
       
   242                 TThreadMapEntry entry = kvp.Value;
       
   243                 Utils.SetValue( row, KColumnNumberThreadName, aSheet, string.Format( "[{0:d5}] {1}", kvp.Key, kvp.Value.iThreadName ) );
       
   244                 if ( entry.iRowIndex == 0 )
       
   245                 {
       
   246                     entry.iRowIndex = row;
       
   247                 }
       
   248                 ++row;
       
   249             }
       
   250 
       
   251             // Size columns
       
   252             Utils.AutoFitColumn( KColumnNumberThreadName, aSheet );
       
   253             Utils.SetColumnWidth( KColumnNumberChangeFactor, aSheet, 15 );
       
   254             Utils.SetColumnWidth( KColumnNumberDelta, aSheet, 15 );
       
   255         }
       
   256 
       
   257         private void SaveWorkbook()
       
   258         {
       
   259             string path = Path.GetDirectoryName( iFileName );
       
   260             System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo( path );
       
   261             if ( !dirInfo.Exists )
       
   262             {
       
   263                 dirInfo.Create();
       
   264             }
       
   265 
       
   266             System.IO.FileInfo fileInfo = new System.IO.FileInfo( iFileName );
       
   267             if ( fileInfo.Exists )
       
   268             {
       
   269                 try
       
   270                 {
       
   271                     fileInfo.Delete();
       
   272                 }
       
   273                 catch ( Exception )
       
   274                 {
       
   275                 }
       
   276             }
       
   277 
       
   278             Microsoft.Office.Interop.Excel.Workbooks workbooks = iExcelApp.Workbooks;
       
   279             Microsoft.Office.Interop.Excel.Workbook workbook = workbooks.get_Item( workbooks.Count );
       
   280 
       
   281             try
       
   282             {
       
   283                 workbook.SaveAs( iFileName,
       
   284                                     Excel.XlFileFormat.xlExcel9795,
       
   285                                     Type.Missing,
       
   286                                     Type.Missing,
       
   287                                     Type.Missing,
       
   288                                     Type.Missing,
       
   289                                     Excel.XlSaveAsAccessMode.xlNoChange,
       
   290                                     Type.Missing,
       
   291                                     Type.Missing,
       
   292                                     Type.Missing,
       
   293                                     Type.Missing,
       
   294                                     Type.Missing );
       
   295             }
       
   296             catch ( System.IO.IOException )
       
   297             {
       
   298             }
       
   299 
       
   300             workbook.Close( false, Type.Missing, Type.Missing );
       
   301         }
       
   302 
       
   303         private void SortByChangeFactor( Excel.Worksheet aSheet )
       
   304         {
       
   305             int colCount = KColumnNumberCycleFirst + iDataSetCount;
       
   306             
       
   307             Excel.Range masterSortCell = (Excel.Range) aSheet.Cells[ 1, KColumnNumberChangeFactor ];
       
   308             Excel.Range range = Utils.GetRangeByColumnAndRow( 1, KColumnNumberThreadName, 1 + iThreadMap.Count, colCount, aSheet );
       
   309             range.Sort( masterSortCell.Columns[ 1, Type.Missing ], Microsoft.Office.Interop.Excel.XlSortOrder.xlDescending,
       
   310                         Type.Missing, Type.Missing, Microsoft.Office.Interop.Excel.XlSortOrder.xlAscending, 
       
   311                         Type.Missing, Microsoft.Office.Interop.Excel.XlSortOrder.xlAscending, Microsoft.Office.Interop.Excel.XlYesNoGuess.xlYes,
       
   312                         Type.Missing, Type.Missing,
       
   313                         Microsoft.Office.Interop.Excel.XlSortOrientation.xlSortColumns,
       
   314                         Microsoft.Office.Interop.Excel.XlSortMethod.xlPinYin,
       
   315                         Microsoft.Office.Interop.Excel.XlSortDataOption.xlSortNormal,
       
   316                         Microsoft.Office.Interop.Excel.XlSortDataOption.xlSortNormal,
       
   317                         Microsoft.Office.Interop.Excel.XlSortDataOption.xlSortNormal );
       
   318         }
       
   319 
       
   320         private void CalculateChangeFactor( Excel.Worksheet aSheet, TThreadMapEntry.TType aType )
       
   321         {
       
   322             aSheet.Activate();
       
   323 
       
   324             foreach ( KeyValuePair<long, TThreadMapEntry> kvp in iThreadMap )
       
   325             {
       
   326                 TThreadMapEntry entry = kvp.Value;
       
   327                 //
       
   328                 string formula = entry.ChangeFactor( aType );
       
   329                 Utils.SetValue( entry.iRowIndex, KColumnNumberChangeFactor, aSheet, formula );
       
   330             }
       
   331         }
       
   332 
       
   333         private void CalculateDelta( Excel.Worksheet aSheet, TThreadMapEntry.TType aType )
       
   334         {
       
   335             aSheet.Activate();
       
   336 
       
   337             foreach ( KeyValuePair<long, TThreadMapEntry> kvp in iThreadMap )
       
   338             {
       
   339                 TThreadMapEntry entry = kvp.Value;
       
   340                 //
       
   341                 string formula = entry.Delta( aType );
       
   342                 Utils.SetValue( entry.iRowIndex, KColumnNumberDelta, aSheet, formula );
       
   343             }
       
   344         }
       
   345 
       
   346         private static int NetEffectForDelta( long aDelta )
       
   347         {
       
   348             int ret = -1;
       
   349             //
       
   350             if ( aDelta > 0 )
       
   351             {
       
   352                 ret = 1;
       
   353             }
       
   354             else if ( aDelta == 0 )
       
   355             {
       
   356                 ret = 0;
       
   357             }
       
   358             //
       
   359             return ret;
       
   360         }
       
   361         #endregion
       
   362 
       
   363         #region Internal constants
       
   364         private const int KColumnNumberThreadName = 1;
       
   365         private const int KColumnNumberChangeFactor = 2;
       
   366         private const int KColumnNumberDelta = 3;
       
   367 
       
   368         private const int KColumnNumberCycleFirst = 5;
       
   369 
       
   370         private const string KColumnNumberFormatDelta = "[Red]###,###,##0;[Blue]-###,###,##0";
       
   371         private const string KColumnNumberFormatCycle = "###,###,##0";
       
   372         private const string KColumnNumberFormatChangeFactor = "[Red]#,##0.000000;[Blue]-#,##0.000000";
       
   373         #endregion
       
   374 
       
   375         #region Data members
       
   376         private readonly string iFileName;
       
   377         private readonly int iDataSetCount;
       
   378         private readonly Dictionary<long, TThreadMapEntry> iThreadMap;
       
   379         private Excel.Worksheet iSheetFree;
       
   380         private Excel.Worksheet iSheetAlloc;
       
   381         private Excel.Worksheet iSheetChunkSize;
       
   382         private Excel.Application iExcelApp;
       
   383         private int iColumnCounter = KColumnNumberCycleFirst;
       
   384         #endregion
       
   385     }
       
   386 
       
   387     #region Internal class
       
   388     internal class TThreadMapEntry
       
   389     {
       
   390         #region Enumerations
       
   391         public enum TType
       
   392         {
       
   393             ETypeChunk = 0,
       
   394             ETypeAlloc,
       
   395             ETypeFree
       
   396         }
       
   397         #endregion
       
   398 
       
   399         #region API
       
   400         public string ChangeFactor( TType aType )
       
   401         {
       
   402             string ret = string.Empty;
       
   403             //
       
   404             if ( aType == TType.ETypeChunk )
       
   405             {
       
   406                 ret = ChangeFactor( iNetEffectChunk, iDeltaChunk, iRangeChunk );
       
   407             }
       
   408             else if ( aType == TType.ETypeAlloc )
       
   409             {
       
   410                 ret = ChangeFactor( iNetEffectAlloc, iDeltaAlloc, iRangeAlloc );
       
   411             }
       
   412             else if ( aType == TType.ETypeFree )
       
   413             {
       
   414                 ret = ChangeFactor( iNetEffectFree, iDeltaFree, iRangeFree );
       
   415             }
       
   416             //
       
   417             return ret;
       
   418         }
       
   419 
       
   420         public string Delta( TType aType )
       
   421         {
       
   422             string ret = string.Empty;
       
   423             //
       
   424             if ( aType == TType.ETypeChunk )
       
   425             {
       
   426                 ret = ( iDeltaChunk != 0 ) ? "=" + iDeltaChunk.ToString() : string.Empty;
       
   427             }
       
   428             else if ( aType == TType.ETypeAlloc )
       
   429             {
       
   430                 ret = ( iDeltaAlloc != 0 ) ? "=" + iDeltaAlloc.ToString() : string.Empty;
       
   431             }
       
   432             else if ( aType == TType.ETypeFree )
       
   433             {
       
   434                 ret = ( iDeltaFree != 0 ) ? "=" + iDeltaFree.ToString() : string.Empty;
       
   435             }
       
   436             //
       
   437             return ret;
       
   438         }
       
   439         #endregion
       
   440 
       
   441         #region Internal methods
       
   442         private string ChangeFactor( int aNetEffect, long aDelta, AddressRange aRange )
       
   443         {
       
   444             StringBuilder ret = new StringBuilder();
       
   445 
       
   446             //      ( Total net effect * Total delta )
       
   447             // --------------------------------------------
       
   448             // (Max - Min) * (Number of Matching Data Sets)
       
   449             // 
       
   450             if ( aRange.Max - aRange.Min == 0 )
       
   451             {
       
   452                 // Avoid divide by zero when there has been no change
       
   453             }
       
   454             else if ( aDelta == 0 )
       
   455             {
       
   456                 // Overall change delta was zero
       
   457             }
       
   458             else
       
   459             {
       
   460                 ret.Append( "=" );
       
   461                 ret.AppendFormat( "( {0} * ABS({1}) )", aNetEffect, aDelta );
       
   462                 ret.Append( " / " );
       
   463                 ret.AppendFormat( "( ({0} - {1}) * {2} )", aRange.Max, aRange.Min, iNumberOfMatchingDataSets );
       
   464             }
       
   465 
       
   466             //
       
   467             return ret.ToString();
       
   468         }
       
   469         #endregion
       
   470 
       
   471         #region Data members
       
   472         public string iThreadName = string.Empty;
       
   473         public long iThreadId = 0;
       
   474         public int iRowIndex = 0;
       
   475         public int iNumberOfMatchingDataSets = 0;
       
   476 
       
   477         public AddressRange iRangeChunk = new AddressRange();
       
   478         public AddressRange iRangeAlloc = new AddressRange();
       
   479         public AddressRange iRangeFree = new AddressRange();
       
   480 
       
   481         public long iLastChunk = 0;
       
   482         public long iLastAlloc = 0;
       
   483         public long iLastFree = 0;
       
   484 
       
   485         public long iDeltaChunk = 0;
       
   486         public long iDeltaAlloc = 0;
       
   487         public long iDeltaFree = 0;
       
   488 
       
   489         public int iNetEffectChunk = 0;
       
   490         public int iNetEffectAlloc = 0;
       
   491         public int iNetEffectFree = 0;
       
   492         #endregion
       
   493     }
       
   494     #endregion
       
   495 }