You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi. I probably does not understand things around scripts caching well enough. Here is my "problem".
I have a very simple JavaScript script which just concatenates two strings. When I call this script in a loop of lets say 100 000 iterations, and in each iteration I use the same Context, then it's pretty quick.
But when I want to use "engine sharing" instead, that means in each iteration create new Context but with shared Engine, then it is very slow.
My understanding was, that the script evaluated in first (few) iterations would be parsed, optimized and cached in the engine, so each subsequent context would benefit from the optimizations/parsing in the first (few) iterations. But that does not seem to be true. Could you please clarify to me, how is it intended to work and why there is so big difference?
I have tested it with OpenJDK 21, but also with Graal VM 21/24. The behavior is more or less the same. Graal version 23.1.2, but also the 24.2.1 on JDK 24.
Here is the code which I used to "benchmark" it:
publicclassGraalJsExample {
privatestaticfinalSourceSCRIPT = Source.create("js", "param1 + param2");
publicstaticvoidmain(String[] args) {
System.out.println("Generating random strings...");
finalvarstrings = createRandomStrings(100_001);
System.out.println("Benchmarking");
for (inti = 0; i < 10; i++) {
System.out.println("Iteration " + (i + 1) + " ---------------------");
finallongstartLoop = System.nanoTime();
// Uncomment one of bellow two linesbenchmarkWithContextReuse(strings);
//benchmarkWithSharedEngine(strings);finallongendLoop = System.nanoTime();
finaldoubletotalSeconds = (endLoop - startLoop) / 1_000_000_000.0;
System.out.printf("JS execution loop completed in: %.3f seconds%n", totalSeconds);
System.out.printf("Average time per iteration: %.3f ms%n",
(endLoop - startLoop) / 1_000_000.0 / (strings.size() -1));
}
}
privatestaticvoidbenchmarkWithContextReuse(List<String> strings) {
intcharactersCount = 0;
try (finalContextcontext = Context.newBuilder()
.allowHostAccess(HostAccess.UNTRUSTED)
.build()) {
for (inti = 1; i < strings.size(); i++) {
charactersCount += concatWithJs(context, strings.get(i - 1), strings.get(i)).length();
}
}
System.out.printf("Number of characters (Just to use the script result for something): %d.%n", charactersCount);
}
privatestaticvoidbenchmarkWithSharedEngine(List<String> strings) {
intcharactersCount = 0;
try (finalEngineengine = Engine.create()) {
for (inti = 1; i < strings.size(); i++) {
try (finalContextcontext = Context.newBuilder()
.engine(engine)
.allowHostAccess(HostAccess.UNTRUSTED)
.build()) {
charactersCount += concatWithJs(context, strings.get(i - 1), strings.get(i)).length();
}
}
}
System.out.printf("Number of characters (Just to use the script result for something): %d.%n", charactersCount);
}
privatestaticStringconcatWithJs(Contextcontext, Stringparam1, Stringparam2) {
context.getBindings("js").putMember("param1", param1);
context.getBindings("js").putMember("param2", param2);
returncontext.eval(GraalJsExample.SCRIPT).asString();
}
privatestaticStringconcatWithGroovy(Scriptscript, Stringparam1, Stringparam2) {
finalBindingbinding = newBinding(Map.of("param1", param1, "param2", param2));
script.setBinding(binding);
returnscript.run().toString();
}
privatestaticList<String> createRandomStrings(intcount) {
finalRandomrandom = newRandom();
finalList<String> result = newArrayList<>(count);
// Generate random strings of length 5-15 charactersfor (inti = 0; i < count; i++) {
finalintlength = random.nextInt(11) + 5; // Random length between 5 and 15finalStringBuildersb = newStringBuilder(length);
for (intj = 0; j < length; j++) {
// Generate random printable ASCII characters (from '!' to '~')finalcharc = (char) (random.nextInt(94) + 33);
sb.append(c);
}
result.add(sb.toString());
}
returnresult;
}
}
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Hi. I probably does not understand things around scripts caching well enough. Here is my "problem".
I have a very simple JavaScript script which just concatenates two strings. When I call this script in a loop of lets say 100 000 iterations, and in each iteration I use the same
Context
, then it's pretty quick.But when I want to use "engine sharing" instead, that means in each iteration create new
Context
but with sharedEngine
, then it is very slow.My understanding was, that the script evaluated in first (few) iterations would be parsed, optimized and cached in the engine, so each subsequent context would benefit from the optimizations/parsing in the first (few) iterations. But that does not seem to be true. Could you please clarify to me, how is it intended to work and why there is so big difference?
I have tested it with OpenJDK 21, but also with Graal VM 21/24. The behavior is more or less the same. Graal version 23.1.2, but also the 24.2.1 on JDK 24.
Here is the code which I used to "benchmark" it:
Beta Was this translation helpful? Give feedback.
All reactions