| /* |
| * [The "BSD licence"] |
| * Copyright (c) 2005-2008 Terence Parr |
| * All rights reserved. |
| * |
| * Conversion to C#: |
| * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. 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. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. |
| */ |
| |
| namespace Antlr.Runtime.Debug |
| { |
| using System.Collections.Generic; |
| using System.Collections.ObjectModel; |
| using Antlr.Runtime.Debug.Misc; |
| |
| using Array = System.Array; |
| using CLSCompliantAttribute = System.CLSCompliantAttribute; |
| using Console = System.Console; |
| using DateTime = System.DateTime; |
| using Environment = System.Environment; |
| using Math = System.Math; |
| using StringBuilder = System.Text.StringBuilder; |
| |
| /** <summary>Using the debug event interface, track what is happening in the parser |
| * and record statistics about the runtime. |
| */ |
| public class Profiler : BlankDebugEventListener |
| { |
| public static readonly string DataSeparator = "\t"; |
| public static readonly string NewLine = Environment.NewLine; |
| |
| internal static bool dump = false; |
| |
| /** Because I may change the stats, I need to track that for later |
| * computations to be consistent. |
| */ |
| public static readonly string Version = "3"; |
| public static readonly string RuntimeStatsFilename = "runtime.stats"; |
| |
| /** Ack, should not store parser; can't do remote stuff. Well, we pass |
| * input stream around too so I guess it's ok. |
| */ |
| public DebugParser parser = null; |
| |
| // working variables |
| |
| [CLSCompliant(false)] |
| protected int ruleLevel = 0; |
| //protected int decisionLevel = 0; |
| protected IToken lastRealTokenTouchedInDecision; |
| protected Dictionary<string, bool> uniqueRules = new Dictionary<string, bool>(); |
| protected Stack<string> currentGrammarFileName = new Stack<string>(); |
| protected Stack<string> currentRuleName = new Stack<string>(); |
| protected Stack<int> currentLine = new Stack<int>(); |
| protected Stack<int> currentPos = new Stack<int>(); |
| |
| // Vector<DecisionStats> |
| //protected Vector decisions = new Vector(200); // need setSize |
| protected DoubleKeyMap<string, int, DecisionDescriptor> decisions = new DoubleKeyMap<string, int, DecisionDescriptor>(); |
| |
| // Record a DecisionData for each decision we hit while parsing |
| private List<DecisionEvent> decisionEvents = new List<DecisionEvent>(); |
| protected Stack<DecisionEvent> decisionStack = new Stack<DecisionEvent>(); |
| |
| protected int backtrackDepth; |
| |
| ProfileStats stats = new ProfileStats(); |
| |
| public Profiler() |
| { |
| } |
| |
| public Profiler(DebugParser parser) |
| { |
| this.parser = parser; |
| } |
| |
| public override void EnterRule(string grammarFileName, string ruleName) |
| { |
| //System.out.println("enterRule "+grammarFileName+":"+ruleName); |
| ruleLevel++; |
| stats.numRuleInvocations++; |
| uniqueRules.Add(grammarFileName + ":" + ruleName, true); |
| stats.maxRuleInvocationDepth = Math.Max(stats.maxRuleInvocationDepth, ruleLevel); |
| currentGrammarFileName.Push(grammarFileName); |
| currentRuleName.Push(ruleName); |
| } |
| |
| public override void ExitRule(string grammarFileName, string ruleName) |
| { |
| ruleLevel--; |
| currentGrammarFileName.Pop(); |
| currentRuleName.Pop(); |
| } |
| |
| /** Track memoization; this is not part of standard debug interface |
| * but is triggered by profiling. Code gen inserts an override |
| * for this method in the recognizer, which triggers this method. |
| * Called from alreadyParsedRule(). |
| */ |
| public virtual void ExamineRuleMemoization(IIntStream input, |
| int ruleIndex, |
| int stopIndex, // index or MEMO_RULE_UNKNOWN... |
| string ruleName) |
| { |
| if (dump) |
| Console.WriteLine("examine memo " + ruleName + " at " + input.Index + ": " + stopIndex); |
| if (stopIndex == BaseRecognizer.MemoRuleUnknown) |
| { |
| //System.out.println("rule "+ruleIndex+" missed @ "+input.index()); |
| stats.numMemoizationCacheMisses++; |
| stats.numGuessingRuleInvocations++; // we'll have to enter |
| CurrentDecision().numMemoizationCacheMisses++; |
| } |
| else |
| { |
| // regardless of rule success/failure, if in cache, we have a cache hit |
| //System.out.println("rule "+ruleIndex+" hit @ "+input.index()); |
| stats.numMemoizationCacheHits++; |
| CurrentDecision().numMemoizationCacheHits++; |
| } |
| } |
| |
| /** Warning: doesn't track success/failure, just unique recording event */ |
| public virtual void Memoize(IIntStream input, |
| int ruleIndex, |
| int ruleStartIndex, |
| string ruleName) |
| { |
| // count how many entries go into table |
| if (dump) |
| Console.WriteLine("memoize " + ruleName); |
| stats.numMemoizationCacheEntries++; |
| } |
| |
| public override void Location(int line, int pos) |
| { |
| currentLine.Push(line); |
| currentPos.Push(pos); |
| } |
| |
| public override void EnterDecision(int decisionNumber, bool couldBacktrack) |
| { |
| lastRealTokenTouchedInDecision = null; |
| stats.numDecisionEvents++; |
| int startingLookaheadIndex = parser.TokenStream.Index; |
| ITokenStream input = parser.TokenStream; |
| if (dump) |
| { |
| Console.WriteLine("enterDecision canBacktrack=" + couldBacktrack + " " + decisionNumber + |
| " backtrack depth " + backtrackDepth + |
| " @ " + input.Get(input.Index) + |
| " rule " + LocationDescription()); |
| } |
| string g = currentGrammarFileName.Peek(); |
| DecisionDescriptor descriptor = decisions.Get(g, decisionNumber); |
| if (descriptor == null) |
| { |
| descriptor = new DecisionDescriptor(); |
| decisions.Put(g, decisionNumber, descriptor); |
| descriptor.decision = decisionNumber; |
| descriptor.fileName = currentGrammarFileName.Peek(); |
| descriptor.ruleName = currentRuleName.Peek(); |
| descriptor.line = currentLine.Peek(); |
| descriptor.pos = currentPos.Peek(); |
| descriptor.couldBacktrack = couldBacktrack; |
| } |
| descriptor.n++; |
| |
| DecisionEvent d = new DecisionEvent(); |
| decisionStack.Push(d); |
| d.decision = descriptor; |
| d.startTime = DateTime.Now; |
| d.startIndex = startingLookaheadIndex; |
| } |
| |
| public override void ExitDecision(int decisionNumber) |
| { |
| DecisionEvent d = decisionStack.Pop(); |
| d.stopTime = DateTime.Now; |
| |
| int lastTokenIndex = lastRealTokenTouchedInDecision.TokenIndex; |
| int numHidden = GetNumberOfHiddenTokens(d.startIndex, lastTokenIndex); |
| int depth = lastTokenIndex - d.startIndex - numHidden + 1; // +1 counts consuming start token as 1 |
| d.k = depth; |
| d.decision.maxk = Math.Max(d.decision.maxk, depth); |
| |
| if (dump) |
| { |
| Console.WriteLine("exitDecision " + decisionNumber + " in " + d.decision.ruleName + |
| " lookahead " + d.k + " max token " + lastRealTokenTouchedInDecision); |
| } |
| |
| decisionEvents.Add(d); // done with decision; track all |
| } |
| |
| public override void ConsumeToken(IToken token) |
| { |
| if (dump) |
| Console.WriteLine("consume token " + token); |
| |
| if (!InDecision) |
| { |
| stats.numTokens++; |
| return; |
| } |
| |
| if (lastRealTokenTouchedInDecision == null || |
| lastRealTokenTouchedInDecision.TokenIndex < token.TokenIndex) |
| { |
| lastRealTokenTouchedInDecision = token; |
| } |
| DecisionEvent d = CurrentDecision(); |
| // compute lookahead depth |
| int thisRefIndex = token.TokenIndex; |
| int numHidden = GetNumberOfHiddenTokens(d.startIndex, thisRefIndex); |
| int depth = thisRefIndex - d.startIndex - numHidden + 1; // +1 counts consuming start token as 1 |
| //d.maxk = Math.max(d.maxk, depth); |
| if (dump) |
| { |
| Console.WriteLine("consume " + thisRefIndex + " " + depth + " tokens ahead in " + |
| d.decision.ruleName + "-" + d.decision.decision + " start index " + d.startIndex); |
| } |
| } |
| |
| /** The parser is in a decision if the decision depth > 0. This |
| * works for backtracking also, which can have nested decisions. |
| */ |
| public virtual bool InDecision |
| { |
| get |
| { |
| return decisionStack.Count > 0; |
| } |
| } |
| |
| public override void ConsumeHiddenToken(IToken token) |
| { |
| //System.out.println("consume hidden token "+token); |
| if (!InDecision) |
| stats.numHiddenTokens++; |
| } |
| |
| /** Track refs to lookahead if in a fixed/nonfixed decision. |
| */ |
| public override void LT(int i, IToken t) |
| { |
| if (InDecision && i > 0) |
| { |
| DecisionEvent d = CurrentDecision(); |
| if (dump) |
| { |
| Console.WriteLine("LT(" + i + ")=" + t + " index " + t.TokenIndex + " relative to " + d.decision.ruleName + "-" + |
| d.decision.decision + " start index " + d.startIndex); |
| } |
| |
| if (lastRealTokenTouchedInDecision == null || |
| lastRealTokenTouchedInDecision.TokenIndex < t.TokenIndex) |
| { |
| lastRealTokenTouchedInDecision = t; |
| if (dump) |
| Console.WriteLine("set last token " + lastRealTokenTouchedInDecision); |
| } |
| // get starting index off stack |
| // int stackTop = lookaheadStack.size()-1; |
| // Integer startingIndex = (Integer)lookaheadStack.get(stackTop); |
| // // compute lookahead depth |
| // int thisRefIndex = parser.getTokenStream().index(); |
| // int numHidden = |
| // getNumberOfHiddenTokens(startingIndex.intValue(), thisRefIndex); |
| // int depth = i + thisRefIndex - startingIndex.intValue() - numHidden; |
| // /* |
| // System.out.println("LT("+i+") @ index "+thisRefIndex+" is depth "+depth+ |
| // " max is "+maxLookaheadInCurrentDecision); |
| // */ |
| // if ( depth>maxLookaheadInCurrentDecision ) { |
| // maxLookaheadInCurrentDecision = depth; |
| // } |
| // d.maxk = currentDecision()/ |
| } |
| } |
| |
| /** Track backtracking decisions. You'll see a fixed or cyclic decision |
| * and then a backtrack. |
| * |
| * enter rule |
| * ... |
| * enter decision |
| * LA and possibly consumes (for cyclic DFAs) |
| * begin backtrack level |
| * mark m |
| * rewind m |
| * end backtrack level, success |
| * exit decision |
| * ... |
| * exit rule |
| */ |
| public override void BeginBacktrack(int level) |
| { |
| if (dump) |
| Console.WriteLine("enter backtrack " + level); |
| backtrackDepth++; |
| DecisionEvent e = CurrentDecision(); |
| if (e.decision.couldBacktrack) |
| { |
| stats.numBacktrackOccurrences++; |
| e.decision.numBacktrackOccurrences++; |
| e.backtracks = true; |
| } |
| } |
| |
| /** Successful or not, track how much lookahead synpreds use */ |
| public override void EndBacktrack(int level, bool successful) |
| { |
| if (dump) |
| Console.WriteLine("exit backtrack " + level + ": " + successful); |
| backtrackDepth--; |
| } |
| |
| public override void Mark(int i) |
| { |
| if (dump) |
| Console.WriteLine("mark " + i); |
| } |
| |
| public override void Rewind(int i) |
| { |
| if (dump) |
| Console.WriteLine("rewind " + i); |
| } |
| |
| public override void Rewind() |
| { |
| if (dump) |
| Console.WriteLine("rewind"); |
| } |
| |
| protected virtual DecisionEvent CurrentDecision() |
| { |
| return decisionStack.Peek(); |
| } |
| |
| public override void RecognitionException(RecognitionException e) |
| { |
| stats.numReportedErrors++; |
| } |
| |
| public override void SemanticPredicate(bool result, string predicate) |
| { |
| stats.numSemanticPredicates++; |
| if (InDecision) |
| { |
| DecisionEvent d = CurrentDecision(); |
| d.evalSemPred = true; |
| d.decision.numSemPredEvals++; |
| if (dump) |
| { |
| Console.WriteLine("eval " + predicate + " in " + d.decision.ruleName + "-" + |
| d.decision.decision); |
| } |
| } |
| } |
| |
| public override void Terminate() |
| { |
| foreach (DecisionEvent e in decisionEvents) |
| { |
| //System.out.println("decision "+e.decision.decision+": k="+e.k); |
| e.decision.avgk += e.k; |
| stats.avgkPerDecisionEvent += e.k; |
| if (e.backtracks) |
| { // doesn't count gated syn preds on DFA edges |
| stats.avgkPerBacktrackingDecisionEvent += e.k; |
| } |
| } |
| stats.averageDecisionPercentBacktracks = 0.0f; |
| foreach (DecisionDescriptor d in decisions.Values()) |
| { |
| stats.numDecisionsCovered++; |
| d.avgk /= (float)d.n; |
| if (d.couldBacktrack) |
| { |
| stats.numDecisionsThatPotentiallyBacktrack++; |
| float percentBacktracks = d.numBacktrackOccurrences / (float)d.n; |
| //System.out.println("dec "+d.decision+" backtracks "+percentBacktracks*100+"%"); |
| stats.averageDecisionPercentBacktracks += percentBacktracks; |
| } |
| // ignore rules that backtrack along gated DFA edges |
| if (d.numBacktrackOccurrences > 0) |
| { |
| stats.numDecisionsThatDoBacktrack++; |
| } |
| } |
| stats.averageDecisionPercentBacktracks /= stats.numDecisionsThatPotentiallyBacktrack; |
| stats.averageDecisionPercentBacktracks *= 100; // it's a percentage |
| stats.avgkPerDecisionEvent /= stats.numDecisionEvents; |
| stats.avgkPerBacktrackingDecisionEvent /= (float)stats.numBacktrackOccurrences; |
| |
| Console.Error.WriteLine(ToString()); |
| Console.Error.WriteLine(GetDecisionStatsDump()); |
| |
| // String stats = toNotifyString(); |
| // try { |
| // Stats.writeReport(RUNTIME_STATS_FILENAME,stats); |
| // } |
| // catch (IOException ioe) { |
| // System.err.println(ioe); |
| // ioe.printStackTrace(System.err); |
| // } |
| } |
| |
| public virtual void SetParser(DebugParser parser) |
| { |
| this.parser = parser; |
| } |
| |
| // R E P O R T I N G |
| |
| public virtual string ToNotifyString() |
| { |
| StringBuilder buf = new StringBuilder(); |
| buf.Append(Version); |
| buf.Append('\t'); |
| buf.Append(parser.GetType().Name); |
| // buf.Append('\t'); |
| // buf.Append(numRuleInvocations); |
| // buf.Append('\t'); |
| // buf.Append(maxRuleInvocationDepth); |
| // buf.Append('\t'); |
| // buf.Append(numFixedDecisions); |
| // buf.Append('\t'); |
| // buf.Append(Stats.min(decisionMaxFixedLookaheads)); |
| // buf.Append('\t'); |
| // buf.Append(Stats.max(decisionMaxFixedLookaheads)); |
| // buf.Append('\t'); |
| // buf.Append(Stats.avg(decisionMaxFixedLookaheads)); |
| // buf.Append('\t'); |
| // buf.Append(Stats.stddev(decisionMaxFixedLookaheads)); |
| // buf.Append('\t'); |
| // buf.Append(numCyclicDecisions); |
| // buf.Append('\t'); |
| // buf.Append(Stats.min(decisionMaxCyclicLookaheads)); |
| // buf.Append('\t'); |
| // buf.Append(Stats.max(decisionMaxCyclicLookaheads)); |
| // buf.Append('\t'); |
| // buf.Append(Stats.avg(decisionMaxCyclicLookaheads)); |
| // buf.Append('\t'); |
| // buf.Append(Stats.stddev(decisionMaxCyclicLookaheads)); |
| // buf.Append('\t'); |
| // buf.Append(numBacktrackDecisions); |
| // buf.Append('\t'); |
| // buf.Append(Stats.min(toArray(decisionMaxSynPredLookaheads))); |
| // buf.Append('\t'); |
| // buf.Append(Stats.max(toArray(decisionMaxSynPredLookaheads))); |
| // buf.Append('\t'); |
| // buf.Append(Stats.avg(toArray(decisionMaxSynPredLookaheads))); |
| // buf.Append('\t'); |
| // buf.Append(Stats.stddev(toArray(decisionMaxSynPredLookaheads))); |
| // buf.Append('\t'); |
| // buf.Append(numSemanticPredicates); |
| // buf.Append('\t'); |
| // buf.Append(parser.getTokenStream().size()); |
| // buf.Append('\t'); |
| // buf.Append(numHiddenTokens); |
| // buf.Append('\t'); |
| // buf.Append(numCharsMatched); |
| // buf.Append('\t'); |
| // buf.Append(numHiddenCharsMatched); |
| // buf.Append('\t'); |
| // buf.Append(numberReportedErrors); |
| // buf.Append('\t'); |
| // buf.Append(numMemoizationCacheHits); |
| // buf.Append('\t'); |
| // buf.Append(numMemoizationCacheMisses); |
| // buf.Append('\t'); |
| // buf.Append(numGuessingRuleInvocations); |
| // buf.Append('\t'); |
| // buf.Append(numMemoizationCacheEntries); |
| return buf.ToString(); |
| } |
| |
| public override string ToString() |
| { |
| return ToString(GetReport()); |
| } |
| |
| public virtual ProfileStats GetReport() |
| { |
| //ITokenStream input = parser.TokenStream; |
| //for (int i = 0; i < input.Count && lastRealTokenTouchedInDecision != null && i <= lastRealTokenTouchedInDecision.TokenIndex; i++) |
| //{ |
| // IToken t = input.Get(i); |
| // if (t.Channel != TokenChannels.Default) |
| // { |
| // stats.numHiddenTokens++; |
| // stats.numHiddenCharsMatched += t.Text.Length; |
| // } |
| //} |
| stats.Version = Version; |
| stats.name = parser.GetType().Name; |
| stats.numUniqueRulesInvoked = uniqueRules.Count; |
| //stats.numCharsMatched = lastTokenConsumed.getStopIndex() + 1; |
| return stats; |
| } |
| |
| public virtual DoubleKeyMap<string, int, DecisionDescriptor> GetDecisionStats() |
| { |
| return decisions; |
| } |
| |
| public virtual ReadOnlyCollection<DecisionEvent> DecisionEvents |
| { |
| get |
| { |
| return decisionEvents.AsReadOnly(); |
| } |
| } |
| |
| public static string ToString(ProfileStats stats) |
| { |
| StringBuilder buf = new StringBuilder(); |
| buf.Append("ANTLR Runtime Report; Profile Version "); |
| buf.Append(stats.Version); |
| buf.Append(NewLine); |
| buf.Append("parser name "); |
| buf.Append(stats.name); |
| buf.Append(NewLine); |
| buf.Append("Number of rule invocations "); |
| buf.Append(stats.numRuleInvocations); |
| buf.Append(NewLine); |
| buf.Append("Number of unique rules visited "); |
| buf.Append(stats.numUniqueRulesInvoked); |
| buf.Append(NewLine); |
| buf.Append("Number of decision events "); |
| buf.Append(stats.numDecisionEvents); |
| buf.Append(NewLine); |
| buf.Append("Number of rule invocations while backtracking "); |
| buf.Append(stats.numGuessingRuleInvocations); |
| buf.Append(NewLine); |
| buf.Append("max rule invocation nesting depth "); |
| buf.Append(stats.maxRuleInvocationDepth); |
| buf.Append(NewLine); |
| // buf.Append("number of fixed lookahead decisions "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("min lookahead used in a fixed lookahead decision "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("max lookahead used in a fixed lookahead decision "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("average lookahead depth used in fixed lookahead decisions "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("standard deviation of depth used in fixed lookahead decisions "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("number of arbitrary lookahead decisions "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("min lookahead used in an arbitrary lookahead decision "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("max lookahead used in an arbitrary lookahead decision "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("average lookahead depth used in arbitrary lookahead decisions "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("standard deviation of depth used in arbitrary lookahead decisions "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("number of evaluated syntactic predicates "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("min lookahead used in a syntactic predicate "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("max lookahead used in a syntactic predicate "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("average lookahead depth used in syntactic predicates "); |
| // buf.Append(); |
| // buf.Append(newline); |
| // buf.Append("standard deviation of depth used in syntactic predicates "); |
| // buf.Append(); |
| // buf.Append(newline); |
| buf.Append("rule memoization cache size "); |
| buf.Append(stats.numMemoizationCacheEntries); |
| buf.Append(NewLine); |
| buf.Append("number of rule memoization cache hits "); |
| buf.Append(stats.numMemoizationCacheHits); |
| buf.Append(NewLine); |
| buf.Append("number of rule memoization cache misses "); |
| buf.Append(stats.numMemoizationCacheMisses); |
| buf.Append(NewLine); |
| // buf.Append("number of evaluated semantic predicates "); |
| // buf.Append(); |
| // buf.Append(newline); |
| buf.Append("number of tokens "); |
| buf.Append(stats.numTokens); |
| buf.Append(NewLine); |
| buf.Append("number of hidden tokens "); |
| buf.Append(stats.numHiddenTokens); |
| buf.Append(NewLine); |
| buf.Append("number of char "); |
| buf.Append(stats.numCharsMatched); |
| buf.Append(NewLine); |
| buf.Append("number of hidden char "); |
| buf.Append(stats.numHiddenCharsMatched); |
| buf.Append(NewLine); |
| buf.Append("number of syntax errors "); |
| buf.Append(stats.numReportedErrors); |
| buf.Append(NewLine); |
| return buf.ToString(); |
| } |
| |
| public virtual string GetDecisionStatsDump() |
| { |
| StringBuilder buf = new StringBuilder(); |
| buf.Append("location"); |
| buf.Append(DataSeparator); |
| buf.Append("n"); |
| buf.Append(DataSeparator); |
| buf.Append("avgk"); |
| buf.Append(DataSeparator); |
| buf.Append("maxk"); |
| buf.Append(DataSeparator); |
| buf.Append("synpred"); |
| buf.Append(DataSeparator); |
| buf.Append("sempred"); |
| buf.Append(DataSeparator); |
| buf.Append("canbacktrack"); |
| buf.Append("\n"); |
| foreach (string fileName in decisions.KeySet()) |
| { |
| foreach (int d in decisions.KeySet(fileName)) |
| { |
| DecisionDescriptor s = decisions.Get(fileName, d); |
| buf.Append(s.decision); |
| buf.Append("@"); |
| buf.Append(LocationDescription(s.fileName, s.ruleName, s.line, s.pos)); // decision number |
| buf.Append(DataSeparator); |
| buf.Append(s.n); |
| buf.Append(DataSeparator); |
| buf.Append(string.Format("{0}", s.avgk)); |
| buf.Append(DataSeparator); |
| buf.Append(s.maxk); |
| buf.Append(DataSeparator); |
| buf.Append(s.numBacktrackOccurrences); |
| buf.Append(DataSeparator); |
| buf.Append(s.numSemPredEvals); |
| buf.Append(DataSeparator); |
| buf.Append(s.couldBacktrack ? "1" : "0"); |
| buf.Append(NewLine); |
| } |
| } |
| return buf.ToString(); |
| } |
| |
| protected virtual int[] Trim(int[] X, int n) |
| { |
| if (n < X.Length) |
| { |
| int[] trimmed = new int[n]; |
| Array.Copy(X, 0, trimmed, 0, n); |
| X = trimmed; |
| } |
| return X; |
| } |
| |
| /** Get num hidden tokens between i..j inclusive */ |
| public virtual int GetNumberOfHiddenTokens(int i, int j) |
| { |
| int n = 0; |
| ITokenStream input = parser.TokenStream; |
| for (int ti = i; ti < input.Count && ti <= j; ti++) |
| { |
| IToken t = input.Get(ti); |
| if (t.Channel != TokenChannels.Default) |
| { |
| n++; |
| } |
| } |
| return n; |
| } |
| |
| protected virtual string LocationDescription() |
| { |
| return LocationDescription( |
| currentGrammarFileName.Peek(), |
| currentRuleName.Peek(), |
| currentLine.Peek(), |
| currentPos.Peek()); |
| } |
| |
| protected virtual string LocationDescription(string file, string rule, int line, int pos) |
| { |
| return file + ":" + line + ":" + pos + "(" + rule + ")"; |
| } |
| |
| public class ProfileStats |
| { |
| public string Version; |
| public string name; |
| public int numRuleInvocations; |
| public int numUniqueRulesInvoked; |
| public int numDecisionEvents; |
| public int numDecisionsCovered; |
| public int numDecisionsThatPotentiallyBacktrack; |
| public int numDecisionsThatDoBacktrack; |
| public int maxRuleInvocationDepth; |
| public float avgkPerDecisionEvent; |
| public float avgkPerBacktrackingDecisionEvent; |
| public float averageDecisionPercentBacktracks; |
| public int numBacktrackOccurrences; // doesn't count gated DFA edges |
| |
| public int numFixedDecisions; |
| public int minDecisionMaxFixedLookaheads; |
| public int maxDecisionMaxFixedLookaheads; |
| public int avgDecisionMaxFixedLookaheads; |
| public int stddevDecisionMaxFixedLookaheads; |
| public int numCyclicDecisions; |
| public int minDecisionMaxCyclicLookaheads; |
| public int maxDecisionMaxCyclicLookaheads; |
| public int avgDecisionMaxCyclicLookaheads; |
| public int stddevDecisionMaxCyclicLookaheads; |
| // int Stats.min(toArray(decisionMaxSynPredLookaheads); |
| // int Stats.max(toArray(decisionMaxSynPredLookaheads); |
| // int Stats.avg(toArray(decisionMaxSynPredLookaheads); |
| // int Stats.stddev(toArray(decisionMaxSynPredLookaheads); |
| public int numSemanticPredicates; |
| public int numTokens; |
| public int numHiddenTokens; |
| public int numCharsMatched; |
| public int numHiddenCharsMatched; |
| public int numReportedErrors; |
| public int numMemoizationCacheHits; |
| public int numMemoizationCacheMisses; |
| public int numGuessingRuleInvocations; |
| public int numMemoizationCacheEntries; |
| } |
| |
| public class DecisionDescriptor |
| { |
| public int decision; |
| public string fileName; |
| public string ruleName; |
| public int line; |
| public int pos; |
| public bool couldBacktrack; |
| |
| public int n; |
| public float avgk; // avg across all decision events |
| public int maxk; |
| public int numBacktrackOccurrences; |
| public int numSemPredEvals; |
| } |
| |
| // all about a specific exec of a single decision |
| public class DecisionEvent |
| { |
| public DecisionDescriptor decision; |
| public int startIndex; |
| public int k; |
| public bool backtracks; // doesn't count gated DFA edges |
| public bool evalSemPred; |
| public DateTime startTime; |
| public DateTime stopTime; |
| public int numMemoizationCacheHits; |
| public int numMemoizationCacheMisses; |
| } |
| } |
| } |