• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * [The "BSD licence"]
3  * Copyright (c) 2005-2008 Terence Parr
4  * All rights reserved.
5  *
6  * Conversion to C#:
7  * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 namespace Antlr.Runtime.Debug
34 {
35     using System.Collections.Generic;
36     using System.Collections.ObjectModel;
37     using Antlr.Runtime.Debug.Misc;
38 
39     using Array = System.Array;
40     using CLSCompliantAttribute = System.CLSCompliantAttribute;
41     using Console = System.Console;
42     using DateTime = System.DateTime;
43     using Environment = System.Environment;
44     using Math = System.Math;
45     using StringBuilder = System.Text.StringBuilder;
46 
47     /** <summary>Using the debug event interface, track what is happening in the parser
48      *  and record statistics about the runtime.
49      */
50     public class Profiler : BlankDebugEventListener
51     {
52         public static readonly string DataSeparator = "\t";
53         public static readonly string NewLine = Environment.NewLine;
54 
55         internal static bool dump = false;
56 
57         /** Because I may change the stats, I need to track that for later
58          *  computations to be consistent.
59          */
60         public static readonly string Version = "3";
61         public static readonly string RuntimeStatsFilename = "runtime.stats";
62 
63         /** Ack, should not store parser; can't do remote stuff.  Well, we pass
64          *  input stream around too so I guess it's ok.
65          */
66         public DebugParser parser = null;
67 
68         // working variables
69 
70         [CLSCompliant(false)]
71         protected int ruleLevel = 0;
72         //protected int decisionLevel = 0;
73         protected IToken lastRealTokenTouchedInDecision;
74         protected Dictionary<string, bool> uniqueRules = new Dictionary<string, bool>();
75         protected Stack<string> currentGrammarFileName = new Stack<string>();
76         protected Stack<string> currentRuleName = new Stack<string>();
77         protected Stack<int> currentLine = new Stack<int>();
78         protected Stack<int> currentPos = new Stack<int>();
79 
80         // Vector<DecisionStats>
81         //protected Vector decisions = new Vector(200); // need setSize
82         protected DoubleKeyMap<string, int, DecisionDescriptor> decisions = new DoubleKeyMap<string, int, DecisionDescriptor>();
83 
84         // Record a DecisionData for each decision we hit while parsing
85         private List<DecisionEvent> decisionEvents = new List<DecisionEvent>();
86         protected Stack<DecisionEvent> decisionStack = new Stack<DecisionEvent>();
87 
88         protected int backtrackDepth;
89 
90         ProfileStats stats = new ProfileStats();
91 
Profiler()92         public Profiler()
93         {
94         }
95 
Profiler(DebugParser parser)96         public Profiler(DebugParser parser)
97         {
98             this.parser = parser;
99         }
100 
EnterRule(string grammarFileName, string ruleName)101         public override void EnterRule(string grammarFileName, string ruleName)
102         {
103             //System.out.println("enterRule "+grammarFileName+":"+ruleName);
104             ruleLevel++;
105             stats.numRuleInvocations++;
106             uniqueRules.Add(grammarFileName + ":" + ruleName, true);
107             stats.maxRuleInvocationDepth = Math.Max(stats.maxRuleInvocationDepth, ruleLevel);
108             currentGrammarFileName.Push(grammarFileName);
109             currentRuleName.Push(ruleName);
110         }
111 
ExitRule(string grammarFileName, string ruleName)112         public override void ExitRule(string grammarFileName, string ruleName)
113         {
114             ruleLevel--;
115             currentGrammarFileName.Pop();
116             currentRuleName.Pop();
117         }
118 
119         /** Track memoization; this is not part of standard debug interface
120          *  but is triggered by profiling.  Code gen inserts an override
121          *  for this method in the recognizer, which triggers this method.
122          *  Called from alreadyParsedRule().
123          */
ExamineRuleMemoization(IIntStream input, int ruleIndex, int stopIndex, string ruleName)124         public virtual void ExamineRuleMemoization(IIntStream input,
125                                            int ruleIndex,
126                                            int stopIndex, // index or MEMO_RULE_UNKNOWN...
127                                            string ruleName)
128         {
129             if (dump)
130                 Console.WriteLine("examine memo " + ruleName + " at " + input.Index + ": " + stopIndex);
131             if (stopIndex == BaseRecognizer.MemoRuleUnknown)
132             {
133                 //System.out.println("rule "+ruleIndex+" missed @ "+input.index());
134                 stats.numMemoizationCacheMisses++;
135                 stats.numGuessingRuleInvocations++; // we'll have to enter
136                 CurrentDecision().numMemoizationCacheMisses++;
137             }
138             else
139             {
140                 // regardless of rule success/failure, if in cache, we have a cache hit
141                 //System.out.println("rule "+ruleIndex+" hit @ "+input.index());
142                 stats.numMemoizationCacheHits++;
143                 CurrentDecision().numMemoizationCacheHits++;
144             }
145         }
146 
147         /** Warning: doesn't track success/failure, just unique recording event */
Memoize(IIntStream input, int ruleIndex, int ruleStartIndex, string ruleName)148         public virtual void Memoize(IIntStream input,
149                             int ruleIndex,
150                             int ruleStartIndex,
151                             string ruleName)
152         {
153             // count how many entries go into table
154             if (dump)
155                 Console.WriteLine("memoize " + ruleName);
156             stats.numMemoizationCacheEntries++;
157         }
158 
Location(int line, int pos)159         public override void Location(int line, int pos)
160         {
161             currentLine.Push(line);
162             currentPos.Push(pos);
163         }
164 
EnterDecision(int decisionNumber, bool couldBacktrack)165         public override void EnterDecision(int decisionNumber, bool couldBacktrack)
166         {
167             lastRealTokenTouchedInDecision = null;
168             stats.numDecisionEvents++;
169             int startingLookaheadIndex = parser.TokenStream.Index;
170             ITokenStream input = parser.TokenStream;
171             if (dump)
172             {
173                 Console.WriteLine("enterDecision canBacktrack=" + couldBacktrack + " " + decisionNumber +
174                       " backtrack depth " + backtrackDepth +
175                       " @ " + input.Get(input.Index) +
176                       " rule " + LocationDescription());
177             }
178             string g = currentGrammarFileName.Peek();
179             DecisionDescriptor descriptor = decisions.Get(g, decisionNumber);
180             if (descriptor == null)
181             {
182                 descriptor = new DecisionDescriptor();
183                 decisions.Put(g, decisionNumber, descriptor);
184                 descriptor.decision = decisionNumber;
185                 descriptor.fileName = currentGrammarFileName.Peek();
186                 descriptor.ruleName = currentRuleName.Peek();
187                 descriptor.line = currentLine.Peek();
188                 descriptor.pos = currentPos.Peek();
189                 descriptor.couldBacktrack = couldBacktrack;
190             }
191             descriptor.n++;
192 
193             DecisionEvent d = new DecisionEvent();
194             decisionStack.Push(d);
195             d.decision = descriptor;
196             d.startTime = DateTime.Now;
197             d.startIndex = startingLookaheadIndex;
198         }
199 
ExitDecision(int decisionNumber)200         public override void ExitDecision(int decisionNumber)
201         {
202             DecisionEvent d = decisionStack.Pop();
203             d.stopTime = DateTime.Now;
204 
205             int lastTokenIndex = lastRealTokenTouchedInDecision.TokenIndex;
206             int numHidden = GetNumberOfHiddenTokens(d.startIndex, lastTokenIndex);
207             int depth = lastTokenIndex - d.startIndex - numHidden + 1; // +1 counts consuming start token as 1
208             d.k = depth;
209             d.decision.maxk = Math.Max(d.decision.maxk, depth);
210 
211             if (dump)
212             {
213                 Console.WriteLine("exitDecision " + decisionNumber + " in " + d.decision.ruleName +
214                                    " lookahead " + d.k + " max token " + lastRealTokenTouchedInDecision);
215             }
216 
217             decisionEvents.Add(d); // done with decision; track all
218         }
219 
ConsumeToken(IToken token)220         public override void ConsumeToken(IToken token)
221         {
222             if (dump)
223                 Console.WriteLine("consume token " + token);
224 
225             if (!InDecision)
226             {
227                 stats.numTokens++;
228                 return;
229             }
230 
231             if (lastRealTokenTouchedInDecision == null ||
232                  lastRealTokenTouchedInDecision.TokenIndex < token.TokenIndex)
233             {
234                 lastRealTokenTouchedInDecision = token;
235             }
236             DecisionEvent d = CurrentDecision();
237             // compute lookahead depth
238             int thisRefIndex = token.TokenIndex;
239             int numHidden = GetNumberOfHiddenTokens(d.startIndex, thisRefIndex);
240             int depth = thisRefIndex - d.startIndex - numHidden + 1; // +1 counts consuming start token as 1
241             //d.maxk = Math.max(d.maxk, depth);
242             if (dump)
243             {
244                 Console.WriteLine("consume " + thisRefIndex + " " + depth + " tokens ahead in " +
245                                    d.decision.ruleName + "-" + d.decision.decision + " start index " + d.startIndex);
246             }
247         }
248 
249         /** The parser is in a decision if the decision depth > 0.  This
250          *  works for backtracking also, which can have nested decisions.
251          */
252         public virtual bool InDecision
253         {
254             get
255             {
256                 return decisionStack.Count > 0;
257             }
258         }
259 
ConsumeHiddenToken(IToken token)260         public override void ConsumeHiddenToken(IToken token)
261         {
262             //System.out.println("consume hidden token "+token);
263             if (!InDecision)
264                 stats.numHiddenTokens++;
265         }
266 
267         /** Track refs to lookahead if in a fixed/nonfixed decision.
268          */
LT(int i, IToken t)269         public override void LT(int i, IToken t)
270         {
271             if (InDecision && i > 0)
272             {
273                 DecisionEvent d = CurrentDecision();
274                 if (dump)
275                 {
276                     Console.WriteLine("LT(" + i + ")=" + t + " index " + t.TokenIndex + " relative to " + d.decision.ruleName + "-" +
277                              d.decision.decision + " start index " + d.startIndex);
278                 }
279 
280                 if (lastRealTokenTouchedInDecision == null ||
281                      lastRealTokenTouchedInDecision.TokenIndex < t.TokenIndex)
282                 {
283                     lastRealTokenTouchedInDecision = t;
284                     if (dump)
285                         Console.WriteLine("set last token " + lastRealTokenTouchedInDecision);
286                 }
287                 // get starting index off stack
288                 //			int stackTop = lookaheadStack.size()-1;
289                 //			Integer startingIndex = (Integer)lookaheadStack.get(stackTop);
290                 //			// compute lookahead depth
291                 //			int thisRefIndex = parser.getTokenStream().index();
292                 //			int numHidden =
293                 //				getNumberOfHiddenTokens(startingIndex.intValue(), thisRefIndex);
294                 //			int depth = i + thisRefIndex - startingIndex.intValue() - numHidden;
295                 //			/*
296                 //			System.out.println("LT("+i+") @ index "+thisRefIndex+" is depth "+depth+
297                 //				" max is "+maxLookaheadInCurrentDecision);
298                 //			*/
299                 //			if ( depth>maxLookaheadInCurrentDecision ) {
300                 //				maxLookaheadInCurrentDecision = depth;
301                 //			}
302                 //			d.maxk = currentDecision()/
303             }
304         }
305 
306         /** Track backtracking decisions.  You'll see a fixed or cyclic decision
307          *  and then a backtrack.
308          *
309          * 		enter rule
310          * 		...
311          * 		enter decision
312          * 		LA and possibly consumes (for cyclic DFAs)
313          * 		begin backtrack level
314          * 		mark m
315          * 		rewind m
316          * 		end backtrack level, success
317          * 		exit decision
318          * 		...
319          * 		exit rule
320          */
BeginBacktrack(int level)321         public override void BeginBacktrack(int level)
322         {
323             if (dump)
324                 Console.WriteLine("enter backtrack " + level);
325             backtrackDepth++;
326             DecisionEvent e = CurrentDecision();
327             if (e.decision.couldBacktrack)
328             {
329                 stats.numBacktrackOccurrences++;
330                 e.decision.numBacktrackOccurrences++;
331                 e.backtracks = true;
332             }
333         }
334 
335         /** Successful or not, track how much lookahead synpreds use */
EndBacktrack(int level, bool successful)336         public override void EndBacktrack(int level, bool successful)
337         {
338             if (dump)
339                 Console.WriteLine("exit backtrack " + level + ": " + successful);
340             backtrackDepth--;
341         }
342 
Mark(int i)343         public override void Mark(int i)
344         {
345             if (dump)
346                 Console.WriteLine("mark " + i);
347         }
348 
Rewind(int i)349         public override void Rewind(int i)
350         {
351             if (dump)
352                 Console.WriteLine("rewind " + i);
353         }
354 
Rewind()355         public override void Rewind()
356         {
357             if (dump)
358                 Console.WriteLine("rewind");
359         }
360 
CurrentDecision()361         protected virtual DecisionEvent CurrentDecision()
362         {
363             return decisionStack.Peek();
364         }
365 
RecognitionException(RecognitionException e)366         public override void RecognitionException(RecognitionException e)
367         {
368             stats.numReportedErrors++;
369         }
370 
SemanticPredicate(bool result, string predicate)371         public override void SemanticPredicate(bool result, string predicate)
372         {
373             stats.numSemanticPredicates++;
374             if (InDecision)
375             {
376                 DecisionEvent d = CurrentDecision();
377                 d.evalSemPred = true;
378                 d.decision.numSemPredEvals++;
379                 if (dump)
380                 {
381                     Console.WriteLine("eval " + predicate + " in " + d.decision.ruleName + "-" +
382                                        d.decision.decision);
383                 }
384             }
385         }
386 
Terminate()387         public override void Terminate()
388         {
389             foreach (DecisionEvent e in decisionEvents)
390             {
391                 //System.out.println("decision "+e.decision.decision+": k="+e.k);
392                 e.decision.avgk += e.k;
393                 stats.avgkPerDecisionEvent += e.k;
394                 if (e.backtracks)
395                 { // doesn't count gated syn preds on DFA edges
396                     stats.avgkPerBacktrackingDecisionEvent += e.k;
397                 }
398             }
399             stats.averageDecisionPercentBacktracks = 0.0f;
400             foreach (DecisionDescriptor d in decisions.Values())
401             {
402                 stats.numDecisionsCovered++;
403                 d.avgk /= (float)d.n;
404                 if (d.couldBacktrack)
405                 {
406                     stats.numDecisionsThatPotentiallyBacktrack++;
407                     float percentBacktracks = d.numBacktrackOccurrences / (float)d.n;
408                     //System.out.println("dec "+d.decision+" backtracks "+percentBacktracks*100+"%");
409                     stats.averageDecisionPercentBacktracks += percentBacktracks;
410                 }
411                 // ignore rules that backtrack along gated DFA edges
412                 if (d.numBacktrackOccurrences > 0)
413                 {
414                     stats.numDecisionsThatDoBacktrack++;
415                 }
416             }
417             stats.averageDecisionPercentBacktracks /= stats.numDecisionsThatPotentiallyBacktrack;
418             stats.averageDecisionPercentBacktracks *= 100; // it's a percentage
419             stats.avgkPerDecisionEvent /= stats.numDecisionEvents;
420             stats.avgkPerBacktrackingDecisionEvent /= (float)stats.numBacktrackOccurrences;
421 
422             Console.Error.WriteLine(ToString());
423             Console.Error.WriteLine(GetDecisionStatsDump());
424 
425             //		String stats = toNotifyString();
426             //		try {
427             //			Stats.writeReport(RUNTIME_STATS_FILENAME,stats);
428             //		}
429             //		catch (IOException ioe) {
430             //			System.err.println(ioe);
431             //			ioe.printStackTrace(System.err);
432             //		}
433         }
434 
SetParser(DebugParser parser)435         public virtual void SetParser(DebugParser parser)
436         {
437             this.parser = parser;
438         }
439 
440         // R E P O R T I N G
441 
ToNotifyString()442         public virtual string ToNotifyString()
443         {
444             StringBuilder buf = new StringBuilder();
445             buf.Append(Version);
446             buf.Append('\t');
447             buf.Append(parser.GetType().Name);
448             //		buf.Append('\t');
449             //		buf.Append(numRuleInvocations);
450             //		buf.Append('\t');
451             //		buf.Append(maxRuleInvocationDepth);
452             //		buf.Append('\t');
453             //		buf.Append(numFixedDecisions);
454             //		buf.Append('\t');
455             //		buf.Append(Stats.min(decisionMaxFixedLookaheads));
456             //		buf.Append('\t');
457             //		buf.Append(Stats.max(decisionMaxFixedLookaheads));
458             //		buf.Append('\t');
459             //		buf.Append(Stats.avg(decisionMaxFixedLookaheads));
460             //		buf.Append('\t');
461             //		buf.Append(Stats.stddev(decisionMaxFixedLookaheads));
462             //		buf.Append('\t');
463             //		buf.Append(numCyclicDecisions);
464             //		buf.Append('\t');
465             //		buf.Append(Stats.min(decisionMaxCyclicLookaheads));
466             //		buf.Append('\t');
467             //		buf.Append(Stats.max(decisionMaxCyclicLookaheads));
468             //		buf.Append('\t');
469             //		buf.Append(Stats.avg(decisionMaxCyclicLookaheads));
470             //		buf.Append('\t');
471             //		buf.Append(Stats.stddev(decisionMaxCyclicLookaheads));
472             //		buf.Append('\t');
473             //		buf.Append(numBacktrackDecisions);
474             //		buf.Append('\t');
475             //		buf.Append(Stats.min(toArray(decisionMaxSynPredLookaheads)));
476             //		buf.Append('\t');
477             //		buf.Append(Stats.max(toArray(decisionMaxSynPredLookaheads)));
478             //		buf.Append('\t');
479             //		buf.Append(Stats.avg(toArray(decisionMaxSynPredLookaheads)));
480             //		buf.Append('\t');
481             //		buf.Append(Stats.stddev(toArray(decisionMaxSynPredLookaheads)));
482             //		buf.Append('\t');
483             //		buf.Append(numSemanticPredicates);
484             //		buf.Append('\t');
485             //		buf.Append(parser.getTokenStream().size());
486             //		buf.Append('\t');
487             //		buf.Append(numHiddenTokens);
488             //		buf.Append('\t');
489             //		buf.Append(numCharsMatched);
490             //		buf.Append('\t');
491             //		buf.Append(numHiddenCharsMatched);
492             //		buf.Append('\t');
493             //		buf.Append(numberReportedErrors);
494             //		buf.Append('\t');
495             //		buf.Append(numMemoizationCacheHits);
496             //		buf.Append('\t');
497             //		buf.Append(numMemoizationCacheMisses);
498             //		buf.Append('\t');
499             //		buf.Append(numGuessingRuleInvocations);
500             //		buf.Append('\t');
501             //		buf.Append(numMemoizationCacheEntries);
502             return buf.ToString();
503         }
504 
ToString()505         public override string ToString()
506         {
507             return ToString(GetReport());
508         }
509 
GetReport()510         public virtual ProfileStats GetReport()
511         {
512             //ITokenStream input = parser.TokenStream;
513             //for (int i = 0; i < input.Count && lastRealTokenTouchedInDecision != null && i <= lastRealTokenTouchedInDecision.TokenIndex; i++)
514             //{
515             //    IToken t = input.Get(i);
516             //    if (t.Channel != TokenChannels.Default)
517             //    {
518             //        stats.numHiddenTokens++;
519             //        stats.numHiddenCharsMatched += t.Text.Length;
520             //    }
521             //}
522             stats.Version = Version;
523             stats.name = parser.GetType().Name;
524             stats.numUniqueRulesInvoked = uniqueRules.Count;
525             //stats.numCharsMatched = lastTokenConsumed.getStopIndex() + 1;
526             return stats;
527         }
528 
GetDecisionStats()529         public virtual DoubleKeyMap<string, int, DecisionDescriptor> GetDecisionStats()
530         {
531             return decisions;
532         }
533 
534         public virtual ReadOnlyCollection<DecisionEvent> DecisionEvents
535         {
536             get
537             {
538                 return decisionEvents.AsReadOnly();
539             }
540         }
541 
ToString(ProfileStats stats)542         public static string ToString(ProfileStats stats)
543         {
544             StringBuilder buf = new StringBuilder();
545             buf.Append("ANTLR Runtime Report; Profile Version ");
546             buf.Append(stats.Version);
547             buf.Append(NewLine);
548             buf.Append("parser name ");
549             buf.Append(stats.name);
550             buf.Append(NewLine);
551             buf.Append("Number of rule invocations ");
552             buf.Append(stats.numRuleInvocations);
553             buf.Append(NewLine);
554             buf.Append("Number of unique rules visited ");
555             buf.Append(stats.numUniqueRulesInvoked);
556             buf.Append(NewLine);
557             buf.Append("Number of decision events ");
558             buf.Append(stats.numDecisionEvents);
559             buf.Append(NewLine);
560             buf.Append("Number of rule invocations while backtracking ");
561             buf.Append(stats.numGuessingRuleInvocations);
562             buf.Append(NewLine);
563             buf.Append("max rule invocation nesting depth ");
564             buf.Append(stats.maxRuleInvocationDepth);
565             buf.Append(NewLine);
566             //		buf.Append("number of fixed lookahead decisions ");
567             //		buf.Append();
568             //		buf.Append(newline);
569             //		buf.Append("min lookahead used in a fixed lookahead decision ");
570             //		buf.Append();
571             //		buf.Append(newline);
572             //		buf.Append("max lookahead used in a fixed lookahead decision ");
573             //		buf.Append();
574             //		buf.Append(newline);
575             //		buf.Append("average lookahead depth used in fixed lookahead decisions ");
576             //		buf.Append();
577             //		buf.Append(newline);
578             //		buf.Append("standard deviation of depth used in fixed lookahead decisions ");
579             //		buf.Append();
580             //		buf.Append(newline);
581             //		buf.Append("number of arbitrary lookahead decisions ");
582             //		buf.Append();
583             //		buf.Append(newline);
584             //		buf.Append("min lookahead used in an arbitrary lookahead decision ");
585             //		buf.Append();
586             //		buf.Append(newline);
587             //		buf.Append("max lookahead used in an arbitrary lookahead decision ");
588             //		buf.Append();
589             //		buf.Append(newline);
590             //		buf.Append("average lookahead depth used in arbitrary lookahead decisions ");
591             //		buf.Append();
592             //		buf.Append(newline);
593             //		buf.Append("standard deviation of depth used in arbitrary lookahead decisions ");
594             //		buf.Append();
595             //		buf.Append(newline);
596             //		buf.Append("number of evaluated syntactic predicates ");
597             //		buf.Append();
598             //		buf.Append(newline);
599             //		buf.Append("min lookahead used in a syntactic predicate ");
600             //		buf.Append();
601             //		buf.Append(newline);
602             //		buf.Append("max lookahead used in a syntactic predicate ");
603             //		buf.Append();
604             //		buf.Append(newline);
605             //		buf.Append("average lookahead depth used in syntactic predicates ");
606             //		buf.Append();
607             //		buf.Append(newline);
608             //		buf.Append("standard deviation of depth used in syntactic predicates ");
609             //		buf.Append();
610             //		buf.Append(newline);
611             buf.Append("rule memoization cache size ");
612             buf.Append(stats.numMemoizationCacheEntries);
613             buf.Append(NewLine);
614             buf.Append("number of rule memoization cache hits ");
615             buf.Append(stats.numMemoizationCacheHits);
616             buf.Append(NewLine);
617             buf.Append("number of rule memoization cache misses ");
618             buf.Append(stats.numMemoizationCacheMisses);
619             buf.Append(NewLine);
620             //		buf.Append("number of evaluated semantic predicates ");
621             //		buf.Append();
622             //		buf.Append(newline);
623             buf.Append("number of tokens ");
624             buf.Append(stats.numTokens);
625             buf.Append(NewLine);
626             buf.Append("number of hidden tokens ");
627             buf.Append(stats.numHiddenTokens);
628             buf.Append(NewLine);
629             buf.Append("number of char ");
630             buf.Append(stats.numCharsMatched);
631             buf.Append(NewLine);
632             buf.Append("number of hidden char ");
633             buf.Append(stats.numHiddenCharsMatched);
634             buf.Append(NewLine);
635             buf.Append("number of syntax errors ");
636             buf.Append(stats.numReportedErrors);
637             buf.Append(NewLine);
638             return buf.ToString();
639         }
640 
GetDecisionStatsDump()641         public virtual string GetDecisionStatsDump()
642         {
643             StringBuilder buf = new StringBuilder();
644             buf.Append("location");
645             buf.Append(DataSeparator);
646             buf.Append("n");
647             buf.Append(DataSeparator);
648             buf.Append("avgk");
649             buf.Append(DataSeparator);
650             buf.Append("maxk");
651             buf.Append(DataSeparator);
652             buf.Append("synpred");
653             buf.Append(DataSeparator);
654             buf.Append("sempred");
655             buf.Append(DataSeparator);
656             buf.Append("canbacktrack");
657             buf.Append("\n");
658             foreach (string fileName in decisions.KeySet())
659             {
660                 foreach (int d in decisions.KeySet(fileName))
661                 {
662                     DecisionDescriptor s = decisions.Get(fileName, d);
663                     buf.Append(s.decision);
664                     buf.Append("@");
665                     buf.Append(LocationDescription(s.fileName, s.ruleName, s.line, s.pos)); // decision number
666                     buf.Append(DataSeparator);
667                     buf.Append(s.n);
668                     buf.Append(DataSeparator);
669                     buf.Append(string.Format("{0}", s.avgk));
670                     buf.Append(DataSeparator);
671                     buf.Append(s.maxk);
672                     buf.Append(DataSeparator);
673                     buf.Append(s.numBacktrackOccurrences);
674                     buf.Append(DataSeparator);
675                     buf.Append(s.numSemPredEvals);
676                     buf.Append(DataSeparator);
677                     buf.Append(s.couldBacktrack ? "1" : "0");
678                     buf.Append(NewLine);
679                 }
680             }
681             return buf.ToString();
682         }
683 
Trim(int[] X, int n)684         protected virtual int[] Trim(int[] X, int n)
685         {
686             if (n < X.Length)
687             {
688                 int[] trimmed = new int[n];
689                 Array.Copy(X, 0, trimmed, 0, n);
690                 X = trimmed;
691             }
692             return X;
693         }
694 
695         /** Get num hidden tokens between i..j inclusive */
GetNumberOfHiddenTokens(int i, int j)696         public virtual int GetNumberOfHiddenTokens(int i, int j)
697         {
698             int n = 0;
699             ITokenStream input = parser.TokenStream;
700             for (int ti = i; ti < input.Count && ti <= j; ti++)
701             {
702                 IToken t = input.Get(ti);
703                 if (t.Channel != TokenChannels.Default)
704                 {
705                     n++;
706                 }
707             }
708             return n;
709         }
710 
LocationDescription()711         protected virtual string LocationDescription()
712         {
713             return LocationDescription(
714                 currentGrammarFileName.Peek(),
715                 currentRuleName.Peek(),
716                 currentLine.Peek(),
717                 currentPos.Peek());
718         }
719 
LocationDescription(string file, string rule, int line, int pos)720         protected virtual string LocationDescription(string file, string rule, int line, int pos)
721         {
722             return file + ":" + line + ":" + pos + "(" + rule + ")";
723         }
724 
725         public class ProfileStats
726         {
727             public string Version;
728             public string name;
729             public int numRuleInvocations;
730             public int numUniqueRulesInvoked;
731             public int numDecisionEvents;
732             public int numDecisionsCovered;
733             public int numDecisionsThatPotentiallyBacktrack;
734             public int numDecisionsThatDoBacktrack;
735             public int maxRuleInvocationDepth;
736             public float avgkPerDecisionEvent;
737             public float avgkPerBacktrackingDecisionEvent;
738             public float averageDecisionPercentBacktracks;
739             public int numBacktrackOccurrences; // doesn't count gated DFA edges
740 
741             public int numFixedDecisions;
742             public int minDecisionMaxFixedLookaheads;
743             public int maxDecisionMaxFixedLookaheads;
744             public int avgDecisionMaxFixedLookaheads;
745             public int stddevDecisionMaxFixedLookaheads;
746             public int numCyclicDecisions;
747             public int minDecisionMaxCyclicLookaheads;
748             public int maxDecisionMaxCyclicLookaheads;
749             public int avgDecisionMaxCyclicLookaheads;
750             public int stddevDecisionMaxCyclicLookaheads;
751             //		int Stats.min(toArray(decisionMaxSynPredLookaheads);
752             //		int Stats.max(toArray(decisionMaxSynPredLookaheads);
753             //		int Stats.avg(toArray(decisionMaxSynPredLookaheads);
754             //		int Stats.stddev(toArray(decisionMaxSynPredLookaheads);
755             public int numSemanticPredicates;
756             public int numTokens;
757             public int numHiddenTokens;
758             public int numCharsMatched;
759             public int numHiddenCharsMatched;
760             public int numReportedErrors;
761             public int numMemoizationCacheHits;
762             public int numMemoizationCacheMisses;
763             public int numGuessingRuleInvocations;
764             public int numMemoizationCacheEntries;
765         }
766 
767         public class DecisionDescriptor
768         {
769             public int decision;
770             public string fileName;
771             public string ruleName;
772             public int line;
773             public int pos;
774             public bool couldBacktrack;
775 
776             public int n;
777             public float avgk; // avg across all decision events
778             public int maxk;
779             public int numBacktrackOccurrences;
780             public int numSemPredEvals;
781         }
782 
783         // all about a specific exec of a single decision
784         public class DecisionEvent
785         {
786             public DecisionDescriptor decision;
787             public int startIndex;
788             public int k;
789             public bool backtracks; // doesn't count gated DFA edges
790             public bool evalSemPred;
791             public DateTime startTime;
792             public DateTime stopTime;
793             public int numMemoizationCacheHits;
794             public int numMemoizationCacheMisses;
795         }
796     }
797 }
798