Bug 235448 - Expanding variables is extremely slow if both logical structures and show references are turned on
Summary: Expanding variables is extremely slow if both logical structures and show ref...
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Debug (show other bugs)
Version: 3.4   Edit
Hardware: PC Windows XP
: P3 critical (vote)
Target Milestone: 3.4 RC4   Edit
Assignee: JDT-Debug-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: performance
Depends on:
Blocks:
 
Reported: 2008-06-03 15:47 EDT by Samantha Chan CLA
Modified: 2008-06-04 10:14 EDT (History)
4 users (show)

See Also:
philippe_mulet: review+
darin.eclipse: review+
curtis.windatt.public: review+


Attachments
patch (2.02 KB, patch)
2008-06-03 17:05 EDT, Darin Wright CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Samantha Chan CLA 2008-06-03 15:47:53 EDT
1.  Our products have many logical structures.
2.  When debugging a large application, like a web server, or another instance of Eclipse, etc, we find that expanding a variable from the variables view is extremely slow if both logical structures and show references are turned on in the Variables View.

Here's some timing information when show references is turned on:

            Logical Structures On            Logical Structures Off
Dual Core   ~ 25 seconds                     ~ 1.5 seconds
Single CPU  ~ 45 seconds                     ?
Slow Linux  ~ 8 minutes                      3 seconds


When logical structures are turned on, I see that there are a bunch of JdwpCommandPacket.VM_CLASSES_BY_SIGNATURErequest sent, and they seem be time consuming.

Doing a little more digging, I see these requests are a result of each of the logical structure type delegates having their providesLogicalStructure(IValue value) method being called. They all seem to call IJavaobject.getJavaType(), which results in the JdwpCommandPacket.VM_CLASSES_BY_SIGNATURErequest.

I see that the IJavaObject is really a JDIReferenceListValue.  The getJavaType() method of JDIReferenceListValue does not cache its value, so for every logical structure type delegate, this same JDIReferenceListValue.getJavaType() call results in a JdwpCommandPacket.VM_CLASSES_BY_SIGNATURErequest.

I added caching to the JDIReferenceListValue.getJavaType() method, and the expansion time for the references node dropped to ~1.5 seconds, which is the same as when logical structures is not turned on.

Is there some reason that the getJavaType() method should not be caching the result?
If not, would it be possible to get this change into Eclipse 3.4?

This is my caching version of JDIReferenceListValue.getJavaType() :
	public IJavaType getJavaType() throws DebugException {
		if (fJavaType == null) {
			IJavaType[] javaTypes = getJavaDebugTarget().getJavaTypes(getReferenceTypeName());
			if (javaTypes.length > 0) {
		//		return javaTypes[0];
				fJavaType = javaTypes[0];
			}
		}
	//	return null;
		return fJavaType; 
	}

Here's some timing information when this fix is applied:
            Logical Structures On  
Dual Core   1.5 seconds
Single CPU  3 seconds
Slow Linux  4 seconds

We can try to optimize our code in our logical structures delegate.  Our experiments show that we can only reduce the time to expand variables by half.  We were not able to reduce it down to the "seconds" range.
Comment 1 Darin Wright CLA 2008-06-03 17:05:46 EDT
Created attachment 103436 [details]
patch

This patch does something similar to the suggested fix, but caches the type in the constructor (similar to code in JDIAllInstancesValue).
Comment 2 Darin Wright CLA 2008-06-03 17:10:53 EDT
Philippe, would you agree to this performance fix in 3.4? It turns out that we have the same code to make the "all instances" feature faster, but we did not extend the pattern to the "all references" feature. The fix is small and well understood. Although this is not a regression, the fix dramatically improves performance for large collections of references.
Comment 3 Philipe Mulet CLA 2008-06-04 04:35:09 EDT
Given it is critical, and we have a good fix at hand with drastic performance improvements, I would take it for 3.4.0.
Comment 4 Philipe Mulet CLA 2008-06-04 04:41:59 EDT
Question: wouldn't it be more beneficial to manage a type cache in a more global manner, rather than caching individual types on JDIReferenceListValue ? 
Comment 5 Darin Wright CLA 2008-06-04 09:35:11 EDT
(In reply to comment #4)
> Question: wouldn't it be more beneficial to manage a type cache in a more
> global manner, rather than caching individual types on 
> JDIReferenceListValue ? 

We don't maintain a cache of all loaded types. We retrieve types lazily as requested by the client. Once a type is retrieved, its information is cached. However, in this case the implementation was using an API to dynamically retrieve all types with a known name ("java.lang.Object[]"). 

This implementation of "list value" is only used by the Java 6 "show all references feature". It's a facade representing a value which is an array of objects referencing some other object.
Comment 6 Curtis Windatt CLA 2008-06-04 09:55:08 EDT
+1
Comment 7 Darin Wright CLA 2008-06-04 10:09:07 EDT
Applied patch.
Comment 8 Darin Wright CLA 2008-06-04 10:09:18 EDT
Verified.