when running very long highlighting stress/perf tests do not allow CoreProgressManager to suddenly decide to de-prioritize background processes, defeating the whole purpose

GitOrigin-RevId: 958506d9faa034c8f99bc116622655b7d72f069e
This commit is contained in:
Alexey Kudravtsev
2022-07-19 14:50:26 +00:00
committed by intellij-monorepo-bot
parent 48e4ce23c8
commit 002906ee0f
3 changed files with 72 additions and 40 deletions
@@ -25,6 +25,8 @@ import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.impl.CoreProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.startup.StartupManager;
@@ -41,6 +43,7 @@ import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry
import com.intellij.psi.xml.XmlFileNSInfoProvider;
import com.intellij.testFramework.*;
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.XmlSchemaProvider;
import it.unimi.dsi.fastutil.ints.IntArrayList;
@@ -109,6 +112,16 @@ public abstract class DaemonAnalyzerTestCase extends JavaCodeInsightTestCase {
}
}
// when running very long tasks (e.g. during stress/perf tests) CoreProgressManager might decide to de-prioritize background processes,
// defeating the whole purpose. Do not let him do that.
@Override
protected void runTestRunnable(@NotNull ThrowableRunnable<Throwable> testRunnable) throws Throwable {
((CoreProgressManager)ProgressManager.getInstance()).<Void, Throwable>suppressAllDeprioritizationsDuringLongTestsExecutionIn(()-> {
super.runTestRunnable(testRunnable);
return null;
});
}
protected final void enableInspectionTool(@NotNull InspectionProfileEntry tool) {
InspectionsKt.enableInspectionTool(getProject(), tool, getTestRootDisposable());
}
@@ -839,7 +839,7 @@ public class CoreProgressManager extends ProgressManager implements Disposable {
}
protected boolean sleepIfNeededToGivePriorityToAnotherThread() {
if (!isCurrentThreadEffectivelyPrioritized() && isLowPriorityReallyApplicable()) {
if (isDeprioritizationEnabled() && !isCurrentThreadEffectivelyPrioritized() && isLowPriorityReallyApplicable()) {
LockSupport.parkNanos(1_000_000);
avoidBlockingPrioritizingThread();
return true;
@@ -919,6 +919,21 @@ public class CoreProgressManager extends ProgressManager implements Disposable {
return false;
}
private boolean isDeprioritizationEnabled() {
return myDeprioritizations.get() < 1_000_000;
}
@TestOnly
@ApiStatus.Internal
public <T,E extends Throwable> T suppressAllDeprioritizationsDuringLongTestsExecutionIn(@NotNull ThrowableComputable<T, E> runnable) throws E {
myDeprioritizations.addAndGet(1_000_000);
try {
return runnable.compute();
}
finally {
myDeprioritizations.addAndGet(-1_000_000);
}
}
@NotNull
public static ModalityState getCurrentThreadProgressModality() {
ProgressIndicator indicator = threadTopLevelIndicators.get(Thread.currentThread().getId());
@@ -84,6 +84,8 @@ import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.impl.CoreProgressManager;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
@@ -257,48 +259,50 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
DaemonCodeAnalyzerSettings settings = DaemonCodeAnalyzerSettings.getInstance();
ProjectInspectionProfileManager.getInstance(project); // avoid "severities changed, restart" event
ProcessCanceledException exception = null;
int retries = 1000;
for (int i = 0; i < retries; i++) {
int oldDelay = settings.getAutoReparseDelay();
try {
settings.setAutoReparseDelay(0);
List<HighlightInfo> infos = new ArrayList<>();
EdtTestUtil.runInEdtAndWait(() -> {
codeAnalyzer.runPasses(file, editor.getDocument(), Collections.singletonList(textEditor), toIgnore, canChangeDocument, null);
IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
if (policy != null) {
policy.waitForHighlighting(project, editor);
}
IdentifierHighlighterPassFactory.waitForIdentifierHighlighting();
infos.addAll(DaemonCodeAnalyzerImpl.getHighlights(editor.getDocument(), null, project));
if (readEditorMarkupModel) {
MarkupModelEx markupModel = (MarkupModelEx)editor.getMarkupModel();
DaemonCodeAnalyzerEx.processHighlights(markupModel, project, null, 0, editor.getDocument().getTextLength(),
Processors.cancelableCollectProcessor(infos));
}
});
infos.addAll(DaemonCodeAnalyzerEx.getInstanceEx(project).getFileLevelHighlights(project, file));
return infos;
}
catch (ProcessCanceledException e) {
Throwable cause = e.getCause();
if (cause != null && cause.getClass() != Throwable.class) {
// canceled because of an exception, no need to repeat the same
throw e;
return ((CoreProgressManager)ProgressManager.getInstance()).suppressAllDeprioritizationsDuringLongTestsExecutionIn(() -> {
ProcessCanceledException exception = null;
int retries = 1000;
for (int i = 0; i < retries; i++) {
int oldDelay = settings.getAutoReparseDelay();
try {
settings.setAutoReparseDelay(0);
List<HighlightInfo> infos = new ArrayList<>();
EdtTestUtil.runInEdtAndWait(() -> {
codeAnalyzer.runPasses(file, editor.getDocument(), Collections.singletonList(textEditor), toIgnore, canChangeDocument, null);
IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
if (policy != null) {
policy.waitForHighlighting(project, editor);
}
IdentifierHighlighterPassFactory.waitForIdentifierHighlighting();
infos.addAll(DaemonCodeAnalyzerImpl.getHighlights(editor.getDocument(), null, project));
if (readEditorMarkupModel) {
MarkupModelEx markupModel = (MarkupModelEx)editor.getMarkupModel();
DaemonCodeAnalyzerEx.processHighlights(markupModel, project, null, 0, editor.getDocument().getTextLength(),
Processors.cancelableCollectProcessor(infos));
}
});
infos.addAll(DaemonCodeAnalyzerEx.getInstanceEx(project).getFileLevelHighlights(project, file));
return infos;
}
catch (ProcessCanceledException e) {
Throwable cause = e.getCause();
if (cause != null && cause.getClass() != Throwable.class) {
// canceled because of an exception, no need to repeat the same
throw e;
}
EdtTestUtil.runInEdtAndWait(() -> {
PsiDocumentManager.getInstance(project).commitAllDocuments();
UIUtil.dispatchAllInvocationEvents();
});
exception = e;
EdtTestUtil.runInEdtAndWait(() -> {
PsiDocumentManager.getInstance(project).commitAllDocuments();
UIUtil.dispatchAllInvocationEvents();
});
exception = e;
}
finally {
settings.setAutoReparseDelay(oldDelay);
}
}
finally {
settings.setAutoReparseDelay(oldDelay);
}
}
throw new AssertionError("Unable to highlight after " + retries + " retries", exception);
throw new AssertionError("Unable to highlight after " + retries + " retries", exception);
});
}
public static void ensureIndexesUpToDate(@NotNull Project project) {