oracle / graaljs

A ECMAScript 2023 compliant JavaScript implementation built on GraalVM. With polyglot language interoperability support. Running Node.js applications!
Universal Permissive License v1.0
1.77k stars 189 forks source link

Slow performance of GraalJS im compare with Nashorn. #195

Closed MaksymDarmohval closed 3 years ago

MaksymDarmohval commented 5 years ago

I am working on task to migrate from Nashorn JS engine to GraalJS. During process I figure out that performance with GraalJS is in average 8-10 worse than show Nashorn engine. In our application user can write own script on JS and execute it to manage domain objects or/and do another things like send email, perform HTTP requests etc. In general there are two script to execute by JS engine. One script provide general API functions that provide methods to manipulate over domain objects and second is user script. For binding JS functions and main application are created bindings for java wrappers over service layer. Some of them have to re-created each time when script executed. In generally code with GraalJS looks next way:

private Engine engine;
private Context.Builder contextBuilder;
private Source baseScriptSource;

public void init() {
    engine = Engine.create();
    contextBuilder = Context.newBuilder("js").engine(engine).allowCreateThread(true).allowAllAccess(true);
    baseScriptSource = Source.newBuilder("js", ".../scripts/api.js").build();
}

public void executeScript() {
    Source userSource = Source.create("js", ".../userScript.js");
    try {
        context = contextBuilder.build();

        Value binding = context.getBindings("js");
        binding.putMember("javaApi", new JavaApiWrapper(...));
        binding.putMember("logApi", new LogApiWrapper(...));
        binding.putMember("restApi", new RestApiWrapper(...));
        ........
        binding.putMember("metamodelApi", new MetamodelApiWrapper(...));

        context.eval(baseScriptSource);
        context.eval(userSource);

    } catch (Exception e) {
    ....
    }
}

I try different aproaches like: create new Context eache time to user script execute, caching Context for each user's script with evaluated basic script. No one of these approaches show tolerable result with compare to Nashorn JS engine.

There are logs for performance result for GrallJS: [INFO ] [2019-07-22 13:04:15] (service.scriptContainer.ScriptServiceImpl) exec(ms): 1,642 [INFO ] [2019-07-22 13:04:20] (service.scriptContainer.ScriptServiceImpl) exec(ms): 1,077 [INFO ] [2019-07-22 13:04:33] (service.scriptContainer.ScriptServiceImpl) exec(ms): 1,059 [INFO ] [2019-07-22 13:04:37] (service.scriptContainer.ScriptServiceImpl) exec(ms): 1,051 [INFO ] [2019-07-22 13:04:41] (service.scriptContainer.ScriptServiceImpl) exec(ms): 1,103 [INFO ] [2019-07-22 13:04:45] (service.scriptContainer.ScriptServiceImpl) exec(ms): 908 [INFO ] [2019-07-22 13:04:48] (service.scriptContainer.ScriptServiceImpl) exec(ms): 820 [INFO ] [2019-07-22 13:04:53] (service.scriptContainer.ScriptServiceImpl) exec(ms): 880 [INFO ] [2019-07-22 13:04:57] (service.scriptContainer.ScriptServiceImpl) exec(ms): 825

and logs for that same script for Nashorn JS engine: [INFO ] [2019-07-17 13:14:51] (service.scriptContainer.ScriptServiceImpl) exec(ms): 243 [INFO ] [2019-07-17 13:15:05] (service.scriptContainer.ScriptServiceImpl) exec(ms): 178 [INFO ] [2019-07-17 13:15:17] (service.scriptContainer.ScriptServiceImpl) exec(ms): 194 [INFO ] [2019-07-17 13:15:30] (service.scriptContainer.ScriptServiceImpl) exec(ms): 167 [INFO ] [2019-07-17 13:15:40] (service.scriptContainer.ScriptServiceImpl) exec(ms): 167 [INFO ] [2019-07-17 13:15:48] (service.scriptContainer.ScriptServiceImpl) exec(ms): 149 [INFO ] [2019-07-17 13:15:57] (service.scriptContainer.ScriptServiceImpl) exec(ms): 164

Could you give some advices how to improve GrallJS performance ?

thomaswue commented 5 years ago

What are the Java versions you are running those configurations ("java -version")?

MaksymDarmohval commented 5 years ago

java version "11.0.3" 2019-04-16 LTS Java(TM) SE Runtime Environment 18.9 (build 11.0.3+12-LTS) Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.3+12-LTS, mixed mode)

GraalJS: 19.0.0

thomaswue commented 5 years ago

Are you using a Maven configuration that enables the GraalVM compiler like shown at https://github.com/graalvm/graal-js-jdk11-maven-demo? Otherwise, you will run in interpreted mode only. Generally, we recommend running on a GraalVM download, e.g. GraalVM 19.1.1 (https://www.graalvm.org/downloads/).

MaksymDarmohval commented 5 years ago

Application is deployed under Tomcat 9.0.13. Configured CATALINA_OPTS:

set "GR_COML_PATH=%cd%\compiler" set "CATALINA_OPTS=%CATALINA_OPTS% -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI --module-path=%GR_COML_PATH% --upgrade-module-path=%GR_COML_PATH%\compiler.jar"

After update GrallJS libraries to 19.1.1 performance has improved but stay slow.

[INFO ] [2019-07-26 14:50:15] (service.scriptContainer.ScriptServiceImpl) exec(ms): 864 [INFO ] [2019-07-26 14:50:23] (service.scriptContainer.ScriptServiceImpl) exec(ms): 633 [INFO ] [2019-07-26 14:50:26] (service.scriptContainer.ScriptServiceImpl) exec(ms): 585 [INFO ] [2019-07-26 14:50:29] (service.scriptContainer.ScriptServiceImpl) exec(ms): 608 [INFO ] [2019-07-26 14:50:32] (service.scriptContainer.ScriptServiceImpl) exec(ms): 679 [INFO ] [2019-07-26 14:50:36] (service.scriptContainer.ScriptServiceImpl) exec(ms): 588 [INFO ] [2019-07-26 14:50:38] (service.scriptContainer.ScriptServiceImpl) exec(ms): 574 [INFO ] [2019-07-26 14:50:42] (service.scriptContainer.ScriptServiceImpl) exec(ms): 565 [INFO ] [2019-07-26 14:50:45] (service.scriptContainer.ScriptServiceImpl) exec(ms): 514 [INFO ] [2019-07-26 14:50:48] (service.scriptContainer.ScriptServiceImpl) exec(ms): 580 [INFO ] [2019-07-26 14:50:51] (service.scriptContainer.ScriptServiceImpl) exec(ms): 548

Can't test application on OpenJDK from https://www.graalvm.org/downloads/, get next error: Unrecognized option: --module-path=C:\compiler Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit.

wirthi commented 5 years ago

On our own "GraalVM" build, you don't need the --module-path option, GraalVM already ships with GraalVM compiler as optimizing compiler. Just start your app as you would do on another JDK.

MaksymDarmohval commented 5 years ago

There are performance logs with GraalVM:

[INFO ] [2019-07-26 16:06:23] (service.scriptContainer.ScriptServiceImpl) exec(ms): 886 [INFO ] [2019-07-26 16:06:27] (service.scriptContainer.ScriptServiceImpl) exec(ms): 848 [INFO ] [2019-07-26 16:06:31] (service.scriptContainer.ScriptServiceImpl) exec(ms): 689 [INFO ] [2019-07-26 16:06:34] (service.scriptContainer.ScriptServiceImpl) exec(ms): 848 [INFO ] [2019-07-26 16:06:38] (service.scriptContainer.ScriptServiceImpl) exec(ms): 720 [INFO ] [2019-07-26 16:06:41] (service.scriptContainer.ScriptServiceImpl) exec(ms): 584 [INFO ] [2019-07-26 16:06:44] (service.scriptContainer.ScriptServiceImpl) exec(ms): 620 [INFO ] [2019-07-26 16:06:48] (service.scriptContainer.ScriptServiceImpl) exec(ms): 530 [INFO ] [2019-07-26 16:06:51] (service.scriptContainer.ScriptServiceImpl) exec(ms): 591 [INFO ] [2019-07-26 16:06:54] (service.scriptContainer.ScriptServiceImpl) exec(ms): 586 [INFO ] [2019-07-26 16:06:56] (service.scriptContainer.ScriptServiceImpl) exec(ms): 524 [INFO ] [2019-07-26 16:06:59] (service.scriptContainer.ScriptServiceImpl) exec(ms): 545

performance stay slow.

wirthi commented 5 years ago

Any chance we can execute (parts of) your sourcecode so we can investigate ourselves?

MaksymDarmohval commented 5 years ago

Sent example on mail.

ieugen commented 4 years ago

I think I am having similar issues. @MaksymDarmohval: Did you manage to solve the performance issues? How?

lehvolk commented 4 years ago

We are migrating from Rhino and in our case problem was in calls to Java code: Packages.com.mycompany.service.ServiceClass. In this case Graal JS engine calls com.oracle.truffle.js.runtime.java.JavaPackage#getClass which produces tons of com.oracle.truffle.polyglot.HostLanguage$HostLanguageException inside. That simply kills performance. Replacing Packages.com.mycompany.service.ServiceClass with const ServiceClass = Java.type('...') got 5x performance boost for us.