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