-
-
Notifications
You must be signed in to change notification settings - Fork 612
Description
Describe the bug
I did some profiling on one of the benchmarks Richards. I don’t have the profile data to hand right now but around 20% of time was spent making function environments. A function environment is created on every function call.
The reason for the slow down is because every new function environment is wrapped in GC::New(), most of the GC congestion is coming from creating function environments. The GC eventually needs to collect, so has to stop the world and collect very often.
The benchmarks accentuate the problem because many functions are being called in a loop, so push_function is being called a lot.
Potential Solution
My question is, do we need to wrap all function environments in a GC? We need to keep them around if there’s re-entry (such as async or generators) or if we have a closure escape, but if a function has neither of these we could have a “fast path” where we bypass the GC wrapping.
We already perform escape analysis on functions at the AST level, but we don’t keep the result.
We could have some “is_reentry” field that is passed down into the code block to tell us if the function has any escape or any reentry. This boolean would be sent into push_function here
Then we can set how we want to store the environment inside of push_function This would require a refactor where we have an enum which represents an environment on the stack or in a GC:
#[derive(Clone, Trace, Finalize)]
pub enum EnvironmentPointer {
NonGcAllocated(Box<DeclarativeEnvironment>),
GcAllocated(Gc<DeclarativeEnvironment>),
}Then used in the outer Environment enum as:
#[derive(Clone, Trace, Finalize)]
pub enum Environment {
Declarative(EnvironmentPointer),
Object(Gc<ObjectEnvironment>)
}To Reproduce
- Checkout the boa/data repo. You can do a partial checkout of just the bench/bench-v8 subdirectory.
- build Boa with the
release-dbgprofile. - in the Makefile from the data repo remove the tests but keep Richard’s, run Make
- Use flamegraph or valgrind and run Boa against combined.js
Expected behavior
We see less time spent in push_function an GC Contention.