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(); 131 protected Stack<String> currentRuleName = new Stack(); 132 protected Stack<Integer> currentLine = new Stack(); 133 protected Stack<Integer> currentPos = new Stack(); 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 148 public Profiler() { 149 } 150 151 public Profiler(DebugParser parser) { 152 this.parser = parser; 153 } 154 155 public void enterRule(String grammarFileName, String ruleName) { 156 // System.out.println("enterRule "+grammarFileName+":"+ruleName); 157 ruleLevel++; 158 stats.numRuleInvocations++; 159 uniqueRules.add(grammarFileName+":"+ruleName); 160 stats.maxRuleInvocationDepth = Math.max(stats.maxRuleInvocationDepth, ruleLevel); 161 currentGrammarFileName.push( grammarFileName ); 162 currentRuleName.push( ruleName ); 163 } 164 165 public void exitRule(String grammarFileName, String ruleName) { 166 ruleLevel--; 167 currentGrammarFileName.pop(); 168 currentRuleName.pop(); 169 } 170 171 /** Track memoization; this is not part of standard debug interface 172 * but is triggered by profiling. Code gen inserts an override 173 * for this method in the recognizer, which triggers this method. 174 * Called from alreadyParsedRule(). 175 */ 176 public void examineRuleMemoization(IntStream input, 177 int ruleIndex, 178 int stopIndex, // index or MEMO_RULE_UNKNOWN... 179 String ruleName) 180 { 181 if (dump) System.out.println("examine memo "+ruleName+" at "+input.index()+": "+stopIndex); 182 if ( stopIndex==BaseRecognizer.MEMO_RULE_UNKNOWN ) { 183 //System.out.println("rule "+ruleIndex+" missed @ "+input.index()); 184 stats.numMemoizationCacheMisses++; 185 stats.numGuessingRuleInvocations++; // we'll have to enter 186 currentDecision().numMemoizationCacheMisses++; 187 } 188 else { 189 // regardless of rule success/failure, if in cache, we have a cache hit 190 //System.out.println("rule "+ruleIndex+" hit @ "+input.index()); 191 stats.numMemoizationCacheHits++; 192 currentDecision().numMemoizationCacheHits++; 193 } 194 } 195 196 /** Warning: doesn't track success/failure, just unique recording event */ 197 public void memoize(IntStream input, 198 int ruleIndex, 199 int ruleStartIndex, 200 String ruleName) 201 { 202 // count how many entries go into table 203 if (dump) System.out.println("memoize "+ruleName); 204 stats.numMemoizationCacheEntries++; 205 } 206 207 @Override 208 public void location(int line, int pos) { 209 currentLine.push(line); 210 currentPos.push(pos); 211 } 212 213 public void enterDecision(int decisionNumber, boolean couldBacktrack) { 214 lastRealTokenTouchedInDecision = null; 215 stats.numDecisionEvents++; 216 int startingLookaheadIndex = parser.getTokenStream().index(); 217 TokenStream input = parser.getTokenStream(); 218 if ( dump ) System.out.println("enterDecision canBacktrack="+couldBacktrack+" "+ decisionNumber + 219 " backtrack depth " + backtrackDepth + 220 " @ " + input.get(input.index()) + 221 " rule " +locationDescription()); 222 String g = (String) currentGrammarFileName.peek(); 223 DecisionDescriptor descriptor = decisions.get(g, decisionNumber); 224 if ( descriptor == null ) { 225 descriptor = new DecisionDescriptor(); 226 decisions.put(g, decisionNumber, descriptor); 227 descriptor.decision = decisionNumber; 228 descriptor.fileName = (String)currentGrammarFileName.peek(); 229 descriptor.ruleName = (String)currentRuleName.peek(); 230 descriptor.line = (Integer)currentLine.peek(); 231 descriptor.pos = (Integer)currentPos.peek(); 232 descriptor.couldBacktrack = couldBacktrack; 233 } 234 descriptor.n++; 235 236 DecisionEvent d = new DecisionEvent(); 237 decisionStack.push(d); 238 d.decision = descriptor; 239 d.startTime = System.currentTimeMillis(); 240 d.startIndex = startingLookaheadIndex; 241 } 242 243 public void exitDecision(int decisionNumber) { 244 DecisionEvent d = decisionStack.pop(); 245 d.stopTime = System.currentTimeMillis(); 246 247 int lastTokenIndex = lastRealTokenTouchedInDecision.getTokenIndex(); 248 int numHidden = getNumberOfHiddenTokens(d.startIndex, lastTokenIndex); 249 int depth = lastTokenIndex - d.startIndex - numHidden + 1; // +1 counts consuming start token as 1 250 d.k = depth; 251 d.decision.maxk = Math.max(d.decision.maxk, depth); 252 253 if (dump) System.out.println("exitDecision "+decisionNumber+" in "+d.decision.ruleName+ 254 " lookahead "+d.k +" max token "+lastRealTokenTouchedInDecision); 255 decisionEvents.add(d); // done with decision; track all 256 } 257 258 public void consumeToken(Token token) { 259 if (dump) System.out.println("consume token "+token); 260 if ( !inDecision() ) { 261 stats.numTokens++; 262 return; 263 } 264 if ( lastRealTokenTouchedInDecision==null || 265 lastRealTokenTouchedInDecision.getTokenIndex() < token.getTokenIndex() ) 266 { 267 lastRealTokenTouchedInDecision = token; 268 } 269 DecisionEvent d = currentDecision(); 270 // compute lookahead depth 271 int thisRefIndex = token.getTokenIndex(); 272 int numHidden = getNumberOfHiddenTokens(d.startIndex, thisRefIndex); 273 int depth = thisRefIndex - d.startIndex - numHidden + 1; // +1 counts consuming start token as 1 274 //d.maxk = Math.max(d.maxk, depth); 275 if (dump) System.out.println("consume "+thisRefIndex+" "+depth+" tokens ahead in "+ 276 d.decision.ruleName+"-"+d.decision.decision+" start index "+d.startIndex); 277 } 278 279 /** The parser is in a decision if the decision depth > 0. This 280 * works for backtracking also, which can have nested decisions. 281 */ 282 public boolean inDecision() { 283 return decisionStack.size()>0; 284 } 285 286 public void consumeHiddenToken(Token token) { 287 //System.out.println("consume hidden token "+token); 288 if ( !inDecision() ) stats.numHiddenTokens++; 289 } 290 291 /** Track refs to lookahead if in a fixed/nonfixed decision. 292 */ 293 public void LT(int i, Token t) { 294 if ( inDecision() && i>0 ) { 295 DecisionEvent d = currentDecision(); 296 if (dump) System.out.println("LT("+i+")="+t+" index "+t.getTokenIndex()+" relative to "+d.decision.ruleName+"-"+ 297 d.decision.decision+" start index "+d.startIndex); 298 if ( lastRealTokenTouchedInDecision==null || 299 lastRealTokenTouchedInDecision.getTokenIndex() < t.getTokenIndex() ) 300 { 301 lastRealTokenTouchedInDecision = t; 302 if (dump) System.out.println("set last token "+lastRealTokenTouchedInDecision); 303 } 304 // get starting index off stack 305 // int stackTop = lookaheadStack.size()-1; 306 // Integer startingIndex = (Integer)lookaheadStack.get(stackTop); 307 // // compute lookahead depth 308 // int thisRefIndex = parser.getTokenStream().index(); 309 // int numHidden = 310 // getNumberOfHiddenTokens(startingIndex.intValue(), thisRefIndex); 311 // int depth = i + thisRefIndex - startingIndex.intValue() - numHidden; 312 // /* 313 // System.out.println("LT("+i+") @ index "+thisRefIndex+" is depth "+depth+ 314 // " max is "+maxLookaheadInCurrentDecision); 315 // */ 316 // if ( depth>maxLookaheadInCurrentDecision ) { 317 // maxLookaheadInCurrentDecision = depth; 318 // } 319 // d.maxk = currentDecision()/ 320 } 321 } 322 323 /** Track backtracking decisions. You'll see a fixed or cyclic decision 324 * and then a backtrack. 325 * 326 * enter rule 327 * ... 328 * enter decision 329 * LA and possibly consumes (for cyclic DFAs) 330 * begin backtrack level 331 * mark m 332 * rewind m 333 * end backtrack level, success 334 * exit decision 335 * ... 336 * exit rule 337 */ 338 public void beginBacktrack(int level) { 339 if (dump) System.out.println("enter backtrack "+level); 340 backtrackDepth++; 341 DecisionEvent e = currentDecision(); 342 if ( e.decision.couldBacktrack ) { 343 stats.numBacktrackOccurrences++; 344 e.decision.numBacktrackOccurrences++; 345 e.backtracks = true; 346 } 347 } 348 349 /** Successful or not, track how much lookahead synpreds use */ 350 public void endBacktrack(int level, boolean successful) { 351 if (dump) System.out.println("exit backtrack "+level+": "+successful); 352 backtrackDepth--; 353 } 354 355 @Override 356 public void mark(int i) { 357 if (dump) System.out.println("mark "+i); 358 } 359 360 @Override 361 public void rewind(int i) { 362 if (dump) System.out.println("rewind "+i); 363 } 364 365 @Override 366 public void rewind() { 367 if (dump) System.out.println("rewind"); 368 } 369 370 371 372 protected DecisionEvent currentDecision() { 373 return decisionStack.peek(); 374 } 375 376 public void recognitionException(RecognitionException e) { 377 stats.numReportedErrors++; 378 } 379 380 public void semanticPredicate(boolean result, String predicate) { 381 stats.numSemanticPredicates++; 382 if ( inDecision() ) { 383 DecisionEvent d = currentDecision(); 384 d.evalSemPred = true; 385 d.decision.numSemPredEvals++; 386 if (dump) System.out.println("eval "+predicate+" in "+d.decision.ruleName+"-"+ 387 d.decision.decision); 388 } 389 } 390 391 public void terminate() { 392 for (DecisionEvent e : decisionEvents) { 393 //System.out.println("decision "+e.decision.decision+": k="+e.k); 394 e.decision.avgk += e.k; 395 stats.avgkPerDecisionEvent += e.k; 396 if ( e.backtracks ) { // doesn't count gated syn preds on DFA edges 397 stats.avgkPerBacktrackingDecisionEvent += e.k; 398 } 399 } 400 stats.averageDecisionPercentBacktracks = 0.0f; 401 for (DecisionDescriptor d : decisions.values()) { 402 stats.numDecisionsCovered++; 403 d.avgk /= (double)d.n; 404 if ( d.couldBacktrack ) { 405 stats.numDecisionsThatPotentiallyBacktrack++; 406 float percentBacktracks = d.numBacktrackOccurrences / (float)d.n; 407 //System.out.println("dec "+d.decision+" backtracks "+percentBacktracks*100+"%"); 408 stats.averageDecisionPercentBacktracks += percentBacktracks; 409 } 410 // ignore rules that backtrack along gated DFA edges 411 if ( d.numBacktrackOccurrences > 0 ) { 412 stats.numDecisionsThatDoBacktrack++; 413 } 414 } 415 stats.averageDecisionPercentBacktracks /= stats.numDecisionsThatPotentiallyBacktrack; 416 stats.averageDecisionPercentBacktracks *= 100; // it's a percentage 417 stats.avgkPerDecisionEvent /= stats.numDecisionEvents; 418 stats.avgkPerBacktrackingDecisionEvent /= (double)stats.numBacktrackOccurrences; 419 420 System.err.println(toString()); 421 System.err.println(getDecisionStatsDump()); 422 423 // String stats = toNotifyString(); 424 // try { 425 // Stats.writeReport(RUNTIME_STATS_FILENAME,stats); 426 // } 427 // catch (IOException ioe) { 428 // System.err.println(ioe); 429 // ioe.printStackTrace(System.err); 430 // } 431 } 432 433 public void setParser(DebugParser parser) { 434 this.parser = parser; 435 } 436 437 // R E P O R T I N G 438 439 public String toNotifyString() { 440 StringBuffer buf = new StringBuffer(); 441 buf.append(Version); 442 buf.append('\t'); 443 buf.append(parser.getClass().getName()); 444 // buf.append('\t'); 445 // buf.append(numRuleInvocations); 446 // buf.append('\t'); 447 // buf.append(maxRuleInvocationDepth); 448 // buf.append('\t'); 449 // buf.append(numFixedDecisions); 450 // buf.append('\t'); 451 // buf.append(Stats.min(decisionMaxFixedLookaheads)); 452 // buf.append('\t'); 453 // buf.append(Stats.max(decisionMaxFixedLookaheads)); 454 // buf.append('\t'); 455 // buf.append(Stats.avg(decisionMaxFixedLookaheads)); 456 // buf.append('\t'); 457 // buf.append(Stats.stddev(decisionMaxFixedLookaheads)); 458 // buf.append('\t'); 459 // buf.append(numCyclicDecisions); 460 // buf.append('\t'); 461 // buf.append(Stats.min(decisionMaxCyclicLookaheads)); 462 // buf.append('\t'); 463 // buf.append(Stats.max(decisionMaxCyclicLookaheads)); 464 // buf.append('\t'); 465 // buf.append(Stats.avg(decisionMaxCyclicLookaheads)); 466 // buf.append('\t'); 467 // buf.append(Stats.stddev(decisionMaxCyclicLookaheads)); 468 // buf.append('\t'); 469 // buf.append(numBacktrackDecisions); 470 // buf.append('\t'); 471 // buf.append(Stats.min(toArray(decisionMaxSynPredLookaheads))); 472 // buf.append('\t'); 473 // buf.append(Stats.max(toArray(decisionMaxSynPredLookaheads))); 474 // buf.append('\t'); 475 // buf.append(Stats.avg(toArray(decisionMaxSynPredLookaheads))); 476 // buf.append('\t'); 477 // buf.append(Stats.stddev(toArray(decisionMaxSynPredLookaheads))); 478 // buf.append('\t'); 479 // buf.append(numSemanticPredicates); 480 // buf.append('\t'); 481 // buf.append(parser.getTokenStream().size()); 482 // buf.append('\t'); 483 // buf.append(numHiddenTokens); 484 // buf.append('\t'); 485 // buf.append(numCharsMatched); 486 // buf.append('\t'); 487 // buf.append(numHiddenCharsMatched); 488 // buf.append('\t'); 489 // buf.append(numberReportedErrors); 490 // buf.append('\t'); 491 // buf.append(numMemoizationCacheHits); 492 // buf.append('\t'); 493 // buf.append(numMemoizationCacheMisses); 494 // buf.append('\t'); 495 // buf.append(numGuessingRuleInvocations); 496 // buf.append('\t'); 497 // buf.append(numMemoizationCacheEntries); 498 return buf.toString(); 499 } 500 501 public String toString() { 502 return toString(getReport()); 503 } 504 505 public ProfileStats getReport() { 506 // TokenStream input = parser.getTokenStream(); 507 // for (int i=0; i<input.size()&& lastRealTokenTouchedInDecision !=null&&i<= lastRealTokenTouchedInDecision.getTokenIndex(); i++) { 508 // Token t = input.get(i); 509 // if ( t.getChannel()!=Token.DEFAULT_CHANNEL ) { 510 // stats.numHiddenTokens++; 511 // stats.numHiddenCharsMatched += t.getText().length(); 512 // } 513 // } 514 stats.Version = Version; 515 stats.name = parser.getClass().getName(); 516 stats.numUniqueRulesInvoked = uniqueRules.size(); 517 //stats.numCharsMatched = lastTokenConsumed.getStopIndex() + 1; 518 return stats; 519 } 520 521 public DoubleKeyMap getDecisionStats() { 522 return decisions; 523 } 524 525 public List getDecisionEvents() { 526 return decisionEvents; 527 } 528 529 public static String toString(ProfileStats stats) { 530 StringBuffer buf = new StringBuffer(); 531 buf.append("ANTLR Runtime Report; Profile Version "); 532 buf.append(stats.Version); 533 buf.append(newline); 534 buf.append("parser name "); 535 buf.append(stats.name); 536 buf.append(newline); 537 buf.append("Number of rule invocations "); 538 buf.append(stats.numRuleInvocations); 539 buf.append(newline); 540 buf.append("Number of unique rules visited "); 541 buf.append(stats.numUniqueRulesInvoked); 542 buf.append(newline); 543 buf.append("Number of decision events "); 544 buf.append(stats.numDecisionEvents); 545 buf.append(newline); 546 buf.append("Overall average k per decision event "); 547 buf.append(stats.avgkPerDecisionEvent); 548 buf.append(newline); 549 buf.append("Number of backtracking occurrences (can be multiple per decision) "); 550 buf.append(stats.numBacktrackOccurrences); 551 buf.append(newline); 552 buf.append("Overall average k per decision event that backtracks "); 553 buf.append(stats.avgkPerBacktrackingDecisionEvent); 554 buf.append(newline); 555 buf.append("Number of rule invocations while backtracking "); 556 buf.append(stats.numGuessingRuleInvocations); 557 buf.append(newline); 558 buf.append("num decisions that potentially backtrack "); 559 buf.append(stats.numDecisionsThatPotentiallyBacktrack); 560 buf.append(newline); 561 buf.append("num decisions that do backtrack "); 562 buf.append(stats.numDecisionsThatDoBacktrack); 563 buf.append(newline); 564 buf.append("num decisions that potentially backtrack but don't "); 565 buf.append(stats.numDecisionsThatPotentiallyBacktrack - stats.numDecisionsThatDoBacktrack); 566 buf.append(newline); 567 buf.append("average % of time a potentially backtracking decision backtracks "); 568 buf.append(stats.averageDecisionPercentBacktracks); 569 buf.append(newline); 570 buf.append("num unique decisions covered "); 571 buf.append(stats.numDecisionsCovered); 572 buf.append(newline); 573 buf.append("max rule invocation nesting depth "); 574 buf.append(stats.maxRuleInvocationDepth); 575 buf.append(newline); 576 577 // buf.append("number of fixed lookahead decisions "); 578 // buf.append(); 579 // buf.append('\n'); 580 // buf.append("min lookahead used in a fixed lookahead decision "); 581 // buf.append(); 582 // buf.append('\n'); 583 // buf.append("max lookahead used in a fixed lookahead decision "); 584 // buf.append(); 585 // buf.append('\n'); 586 // buf.append("average lookahead depth used in fixed lookahead decisions "); 587 // buf.append(); 588 // buf.append('\n'); 589 // buf.append("standard deviation of depth used in fixed lookahead decisions "); 590 // buf.append(); 591 // buf.append('\n'); 592 // buf.append("number of arbitrary lookahead decisions "); 593 // buf.append(); 594 // buf.append('\n'); 595 // buf.append("min lookahead used in an arbitrary lookahead decision "); 596 // buf.append(); 597 // buf.append('\n'); 598 // buf.append("max lookahead used in an arbitrary lookahead decision "); 599 // buf.append(); 600 // buf.append('\n'); 601 // buf.append("average lookahead depth used in arbitrary lookahead decisions "); 602 // buf.append(); 603 // buf.append('\n'); 604 // buf.append("standard deviation of depth used in arbitrary lookahead decisions "); 605 // buf.append(); 606 // buf.append('\n'); 607 // buf.append("number of evaluated syntactic predicates "); 608 // buf.append(); 609 // buf.append('\n'); 610 // buf.append("min lookahead used in a syntactic predicate "); 611 // buf.append(); 612 // buf.append('\n'); 613 // buf.append("max lookahead used in a syntactic predicate "); 614 // buf.append(); 615 // buf.append('\n'); 616 // buf.append("average lookahead depth used in syntactic predicates "); 617 // buf.append(); 618 // buf.append('\n'); 619 // buf.append("standard deviation of depth used in syntactic predicates "); 620 // buf.append(); 621 // buf.append('\n'); 622 buf.append("rule memoization cache size "); 623 buf.append(stats.numMemoizationCacheEntries); 624 buf.append(newline); 625 buf.append("number of rule memoization cache hits "); 626 buf.append(stats.numMemoizationCacheHits); 627 buf.append(newline); 628 buf.append("number of rule memoization cache misses "); 629 buf.append(stats.numMemoizationCacheMisses); 630 buf.append(newline); 631 // buf.append("number of evaluated semantic predicates "); 632 // buf.append(); 633 // buf.append(newline); 634 buf.append("number of tokens "); 635 buf.append(stats.numTokens); 636 buf.append(newline); 637 buf.append("number of hidden tokens "); 638 buf.append(stats.numHiddenTokens); 639 buf.append(newline); 640 buf.append("number of char "); 641 buf.append(stats.numCharsMatched); 642 buf.append(newline); 643 buf.append("number of hidden char "); 644 buf.append(stats.numHiddenCharsMatched); 645 buf.append(newline); 646 buf.append("number of syntax errors "); 647 buf.append(stats.numReportedErrors); 648 buf.append(newline); 649 return buf.toString(); 650 } 651 652 public String getDecisionStatsDump() { 653 StringBuffer buf = new StringBuffer(); 654 buf.append("location"); 655 buf.append(DATA_SEP); 656 buf.append("n"); 657 buf.append(DATA_SEP); 658 buf.append("avgk"); 659 buf.append(DATA_SEP); 660 buf.append("maxk"); 661 buf.append(DATA_SEP); 662 buf.append("synpred"); 663 buf.append(DATA_SEP); 664 buf.append("sempred"); 665 buf.append(DATA_SEP); 666 buf.append("canbacktrack"); 667 buf.append("\n"); 668 for (String fileName : decisions.keySet()) { 669 for (int d : decisions.keySet(fileName)) { 670 DecisionDescriptor s = decisions.get(fileName, d); 671 buf.append(s.decision); 672 buf.append("@"); 673 buf.append(locationDescription(s.fileName,s.ruleName,s.line,s.pos)); // decision number 674 buf.append(DATA_SEP); 675 buf.append(s.n); 676 buf.append(DATA_SEP); 677 buf.append(String.format("%.2f",s.avgk)); 678 buf.append(DATA_SEP); 679 buf.append(s.maxk); 680 buf.append(DATA_SEP); 681 buf.append(s.numBacktrackOccurrences); 682 buf.append(DATA_SEP); 683 buf.append(s.numSemPredEvals); 684 buf.append(DATA_SEP); 685 buf.append(s.couldBacktrack ?"1":"0"); 686 buf.append(newline); 687 } 688 } 689 return buf.toString(); 690 } 691 692 protected int[] trim(int[] X, int n) { 693 if ( n<X.length ) { 694 int[] trimmed = new int[n]; 695 System.arraycopy(X,0,trimmed,0,n); 696 X = trimmed; 697 } 698 return X; 699 } 700 701 protected int[] toArray(List a) { 702 int[] x = new int[a.size()]; 703 for (int i = 0; i < a.size(); i++) { 704 Integer I = (Integer) a.get(i); 705 x[i] = I.intValue(); 706 } 707 return x; 708 } 709 710 /** Get num hidden tokens between i..j inclusive */ 711 public int getNumberOfHiddenTokens(int i, int j) { 712 int n = 0; 713 TokenStream input = parser.getTokenStream(); 714 for (int ti = i; ti<input.size() && ti <= j; ti++) { 715 Token t = input.get(ti); 716 if ( t.getChannel()!=Token.DEFAULT_CHANNEL ) { 717 n++; 718 } 719 } 720 return n; 721 } 722 723 protected String locationDescription() { 724 return locationDescription( 725 currentGrammarFileName.peek(), 726 currentRuleName.peek(), 727 currentLine.peek(), 728 currentPos.peek()); 729 } 730 731 protected String locationDescription(String file, String rule, int line, int pos) { 732 return file+":"+line+":"+pos+"(" + rule + ")"; 733 } 734 } 735