mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
DataFlowRunner: add reporting of slow analysis in EAP/internal
This commit is contained in:
@@ -8,6 +8,8 @@ import com.intellij.codeInspection.dataFlow.value.DfaExpressionFactory;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaValue;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Attachment;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.diagnostic.RuntimeExceptionWithAttachments;
|
||||
@@ -30,7 +32,10 @@ import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -150,7 +155,9 @@ public class DataFlowRunner {
|
||||
ControlFlow flow = null;
|
||||
DfaInstructionState lastInstructionState = null;
|
||||
try {
|
||||
TimeStats stats = new TimeStats();
|
||||
flow = new ControlFlowAnalyzer(myValueFactory, psiBlock, ignoreAssertions, myInlining).buildControlFlow();
|
||||
stats.endFlow();
|
||||
if (flow == null) return RunnerResult.NOT_APPLICABLE;
|
||||
int[] loopNumber = LoopAnalyzer.calcInLoop(flow);
|
||||
|
||||
@@ -181,7 +188,9 @@ public class DataFlowRunner {
|
||||
int stateLimit = Registry.intValue("ide.dfa.state.limit");
|
||||
int count = 0;
|
||||
while (!queue.isEmpty()) {
|
||||
stats.startMerge();
|
||||
List<DfaInstructionState> states = queue.getNextInstructionStates(joinInstructions);
|
||||
stats.endMerge();
|
||||
if (states.size() > MAX_STATES_PER_BRANCH) {
|
||||
LOG.trace("Too complex because too many different possible states");
|
||||
return RunnerResult.TOO_COMPLEX;
|
||||
@@ -209,7 +218,9 @@ public class DataFlowRunner {
|
||||
continue;
|
||||
}
|
||||
if (processed.size() > MERGING_BACK_BRANCHES_THRESHOLD) {
|
||||
stats.startMerge();
|
||||
instructionState = mergeBackBranches(instructionState, processed);
|
||||
stats.endMerge();
|
||||
if (containsState(processed, instructionState)) {
|
||||
continue;
|
||||
}
|
||||
@@ -262,6 +273,11 @@ public class DataFlowRunner {
|
||||
|
||||
LOG.trace("Analysis ok");
|
||||
myWasForciblyMerged |= queue.wasForciblyMerged();
|
||||
stats.endProcess();
|
||||
if (stats.isTooSlow()) {
|
||||
String message = "Too slow DFA\nIf you report this problem, please consider including the attachments\n" + stats;
|
||||
reportDfaProblem(psiBlock, flow, null, new RuntimeException(message));
|
||||
}
|
||||
return RunnerResult.OK;
|
||||
}
|
||||
catch (ProcessCanceledException ex) {
|
||||
@@ -578,4 +594,60 @@ public class DataFlowRunner {
|
||||
|
||||
return Pair.create(trueSet, falseSet);
|
||||
}
|
||||
|
||||
private static class TimeStats {
|
||||
private static final long DFA_EXECUTION_TIME_TO_REPORT_NANOS = TimeUnit.SECONDS.toNanos(1);
|
||||
private final @Nullable ThreadMXBean myMxBean;
|
||||
private final long myStart;
|
||||
private long myMergeStart, myFlowTime, myMergeTime, myProcessTime;
|
||||
|
||||
TimeStats() {
|
||||
Application application = ApplicationManager.getApplication();
|
||||
if (application.isInternal() || application.isEAP()) {
|
||||
myMxBean = ManagementFactory.getThreadMXBean();
|
||||
myStart = myMxBean.getCurrentThreadCpuTime();
|
||||
} else {
|
||||
myMxBean = null;
|
||||
myStart = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void endFlow() {
|
||||
if (myMxBean != null) {
|
||||
myFlowTime = myMxBean.getCurrentThreadCpuTime() - myStart;
|
||||
}
|
||||
}
|
||||
|
||||
void startMerge() {
|
||||
if (myMxBean != null) {
|
||||
myMergeStart = myMxBean.getCurrentThreadCpuTime();
|
||||
}
|
||||
}
|
||||
|
||||
void endMerge() {
|
||||
if (myMxBean != null) {
|
||||
myMergeTime += myMxBean.getCurrentThreadCpuTime() - myMergeStart;
|
||||
}
|
||||
}
|
||||
|
||||
void endProcess() {
|
||||
if (myMxBean != null) {
|
||||
myProcessTime = myMxBean.getCurrentThreadCpuTime() - myStart;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isTooSlow() {
|
||||
return myProcessTime > DFA_EXECUTION_TIME_TO_REPORT_NANOS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
double flowTime = myFlowTime/1e9;
|
||||
double mergeTime = myMergeTime/1e9;
|
||||
double interpretTime = (myProcessTime - myFlowTime - myMergeTime)/1e9;
|
||||
double totalTime = myProcessTime/1e9;
|
||||
return String.format(Locale.ENGLISH, "Building ControlFlow: %.2fs\nMerging states: %.2fs\nInterpreting: %.2fs\nTotal: %.2fs",
|
||||
flowTime, mergeTime, interpretTime, totalTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user