Bug 567595 - JavaRuntime.resolveRuntimeClasspath has poor performance on large classpath with JDK >= 9
Summary: JavaRuntime.resolveRuntimeClasspath has poor performance on large classpath w...
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Debug (show other bugs)
Version: 4.17   Edit
Hardware: PC All
: P3 normal (vote)
Target Milestone: 4.21 M2   Edit
Assignee: Andreas Huber CLA
QA Contact:
URL:
Whiteboard:
Keywords: performance
Depends on:
Blocks:
 
Reported: 2020-10-05 05:38 EDT by Gunnar Wagenknecht CLA
Modified: 2021-08-03 10:34 EDT (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Gunnar Wagenknecht CLA 2020-10-05 05:38:24 EDT
Looking at the implementation it seems to be at least O(NĀ²):

JavaRuntime.resolveRuntimeClasspath(IRuntimeClasspathEntry[], ILaunchConfiguration)

- loops over all entries given as parameter (in our case > 1500)
- calls JavaProject#findPackageFragmentRoot(IRuntimeClasspathEntry#getPath())
- JavaProject#findPackageFragmentRoot itself calls findPackageFragmentRoot0
- findPackageFragmentRoot0 calls getAllPackageFragmentRoots and then loops over all the roots to find a match
- getAllPackageFragmentRoots loops over the resolved classpath calling computePackageFragmentRoots for each entry

The worst case could potentially be much higher.
Comment 1 Gunnar Wagenknecht CLA 2020-10-05 05:47:21 EDT
Note, this method is called multiple times during launching a JUnit launch configuration, making it slow to launch.
Comment 2 Andreas Huber CLA 2021-02-26 07:43:42 EST
I can only reproduce this on Windows.
I can reproduce this with TestNG as well. TestNG also resolves the classpath five times.

A profiler shows that most time is spend in File.getCanonicalPath() called by JavaProject.canonicalizePath(). 
JavaProject.canonicalizePath() is doing a lot more work if the file system is case-insensitive. NTSF is case-insensitive.

- When I import the projects with the buildship plugin the hot spot is in JavaRuntime.resolveRuntimeClasspath(). More precisely GradleClasspathContainerRuntimeClasspathEntryResolver.runtimeClasspathWithTestSources().
- When I use Gradle's 'eclipse' plugin and import the projects using "Existing Projects into Workspace", then the hot spot is in DefaultProjectClasspathEntry.expandProject() called by JavaRuntime.computeUnresolvedRuntimeDependencies().
Comment 3 Eclipse Genie CLA 2021-05-11 06:04:34 EDT
New Gerrit change created: https://git.eclipse.org/r/c/jdt/eclipse.jdt.debug/+/180456
Comment 4 Andreas Huber CLA 2021-05-14 08:36:56 EDT
The exampleWorkspace.zip (https://bugs.eclipse.org/bugs/attachment.cgi?id=286382) attached to Bug 573479 can be used to reproduce the issue. Please note that a performance improvement is not really visible until Bug 573479 is fixed. On my machine Bug 573479 improves the launch time from 45s to 5s and the fix of this ticket further improves the launch time from 5s to 2s. 
I ran the tests on Windows. I get much better launch times on Linux.
Comment 6 Andrey Loskutov CLA 2021-07-26 08:40:40 EDT
Thanks Andreas. 

Would be great, if you could verify the fix of this bug and bug 573479 by using latest 4.21 nightly build from https://download.eclipse.org/eclipse/downloads/drops4/I20210725-1800.
Comment 7 Andreas Huber CLA 2021-08-03 10:34:57 EDT
Thanks Andrey.

Verified.
The performance improved as expected.
I tested TestNG and Junit tests.
I did not come across any class path related issues.