High CPU consumption with Java-21 + Nashorn 15.4

Packiaraj S s.packiaraj at gmail.com
Sat Oct 26 20:15:01 UTC 2024


Thanks Rony & Ben,
Using JavaFX is an interesting idea, but that is a huge change for us and
not the first choice at this point in time.

Spent some more time in optimizing the Nashorn engine itself ( forgetting
licensing issues for a bit; I think that is worth a separate issue as such
) .
Converting  Context.ClassCache
<https://github.com/openjdk/nashorn/blob/main/src/org.openjdk.nashorn/share/classes/org/openjdk/nashorn/internal/runtime/Context.java#L387>
into
a global cache will share the code-cache  across threads; as simple as
making it static. We may need to make other parts of ClassCache as thread
safe as well
Do you see any issue in making Context.ClassCache
<https://github.com/openjdk/nashorn/blob/main/src/org.openjdk.nashorn/share/classes/org/openjdk/nashorn/internal/runtime/Context.java#L387>
as
global cache.

Really appreciate your help.

thanks
Sakkanan


Here is the decompile 'script' class for reference
==============================

package org.openjdk.nashorn.internal.scripts;

import org.openjdk.nashorn.internal.runtime.PropertyMap;
import org.openjdk.nashorn.internal.runtime.ScriptFunction;
import org.openjdk.nashorn.internal.runtime.ScriptObject;
import org.openjdk.nashorn.internal.runtime.ScriptRuntime;
import org.openjdk.nashorn.internal.runtime.Source;

public class Script$1$\^eval\_ extends JS {
  private static Source source;

  private static Object[] constants;

  public static final boolean strictMode = false;

  public static boolean :program(ScriptFunction :callee, Object :this) {
    ScriptObject :scope = :callee.getScope();
    JO0P0 jO0P0 = new JO0P0(:getMap(0), :scope);
    :scope = ScriptRuntime.mergeScope((ScriptObject)jO0P0);
    return false;
  }

  public static ScriptFunction :createProgramFunction(ScriptObject
paramScriptObject) {
    return ScriptFunction.create(constants, 1, paramScriptObject);
  }

  public static PropertyMap :getMap(int paramInt) {
    return (PropertyMap)constants[paramInt];
  }

  public static void :setMap(int paramInt, PropertyMap paramPropertyMap) {
    constants[paramInt] = paramPropertyMap;
  }
}

===========


On Sat, Oct 26, 2024 at 7:50 AM Rony G. Flatscher <Rony.Flatscher at wu.ac.at>
wrote:

> Just a somewhat "crazy" idea: it seems you are well acquainted with the
> details and if it turns out that Nashorn is not viable, how about trying to
> use JavaFX WebKit's JavaScript instead for your purposes? You may be able
> to implement a ScriptEngine for it that could better serve your needs?
>
> You could check out the documentation of the JavaFX module javafx.web and
> take a look at its javafx.scene.web.WebEngine class as it documents its
> interfaces to JavaScript (note that this implementation mandates that
> WebEngine objects are created and accessed on the JavaFX Application/GUI
> thread only).
>
> If exploring that route, maybe the first thing to do is to ask about the
> viability of such an approach on the javafx mailing list (openjfx-dev
> mailing list of openjdk.org) first?
>
> ---rony
>
>
> On 26.10.2024 00:45, Packiaraj S wrote:
>
> Thanks Ben.
> I used visualVM just to compare CPU consumption between Java-11 & Java 21.
> Definitely spending more time using profilers will help to identify the
> issue but Nashorn's licensing (GPL v2) and inability to create Issue/PR in
> github repo makes me think if its a right direction towards the
> resolution of the issue.
>
> On Fri, Oct 25, 2024 at 2:50 PM Ben Evans <benjamin.john.evans at gmail.com>
> wrote:
>
>> You might try investigating further with a combination of JFR (JDK
>> Flight Recorder, built-in to the JDK) and the GUI tool JMC (JDK
>> Mission Control, available here: https://adoptium.net/en-GB/jmc/)
>>
>> I often find it to be significantly more useful than the capabilities
>> of VisualVM.
>>
>> Thanks,
>>
>> Ben
>>
>> On Fri, Oct 25, 2024 at 4:21 PM Packiaraj S <s.packiaraj at gmail.com>
>> wrote:
>> >
>> > Hello,
>> >
>> > We use Nashorn with Tomcat as a long running service. We recently
>> migrated to Java 21. ( from java 11 and the performance is good with
>> Java-11).
>> > Since Nashorn is moved out of JDK we have pulled in
>> 'nashorn-core-15.4.jar' and its dependency (asm*) and loaded it as a
>> regular jar. Functionality everything looks ok.
>> >
>> > During the performance test we observed very high cpu usage when
>> nashorn engine's 'eval' is called.  The CPU consumption is so high that
>> instances are throttled and performance becomes 10x slower compared to
>> java-11.
>> >
>> > Upon investigation using profiler (jvisualVM) looks like most of the
>> CPU is spent in compile method, more specifically during
>> ContextCodeInstaller.initialize and NamedContextCodeInstaller.install
>> >
>> > Looks like the compile method is optimized with cache, unfortunately
>> the cache is in context scope, meaning it's not shared between
>> ScriptEngines and Nashorn is not thread-safe (as per the docs) to use a
>> single instance of ScriptEngine across all threads. Also the cache uses
>> 'soft-reference', would it cause double whammy when there is a memory
>> pressure.
>> >
>> > so, how to improve the performance of the Nashorn engine, specifically
>> the `compile` part.
>> > Is there any other option we can try? BTW,  persistent-code-cache did
>> not help as OptimisticTypesPersistence.getVersionDirName is performing
>> poorly
>> >
>> > Test code that we used to study this high CPU issue is attached.
>> >
>> > Thanks a lot for hemp & any insight
>> > Sakkanan
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/nashorn-dev/attachments/20241026/3f9487be/attachment-0001.htm>


More information about the nashorn-dev mailing list