Skip to content

Poor performance when having to "reset" JavaScript bindings scope #561

Open
@erstr2ggl

Description

@erstr2ggl

Hello,

we're still in the process of migrating our application from Rhino to GraalVM and are now at a place where we can compare our new GraalVM implementation with the old Rhino implementation. Sadly, performance is not as good as we had hoped.

The time to run one "action" has actually increased by a factor of around 2x compared to Rhino, which really isn't acceptable for our use case.

When profiling, the bottleneck quickly becomes apparent:
With our current implementation, we're creating a Context once and are then, when we need to reset the bindings scope, setting it with this method:

public static void setJavascriptScope(Map<String, Object> scope) {
    Value bindings = context.getBindings("js");
    for (String member : bindings.getMemberKeys()) {
        if (scope.containsKey(member)) {
            bindings.putMember(member, scope.get(member));
            scope.remove(member);
        } else {
            bindings.removeMember(member);
        }
    }

    for (Map.Entry<String, Object> newMember : scope.entrySet()) {
        bindings.putMember(newMember.getKey(), newMember.getValue());
    }
}

The problem lies with the call to removeMember(), which takes up ~90% of the time within this method.
In fact, simply setting the scope takes up ~70% of the time compared to ~30% of time that is spent actually evaluating our JavaScript code!

Now, the usual recommendation is to create a new Context instead of resetting the bindings scope like this, but we've found that this way is actually slightly faster and definitely easier to implement in our application.

Nonetheless, we've tried to create a new Context everytime we need to reset the bindings scope. Sadly, as we had already measured, performance isn't really faster that way. Instead of the bottleneck being the removeMember() method, now it's the creation of the new Context each time, meaning that performance is still ~2x worse.

For background, in our application, we're dealing with a lot (hundreds) of scope objects that need to be changed and set thousands (in some cases a few orders of magnitude more) of times during one "action". The actual JavaScript that is executed on the other hand is relatively basic and simple.

We fear that such a use case of GraalJS has (perhaps?) not yet been on your radar and that therefore, performance in this use case could be improved by optimizing the process of (re)setting the bindings scope.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions