Bug 312038 - JREContainer hasChildren locks up the UI for more than 30s
Summary: JREContainer hasChildren locks up the UI for more than 30s
Status: RESOLVED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Debug (show other bugs)
Version: 3.6   Edit
Hardware: PC Linux-GTK
: P2 major with 1 vote (vote)
Target Milestone: 3.7 M7   Edit
Assignee: Michael Rennie CLA
QA Contact:
URL:
Whiteboard:
Keywords: performance, polish
: 331356 338251 (view as bug list)
Depends on:
Blocks:
 
Reported: 2010-05-07 06:33 EDT by James Blackburn CLA
Modified: 2011-04-21 05:29 EDT (History)
7 users (show)

See Also:
curtis.windatt.public: review+


Attachments
backtrace and example of recursive stat (56.79 KB, text/plain)
2010-05-07 06:33 EDT, James Blackburn CLA
no flags Details
strace-pid-4095.txt.bz2 (416.61 KB, application/octet-stream)
2010-05-07 06:54 EDT, James Blackburn CLA
no flags Details
patch 1 (4.48 KB, patch)
2010-11-05 06:42 EDT, James Blackburn CLA
no flags Details | Diff
proposed fix (16.90 KB, patch)
2011-04-13 15:32 EDT, Michael Rennie CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description James Blackburn CLA 2010-05-07 06:33:40 EDT
Created attachment 167452 [details]
backtrace and example of recursive stat

3.6M7 
I'm seeing this very frequently.  Changing a Manifest.MF, for example, causes the entire Eclipse UI to lockup.   There seems to be an issue in the way that the JDT discovers whether a source directory is available.

Using jstack multiple times, I see that the main thread is locked up in java.io.File.isFile(), called as a result of TreeViewer.isExpandable():

java.lang.Thread.State: RUNNABLE
at java.io.UnixFileSystem.getBooleanAttributes0(Native Method)
at java.io.UnixFileSystem.getBooleanAttributes(UnixFileSystem.java:228)
at java.io.File.isFile(File.java:778)
at org.eclipse.jdt.internal.launching.StandardVMType.getDefaultSystemLibrarySource(StandardVMType.java:237)
at org.eclipse.jdt.internal.launching.StandardVMType.getDefaultLibraryLocations(StandardVMType.java:310)
at org.eclipse.jdt.launching.JavaRuntime.getLibraryLocations(JavaRuntime.java:1639)
at org.eclipse.jdt.internal.launching.JREContainer.computeClasspathEntries(JREContainer.java:293)
...

Stracing the process shows that's it's iterating up the tree recursively looking for src.zip / src.jar. When it hits a NFS automount directory the thread main thread is context switched out, and the stat is 100+ times slower.

It seems to be doing this again and again on the UI thread:

[pid  4095] 11:08:21 stat("/tools/oss/packages/x86_64-rhel4/java/jdk1.6.0_11/jre/lib/src.jar", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000017>
[pid  4095] 11:08:21 stat("/tools/oss/packages/x86_64-rhel4/java/jdk1.6.0_11/jre/lib/src.zip", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000013>
[pid  4095] 11:08:21 stat("/tools/oss/packages/x86_64-rhel4/java/jdk1.6.0_11/jre/src.jar", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000012>
[pid  4095] 11:08:21 stat("/tools/oss/packages/x86_64-rhel4/java/jdk1.6.0_11/jre/src.zip", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000012>
[pid  4095] 11:08:21 stat("/tools/oss/packages/x86_64-rhel4/java/jdk1.6.0_11/src.jar", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000011>
[pid  4095] 11:08:21 stat("/tools/oss/packages/x86_64-rhel4/java/jdk1.6.0_11/src.zip", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000012>
[pid  4095] 11:08:21 stat("/tools/oss/packages/x86_64-rhel4/java/src.jar", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000015>
[pid  4095] 11:08:21 stat("/tools/oss/packages/x86_64-rhel4/java/src.zip", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000010>
[pid  4095] 11:08:21 stat("/tools/oss/packages/x86_64-rhel4/src.jar", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000013>
[pid  4095] 11:08:21 stat("/tools/oss/packages/x86_64-rhel4/src.zip", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000010>
[pid  4095] 11:08:21 stat("/tools/oss/packages/src.jar", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000011>
[pid  4095] 11:08:21 stat("/tools/oss/packages/src.zip", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000010>
[pid  4095] 11:08:21 stat("/tools/oss/src.jar", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000007>
[pid  4095] 11:08:21 stat("/tools/oss/src.zip", 0x402288d0) = -1 ENOENT (No such file or directory) <0.000008>
[pid  4095] 11:08:21 stat("/tools/src.jar",  <unfinished ...>

This is really bad for performance, and hurts automounters badly.  I attached strace some time after the start of the hang and I have 28M of stat()s...
Comment 1 James Blackburn CLA 2010-05-07 06:54:05 EDT
Created attachment 167453 [details]
strace-pid-4095.txt.bz2

Compressed strace log of pid 4095 (main nid=0xfff). As you can see it's doing a huge number of I/O on the UI thread.
Comment 2 James Blackburn CLA 2010-05-07 07:13:08 EDT
Moving to core as JavaProject.resolveClasspath seems to be in jdt.core.
Comment 3 Olivier Thomann CLA 2010-05-07 08:57:39 EDT
Moving to JDT/Debug
Comment 4 James Blackburn CLA 2010-11-05 06:42:31 EDT
Created attachment 182461 [details]
patch 1

Potential patch for the issue which adds a cache to JavaRuntime#getLibraryLocations.  This seems to make a massive different to the performance of this call...
Comment 5 James Blackburn CLA 2010-11-09 09:27:34 EST
This is such a bad performance bug for me.  When my filer is slow, the IDE locks up on every ctrl-S...
Comment 6 Markus Keller CLA 2010-11-09 10:20:13 EST
(In reply to comment #4)
> Created an attachment (id=182461) [details] [diff]
> patch 1

That patch looks dangerous, since the cache is never updated and outdated IVMInstalls are never deleted.

Moreover, I'm not sure if you can use an IVMInstall as key of a map, since it doesn't have well-defined hashCode() and equals(Object) methods (you rely on implementation details of the default implementation).
Comment 7 Remy Suen CLA 2010-11-29 12:54:55 EST
*** Bug 331356 has been marked as a duplicate of this bug. ***
Comment 8 Paul Austin CLA 2010-11-29 13:50:09 EST
I have found out what the problem is. The code which is looking for src.jar and src.zip is not finding the file as eclipse is looking in the following directory.

/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home

But the src.jar is in the new location.

/Library/Java/JavaVirtualMachines/1.6.0_22-b04-307.jdk/Contents/Home/src.jar

I copied the src.jar file into the old location and now it works.

I found this out as it was also hanging when I went into the Preferences to look at the installed JRE's and it was hanging there. I then did a thread dump and looked for the source code which told me it was looking for the src.jar or src.zip file.

Paul
Comment 9 James Blackburn CLA 2010-12-30 12:38:07 EST
(In reply to comment #6)
> That patch looks dangerous, since the cache is never updated and outdated
> IVMInstalls are never deleted.

Agreed. I've never ventured into the JDK, so it was a naive attempt...

I've just been syncing my core.resources plugins and Eclipse locked-up for half-an-hour is no fun after the MANIFEST.MF change.  It was in the attached backtrace every time I jstack'd it.

Do you have any ideas on how to fix this?
Comment 10 Johannes Rieken CLA 2011-02-25 12:53:45 EST
This is driving me nuts as I very single change of the MANIFEST.MF stalls my workbench for a couple of minutes. Add a new plugin to our project is broken for me.
Comment 11 James Blackburn CLA 2011-02-25 12:57:40 EST
*** Bug 338251 has been marked as a duplicate of this bug. ***
Comment 12 Markus Keller CLA 2011-03-02 10:23:43 EST
I think org.eclipse.jdt.internal.launching.StandardVMType
#getDefaultLibraryLocations(File) should implement a workaround for this performance bottleneck.

Unfortunately, we don't know when the JRE installs are modified on disk, so we cannot cache the source locations once and for all. But I guess a simple cache around the call to getDefaultSystemLibrarySource(lib) (HashMap<File, IPath) would solve the problem.

To avoid using stale information forever, the cache should be cleared every few minutes.
Comment 13 Michael Rennie CLA 2011-04-11 16:58:27 EDT
(In reply to comment #12)

> Unfortunately, we don't know when the JRE installs are modified on disk, so we
> cannot cache the source locations once and for all. But I guess a simple cache
> around the call to getDefaultSystemLibrarySource(lib) (HashMap<File, IPath)
> would solve the problem.

We do have a listener system so we can know when an IVMInstall has been added / changed / removed. See IVMInstallChangedListener for more details.

I think we could add a cache for the computed system libs and the computed system lib source and refresh it when the backing IVMInstall changes. LaunchingPlugin is our de-facto IVMInstallChangedfListener, so we could just add some code in there to force a cache refresh if the VM changes.

We already do something similar to this in LaunchingPlugin for default library infos for VMs, where we have: HashMap<installpath, LibraryInfo> which is cleared via the callback from IVMInstallType#disposeVMInstall.
Comment 14 Michael Rennie CLA 2011-04-13 15:32:39 EDT
Created attachment 193189 [details]
proposed fix

The patch provides a cache of the default library locations within StandardVMType#getDefaultLibraryLocations(..). The cache is cleared on the disposeVmInstall callback, and not touched otherwise. 

This works because the default set of LibraryLocations do not change over time, and any changes (edits, etc) to the VM install are saved in AbstractVMInstall which does not affect the default set of libraries - which contain the default source locations as well.

With this cache in place the only time the code was run to compute default VM libraries was during Eclipse startup, after that the cached values are returned. Testing showed that a simple no-op edit to a MANIFEST.MF file hit the cache 6 times - basically each time we need to ask "did this VM install change" the default set of libraries is consulted. There is a similar cache hit rate for simply opening the installed JREs page as well as closing Eclipse.
Comment 15 Michael Rennie CLA 2011-04-13 15:36:17 EDT
(In reply to comment #14)
> Created attachment 193189 [details]
> proposed fix
> 
> The patch provides a cache of the default library locations within
> StandardVMType#getDefaultLibraryLocations(..). The cache is cleared on the
> disposeVmInstall callback, and not touched otherwise. 

I should have also noted that the cache is not persisted to disk, so each time Eclipse is started the default lib locations + source locations are re-computed.
Comment 16 Michael Rennie CLA 2011-04-13 15:36:57 EDT
Curtis et. al. please review the patch.
Comment 17 Michael Rennie CLA 2011-04-18 10:54:46 EDT
Applied patch to HEAD
Comment 18 Curtis Windatt CLA 2011-04-18 17:31:04 EDT
The fix looks good to me.  I wasn't able to reproduce the super long wait times described in comment 0, so I can't confirm that the issue is resolved.  Can one of the original reporters confirm?  I tried with 5+ JREs installed and changed some of their source attachments, but saving never took more than a second or two.
Comment 19 Dani Megert CLA 2011-04-21 05:28:31 EDT
(In reply to comment #10)
> This is driving me nuts as I very single change of the MANIFEST.MF stalls my
> workbench for a couple of minutes. Add a new plugin to our project is broken
> for me.

Note that the reason for the MANIFEST.MF issue could also have been bug 290324.

James, would you be able to verify that the fix improves things for you?
Comment 20 James Blackburn CLA 2011-04-21 05:29:36 EDT
Yes, will do.