1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-22 06:02:11 +02:00

Bug 565553 - Improve performance of build command parsers with large number of files

Add more caches for methods in AbstractLanguageSettingsOutputScanner
that are IO heavy:
- getFilesystemLocation
- determineMappedURI
- resolvePathEntryInFilesystem (File.exists)

These cut down the execution time of command parsing by around 50% on
Windows, more so when considering Java >=12 when
File.getCanonicalPath/File caching is not manually enabled.
See also https://bugs.eclipse.org/bugs/show_bug.cgi?id=565553#c17
and https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8258036

Change-Id: I80828f969547f824d2e45e60b5f4459d03c70bb1
Signed-off-by: Marc-Andre Laperle <malaperle@gmail.com>
This commit is contained in:
Marc-Andre Laperle 2020-11-22 13:45:09 -05:00 committed by Marc-André Laperle
parent 25cbbcd5b5
commit f6d1132d8e
2 changed files with 99 additions and 39 deletions

View file

@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2 Bundle-ManifestVersion: 2
Bundle-Name: %pluginName Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.cdt.managedbuilder.core; singleton:=true Bundle-SymbolicName: org.eclipse.cdt.managedbuilder.core; singleton:=true
Bundle-Version: 9.1.0.qualifier Bundle-Version: 9.1.100.qualifier
Bundle-Activator: org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin Bundle-Activator: org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin
Bundle-Vendor: %providerName Bundle-Vendor: %providerName
Bundle-Localization: plugin Bundle-Localization: plugin

View file

@ -100,6 +100,56 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett
FIND_RESOURCES_CACHE_SIZE); FIND_RESOURCES_CACHE_SIZE);
private HashMap<IProject, LRUCache<IPath, List<IResource>>> findPathInProjectCache = new HashMap<>(); private HashMap<IProject, LRUCache<IPath, List<IResource>>> findPathInProjectCache = new HashMap<>();
//String pathStr, URI baseURI -> URI
private static class MappedURIKey {
URI baseURI;
String pathStr;
public MappedURIKey(URI baseURI, String pathStr) {
super();
this.baseURI = baseURI;
this.pathStr = pathStr;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((baseURI == null) ? 0 : baseURI.hashCode());
result = prime * result + ((pathStr == null) ? 0 : pathStr.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MappedURIKey other = (MappedURIKey) obj;
if (baseURI == null) {
if (other.baseURI != null)
return false;
} else if (!baseURI.equals(other.baseURI))
return false;
if (pathStr == null) {
if (other.pathStr != null)
return false;
} else if (!pathStr.equals(other.pathStr))
return false;
return true;
}
}
// Caches the result of determineMappedURI
private LRUCache<MappedURIKey, URI> mappedURICache = new LRUCache<>(FIND_RESOURCES_CACHE_SIZE);
// Caches the result of getFilesystemLocation
private LRUCache<URI, IPath> fileSystemLocationCache = new LRUCache<>(FIND_RESOURCES_CACHE_SIZE);
// Caches the result of new File(pathname).exists()
private LRUCache<IPath, Boolean> pathExistsCache = new LRUCache<>(FIND_RESOURCES_CACHE_SIZE);
/** @since 8.2 */ /** @since 8.2 */
protected EFSExtensionProvider efsProvider = null; protected EFSExtensionProvider efsProvider = null;
@ -498,6 +548,9 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett
workspaceRootFindContainersForLocationURICache.clear(); workspaceRootFindContainersForLocationURICache.clear();
workspaceRootFindFilesForLocationURICache.clear(); workspaceRootFindFilesForLocationURICache.clear();
findPathInProjectCache.clear(); findPathInProjectCache.clear();
mappedURICache.clear();
fileSystemLocationCache.clear();
pathExistsCache.clear();
} }
@Override @Override
@ -958,34 +1011,36 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett
* @return {@link URI} of the resource * @return {@link URI} of the resource
*/ */
private URI determineMappedURI(String pathStr, URI baseURI) { private URI determineMappedURI(String pathStr, URI baseURI) {
URI uri = null; return mappedURICache.computeIfAbsent(new MappedURIKey(baseURI, pathStr), key -> {
URI uri = null;
if (baseURI == null) { if (baseURI == null) {
if (new Path(pathStr).isAbsolute()) { if (new Path(pathStr).isAbsolute()) {
uri = resolvePathFromBaseLocation(pathStr, Path.ROOT); uri = resolvePathFromBaseLocation(pathStr, Path.ROOT);
} }
} else if (baseURI.getScheme().equals(EFS.SCHEME_FILE)) { } else if (baseURI.getScheme().equals(EFS.SCHEME_FILE)) {
// location on the local file-system // location on the local file-system
IPath baseLocation = org.eclipse.core.filesystem.URIUtil.toPath(baseURI); IPath baseLocation = org.eclipse.core.filesystem.URIUtil.toPath(baseURI);
// careful not to use Path here but 'pathStr' as String as we want to properly navigate symlinks // careful not to use Path here but 'pathStr' as String as we want to properly navigate symlinks
uri = resolvePathFromBaseLocation(pathStr, baseLocation); uri = resolvePathFromBaseLocation(pathStr, baseLocation);
} else { } else {
// location on a remote file-system // location on a remote file-system
IPath path = new Path(pathStr); // use canonicalized path here, in particular replace all '\' with '/' for Windows paths IPath path = new Path(pathStr); // use canonicalized path here, in particular replace all '\' with '/' for Windows paths
URI remoteUri = efsProvider.append(baseURI, path.toString()); URI remoteUri = efsProvider.append(baseURI, path.toString());
if (remoteUri != null) { if (remoteUri != null) {
String localPath = efsProvider.getMappedPath(remoteUri); String localPath = efsProvider.getMappedPath(remoteUri);
if (localPath != null) { if (localPath != null) {
uri = org.eclipse.core.filesystem.URIUtil.toURI(localPath); uri = org.eclipse.core.filesystem.URIUtil.toURI(localPath);
}
} }
} }
}
if (uri == null) { if (uri == null) {
// if everything fails just wrap string to URI // if everything fails just wrap string to URI
uri = org.eclipse.core.filesystem.URIUtil.toURI(pathStr); uri = org.eclipse.core.filesystem.URIUtil.toURI(pathStr);
} }
return uri; return uri;
});
} }
/** /**
@ -1103,22 +1158,24 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett
if (uri == null) if (uri == null)
return null; return null;
String pathStr = efsProvider.getMappedPath(uri); return fileSystemLocationCache.computeIfAbsent(uri, (k) -> {
uri = org.eclipse.core.filesystem.URIUtil.toURI(pathStr); String pathStr = efsProvider.getMappedPath(uri);
URI resUri = org.eclipse.core.filesystem.URIUtil.toURI(pathStr);
if (uri != null && uri.isAbsolute()) { if (resUri != null && resUri.isAbsolute()) {
try { try {
File file = new java.io.File(uri); File file = new java.io.File(resUri);
String canonicalPathStr = file.getCanonicalPath(); String canonicalPathStr = file.getCanonicalPath();
if (new Path(pathStr).getDevice() == null) { if (new Path(pathStr).getDevice() == null) {
return new Path(canonicalPathStr).setDevice(null); return new Path(canonicalPathStr).setDevice(null);
}
return new Path(canonicalPathStr);
} catch (Exception e) {
ManagedBuilderCorePlugin.log(e);
} }
return new Path(canonicalPathStr);
} catch (Exception e) {
ManagedBuilderCorePlugin.log(e);
} }
} return null;
return null; });
} }
/** /**
@ -1199,7 +1256,10 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett
IPath location = getFilesystemLocation(uri); IPath location = getFilesystemLocation(uri);
if (location != null) { if (location != null) {
String loc = location.toString(); String loc = location.toString();
if (new File(loc).exists()) { boolean exists = pathExistsCache.computeIfAbsent(location, (s) -> {
return new File(loc).exists();
});
if (exists) {
return optionParser.createEntry(loc, loc, flag); return optionParser.createEntry(loc, loc, flag);
} }
} }