Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc-Andre Laperle2020-07-19 18:41:53 -0400
committerMarc-Andre Laperle2020-08-03 21:46:22 -0400
commit4ebaaf7b2551b5bab1a7cd358d18eeb701246de9 (patch)
tree299e9618bd047b2540d7c4870c5cc9ff177c8196 /build/org.eclipse.cdt.managedbuilder.core/src/org
parent6d4f20edd6ab7d2990e1699833629af6031afcd9 (diff)
downloadorg.eclipse.cdt-4ebaaf7b2551b5bab1a7cd358d18eeb701246de9.tar.gz
org.eclipse.cdt-4ebaaf7b2551b5bab1a7cd358d18eeb701246de9.tar.xz
org.eclipse.cdt-4ebaaf7b2551b5bab1a7cd358d18eeb701246de9.zip
Bug 565457 - CDB settings provider/parser's automatic exclusion of files is very slow
Implement a file exclusion algorithm that favors excluding whole folders when possible. The way it works is we gather exclusion information of each folder as we visit each children. When "leaving" the folder, we can act on whether or not it can be considered for exclusion as a whole or instead individually exclude a subset of its children. Using LLVM code base as a test: Before: 613 sec After: 2.4 sec Change-Id: Ib882a72cae157e3db6b6c94a1a09cb6f05b66bc4 Signed-off-by: Marc-Andre Laperle <malaperle@gmail.com>
Diffstat (limited to 'build/org.eclipse.cdt.managedbuilder.core/src/org')
-rw-r--r--build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompilationDatabaseParser.java109
1 files changed, 78 insertions, 31 deletions
diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompilationDatabaseParser.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompilationDatabaseParser.java
index 008b05e9c11..36fdfed7181 100644
--- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompilationDatabaseParser.java
+++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/language/settings/providers/CompilationDatabaseParser.java
@@ -22,8 +22,10 @@ import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.text.MessageFormat;
+import java.util.ArrayList;
import java.util.List;
import java.util.Set;
+import java.util.Stack;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager;
@@ -54,6 +56,7 @@ import org.eclipse.core.resources.IResourceProxyVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
@@ -130,39 +133,39 @@ public class CompilationDatabaseParser extends LanguageSettingsSerializableProvi
return lastModifiedTime.toMillis();
}
- // Wanted to use this as a base to also count the number of translation unit
- // for the progress monitor but it's too slow so only use it to exclude for now.
- private abstract class SourceFilesVisitor implements ICElementVisitor {
- @Override
- public boolean visit(ICElement element) throws CoreException {
- int elementType = element.getElementType();
- if (elementType != ICElement.C_UNIT) {
- return elementType == ICElement.C_CCONTAINER || elementType == ICElement.C_PROJECT;
- }
-
- ITranslationUnit tu = (ITranslationUnit) element;
- if (tu.isSourceUnit()) {
- handleTranslationUnit(tu);
- }
- return false;
- }
-
- abstract void handleTranslationUnit(ITranslationUnit tu) throws CoreException;
- }
-
- private final class ExcludeSourceFilesVisitor extends SourceFilesVisitor {
+ /**
+ * Visit all folders and exclude all files that do not have entries coming from the CDB.
+ * The algorithm detects when whole folders can be excluded to prevent a large number of
+ * individual file exclusions.
+ */
+ private final class ExcludeSourceFilesVisitor implements ICElementVisitor {
private final ICConfigurationDescription cfgDescription;
ICSourceEntry[] entries = null;
private final IProgressMonitor monitor;
private final int sourceFilesCount;
private int nbChecked = 0;
+ // Keep track of excluded files and folders as we visit each folder in a depth-first manner.
+ private Stack<FolderExclusionInfo> folderExclusionInfos = new Stack<>();
+
+ private class FolderExclusionInfo {
+ // In case not all files are excluded in this folder, we need to keep track of which folders we'll exclude individually.
+ private ArrayList<IPath> childrenFoldersWithAllFilesExcluded = new ArrayList<>();
+ // In case not all files are excluded in this folder, we need to keep track of which files we'll exclude individually.
+ private ArrayList<IPath> excludedSourceFiles = new ArrayList<>();
+ // True if all children of the folder are excluded, recursively.
+ // Children folders can set this to false on their parent when non-excluded files are detected.
+ // Therefore, this value is reliable only when all children are visited.
+ private boolean allFilesExcluded = true;
+ }
+
//Note: monitor already has ticks allocated for number of source files (not considering exclusions though)
private ExcludeSourceFilesVisitor(IProgressMonitor monitor, int sourceFilesCount,
ICConfigurationDescription cfgDescription) {
this.monitor = monitor;
this.sourceFilesCount = sourceFilesCount;
this.cfgDescription = cfgDescription;
+ this.entries = cfgDescription.getSourceEntries();
}
public ICSourceEntry[] getSourceEntries() {
@@ -170,18 +173,33 @@ public class CompilationDatabaseParser extends LanguageSettingsSerializableProvi
}
@Override
- void handleTranslationUnit(ITranslationUnit tu) throws CoreException {
- boolean isExcluded = CDataUtil.isExcluded(tu.getPath(), cfgDescription.getSourceEntries());
- if (!isExcluded) {
- List<ICLanguageSettingEntry> list = getSettingEntries(cfgDescription, tu.getResource(),
- tu.getLanguage().getId());
- if (list == null) {
- if (entries == null) {
- entries = cfgDescription.getSourceEntries();
- }
- entries = CDataUtil.setExcluded(tu.getResource().getFullPath(), false, true, entries);
+ public boolean visit(ICElement element) throws CoreException {
+ int elementType = element.getElementType();
+ if (elementType != ICElement.C_UNIT) {
+ boolean isSourceContainer = elementType == ICElement.C_CCONTAINER || elementType == ICElement.C_PROJECT;
+ if (isSourceContainer) {
+ folderExclusionInfos.push(new FolderExclusionInfo());
}
+ return isSourceContainer;
}
+
+ ITranslationUnit tu = (ITranslationUnit) element;
+ if (tu.isSourceUnit()) {
+ handleTranslationUnit(tu);
+ }
+ return false;
+ }
+
+ private void handleTranslationUnit(ITranslationUnit tu) throws CoreException {
+ FolderExclusionInfo folderInfo = folderExclusionInfos.peek();
+ List<ICLanguageSettingEntry> list = getSettingEntries(cfgDescription, tu.getResource(),
+ tu.getLanguage().getId());
+ if (list == null) {
+ folderInfo.excludedSourceFiles.add(tu.getResource().getFullPath());
+ } else {
+ folderInfo.allFilesExcluded = false;
+ }
+
monitor.worked(1);
if (nbChecked % 100 == 0) {
monitor.subTask(String.format(Messages.CompilationDatabaseParser_ProgressExcludingFiles, nbChecked,
@@ -189,6 +207,35 @@ public class CompilationDatabaseParser extends LanguageSettingsSerializableProvi
}
nbChecked++;
}
+
+ @Override
+ public void leave(ICElement element) throws CoreException {
+ int elementType = element.getElementType();
+ if (elementType == ICElement.C_CCONTAINER || elementType == ICElement.C_PROJECT) {
+
+ FolderExclusionInfo folderInfo = folderExclusionInfos.pop();
+
+ if (folderInfo.allFilesExcluded && !folderExclusionInfos.isEmpty()) {
+ // Consider this folder for exclusion later, maybe the parent will also be excluded
+ folderExclusionInfos.peek().childrenFoldersWithAllFilesExcluded.add(element.getPath());
+ } else {
+ if (!folderExclusionInfos.isEmpty()) {
+ folderExclusionInfos.peek().allFilesExcluded = false;
+ }
+
+ // Exclude all children folders previously considered for exclusion, since the parent
+ // (the currently visited element) cannot be excluded, we have to exclude them individually.
+ for (IPath excludedFolder : folderInfo.childrenFoldersWithAllFilesExcluded) {
+ entries = CDataUtil.setExcluded(excludedFolder, true, true, entries);
+ }
+
+ // Exclude all direct children files that need to be excluded.
+ for (IPath excludedFile : folderInfo.excludedSourceFiles) {
+ entries = CDataUtil.setExcluded(excludedFile, false, true, entries);
+ }
+ }
+ }
+ }
}
private static class CDBWorkingDirectoryTracker implements IWorkingDirectoryTracker {

Back to the top