sysperfana/heapanalyser/UI/UIs/Console/HAUIConsole.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.Text;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using System.Windows.Forms;
using SymbianUtils;
using SymbianUtils.Settings;
using SymbianUtils.Tracer;
using SymbianUtils.FileSystem.Utilities;
using SymbianXmlInputLib.Parser;
using SymbianXmlInputLib.Parser.Nodes;
using SymbianXmlInputLib.Elements;
using SymbianXmlInputLib.Elements.Types.Category;
using SymbianXmlInputLib.Elements.Types.FileSystem;
using SymbianXmlInputLib.Elements.Types.Command;
using SymbianDebugLib.Engine;
using SymbianDebugLib.Entity;
using SymbianStructuresLib.CodeSegments;
using HeapLib;
using HeapLib.Reconstructor;
using HeapLib.Reconstructor.Misc;
using HeapLib.Reconstructor.DataSources;
using HeapLib.Reconstructor.DataSources.Analyser;
using HeapUiLib.Dialogs;
using HeapUiLib.Forms;
using HeapAnalyser.Engine;
using HeapAnalyser.Engine.Types;
using HeapAnalyser.Exceptions;
using HeapComparisonUiLib.Progress;
using HeapAnalyser.UIs.Console.Files;
using HeapAnalyser.UIs.Console.Inputs;

namespace HeapAnalyser.UIs.Console
{
	public class HAUIConsole : HAUI
	{
		#region Constructors
        public HAUIConsole( string[] aArgs, XmlSettings aSettings, HeapWizardEngine aEngine, ITracer aTracer )
            : base( aArgs, aSettings, aEngine, aTracer )
		{
            iInputs = new HACmdLineInputParameters( this, aEngine );
		}
		#endregion

        #region From HAUI
        public override bool IsAppropriateUI
        {
            get
            { 
                // There must be command line arguments in order to use the command line UI
                bool ret = base.Args.Length != 0;
                //
                if ( ret )
                {
                    string[] args = base.Args;
                    for ( int i = 0; i < args.Length; i++ )
                    {
                        string cmd = args[ i ].Trim().ToUpper();
                        string nextArg = ( i < args.Length - 1 ? args[ i + 1 ].Trim().ToUpper() : string.Empty );
                        //
                        try
                        {
                            if ( cmd == KPluginInputParameter && nextArg != string.Empty )
                            {
                                ret = true;
                                break;
                            }
                        }
                        catch ( Exception )
                        {
                        }
                    }
                }
                //
                return ret;
            }
        }

        public override Form PrepareInitialForm()
        {
            Form formToShow = null;
            //
            ParseInputs();
            PrimeDebugEngine();
            
            // If we're running the graphical UI then show the main analysis form,
            // otherwise just run the comparison operation and exit.
            switch ( base.Engine.OperationType )
            {
            case HeapWizardEngine.TOperationType.EOperationTypeAnalyseAndView:
                formToShow = RunAnalyser();
                break;
            case HeapWizardEngine.TOperationType.EOperationTypeCompareHeapDumps:
                RunComparison();
                break;
            }

            return formToShow;
        }

        public override Form HandleFormClosed( object aSender, EventArgs aArgs )
        {
            Form ret = null;
            return ret;
        }
        #endregion

		#region Properties
		#endregion

        #region Event handlers
        private void DbgEngine_EntityPrimingStarted( DbgEngine aEngine, DbgEntity aEntity, object aContext )
        {
            Trace( "[HA Cmd] Priming debug meta-data: " + aEntity.FullName );
        }

        private void DbgEngine_EntityPrimingProgress( DbgEngine aEngine, DbgEntity aEntity, object aContext )
        {
            if ( aContext != null )
            {
                if ( aContext.GetType() == typeof( int ) )
                {
                    int value = (int) aContext;
                    Trace( "[HA Cmd] Priming debug meta-data progress: {0:d3}% {1}", value, aEntity.FullName );
                }
            }
        }

        private void DbgEngine_EntityPrimingComplete( DbgEngine aEngine, DbgEntity aEntity, object aContext )
        {
            Trace( "[HA Cmd] Primed debug meta-data: " + aEntity.FullName );
        }

        private void SymbolLibCodeSegDefinitionResolver_LocatedFile( string aFileName )
        {
            Trace( "[HA Cmd] Located debug meta data: " + aFileName );
        }
        #endregion

        #region Internal constants
        private const string KPluginInputParameter = "-INPUT";
        #endregion

		#region Internal methods
        private void ParseInputs()
        {
            Trace( "[HA Cmd] ParseInputs() - START " );
            Trace( string.Empty );
            Trace( "[HA Cmd] command line: " + System.Environment.CommandLine );
            Trace( "[HA Cmd] command wd:   " + System.Environment.CurrentDirectory );
            Trace( "[HA Cmd] proc count:   " + System.Environment.ProcessorCount );
            Trace( "[HA Cmd] sysdir:       " + System.Environment.SystemDirectory );
            Trace( "[HA Cmd] version:      " + System.Environment.Version.ToString() );
            Trace( string.Empty );

            // We expect to see an "-input" parameter
            string inputFileName = ExtractCommandLineInputParameter( Args );

            // If no file was found then inputFileName will be an empty string.
            if ( string.IsNullOrEmpty( inputFileName ) )
            {
                throw new HAUIException( "Input file parameter missing", HAUIException.KErrCommandLineArgumentsMissing );
            }
            else if ( !FSUtilities.Exists( inputFileName ) )
            {
                throw new HAUIException( "Input file not found", HAUIException.KErrCommandLineArgumentsFileNotFound );
            }
            else
            {
                Trace( "[HA Cmd] ParseInputs() - start read inputs" );
                iInputs.Read( inputFileName );
                Trace( "[HA Cmd] ParseInputs() - inputs read successfully" );

                // Validate the inputs are correct.
                if ( string.IsNullOrEmpty( iInputs.ThreadName ) )
                {
                    throw new HAUIException( "The specified thread name is invalid", HAUIException.KErrCommandLineAnalysisThreadNameInvalid );
                }
                else 
                {
                    // Validate input data
                    int sourceCount = iInputs.SourceFiles.Count;
                    switch( base.Engine.OperationType )
                    {
                    case HeapWizardEngine.TOperationType.EOperationTypeAnalyseAndView:
                        if ( iInputs.SourceFiles.Count != 1 && iInputs.SourceFiles[ 0 ].IsFile )
                        {
                            Trace( "[HA Cmd] ParseInputs() - viewer - missing source file!" );
                            throw new HAUIException( "Source file not specified", HAUIException.KErrCommandLineSourceFileNotFound );
                        }
                        break;
                    case HeapWizardEngine.TOperationType.EOperationTypeCompareHeapDumps:
                        if ( iInputs.SourceFiles.Count != 2 && iInputs.SourceFiles[ 0 ].IsFile && iInputs.SourceFiles[ 1 ].IsFile )
                        {
                            Trace( "[HA Cmd] ParseInputs() - comparison - missing source files!" );
                            throw new HAUIException( "Source files not specified", HAUIException.KErrCommandLineSourceFileNotFound );
                        }
                        break;
                    }

                    // Validate output (where needed)
                    if ( base.Engine.OperationType == HeapWizardEngine.TOperationType.EOperationTypeCompareHeapDumps )
                    {
                        bool outputSet = iInputs.OutputFile != null;
                        if ( !outputSet )
                        {
                            throw new HAUIException( "Output file not specified", HAUIException.KErrCommandLineAnalysisOutputInvalid );
                        }
                    }
                }
            }

            Trace( "[HA Cmd] ParseInputs() - END" );
        }

        private void PrimeDebugEngine()
        {
            DbgEngine debugEngine = base.Engine.DebugEngine;
            //
            Exception primerException = null;
            HACmdLineFSEntityList<HACmdLineFSEntity> metaDataFiles = iInputs.MetaDataFiles;
            //
            try
            {
                debugEngine.Clear();

                foreach ( HACmdLineFSEntity entry in metaDataFiles )
                {
                    Trace( "[HA Cmd] Seeding debug meta engine with entry: " + entry.Name );
                    DbgEntity entity = debugEngine.Add( entry.Name );
                    if ( entity != null )
                    {
                        Trace( "[HA Cmd] Entry type detected as: [" + entity.CategoryName + "]" );
                        entity.Tag = entry;
                    }
                    else
                    {
                        Trace( "[HA Cmd] Entry not handled: " + entry.Name );
                    }
                }

                // Listen to prime events
                try
                {
                    Trace( "[HA Cmd] Starting prime operation... " );
                    debugEngine.EntityPrimingStarted += new DbgEngine.EventHandler( DbgEngine_EntityPrimingStarted );
                    debugEngine.EntityPrimingProgress += new DbgEngine.EventHandler( DbgEngine_EntityPrimingProgress );
                    debugEngine.EntityPrimingComplete += new DbgEngine.EventHandler( DbgEngine_EntityPrimingComplete );
                    debugEngine.Prime( TSynchronicity.EAsynchronous );
                    Trace( "[HA Cmd] Debug meta data priming completed successfully." );
                }
                finally
                {
                    debugEngine.EntityPrimingStarted -= new DbgEngine.EventHandler( DbgEngine_EntityPrimingStarted );
                    debugEngine.EntityPrimingProgress -= new DbgEngine.EventHandler( DbgEngine_EntityPrimingProgress );
                    debugEngine.EntityPrimingComplete -= new DbgEngine.EventHandler( DbgEngine_EntityPrimingComplete );
                }
            }
            catch ( Exception exception )
            {
                Trace( "[HA Cmd] Debug meta data priming exception: " + exception.Message + ", " + exception.StackTrace );
                primerException = exception;
            }
        }

        private Form RunAnalyser()
        {
            string file = iInputs.SourceFiles[ 0 ].File.FullName;
            base.Engine.AnalysisEngine.DataSource = PrepareDataSource( file );
            base.Engine.AnalysisEngine.CreateParser();
            //
            Form ret = new HeapViewerForm( base.Engine.AnalysisEngine.Reconstructor, base.Settings );
            return ret;
        }

        private void RunComparison()
        {
            // Does the output file already exist? If so, try to delete it.
            // If not, then carry on.
            if ( iInputs.OutputFile.File.Exists )
            {
                // If deletion fails then return an error by way of heap analyser exception.
                try
                {
                    iInputs.OutputFile.File.Delete();
                }
                catch ( Exception )
                {
                    throw new HAUIException( "Could not overwrite output file", HAUIException.KErrCommandLineAnalysisOutputInvalid );
                }
            }

            ComparisonEngineHeapData comparisonEngine = base.Engine.ComparisonEngineData;
            //
            string file1 = iInputs.SourceFiles[ 0 ].File.FullName;
            comparisonEngine.DataSource1 = PrepareDataSource( file1 );
            //
            string file2 = iInputs.SourceFiles[ 1 ].File.FullName;
            comparisonEngine.DataSource2 = PrepareDataSource( file2 );
            //
            comparisonEngine.OutputFileName = iInputs.OutputFile.File.FullName;
            base.Engine.ComparisonEngineData.CreateReconstructors();
            ComparisonProgressDialogData.Compare( comparisonEngine.Reconstructor1,
                                                  comparisonEngine.Reconstructor2,
                                                  comparisonEngine.OutputFileName );

        }

        private DataSource PrepareDataSource( string aFileName )
        {
            DataSourceAnalyser analyser = HeapReconstructorDataSourceAnalyserDialog.Analyse( aFileName );
            DataSourceCollection sources = analyser.DataSources;
            DataSource source = sources[ iInputs.ThreadName ];
            if ( source == null )
            {
                throw new HAUIException( "Thread was not found in source data", HAUIException.KErrCommandLineAnalysisThreadNameInvalid );
            }
            //
            return source;
        }

        private static string ExtractCommandLineInputParameter( string[] aArgs )
        {
            string ret = string.Empty;

            // -input d:\ca_fullsummary.xml
            for ( int i = 0; i < aArgs.Length; i++ )
            {
                string cmd = aArgs[ i ].Trim().ToUpper();
                string nextArg = ( i < aArgs.Length - 1 ? aArgs[ i + 1 ].Trim().ToUpper() : string.Empty );
                //
                if ( cmd == KPluginInputParameter && nextArg != string.Empty )
                {
                    ret = nextArg;
                }
            }

            return ret;
        }
        #endregion

		#region Data members
        private readonly HACmdLineInputParameters iInputs;
        #endregion
	}
}