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 33namespace 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 92 public Profiler() 93 { 94 } 95 96 public Profiler(DebugParser parser) 97 { 98 this.parser = parser; 99 } 100 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 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 */ 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 */ 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 159 public override void Location(int line, int pos) 160 { 161 currentLine.Push(line); 162 currentPos.Push(pos); 163 } 164 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 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 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 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 */ 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 */ 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 */ 336 public override void EndBacktrack(int level, bool successful) 337 { 338 if (dump) 339 Console.WriteLine("exit backtrack " + level + ": " + successful); 340 backtrackDepth--; 341 } 342 343 public override void Mark(int i) 344 { 345 if (dump) 346 Console.WriteLine("mark " + i); 347 } 348 349 public override void Rewind(int i) 350 { 351 if (dump) 352 Console.WriteLine("rewind " + i); 353 } 354 355 public override void Rewind() 356 { 357 if (dump) 358 Console.WriteLine("rewind"); 359 } 360 361 protected virtual DecisionEvent CurrentDecision() 362 { 363 return decisionStack.Peek(); 364 } 365 366 public override void RecognitionException(RecognitionException e) 367 { 368 stats.numReportedErrors++; 369 } 370 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 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 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 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 505 public override string ToString() 506 { 507 return ToString(GetReport()); 508 } 509 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 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 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 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 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 */ 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 711 protected virtual string LocationDescription() 712 { 713 return LocationDescription( 714 currentGrammarFileName.Peek(), 715 currentRuleName.Peek(), 716 currentLine.Peek(), 717 currentPos.Peek()); 718 } 719 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