Calculate detailed transition statistics per decision

This commit is contained in:
Sam Harwell 2013-05-18 14:22:09 -05:00
parent 0644d1a471
commit ec8457383c
1 changed files with 200 additions and 22 deletions

View File

@ -55,6 +55,7 @@ import org.antlr.v4.runtime.atn.PredictionContextCache;
import org.antlr.v4.runtime.atn.PredictionMode;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.dfa.DFAState;
import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.misc.Nullable;
import org.antlr.v4.runtime.misc.ParseCancellationException;
@ -251,6 +252,7 @@ public class TestPerformance extends BaseTest {
* required on-the-fly computation.
*/
private static final boolean COMPUTE_TRANSITION_STATS = false;
private static final boolean SHOW_TRANSITION_STATS_PER_FILE = false;
/**
* If {@code true}, the transition statistics will be adjusted to a running
* total before reporting the final results.
@ -356,6 +358,30 @@ public class TestPerformance extends BaseTest {
}
}
private static final long[][][] decisionInvocationsPerFile;
private static final long[][][] fullContextFallbackPerFile;
private static final long[][][] nonSllPerFile;
private static final long[][][] totalTransitionsPerDecisionPerFile;
private static final long[][][] computedTransitionsPerDecisionPerFile;
private static final long[][][] fullContextTransitionsPerDecisionPerFile;
static {
if (COMPUTE_TRANSITION_STATS && DETAILED_DFA_STATE_STATS) {
decisionInvocationsPerFile = new long[PASSES][][];
fullContextFallbackPerFile = new long[PASSES][][];
nonSllPerFile = new long[PASSES][][];
totalTransitionsPerDecisionPerFile = new long[PASSES][][];
computedTransitionsPerDecisionPerFile = new long[PASSES][][];
fullContextTransitionsPerDecisionPerFile = new long[PASSES][][];
} else {
decisionInvocationsPerFile = null;
fullContextFallbackPerFile = null;
nonSllPerFile = null;
totalTransitionsPerDecisionPerFile = null;
computedTransitionsPerDecisionPerFile = null;
fullContextTransitionsPerDecisionPerFile = null;
}
}
private static final long[][] timePerFile;
private static final int[][] tokensPerFile;
static {
@ -398,6 +424,15 @@ public class TestPerformance extends BaseTest {
if (COMPUTE_TRANSITION_STATS) {
totalTransitionsPerFile[i] = new long[Math.min(sources.size(), MAX_FILES_PER_PARSE_ITERATION)];
computedTransitionsPerFile[i] = new long[Math.min(sources.size(), MAX_FILES_PER_PARSE_ITERATION)];
if (DETAILED_DFA_STATE_STATS) {
decisionInvocationsPerFile[i] = new long[Math.min(sources.size(), MAX_FILES_PER_PARSE_ITERATION)][];
fullContextFallbackPerFile[i] = new long[Math.min(sources.size(), MAX_FILES_PER_PARSE_ITERATION)][];
nonSllPerFile[i] = new long[Math.min(sources.size(), MAX_FILES_PER_PARSE_ITERATION)][];
totalTransitionsPerDecisionPerFile[i] = new long[Math.min(sources.size(), MAX_FILES_PER_PARSE_ITERATION)][];
computedTransitionsPerDecisionPerFile[i] = new long[Math.min(sources.size(), MAX_FILES_PER_PARSE_ITERATION)][];
fullContextTransitionsPerDecisionPerFile[i] = new long[Math.min(sources.size(), MAX_FILES_PER_PARSE_ITERATION)][];
}
}
if (COMPUTE_TIMING_STATS) {
@ -465,7 +500,7 @@ public class TestPerformance extends BaseTest {
executorService.shutdown();
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
if (COMPUTE_TRANSITION_STATS) {
if (COMPUTE_TRANSITION_STATS && SHOW_TRANSITION_STATS_PER_FILE) {
computeTransitionStatistics();
}
@ -804,8 +839,17 @@ public class TestPerformance extends BaseTest {
try {
FileParseResult fileResult = future.get();
if (COMPUTE_TRANSITION_STATS) {
totalTransitionsPerFile[currentPass][currentIndex] = fileResult.parserTotalTransitions;
computedTransitionsPerFile[currentPass][currentIndex] = fileResult.parserComputedTransitions;
totalTransitionsPerFile[currentPass][currentIndex] = sum(fileResult.parserTotalTransitions);
computedTransitionsPerFile[currentPass][currentIndex] = sum(fileResult.parserComputedTransitions);
if (DETAILED_DFA_STATE_STATS) {
decisionInvocationsPerFile[currentPass][currentIndex] = fileResult.decisionInvocations;
fullContextFallbackPerFile[currentPass][currentIndex] = fileResult.fullContextFallback;
nonSllPerFile[currentPass][currentIndex] = fileResult.nonSll;
totalTransitionsPerDecisionPerFile[currentPass][currentIndex] = fileResult.parserTotalTransitions;
computedTransitionsPerDecisionPerFile[currentPass][currentIndex] = fileResult.parserComputedTransitions;
fullContextTransitionsPerDecisionPerFile[currentPass][currentIndex] = fileResult.parserFullContextTransitions;
}
}
if (COMPUTE_TIMING_STATS) {
@ -907,7 +951,13 @@ public class TestPerformance extends BaseTest {
System.out.format("There are %d parser DFAState instances, %d configs (%d unique).%n", states, configs, uniqueConfigs.size());
if (DETAILED_DFA_STATE_STATS) {
System.out.format("\tDecision\tStates\tConfigs\tRule%n");
if (COMPUTE_TRANSITION_STATS) {
System.out.format("\tDecision\tStates\tConfigs\tPredict (ALL)\tPredict (LL)\tNon-SLL\tTransitions\tTransitions (ATN)\tTransitions (LL)\tLA (SLL)\tLA (LL)\tRule%n");
}
else {
System.out.format("\tDecision\tStates\tConfigs\tRule%n");
}
for (int i = 0; i < decisionToDFA.length; i++) {
DFA dfa = decisionToDFA[i];
if (dfa == null || dfa.states.isEmpty()) {
@ -920,7 +970,57 @@ public class TestPerformance extends BaseTest {
}
String ruleName = parser.getRuleNames()[parser.getATN().decisionToState.get(dfa.decision).ruleIndex];
System.out.format("\t%d\t%d\t%d\t%s%n", dfa.decision, dfa.states.size(), decisionConfigs, ruleName);
long calls = 0;
long fullContextCalls = 0;
long nonSllCalls = 0;
long transitions = 0;
long computedTransitions = 0;
long fullContextTransitions = 0;
double lookahead = 0;
double fullContextLookahead = 0;
String formatString;
if (COMPUTE_TRANSITION_STATS) {
for (long[] data : decisionInvocationsPerFile[currentPass]) {
calls += data[i];
}
for (long[] data : fullContextFallbackPerFile[currentPass]) {
fullContextCalls += data[i];
}
for (long[] data : nonSllPerFile[currentPass]) {
nonSllCalls += data[i];
}
for (long[] data : totalTransitionsPerDecisionPerFile[currentPass]) {
transitions += data[i];
}
for (long[] data : computedTransitionsPerDecisionPerFile[currentPass]) {
computedTransitions += data[i];
}
for (long[] data : fullContextTransitionsPerDecisionPerFile[currentPass]) {
fullContextTransitions += data[i];
}
if (calls > 0) {
lookahead = (double)(transitions - fullContextTransitions) / (double)calls;
}
if (fullContextCalls > 0) {
fullContextLookahead = (double)fullContextTransitions / (double)fullContextCalls;
}
formatString = "\t%1$d\t%2$d\t%3$d\t%4$d\t%5$d\t%6$d\t%7$d\t%8$d\t%9$d\t%10$f\t%11$f\t%12$s%n";
}
else {
calls = 0;
formatString = "\t%1$d\t%2$d\t%3$d\t%12$s%n";
}
System.out.format(formatString, dfa.decision, dfa.states.size(), decisionConfigs, calls, fullContextCalls, nonSllCalls, transitions, computedTransitions, fullContextTransitions, lookahead, fullContextLookahead, ruleName);
}
}
}
@ -987,6 +1087,15 @@ public class TestPerformance extends BaseTest {
}
}
private static long sum(long[] array) {
long result = 0;
for (int i = 0; i < array.length; i++) {
result += array[i];
}
return result;
}
protected void compileJavaParser(boolean leftRecursive) throws IOException {
String grammarFileName = "Java.g4";
String sourceName = leftRecursive ? "Java-LR.g4" : "Java.g4";
@ -1275,9 +1384,12 @@ public class TestPerformance extends BaseTest {
public final long lexerComputedTransitions;
public final int parserDFASize;
public final long parserTotalTransitions;
public final long parserComputedTransitions;
public final long parserFullContextTransitions;
public final long[] decisionInvocations;
public final long[] fullContextFallback;
public final long[] nonSll;
public final long[] parserTotalTransitions;
public final long[] parserComputedTransitions;
public final long[] parserFullContextTransitions;
public FileParseResult(String sourceName, int checksum, @Nullable ParseTree parseTree, int tokenCount, long startTime, Lexer lexer, Parser parser) {
this.sourceName = sourceName;
@ -1314,13 +1426,19 @@ public class TestPerformance extends BaseTest {
if (parser != null) {
ParserATNSimulator interpreter = parser.getInterpreter();
if (interpreter instanceof StatisticsParserATNSimulator) {
decisionInvocations = ((StatisticsParserATNSimulator)interpreter).decisionInvocations;
fullContextFallback = ((StatisticsParserATNSimulator)interpreter).fullContextFallback;
nonSll = ((StatisticsParserATNSimulator)interpreter).nonSll;
parserTotalTransitions = ((StatisticsParserATNSimulator)interpreter).totalTransitions;
parserComputedTransitions = ((StatisticsParserATNSimulator)interpreter).computedTransitions;
parserFullContextTransitions = ((StatisticsParserATNSimulator)interpreter).fullContextTransitions;
} else {
parserTotalTransitions = 0;
parserComputedTransitions = 0;
parserFullContextTransitions = 0;
decisionInvocations = new long[0];
fullContextFallback = new long[0];
nonSll = new long[0];
parserTotalTransitions = new long[0];
parserComputedTransitions = new long[0];
parserFullContextTransitions = new long[0];
}
int dfaSize = 0;
@ -1333,9 +1451,12 @@ public class TestPerformance extends BaseTest {
parserDFASize = dfaSize;
} else {
parserDFASize = 0;
parserTotalTransitions = 0;
parserComputedTransitions = 0;
parserFullContextTransitions = 0;
decisionInvocations = new long[0];
fullContextFallback = new long[0];
nonSll = new long[0];
parserTotalTransitions = new long[0];
parserComputedTransitions = new long[0];
parserFullContextTransitions = new long[0];
}
}
}
@ -1368,36 +1489,71 @@ public class TestPerformance extends BaseTest {
private static class StatisticsParserATNSimulator extends ParserATNSimulator {
public long totalTransitions;
public long computedTransitions;
public long fullContextTransitions;
public final long[] decisionInvocations;
public final long[] fullContextFallback;
public final long[] nonSll;
public final long[] totalTransitions;
public final long[] computedTransitions;
public final long[] fullContextTransitions;
private int decision;
public StatisticsParserATNSimulator(ATN atn, DFA[] decisionToDFA, PredictionContextCache sharedContextCache) {
super(atn, decisionToDFA, sharedContextCache);
decisionInvocations = new long[atn.decisionToState.size()];
fullContextFallback = new long[atn.decisionToState.size()];
nonSll = new long[atn.decisionToState.size()];
totalTransitions = new long[atn.decisionToState.size()];
computedTransitions = new long[atn.decisionToState.size()];
fullContextTransitions = new long[atn.decisionToState.size()];
}
public StatisticsParserATNSimulator(Parser parser, ATN atn, DFA[] decisionToDFA, PredictionContextCache sharedContextCache) {
super(parser, atn, decisionToDFA, sharedContextCache);
decisionInvocations = new long[atn.decisionToState.size()];
fullContextFallback = new long[atn.decisionToState.size()];
nonSll = new long[atn.decisionToState.size()];
totalTransitions = new long[atn.decisionToState.size()];
computedTransitions = new long[atn.decisionToState.size()];
fullContextTransitions = new long[atn.decisionToState.size()];
}
@Override
public int adaptivePredict(TokenStream input, int decision, ParserRuleContext outerContext) {
try {
this.decision = decision;
decisionInvocations[decision]++;
return super.adaptivePredict(input, decision, outerContext);
}
finally {
this.decision = -1;
}
}
@Override
protected int execATNWithFullContext(DFA dfa, DFAState D, ATNConfigSet s0, TokenStream input, int startIndex, ParserRuleContext outerContext) {
fullContextFallback[decision]++;
return super.execATNWithFullContext(dfa, D, s0, input, startIndex, outerContext);
}
@Override
protected DFAState getExistingTargetState(DFAState previousD, int t) {
totalTransitions++;
totalTransitions[decision]++;
return super.getExistingTargetState(previousD, t);
}
@Override
protected DFAState computeTargetState(DFA dfa, DFAState previousD, int t) {
computedTransitions++;
computedTransitions[decision]++;
return super.computeTargetState(dfa, previousD, t);
}
@Override
protected ATNConfigSet computeReachSet(ATNConfigSet closure, int t, boolean fullCtx) {
if (fullCtx) {
totalTransitions++;
computedTransitions++;
fullContextTransitions++;
totalTransitions[decision]++;
computedTransitions[decision]++;
fullContextTransitions[decision]++;
}
return super.computeReachSet(closure, t, fullCtx);
@ -1436,9 +1592,21 @@ public class TestPerformance extends BaseTest {
}
private static class SummarizingDiagnosticErrorListener extends DiagnosticErrorListener {
private BitSet _sllConflict;
private ATNConfigSet _sllConfigs;
@Override
public void reportAmbiguity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, boolean exact, BitSet ambigAlts, ATNConfigSet configs) {
if (COMPUTE_TRANSITION_STATS && DETAILED_DFA_STATE_STATS) {
BitSet sllPredictions = _sllConflict != null ? _sllConflict : getRepresentedAlts(_sllConfigs);
int sllPrediction = sllPredictions.nextSetBit(0);
BitSet llPredictions = ambigAlts != null ? ambigAlts : getRepresentedAlts(configs);
int llPrediction = llPredictions.cardinality() == 0 ? ATN.INVALID_ALT_NUMBER : llPredictions.nextSetBit(0);
if (sllPrediction != llPrediction) {
((StatisticsParserATNSimulator)recognizer.getInterpreter()).nonSll[dfa.decision]++;
}
}
if (!REPORT_AMBIGUITIES) {
return;
}
@ -1453,6 +1621,8 @@ public class TestPerformance extends BaseTest {
@Override
public void reportAttemptingFullContext(Parser recognizer, DFA dfa, int startIndex, int stopIndex, BitSet conflictingAlts, ATNConfigSet configs) {
_sllConflict = conflictingAlts;
_sllConfigs = configs;
if (!REPORT_FULL_CONTEXT) {
return;
}
@ -1468,6 +1638,14 @@ public class TestPerformance extends BaseTest {
@Override
public void reportContextSensitivity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, int prediction, ATNConfigSet configs) {
if (COMPUTE_TRANSITION_STATS && DETAILED_DFA_STATE_STATS) {
BitSet sllPredictions = _sllConflict != null ? _sllConflict : getRepresentedAlts(_sllConfigs);
int sllPrediction = sllPredictions.nextSetBit(0);
if (sllPrediction != prediction) {
((StatisticsParserATNSimulator)recognizer.getInterpreter()).nonSll[dfa.decision]++;
}
}
if (!REPORT_CONTEXT_SENSITIVITY) {
return;
}