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