Instead of dropping resolve cache after each file (can be expensive), drop caches regularly twice a second

This commit is contained in:
Alexey Kudravtsev
2018-11-29 15:28:48 +03:00
parent 9ad31d4007
commit 2b1e2a8e50
7 changed files with 93 additions and 83 deletions
@@ -33,6 +33,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.roots.DependencyScope;
@@ -93,13 +94,11 @@ public class InferNullityAnnotationsAction extends BaseAnalysisAction {
public void visitFile(PsiFile file) {
fileCount[0]++;
final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
if (progressIndicator != null) {
final VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null) {
progressIndicator.setText2(ProjectUtil.calcRelativeToProjectPath(virtualFile, project));
}
progressIndicator.setText(AnalysisScopeBundle.message("scanning.scope.progress.title"));
final VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null) {
progressIndicator.setText2(ProjectUtil.calcRelativeToProjectPath(virtualFile, project));
}
progressIndicator.setText(AnalysisScopeBundle.message("scanning.scope.progress.title"));
if (!(file instanceof PsiJavaFile)) return;
final Module module = ModuleUtilCore.findModuleForPsiElement(file);
if (module != null && processed.add(module)) {
@@ -181,26 +180,30 @@ public class InferNullityAnnotationsAction extends BaseAnalysisAction {
final int fileCount) {
final NullityInferrer inferrer = new NullityInferrer(isAnnotateLocalVariables(), project);
final PsiManager psiManager = PsiManager.getInstance(project);
final Runnable searchForUsages = () -> scope.accept(new PsiElementVisitor() {
int myFileCount;
final Runnable searchForUsages = () -> {
ProgressIndicator indicator = ProgressManager.getGlobalProgressIndicator();
ProgressIndicatorUtils.dropResolveCacheRegularly(indicator, project);
scope.accept(new PsiElementVisitor() {
int myFileCount;
@Override
public void visitFile(final PsiFile file) {
myFileCount++;
final VirtualFile virtualFile = file.getVirtualFile();
final FileViewProvider viewProvider = psiManager.findViewProvider(virtualFile);
final Document document = viewProvider == null ? null : viewProvider.getDocument();
if (document == null || virtualFile.getFileType().isBinary()) return; //do not inspect binary files
final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
if (progressIndicator != null) {
progressIndicator.setText2(ProjectUtil.calcRelativeToProjectPath(virtualFile, project));
progressIndicator.setFraction(((double)myFileCount) / fileCount);
@Override
public void visitFile(final PsiFile file) {
myFileCount++;
final VirtualFile virtualFile = file.getVirtualFile();
final FileViewProvider viewProvider = psiManager.findViewProvider(virtualFile);
final Document document = viewProvider == null ? null : viewProvider.getDocument();
if (document == null || virtualFile.getFileType().isBinary()) return; //do not inspect binary files
final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
if (progressIndicator != null) {
progressIndicator.setText2(ProjectUtil.calcRelativeToProjectPath(virtualFile, project));
progressIndicator.setFraction(((double)myFileCount) / fileCount);
}
if (file instanceof PsiJavaFile) {
inferrer.collect(file);
}
}
if (file instanceof PsiJavaFile) {
inferrer.collect(file);
}
}
});
});
};
if (ApplicationManager.getApplication().isDispatchThread()) {
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(searchForUsages, INFER_NULLITY_ANNOTATIONS, true, project)) {
return null;
@@ -20,26 +20,34 @@ import com.intellij.analysis.AnalysisScopeBundle;
import com.intellij.analysis.PerformAnalysisInBackgroundOption;
import com.intellij.cyclicDependencies.CyclicDependenciesBuilder;
import com.intellij.cyclicDependencies.ui.CyclicDependenciesPanel;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
import com.intellij.openapi.project.Project;
import com.intellij.packageDependencies.DependenciesToolWindow;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class CyclicDependenciesHandler {
@NotNull
private final Project myProject;
private final AnalysisScope myScope;
public CyclicDependenciesHandler(Project project, AnalysisScope scope) {
public CyclicDependenciesHandler(@NotNull Project project, AnalysisScope scope) {
myProject = project;
myScope = scope;
}
public void analyze() {
final CyclicDependenciesBuilder builder = new CyclicDependenciesBuilder(myProject, myScope);
final Runnable process = () -> builder.analyze();
final Runnable process = () -> {
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
ProgressIndicatorUtils.dropResolveCacheRegularly(indicator, myProject);
builder.analyze();
};
final Runnable successRunnable = () -> SwingUtilities.invokeLater(() -> {
CyclicDependenciesPanel panel = new CyclicDependenciesPanel(myProject, builder);
Content content = ContentFactory.SERVICE.getInstance().createContent(panel, AnalysisScopeBundle.message(
@@ -228,7 +228,7 @@ public class AnalysisScope {
}
else if (myType == DIRECTORY || myType == PROJECT || myType == MODULES || myType == MODULE || myType == CUSTOM) {
myFilesSet = new THashSet<>();
accept(createFileSearcher(), false);
accept(createFileSearcher());
}
else if (myType == VIRTUAL_FILES) {
myFilesSet = new THashSet<>();
@@ -256,10 +256,6 @@ public class AnalysisScope {
public void accept(@NotNull final PsiElementVisitor visitor) {
accept(visitor, true);
}
private void accept(@NotNull final PsiElementVisitor visitor, final boolean clearResolveCache) {
final boolean needReadAction = !ApplicationManager.getApplication().isReadAccessAllowed();
final PsiManager psiManager = PsiManager.getInstance(myProject);
final FileIndex fileIndex = getFileIndex();
@@ -268,7 +264,7 @@ public class AnalysisScope {
if (ProjectCoreUtil.isProjectOrWorkspaceFile(file)) return true;
if (fileIndex.isInContent(file) && !isFilteredOut(file)
&& !GeneratedSourcesFilter.isGeneratedSourceByAnyFilter(file, myProject)) {
return processFile(file, visitor, psiManager, needReadAction, clearResolveCache);
return processFile(file, visitor, psiManager, needReadAction);
}
return true;
});
@@ -340,13 +336,12 @@ public class AnalysisScope {
private static boolean processFile(@NotNull final VirtualFile vFile,
@NotNull final PsiElementVisitor visitor,
@NotNull final PsiManager psiManager,
final boolean needReadAction,
final boolean clearResolveCache) {
final boolean needReadAction) {
if (needReadAction && !ApplicationManager.getApplication().isDispatchThread()) {
commitAndRunInSmartMode(() -> doProcessFile(visitor, psiManager, vFile, clearResolveCache), psiManager.getProject());
commitAndRunInSmartMode(() -> doProcessFile(visitor, psiManager, vFile), psiManager.getProject());
}
else {
doProcessFile(visitor, psiManager, vFile, clearResolveCache);
doProcessFile(visitor, psiManager, vFile);
}
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
return indicator == null || !indicator.isCanceled();
@@ -389,18 +384,14 @@ public class AnalysisScope {
}
}
private static void doProcessFile(@NotNull PsiElementVisitor visitor, @NotNull PsiManager psiManager, @NotNull VirtualFile vFile,
boolean clearResolveCache) {
private static void doProcessFile(@NotNull PsiElementVisitor visitor, @NotNull PsiManager psiManager, @NotNull VirtualFile vFile) {
ProgressManager.checkCanceled();
if (!vFile.isValid()) return;
PsiFile psiFile = psiManager.findFile(vFile);
if (psiFile == null || !shouldHighlightFile(psiFile)) return;
psiFile.accept(visitor);
if (clearResolveCache) {
psiManager.dropResolveCaches();
InjectedLanguageManager.getInstance(psiManager.getProject()).dropFileCaches(psiFile);
}
InjectedLanguageManager.getInstance(psiManager.getProject()).dropFileCaches(psiFile);
}
protected boolean accept(@NotNull final PsiDirectory dir, @NotNull final Processor<? super VirtualFile> processor) {
@@ -431,7 +431,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
final List<Tools> globalSimpleTools = new ArrayList<>();
initializeTools(globalTools, localTools, globalSimpleTools);
appendPairedInspectionsForUnfairTools(globalTools, globalSimpleTools, localTools);
ProgressIndicatorUtils.dropResolveCacheRegularly(progressIndicator, getProject());
runGlobalTools(scope, inspectionManager, globalTools, isOfflineInspections);
if (runGlobalToolsOnly || localTools.isEmpty() && globalSimpleTools.isEmpty()) return;
@@ -957,12 +957,12 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
Task task = modal ? new Task.Modal(getProject(), title, true) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
cleanup(scope, profile, postRunnable, commandName, shouldApplyFix);
cleanup(scope, profile, postRunnable, commandName, shouldApplyFix, indicator);
}
} : new Task.Backgroundable(getProject(), title, true) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
cleanup(scope, profile, postRunnable, commandName, shouldApplyFix);
cleanup(scope, profile, postRunnable, commandName, shouldApplyFix, indicator);
}
};
ProgressManager.getInstance().run(task);
@@ -972,14 +972,12 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
@NotNull InspectionProfile profile,
@Nullable final Runnable postRunnable,
@Nullable final String commandName,
@NotNull Predicate<? super ProblemDescriptor> shouldApplyFix) {
@NotNull Predicate<? super ProblemDescriptor> shouldApplyFix,
@NotNull ProgressIndicator progressIndicator) {
setCurrentScope(scope);
final int fileCount = scope.getFileCount();
final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
if (progressIndicator != null) {
progressIndicator.setIndeterminate(false);
}
progressIndicator.setIndeterminate(false);
ProgressIndicatorUtils.dropResolveCacheRegularly(progressIndicator, getProject());
final SearchScope searchScope = ReadAction.compute(scope::toSearchScope);
final TextRange range;
if (searchScope instanceof LocalSearchScope) {
@@ -1003,9 +1001,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
private int myCount;
@Override
public void visitFile(PsiFile file) {
if (progressIndicator != null) {
progressIndicator.setFraction((double)++myCount / fileCount);
}
progressIndicator.setFraction((double)++myCount / fileCount);
if (isBinary(file)) return;
final List<LocalInspectionToolWrapper> lTools = new ArrayList<>();
for (final Tools tools : inspectionTools) {
@@ -28,6 +28,7 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.progress.impl.ProgressManagerImpl;
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
@@ -39,8 +40,10 @@ import com.intellij.openapi.util.Factory;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.StatusBar;
import com.intellij.openapi.wm.ex.ProgressIndicatorEx;
import com.intellij.psi.*;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiInvalidElementAccessException;
import com.intellij.psi.search.*;
import com.intellij.ui.LightweightHint;
import com.intellij.ui.content.Content;
@@ -79,12 +82,12 @@ public class FindUsagesManager {
private static final Key<String> KEY_START_USAGE_AGAIN = Key.create("KEY_START_USAGE_AGAIN");
@NonNls private static final String VALUE_START_USAGE_AGAIN = "START_AGAIN";
private final Project myProject;
private final com.intellij.usages.UsageViewManager myAnotherManager;
private final UsageViewManager myAnotherManager;
private PsiElement2UsageTargetComposite myLastSearchInFileData; // EDT only
private final UsageHistory myHistory = new UsageHistory();
public FindUsagesManager(@NotNull Project project, @NotNull com.intellij.usages.UsageViewManager anotherManager) {
public FindUsagesManager(@NotNull Project project, @NotNull UsageViewManager anotherManager) {
myProject = project;
myAnotherManager = anotherManager;
}
@@ -340,7 +343,9 @@ public class FindUsagesManager {
PsiElement[] secondaryElements = ReadAction.compute(() -> PsiElement2UsageTargetAdapter.convertToPsiElements(secondaryTargets));
Project project = ReadAction.compute(() -> scopeFile != null ? scopeFile.getProject() : primaryElements[0].getProject());
dropResolveCacheRegularly(ProgressManager.getInstance().getProgressIndicator(), project);
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
LOG.assertTrue(indicator != null, "Must run under progress. see ProgressManager.run*");
ProgressIndicatorUtils.dropResolveCacheRegularly(indicator, project);
if (scopeFile != null) {
optionsClone.searchScope = new LocalSearchScope(scopeFile);
@@ -427,26 +432,6 @@ public class FindUsagesManager {
return usageView;
}
private static void dropResolveCacheRegularly(ProgressIndicator indicator, @NotNull final Project project) {
if (indicator instanceof ProgressIndicatorEx) {
((ProgressIndicatorEx)indicator).addStateDelegate(new ProgressIndicatorBase() {
volatile long lastCleared = System.currentTimeMillis();
@Override
public void setFraction(double fraction) {
super.setFraction(fraction);
long current = System.currentTimeMillis();
if (current - lastCleared >= 500) {
lastCleared = current;
// fraction is changed when each file is processed =>
// resolve caches used when searching in that file are likely to be not needed anymore
PsiManager.getInstance(project).dropResolveCaches();
}
}
});
}
}
@NotNull
private static UsageViewPresentation createPresentation(@NotNull PsiElement psiElement,
@NotNull FindUsagesOptions options,
@@ -22,6 +22,7 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
@@ -42,11 +43,12 @@ import java.util.Set;
* @author nik
*/
public abstract class DependenciesHandlerBase {
@NotNull
protected final Project myProject;
private final List<? extends AnalysisScope> myScopes;
private final Set<PsiFile> myExcluded;
public DependenciesHandlerBase(final Project project, final List<? extends AnalysisScope> scopes, Set<PsiFile> excluded) {
public DependenciesHandlerBase(@NotNull Project project, final List<? extends AnalysisScope> scopes, Set<PsiFile> excluded) {
myScopes = scopes;
myExcluded = excluded;
myProject = project;
@@ -61,7 +63,7 @@ public abstract class DependenciesHandlerBase {
@Override
public void run(@NotNull final ProgressIndicator indicator) {
indicator.setIndeterminate(false);
perform(builders);
perform(builders, indicator);
}
@Override
@@ -74,7 +76,7 @@ public abstract class DependenciesHandlerBase {
@Override
public void run(@NotNull ProgressIndicator indicator) {
indicator.setIndeterminate(false);
perform(builders);
perform(builders, indicator);
}
@Override
@@ -100,7 +102,8 @@ public abstract class DependenciesHandlerBase {
protected abstract DependenciesBuilder createDependenciesBuilder(AnalysisScope scope);
private void perform(List<DependenciesBuilder> builders) {
private void perform(List<DependenciesBuilder> builders, @NotNull ProgressIndicator indicator) {
ProgressIndicatorUtils.dropResolveCacheRegularly(indicator, myProject);
try {
PerformanceWatcher.Snapshot snapshot = PerformanceWatcher.takeSnapshot();
for (AnalysisScope scope : myScopes) {
@@ -12,8 +12,11 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.wm.ex.ProgressIndicatorEx;
import com.intellij.psi.PsiManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.ide.PooledThreadExecutor;
@@ -246,4 +249,25 @@ public class ProgressIndicatorUtils {
}
application.invokeAndWait(EmptyRunnable.INSTANCE, ModalityState.any());
}
public static void dropResolveCacheRegularly(@NotNull ProgressIndicator indicator, @NotNull final Project project) {
indicator = ProgressWrapper.unwrap(indicator);
if (indicator instanceof ProgressIndicatorEx) {
((ProgressIndicatorEx)indicator).addStateDelegate(new ProgressIndicatorBase() {
volatile long lastCleared = System.currentTimeMillis();
@Override
public void setFraction(double fraction) {
super.setFraction(fraction);
long current = System.currentTimeMillis();
if (current - lastCleared >= 500) {
lastCleared = current;
// fraction is changed when each file is processed =>
// resolve caches used when searching in that file are likely to be not needed anymore
PsiManager.getInstance(project).dropResolveCaches();
}
}
});
}
}
}