JDK-8055954 : Questionable use of parallelStream() in jdk.nashorn.internal.runtime.Context$ContextCodeInstaller.initialize()
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: jdk.nashorn
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2014-08-25
  • Updated: 2015-06-04
  • Resolved: 2014-08-26
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
8u40Fixed 9 b29Fixed
Related Reports
Relates :  
Relates :  
A simple instrumentation tells that most of the time we are installing just a few classes, with total work under <400 us. This is not enough to get decent parallel improvements. In fact, it is close to the break-even against the sequential version. Therefore, the use of parallelStream is questionable. The fix is very simple:

$ hg diff
diff -r ad7a46083364 src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Mon Aug 25 20:26:53 2014 +0530
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Mon Aug 25 22:44:54 2014 +0400
@@ -166,7 +166,7 @@
             // do these in parallel, this significantly reduces class installation overhead
             // however - it still means that every thread needs a separate doPrivileged
             final Global global = currentGlobal.get();
-            classes.parallelStream().forEach(
+            classes.stream().forEach(
                 new Consumer<Class<?>>() {
                     public void accept(final Class<?> clazz) {

On the current jdk9/dev and this simple benchmark:

$ for I in `seq 1 5`; do ~/trunks/jdk9-dev/build/linux-x86_64-normal-server-release/images/j2sdk-image/bin/java -jar ~/trunks/jdk9-dev/build/linux-x86_64-normal-server-release/images/j2sdk-image/jre/lib/ext/nashorn.jar  -Dnashorn.typeInfo.disabled=false --class-cache-size=0 --persistent-code-cache=false -scripting --log=time test/script/basic/compile-octane.js -- --iterations 1 2>&1 | grep "Class Installation"; done

...yields a nice improvement. 

Before (parallel):
 [time] 'Class Installation'               4616 ms
 [time] 'Class Installation'               4563 ms
 [time] 'Class Installation'               4712 ms
 [time] 'Class Installation'               4637 ms
 [time] 'Class Installation'               4668 ms

After (sequential):
 [time] 'Class Installation'               2831 ms
 [time] 'Class Installation'               2755 ms
 [time] 'Class Installation'               2885 ms
 [time] 'Class Installation'               2816 ms
 [time] 'Class Installation'               2943 ms

One might consider a threshold for going to parallel version, but that threshold should be figured out experimentally.
What happened here is that we believed when they told us the stream can figure out on its own whether it's worth parallelizing or not. *sigh*

Additional thought: JDK-8055909 is about optimizing the payload for this stream. If we are successful there, the possible "win" for parallel class installation would be even lower.