Skip to content
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

RFC: Add instance allocator support to Wasmtime. #5

Merged
merged 6 commits into from
Feb 26, 2021

Conversation

peterhuene
Copy link
Member

Rendered RFC

This RFC proposes adding an "instance allocator" abstraction to Wasmtime to
allow for alternative instance resource allocation strategies.

One such strategy will be a "pooling instance allocator" that can quickly
allocate instances, memories, and tables from the host address space that has
been reserved in advance.

This RFC is inspired by a Lucet performance feature called "regions".

This RFC proposes adding an "instance allocator" abstraction to Wasmtime to
allow for alternative instance resource allocation strategies.

One such strategy will be a "pooling instance allocator" that can quickly
allocate instances, memories, and tables from the host address space that has
been reserved in advance.

This RFC is inspired by a Lucet performance feature called "regions".
@alexcrichton
Copy link
Member

Thanks for writing this up! The main piece I'm wondering about is whether, with this design, the InstanceAllocator traits are necessary. The Instance type (in both the wasmtime-runtime and wasmtime crates) doesn't have any sort of low-level constructor so there's really no way to implement this outside of the wasmtime crates themselves.

I think it'd be great if we could stabilize some form of low-level, possibly unsafe, constructor which would enable external crates to build on as well, but otherwise if all the types implementing these traits are local to the wasmtime crates themselves we may as well avoid the traits entirely and just have dedicated methods on Config?

@peterhuene
Copy link
Member Author

I agree that the traits aren't adding much given the very-much-internal definitions of both Instance and InstanceHandle, other than perhaps a future allocator implementation doesn't need to change Config to implement. That's not worth a lot, though.

I think it would be beneficial to try to make Instance and InstanceHandle unsafe externally constructable so that the pool allocator can be put in its own crate and then the traits would have merit. I'll see what I can do.

@peterhuene
Copy link
Member Author

@alexcrichton how awful would it be for Config to expose a method taking an Arc<dyn wasmtime_runtime::InstanceAllocator>? A complete non-starter?

This asymmetry between the InstanceAllocator traits in wasmtime and wasmtime-runtime necessitate a back pointer from wasmtime_runtime::Instance to the allocator that created it so that the instance can call into the allocator upon deallocation of the InstanceHandle. I would really like to see the back pointer removed.

Having Config directly take the runtime trait would both simplify the code (i.e. no duplicated types in the wasmtime crate) and eliminate the problem because Store could use the runtime trait directly to deallocate the instance.

This also means that if we open up the construction of Instance and InstanceHandle in the runtime so that instance allocators can be implemented in external crates, the Wasmtime API can use those implementations without introducing a wrapping type in the wasmtime crate.

@alexcrichton
Copy link
Member

Heh I always start with the idea that anything is possible!

More to the point though a move like that would basically just be about the costs. It would cost us in terms of stability that we would have to document that usage of the method is not covered under our semver stability promises. That's probably feasible to do since we don't expect every user to have to implement this? Especially if we can bundle "common" allocation strategies in the wasmtime crate which are covered under the semver rules.

Other than that the only other alternative I can think of is to sync up on the code you've got and see if anyone else is struck with inspiration of how to not have the dependency

@fitzgen
Copy link
Member

fitzgen commented Nov 30, 2020

It wouldn't solve the duplication issue, but would solve the API stability issues: we could create a wasmtime-traits crate that defines just the InstanceAllocator trait and necessary types (e.g. InstanceRequest) and say it has the same stability that the wasmtime crate does (even re-export it from wasmtime).

@peterhuene
Copy link
Member Author

peterhuene commented Dec 1, 2020

What if we kept the sole InstanceAllocator trait in wasmtime_runtime where it would inherently be unstable (and thus implementors would know that their implementations are subject to breaks in wasmtime_runtime) but we would then consider Config::with_instance_allocator to itself be stable despite taking Arc<dyn wasmtime_runtime::InstanceAllocator> as an argument? The wasmtime crate and any implementors of InstanceAllocator must agree on the definition anyway, right?

The "out of the box" instance allocator implementations could be exported via the wasmtime crate and thus considered stable as their only public API surface are their constructors.

We generally don't expect users to implement the trait themselves as it requires a lot of internal runtime understanding to do so, but we do want an easy mechanism for users to swap out the allocator implementations using the public Wasmtime API.

@fitzgen
Copy link
Member

fitzgen commented Dec 1, 2020

If we don't expect anyone else to implement this trait, then we might as well make it an enum InstanceAllocationStategy { Default, Pool } at the wasmtime API level, and not expose its guts, types, and implementation details. This would let us write the instance pool in its own (internal) crate, preserve API stability, and avoid duplicating types.

@peterhuene
Copy link
Member Author

I can get behind that. We could always extend any such enumeration for Custom if a trait is needed in the future.

Remove the `InstanceAllocator` trait and the `DefaultInstanceAllocator` struct
from the `wasmtime` crate.

Add the `InstanceAllocationStrategy` enum and update the related `Config`
method.
@peterhuene
Copy link
Member Author

I've updated the RFC with an enum approach that hides the implementation details from the wasmtime crate.

@alexcrichton
Copy link
Member

I think that's actually a good point that having an enum here is probably the way to go. We can always extend the enum in a backwards-compatible way (or just add more methods to Config) and I think it's a good observation that the allocation strategy is so tightly coupled to the internals of wasmtime we wouldn't really expect anyone to implement the traits anyway.

The wasmtime crate changes look good here to me! I'm not reading the internal changes too too closely, but I'm assuming they're all fine as well (and are easy to change if a problem arises)

@peterhuene
Copy link
Member Author

I agree that Default doesn't really describe what's going on. I'll go with OnDemand with a comment calling it the default allocation strategy.

Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

The public API looks good to me; the internal details make sense but, since they're internal, they aren't set in stone and we can always tweak and revisit things during implementation.

This commit updates the RFC to expand the `InstanceAllocator` trait so that an
instance allocator can validate modules being compiled and also control how a
JIT compiler is tuned.

This will be necessary for the pooling instance allocator to fail module
compilation early if the module being compiled cannot be instantiated by the
configured allocator.

This also renamed the "default" instance allocator to the more descriptive
`OnDemandInstanceAllocator`.
@peterhuene
Copy link
Member Author

peterhuene commented Jan 23, 2021

Motion to finalize with a disposition to merge

I'm proposing that we merge this RFC.

Early feedback has been received and all requested outstanding changes to the proposal has been made.

An implementation in Wasmtime has already been started.

Stakeholders sign-off

Tagging all employees of BA-affiliated companies who have committed to the Wasmtime repo in the last three months plus anyone who has given feedback on this PR as a stakeholder.

Fastly

IBM

Intel

Mozilla

Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

accepted/wasmtime-instance-allocator.md Outdated Show resolved Hide resolved
Co-authored-by: Andrew Brown <andrew.brown@intel.com>
@peterhuene
Copy link
Member Author

Entering Final Call Period

https://github.com/bytecodealliance/rfcs/blob/main/accepted/rfc-process.md#making-a-decision-merge-or-close

Once any stakeholder from a different group has signed off, the RFC will move into a 10 calendar day final comment period (FCP), long enough to ensure that other stakeholders have at least a full business week to respond.

The FCP will end on February 26th.

@peterhuene
Copy link
Member Author

The FCP has elapsed without any objections being raised; as a result I'm going to merge this. Thanks everyone!

@peterhuene peterhuene merged commit d91539e into bytecodealliance:main Feb 26, 2021
@peterhuene peterhuene deleted the instance-pools branch February 26, 2021 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants