Calculate detailed transition statistics per decision
This commit is contained in:
parent
0644d1a471
commit
ec8457383c
|
@ -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) {
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue