diff -r 8e12a575a9b5 -r 15296fd0af4a sysperfana/heapanalyser/UI/UIs/Console/HAUIConsole.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sysperfana/heapanalyser/UI/UIs/Console/HAUIConsole.cs Tue Jun 15 12:47:20 2010 +0300 @@ -0,0 +1,384 @@ +/* +* 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 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 + } +}