Bug 323012 - [jsr14][compiler] Class literal value is not cached when target is jsr14
Summary: [jsr14][compiler] Class literal value is not cached when target is jsr14
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.7   Edit
Hardware: All All
: P3 major (vote)
Target Milestone: 3.7 M3   Edit
Assignee: JDT-Core-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: performance
Depends on:
Blocks: 313891
  Show dependency tree
 
Reported: 2010-08-18 08:04 EDT by Frederic Fusier CLA
Modified: 2010-10-04 11:41 EDT (History)
6 users (show)

See Also:


Attachments
Profiler output (11.61 KB, application/x-zip-compressed)
2010-09-28 06:23 EDT, Dani Megert CLA
no flags Details
Data from M1 (13.34 KB, application/x-zip-compressed)
2010-09-28 09:31 EDT, Dani Megert CLA
no flags Details
Team Project Set (1022 bytes, text/plain)
2010-10-01 04:06 EDT, Dani Megert CLA
no flags Details
ContextFinder patch (1.21 KB, patch)
2010-10-01 10:10 EDT, Thomas Watson CLA
no flags Details | Diff
Using compiler settings in org.eclipse.osgi from M1 (3.82 KB, text/plain)
2010-10-01 14:39 EDT, Thomas Watson CLA
no flags Details
Using compiler settings in org.eclipse.osgi post-M1 (3.40 KB, text/plain)
2010-10-01 14:41 EDT, Thomas Watson CLA
no flags Details
Proposed fix (1.03 KB, patch)
2010-10-01 15:22 EDT, Olivier Thomann CLA
no flags Details | Diff
Proposed fix + regression test (5.37 KB, patch)
2010-10-01 15:53 EDT, Olivier Thomann CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Frederic Fusier CLA 2010-08-18 08:04:02 EDT
Verifying I20100817-0800 results, it appears that there was a regression on
just after 3.7M1 (since build N20100807-2000) on perf test:
 - ContentTypeTest#testPluginXMLDirty()

This issue looks similar than bug 323009 and bug 323010, but for this test, the regression appears on all machines!?
Comment 1 Dani Megert CLA 2010-08-24 03:26:43 EDT
Will take a look at the test once the setup of the performance tests has been fixed (see bug 323439).
Comment 2 Dani Megert CLA 2010-09-27 11:43:15 EDT
I can reproduce the regression which is around 25%. The regression happened after 3.7 M1 (I20100805-1700). I can see it in N20100806-2000 and also in I20100810-0800. Tracking this down, I found out that the part of the performance test where it fails is not related to Text. The following performance measurement reveals the regression:

	Reader reader= new StringReader("");
	for (int i= 0; i < runs; i++) {
		IContentType contentType= null;
		performanceMeter.start();
		for (int j= 0; j < iterations; j++) {
			IContentDescription descriptionFor= Platform.getContentTypeManager().getDescriptionFor(reader, "plugin.xml", new QualifiedName[0]);
			contentType= descriptionFor.getContentType();
		}
		performanceMeter.stop();
		assertEquals(expectedContentType, contentType);
	}


Looking at the core.map file changes between M1 and I20100810-0800 I only found these two changes:
  plugin@org.eclipse.osgi=v20100809
  plugin@org.eclipse.equinox.supplement=v20100809
hence, I tried 3.7 M1 + org.eclipse.osgi from N20100806-2000. This resulted in the regression. Also, comparing profiler results showed that more time got spent in org.eclipse.core.runtime.internal.adaptor.ContextFinder.

Moving to Equinox for investigation.
Comment 3 Thomas Watson CLA 2010-09-27 12:38:55 EDT
I wonder why ContextFinder even gets used here.  ContextFinder is the context class loader.  I cannot imagine why performance critical code would use the context class loader in Eclipse.
Comment 4 Dani Megert CLA 2010-09-28 06:22:05 EDT
(In reply to comment #3)
> I wonder why ContextFinder even gets used here.  ContextFinder is the context
> class loader.  I cannot imagine why performance critical code would use the
> context class loader in Eclipse.
Yes, that was my impression too.
Comment 5 Dani Megert CLA 2010-09-28 06:23:49 EDT
Created attachment 179724 [details]
Profiler output

Note that this profiler output is based on the original test and not the snippet I pasted in comment 2.
Comment 6 Thomas Watson CLA 2010-09-28 08:40:59 EDT
Thanks Dani, can you run the profiler against a build that does not show the regression?  There was no changes to Context finder in the I20100817-0800 and I cannot think why that would be so much slower in that build.
Comment 7 Dani Megert CLA 2010-09-28 09:31:32 EDT
Created attachment 179740 [details]
Data from M1
Comment 8 Dani Megert CLA 2010-09-28 09:32:01 EDT
(In reply to comment #6)
> Thanks Dani, can you run the profiler against a build that does not show the
> regression?  There was no changes to Context finder in the I20100817-0800 and I
> cannot think why that would be so much slower in that build.
Given the test case I would assume that you can do further traces yourself ;-)
Comment 9 Dani Megert CLA 2010-10-01 04:06:48 EDT
Created attachment 180020 [details]
Team Project Set
Comment 10 Dani Megert CLA 2010-10-01 04:13:51 EDT
Since Tom mentioned, he can't see relevant changes in 'org.eclipse.osgi', I retried the scenario (not the simpler one from comment 2 but the one from the original performance test) and got the same result/regression.

Here are my detailed steps (Windows XP):

 0. close all applications
 1. install I20100805-1700
 2. install N20100806-2000
 3. start using I20100805-1700 with a new workspace
 4. install a 1.4 JRE (I took 1.4.2_20)
 5. install a 1.5 JRE (I took 1.5.0_22)
 6. import the attached Team Project Set (attachment 180020 [details])
 7. import 'org.eclipse.osgi' as binary project (from the active target)
 8. open org.eclipse.jdt.text.tests.performance.ContentTypeTest
 9. delete all tests except testPluginXMLDirty()
10. select ContentTypeTest.testPluginXMLDirty() in the Outline view
11. Run > Run As > JUnit Plug-in Test
    ==> at the end it prints information about the test run to the Console
12. remember the Elapsed Process time and repeat step 10 several times to 
    ensure the numbers are stable

13. import 'org.eclipse.osgi' as binary project from N20100806-2000
    (choose the 'Directory:' option)
14. Run > Run History > ContentTypeTest.testPluginXMLDirty()
    ==> at the end it prints information about the test run to the Console
15. remember the Elapsed Process time and repeat step 10 several times to 
    ensure the numbers are stable

16. compare the numbers and see the regression
Comment 11 Thomas Watson CLA 2010-10-01 08:46:36 EDT
Hi, Dani.  I looked at this in more detail yesterday.  I need to investigate some more.  It appears this may be related to our change to use jsr14 and, but I need to look into it some more.

It looks related to references to XXX.class but I need to do some more testing to confirm that.  In ContextFinder.basicFindClassLoaders() we loop over the stack and do check for (stack[i] == ContextFinder.class).  If I extract out the ContextFinder.class to be a constant then I see a noticeable performance gain.  I am not sure if the move to jsr14 changed the bytecodes in a way to make this less efficient.  Right now the ContextFinder.class reference causes a Class.forName each iteration of the loop which is quite expensive.
Comment 12 Thomas Watson CLA 2010-10-01 08:48:45 EDT
One possibility is that the loop optimizations are not as good with the jsr14 flag.  For example, you could imagine the compiler pulling the ContextFinder.class reference out to a local variable assignment before entering the loop.
Comment 13 Dani Megert CLA 2010-10-01 09:11:42 EDT
> One possibility is that the loop optimizations are not as good with the jsr14
> flag.  For example, you could imagine the compiler pulling the
> ContextFinder.class reference out to a local variable assignment before
> entering the loop.
That could well be. We'd have to look at the byte codes to be sure. As a first step I'd simply take the "good" code and compile it with jsr14.
Comment 14 Thomas Watson CLA 2010-10-01 10:10:27 EDT
Created attachment 180055 [details]
ContextFinder patch

(In reply to comment #13)
> That could well be. We'd have to look at the byte codes to be sure. As a first
> step I'd simply take the "good" code and compile it with jsr14.

I did this, it introduced the same performance degradation of at least 25%.  I then applied this patch and it brought it back to M1 performance.
Comment 15 Thomas Watson CLA 2010-10-01 10:14:15 EDT
I forgot to mention that applying a similar patch to M1 code base did not improve performance so there definitely is bytecode differences causing the slowdown between using jsr14 and our old settings which compiled down to a target of 1.3.
Comment 16 Thomas Watson CLA 2010-10-01 10:54:10 EDT
I released the patch.  I took a look at the bytecode.  It does appear there is an optimization that allows Class.forName call to be done much less when using 1.4 compiler settings vs jsr14.

I will leave this bug open until we confirm the performance improvements in a build.
Comment 17 Dani Megert CLA 2010-10-01 11:06:19 EDT
Olivier, maybe we can do something on the compiler side as well.
Comment 18 BJ Hargrave CLA 2010-10-01 12:56:03 EDT
(In reply to comment #17)
> Olivier, maybe we can do something on the compiler side as well.

I would assume -target jsr14 would enable the same compiler optimizations as -target 1.3 or 1.4?
Comment 19 Dani Megert CLA 2010-10-01 12:58:03 EDT
(In reply to comment #18)
> (In reply to comment #17)
> > Olivier, maybe we can do something on the compiler side as well.
> 
> I would assume -target jsr14 would enable the same compiler optimizations as
> -target 1.3 or 1.4?
Well, jsr14 is not an officially supported options. People using it, are basically on their own, knowing the risks and limitations.
Comment 20 Olivier Thomann CLA 2010-10-01 13:18:30 EDT
(In reply to comment #16)
> I released the patch.  I took a look at the bytecode.  It does appear there is
> an optimization that allows Class.forName call to be done much less when using
> 1.4 compiler settings vs jsr14.
You mean that when you are comparing the code compiled with 1.4 settings you end up with a better performance than using jsr14?
If you would say 1.5 vs jsr14, I could see why. But 1.4 vs jsr14, I need to check exactly what is going on.
In 1.5, the class literal is generated using the ldc bytecode, while in 1.4 there is a pretty big code generated for this.
Are you sure you are comparing 1.4 vs jsr 1.4 ?
Comment 21 Thomas Watson CLA 2010-10-01 14:39:39 EDT
Created attachment 180078 [details]
Using compiler settings in org.eclipse.osgi from M1

Here is the bytecode for ContextFinder#basicFindClassLoaders using the project compiler settings from the version of org.eclipse.osgi in M1

Compiler compliance level:		1.4
Generated .class files compatibility:	1.2
Source compatibility:			1.3
Comment 22 Thomas Watson CLA 2010-10-01 14:41:05 EDT
Created attachment 180079 [details]
Using compiler settings in org.eclipse.osgi post-M1

Here is the same ContextFinder.java file compiled with the project settings from org.eclipse.osgi post-M1.  This uses the jsr14 flag
Comment 23 Thomas Watson CLA 2010-10-01 14:43:04 EDT
The biggest difference I see is the M1 version contains a line:

     51  putstatic org.eclipse.core.runtime.internal.adaptor.ContextFinder.class$0 : java.lang.Class [94]

I assume this puts the ContextFinder.class on the stack as a static field that is referenced for the rest of the call instead of calling Class.forName each iteration.  I am not fluent in bytecode interpretation so I may be wrong.
Comment 24 Olivier Thomann CLA 2010-10-01 14:46:25 EDT
(In reply to comment #22)
> Here is the same ContextFinder.java file compiled with the project settings
> from org.eclipse.osgi post-M1.  This uses the jsr14 flag
ok, I got it. The value is not cached when jsr14 is used. I'll take care of this. This would be a bug in the compiler in jsr14 mode.

Moving to JDT/Core
Comment 25 Olivier Thomann CLA 2010-10-01 15:22:37 EDT
Created attachment 180084 [details]
Proposed fix
Comment 26 Olivier Thomann CLA 2010-10-01 15:52:45 EDT
Moving to JDT/Core
Comment 27 Olivier Thomann CLA 2010-10-01 15:53:10 EDT
Created attachment 180086 [details]
Proposed fix + regression test
Comment 28 Olivier Thomann CLA 2010-10-01 15:54:16 EDT
With the fix, the patch for ContextFinder provided in comment 14 is not required anymore.
Comment 29 Olivier Thomann CLA 2010-10-01 17:11:58 EDT
Released for 3.7M3.
Added regression test in:
org.eclipse.jdt.core.tests.compiler.regression.Jsr14Test#test1
Comment 30 Dani Megert CLA 2010-10-04 11:41:11 EDT
Verified in N20101003-2000.