diff -r 8e12a575a9b5 -r 15296fd0af4a sysperfana/heapanalyser/Libraries/Engine/HeapComparisonLib/CSV/Thread/Parsers/CSVThreadParserFormatNew.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sysperfana/heapanalyser/Libraries/Engine/HeapComparisonLib/CSV/Thread/Parsers/CSVThreadParserFormatNew.cs Tue Jun 15 12:47:20 2010 +0300 @@ -0,0 +1,355 @@ +/* +* 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.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using SymbianUtils; + +namespace HeapComparisonLib.CSV.Thread.Parsers +{ + internal class CSVThreadParserFormatNew + { + #region Constructors & destructor + public CSVThreadParserFormatNew( CSVThreadParser aParser ) + { + iParser = aParser; + } + #endregion + + #region API + public CSVThread ParseLine( string aLine ) + { + if ( !TryToParseEntry( aLine ) ) + { + if ( !TryToParseTimestamp( aLine ) ) + { + TryToParseSupportedTags( aLine ); + } + } + + // Return a constructed entry (or null) if we have one ready + CSVThread ret = iConstructedEntry; + iConstructedEntry = null; + return ret; + } + #endregion + + #region Internal enumerations + private enum TState + { + EStateIdle = 0, + EStateSeenEntryStart, + EStateSeenThreadName, + EStateSeenProcessName, + EStateSeenChunkName, + EStateSeenFieldBody, + EStateSeenEntryEnd, + } + #endregion + + #region Internal methods + private bool TryToParseEntry( string aLine ) + { + Match matchEntry = KRegExEntry.Match( aLine ); + if ( matchEntry.Success ) + { + // Check if it's an opening or closing tag. + bool isOpen = string.IsNullOrEmpty( matchEntry.Groups[ "TagType" ].Value ); + int index = int.Parse( matchEntry.Groups[ "Index" ].Value ); + if ( isOpen ) + { + // Opening tag - starting a new entry, save entry id + ChangeState( TState.EStateSeenEntryStart ); + SaveCurrentEntryIfValidState(); + + iCurrentEntryId = index; + iWorkInProgressThread = CSVThread.New(); + } + else + { + // Closing tag, we should've finished an entry now. + // Validate the index is as we expect + CheckExpectedIndexId( index ); + ChangeState( TState.EStateSeenEntryEnd ); + SaveCurrentEntryIfValidState(); + } + } + + return matchEntry.Success; + } + + private bool TryToParseTimestamp( string aLine ) + { + Match match = KRegExTimestamp.Match( aLine ); + if ( match.Success ) + { + // Get time value + long timestamp = long.Parse( match.Groups[ "Timestamp" ].Value ); + if ( iParser.CurrentDataSet != null ) + { + iParser.CurrentDataSet.TimeStamp = timestamp; + } + } + + return match.Success; + } + + private bool TryToParseSupportedTags( string aLine ) + { + Match matchStandardFields = KRegExTagTypes.Match( aLine ); + if ( matchStandardFields.Success ) + { + if ( iWorkInProgressThread == null ) + { + throw new Exception( "Corruption detected - work in progress thread is null" ); + } + + // Check the index is what we expect it to be + int index = int.Parse( matchStandardFields.Groups[ "Index" ].Value ); + CheckExpectedIndexId( index ); + + // Now digest the tag body + string body = matchStandardFields.Groups[ "Body" ].Value; + string tagName = matchStandardFields.Groups[ "TagName" ].Value; + if ( tagName == "THREAD_NAME" ) + { + iWorkInProgressThread.ThreadName = body; + ChangeState( TState.EStateSeenThreadName ); + } + else if ( tagName == "PROCESS_NAME" ) + { + iWorkInProgressThread.ProcessName = body; + ChangeState( TState.EStateSeenProcessName ); + } + else if ( tagName == "CHUNK_NAME" ) + { + iWorkInProgressThread.ChunkName = body; + ChangeState( TState.EStateSeenChunkName ); + } + else if ( tagName == "FIELDS" ) + { + string[] elements = body.Trim().Split( ',' ); + ExtractFields( elements ); + ChangeState( TState.EStateSeenFieldBody ); + } + } + + return matchStandardFields.Success; + } + + private void ChangeState( TState aState ) + { + iState = aState; + } + + private void CheckExpectedIndexId( int aValue ) + { + if ( aValue != iCurrentEntryId ) + { + throw new Exception( "Corruption detected - index id incorrect" ); + } + } + + private void SaveCurrentEntryIfValidState() + { + if ( iWorkInProgressThread != null ) + { + // Perhaps we didn't encounter the closing tag for some odd reason? + if ( iState == TState.EStateSeenFieldBody || iState == TState.EStateSeenEntryEnd ) + { + iConstructedEntry = iWorkInProgressThread; + iWorkInProgressThread = null; + } + } + } + + private void ExtractFields( string[] aValues ) + { + if ( aValues.Length != KExpectedFieldCount ) + { + throw new Exception( "Corruption detected - field count incorrect" ); + } + + // TID + iWorkInProgressThread.ThreadId = ParseDecimalValue( aValues[ 0 ] ); + + // CHUNK + iWorkInProgressThread.ChunkHandle = ParseHexValue( aValues[ 1 ] ); + iWorkInProgressThread.ChunkBaseAddress = ParseHexValue( aValues[ 2 ] ); + + // HEAP + iWorkInProgressThread.SizeCurrent = ParseDecimalValue( aValues[ 3 ] ); + iWorkInProgressThread.SizeMin = ParseDecimalValue( aValues[ 4 ] ); + iWorkInProgressThread.SizeMax = ParseDecimalValue( aValues[ 5 ] ); + + // FIRST FREE CELL + iWorkInProgressThread.FirstFreeCellAddress = ParseHexValue( aValues[ 6 ] ); + iWorkInProgressThread.FirstFreeCellLength = ParseDecimalValue( aValues[ 7 ] ); + + // OTHER FREE CELL INFO + iWorkInProgressThread.FreeCellCount = ParseDecimalValue( aValues[ 8 ] ); + iWorkInProgressThread.FreeSpaceTotal = ParseDecimalValue( aValues[ 9 ] ); + iWorkInProgressThread.FreeSpaceSlack = ParseDecimalValue( aValues[ 10 ] ); + iWorkInProgressThread.FreeCellLargest = ParseDecimalValue( aValues[ 11 ] ); + + // ALLOC CELL INFO + iWorkInProgressThread.AllocCellLargest = ParseDecimalValue( aValues[ 12 ] ); + iWorkInProgressThread.AllocCellCount = ParseDecimalValue( aValues[ 13 ] ); + iWorkInProgressThread.AllocSpaceTotal = ParseDecimalValue( aValues[ 15 ] ); // NB: this is item 15, not 14! + + // MISC + iWorkInProgressThread.MinCellSize = ParseDecimalValue( aValues[ 14 ] ); + iWorkInProgressThread.IsSharedHeap = ( ParseDecimalValue( aValues[ 16 ] ) != 0 ); + } + + private static long ParseHexValue( string aItem ) + { + long ret = 0; + // + if ( aItem.Length > 0 ) + { + const string KHexPrefix = "0x"; + if ( aItem.IndexOf( KHexPrefix ) == 0 ) + { + aItem = aItem.Substring( KHexPrefix.Length ); + } + + ret = System.Convert.ToInt32( aItem, 16 ); + } + // + return ret; + } + + private static long ParseDecimalValue( string aItem ) + { + long ret = 0; + // + if ( aItem.Length > 0 ) + { + ret = System.Convert.ToInt32( aItem ); + } + // + return ret; + } + #endregion + + #region Internal constants + private const int KExpectedFieldCount = 17; + #endregion + + #region Internal regular expression + private static Regex KRegExEntry = new Regex( + "\\<(?/|)ENTRY_(?[0-9]{4})\\>", + RegexOptions.Singleline + | RegexOptions.CultureInvariant + | RegexOptions.IgnorePatternWhitespace + | RegexOptions.Compiled + ); + + private static Regex KRegExTimestamp = new Regex( + "\\(?[0-9].+?)\\", + RegexOptions.Singleline + | RegexOptions.CultureInvariant + | RegexOptions.IgnorePatternWhitespace + | RegexOptions.Compiled + ); + + // + // Regular expression built for C# on: Wed, Sep 10, 2008, 09:39:13 AM + // Using Expresso Version: 3.0.2766, http://www.ultrapico.com + // + // A description of the regular expression: + // + // Literal < + // [TagName]: A named capture group. [THREAD_NAME|PROCESS_NAME|CHUNK_NAME|FIELDS] + // Select from 4 alternatives + // THREAD_NAME + // THREAD_NAME + // PROCESS_NAME + // PROCESS_NAME + // CHUNK_NAME + // CHUNK_NAME + // FIELDS + // FIELDS + // _ + // [Index]: A named capture group. [[0-9]{4}] + // Any character in this class: [0-9], exactly 4 repetitions + // Literal > + // [Body]: A named capture group. [.+?] + // Any character, one or more repetitions, as few as possible + // \ + // + // + // + private static Regex KRegExTagTypes = new Regex( + "\\<(?THREAD_NAME|PROCESS_NAME|CHUNK_NAME|FIELDS)_(?" + + "[0-9]{4})\\>(?.+?)\\", + RegexOptions.Singleline + | RegexOptions.CultureInvariant + | RegexOptions.IgnorePatternWhitespace + | RegexOptions.Compiled + ); + #endregion + + #region Data members + private readonly CSVThreadParser iParser; + private TState iState = TState.EStateIdle; + private int iCurrentEntryId = -1; + private CSVThread iWorkInProgressThread = null; + private CSVThread iConstructedEntry = null; + #endregion + } +}