-
Notifications
You must be signed in to change notification settings - Fork 195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unremovable Javascript Bindings #146
Comments
Thanks for your report, I can confirm this is the current behavior. I will need some more investigation here. While we do not support the removing of bindings at all from JavaScript, this is somewhat correct as you could also not (successfully) remove the objects you create via Same applies to Best, |
@wirthi thanks for the response. The suggested Regarding creating new Contexts: Even using a single Engine and Sources for caching across Contexts (from the same engine) does not provide the performance of reusing pooled/warmed Contexts. We have a real-time low-latency product, so this area is critical for us. |
Also looking for a way to "reset" things or restore global to a known state as a workaround for oracle/graal#631. Can anyone comment on how the graaljs ScriptEngine implementation achieve this? The JSR 223 mandates this behaviour via |
Did a little more investigation into workarounds for this, including wrapping / scoping to be able to 'reset' the context. It seems like there are a few ways to do this with normal JS, anonymous functions etc as described above. There appears to be a gap around using ES6 modules (which work well in graaljs), because ES6 modules Seems like we are stuck between this issue (resetting and reuse within the current context) and oracle/graal#631 (reuse an object across contexts). With no options that work for all approaches? 😢 |
+1 for context reset to a snapshot state. Sharing values across context and/or returning to prior context states would be extremely helpful for our transition from Nashorn to GraalJS. |
The solution we suggest is to create a new context and use caching to achieve the necessary performance. https://www.graalvm.org/docs/reference-manual/embed/#code-caching-across-multiple-contexts Reseting the context to a certain state - e.g. by removing certain bindings - is not possible right now and would not be faster regarding peak performance. @hashtag-smashtag you state this solution would not be fast enough - do you have a working benchmark for that? What do you compare it to, an existing solution in Nashorn? Best, |
That only really works for code, not data. A JSON Parsed object isnt going to be fast to read into a new context second time.
A specific example I have is managing a 10MB JSON state file. In nashorn the in memory object (effectively a map) can be passed from one context to another (we managing synchronizing map access) so overhead is effectively zero, in graal that would mean stringify and parse again 10MB of data. That’s going to take some time (and cycles). It feels like you could do this but are blocked by the object sharing across context guard.
As mentioned if you could reset a context, you could avoid the persist/parse step and make it more like nashorn, but we can’t do that either.. so that leaves no options effectively?
Maybe a possible answer is to add an option to disable the object sharing guard? At the users peril / no guarantees / it will break things etc disclaimers, same as the guarantees nashorn made about concurrent execution (it’s not supported but not prevented).
…On 11 Jun 2019, 10:12 PM +1000, Christian Wirth ***@***.***>, wrote:
The solution we suggest is to create a new context and use caching to achieve the necessary performance. https://www.graalvm.org/docs/reference-manual/embed/#code-caching-across-multiple-contexts
Reseting the context to a certain state - e.g. by removing certain bindings - is not possible right now and would not be faster regarding peak performance. @hashtag-smashtag you state this solution would not be fast enough - do you have a working benchmark for that? What do you compare it to, an existing solution in Nashorn?
Best,
Christian
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
|
Came across this, thought it might be a decent workaround, its kinda overkill. Doesn't work OTB either, could likely patch it to work or lift some ideas to solve for immutable global object in graal. https://github.com/Agoric/realms-shim Edit: Just realised this obviously doesn't solve for the es6 modules problem, ignore me.. |
Don't see any immediate TODO here for us. Our preferred and strongly suggested methods for this kind of Problem is: Create a new Context for each iteration and use the Source code sharing to still have the execution fast. Regarding https://github.com/Agoric/realms-shim: we do adopt ECMAScript proposals once their adoption seems reasonably safe, i.e. when they reach stage 3. Happy to accept contributions earlier, though. |
@wirthi Are you aware that even with source code sharing, loading a library into a clean context is quite slow? 95 millis passed creating 1000 graal contexts I am creating the contexts in the same Engine instance. |
Exactly, Source sharing is not sufficient when one needs to load/eval a bunch of classes/libs into a new Context every time. It's that 'ok this is how I want every new Context to be populated' state that we need on every new Context, quickly. |
Can you please share a minified but running example, so we can argue about actual code and inspect its runtime behavior. |
Hi! Built 1000 contexts in 59ms |
Hi @fdlk thanks for your code. Makes it a lot easier to argue. part 1 - not evaluating anything
part 2 - evaluating the cached magma.js
Yes, the first few iterations are slow. The very first especially, as this is running mostly interpreted, nothing compiled yet. It gets faster though as during each iteration more code is compiled (and cached), until ultimately:
So we are down to 2-4 ms per iteration, while evaling the (cached!) lib of 34kb each time. With one outlier of 15ms here (could be GC, could be another process intervening, etc.).
I'd call that: the cache working. Best, |
@wirthi
It still is a significant difference, and that is also what we are seeing in production. |
Hi @fdlk confirmed, I see a 1:6 difference between just We are working on all kinds of performance optimizations (especially around warmup, but of course also peak performance), and performance of the API (as in this case; you are not actually running a lot of JS code here) is watched (and improved) a lot. I don't think we can do anything immediate in this very area but we strive to improve here, of course. Have you measured the performance degradation you care about is actually happening in practice? Assuming Graal.js IS faster than Nashorn when executing JS code (if that is not the case, that is a whole different issue we are happy to have a look at), this slower start per context should be compensated for by faster JS execution afterwards, when warmed up. Or asked concretely: How much is the impact of slower startup on the full execution? What is the whole roundtrip time of an execution (opening context, loading library, executing user code, closing context) on Graal.js VS Nashorn? Best, |
Hi @wirthi We really do see something like a factor 4 impact in production, but to be fair the complete comparison with Nashorn is a bit more nuanced. Some contextWe have a mapping project where we map 10000-20000 entities of one type to entities of another type. Speedup: Proxying vs CopyingThe time-intensive step in Nashorn was creating a Map<String, Object> for the row because Nashorn didn't allow us to proxy native Java entities into the context, and the entities can reference other entities so we had to clone them up to a certain depth. Now, in GraalJS (like we used to way back when in RhinoScript) we can create an ObjectProxy and need not copy a ton of attributes that the algorithm will only rarely use. This is great, for a typical project with entities that got copied 3 deep I saw a speedup from 3m 37s (Nashorn) to 46s (GraalJS). Yay! You could say this is more something Nashorn was bad at than something that GraalJS does really great, but I really like it! 👍 Slowdown: Loading the libraryBut this speedup only works when we reuse the same Context for the entire mapping project. In Nashorn we created a fresh context for each cell and copied the bindings (like MagmaScript object and $ function) into it, to clean up any mess the previous evaluation might have left behind. If we create a new context per entity, the execution goes back up to 1m46s. If we create a new context per attribute, we're back at 3m 33s. What we didWe decided this was not worth the slowdown and now reuse the same context between evaluations where we have a clear large unit of work, like these mapping jobs. It took some twiddling to prevent an extra Context parameter in each method call of the mapping service. TL;DRWhen running lots of little scripts that depend on a library, it really hurts if you need to load the library for each execution and we'd be seriously helped if there were some way to clean up a context after use or to copy compiled objects around between contexts. I suspect that others see this too. |
Have exactly the same problem here. Even in the same conditions migrating from nashorn. Is there a hope to get a solution? |
It is very important to share binding value across context. if we take example 1MB JSON data evaluation repeatedly with new context , it will hurt the performance. |
Context bindings added by javascript are not removable.
Example test written in Groovy:
While bindings we add via
bindings.putMember
are removable viabindings.removeMember
.Part of our design, like others (#67, #121), involves reusing pooled Contexts from a single Engine. We want to clear away bindings on context reuse. The only way we've found to achieve this is to ensure that all Javascript code on the Context runs wrapped in an anonymous function (example in Groovy):
Ideally
bindings.removeMember
could work for any binding? Or maybe abindings.clearAll()
method? Another idea is a bindings proxy: #44The text was updated successfully, but these errors were encountered: