-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Make table/memory creation async functions #11470
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
Make table/memory creation async functions #11470
Conversation
|
I'll note that I've split this into two commits, the first of which is #11456 resurrected here. That commit cannot be split out to a second PR due to all the various constraints in play unfortunately, so this is a bit larger than I would have otherwise anticipated. |
|
Oh, I should also note, this is a 5% performance penalty overhead to instance instantiation. Benchmarking makes me think it's primarily related to the |
This commit is a step in preparation for bytecodealliance#11430, notably core instance allocation, or `StoreOpaque::allocate_instance` is now an `async fn`. This function does not actually use the `async`-ness just yet so it's a noop from that point of view, but this propagates outwards to enough locations that I wanted to split this off to make future changes more digestable. Notably some creation functions here such as making an `Instance`, `Table`, or `Memory` are refactored internally to use this new `async` function. Annotations of `assert_ready` or `one_poll` are used as appropriate as well. For reference this commit was benchmarked with our `instantiation.rs` benchmark in the pooling allocator and shows no changes relative to the original baseline from before-`async`-PRs.
This commit is a large-ish refactor which is made possible by the many previous refactorings to internals w.r.t. async-in-Wasmtime. The end goal of this change is that table and memory allocation are both `async` functions. Achieving this, however, required some refactoring to enable it to work: * To work with `Send` neither function can close over `dyn VMStore`. This required changing their `Option<&mut dyn VMStore>` arugment to `Option<&mut StoreResourceLimiter<'_>>` * Somehow a `StoreResourceLimiter` needed to be acquired from an `InstanceAllocationRequest`. Previously the store was stored here as an unsafe raw pointer, but I've refactored this now so `InstanceAllocationRequest` directly stores `&StoreOpaque` and `Option<&mut StoreResourceLimiter>` meaning it's trivial to acquire them. This additionally means no more `unsafe` access of the store during instance allocation (yay!). * Now-redundant fields of `InstanceAllocationRequest` were removed since they can be safely inferred from `&StoreOpaque`. For example passing around `&Tunables` is now all gone. * Methods upwards from table/memory allocation to the `InstanceAllocator` trait needed to be made `async`. This includes new `#[async_trait]` methods for example. * `StoreOpaque::ensure_gc_store` is now an `async` function. This internally carries a new `unsafe` block carried over from before with the raw point passed around in `InstanceAllocationRequest`. A future PR will delete this `unsafe` block, it's just temporary. I attempted a few times to split this PR up into separate commits but everything is relatively intertwined here so this is the smallest "atomic" unit I could manage to land these changes and refactorings.
02b763f to
cfc2cea
Compare
| vm::one_poll(Table::_new(store.as_context_mut().0, ty, init)) | ||
| .expect("must use `new_async` when async resource limiters are in use") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we not assert that this is a non-async config before the .expect(..) to catch mismatches a little earlier?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh this is actually replicating the documented behavior where this works with async_support so long as an async resource limiter isn't used. In that sense to avoid breaking the semantics here one_poll is what's required as opposed to an assert!(!async_support) plus vm::assert_ready.
| ); | ||
| store.on_fiber(|store| self.instantiate_impl(store)).await? | ||
| pub async fn instantiate_async(&self, store: impl AsContextMut<Data = T>) -> Result<Instance> { | ||
| self._instantiate(store).await |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And similarly assert that the config is async here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I've been making these changes I've actually been undoing a lot of assert!(async_support)-style assertions. Previously that was required because on_fiber was immediately used which required async_support to be turned on, but now it's just normal Rust async functions so there's no reason to prevent usage when async_support is disabled. In that sense it's intentional that the assert here is lost, but how's that sound to you?
| // FIXME(rust-lang/rust#145127) this should ideally use a version of | ||
| // `with_flush_and_retry` but adapted for async closures instead of only | ||
| // sync closures. Right now that won't compile though so this is the | ||
| // manually expanded version of the method. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a note for this to our items to discuss with the lang team, if we don't have one already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh this one's technically already fixed and just waiting on stabilization, and browsing rust-lang/rust#110338 shows this is pretty well-known, so not a major issue.
| /// The store that this instance is being allocated into. | ||
| pub store: &'a StoreOpaque, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is so nice to clean up
|
I'm going to go ahead and land this, but @fitzgen if you have follow up comments I'm happy to address them. |
Nope, looks good |
* Make core instance allocation an `async` function This commit is a step in preparation for bytecodealliance#11430, notably core instance allocation, or `StoreOpaque::allocate_instance` is now an `async fn`. This function does not actually use the `async`-ness just yet so it's a noop from that point of view, but this propagates outwards to enough locations that I wanted to split this off to make future changes more digestable. Notably some creation functions here such as making an `Instance`, `Table`, or `Memory` are refactored internally to use this new `async` function. Annotations of `assert_ready` or `one_poll` are used as appropriate as well. For reference this commit was benchmarked with our `instantiation.rs` benchmark in the pooling allocator and shows no changes relative to the original baseline from before-`async`-PRs. * Make table/memory creation `async` functions This commit is a large-ish refactor which is made possible by the many previous refactorings to internals w.r.t. async-in-Wasmtime. The end goal of this change is that table and memory allocation are both `async` functions. Achieving this, however, required some refactoring to enable it to work: * To work with `Send` neither function can close over `dyn VMStore`. This required changing their `Option<&mut dyn VMStore>` arugment to `Option<&mut StoreResourceLimiter<'_>>` * Somehow a `StoreResourceLimiter` needed to be acquired from an `InstanceAllocationRequest`. Previously the store was stored here as an unsafe raw pointer, but I've refactored this now so `InstanceAllocationRequest` directly stores `&StoreOpaque` and `Option<&mut StoreResourceLimiter>` meaning it's trivial to acquire them. This additionally means no more `unsafe` access of the store during instance allocation (yay!). * Now-redundant fields of `InstanceAllocationRequest` were removed since they can be safely inferred from `&StoreOpaque`. For example passing around `&Tunables` is now all gone. * Methods upwards from table/memory allocation to the `InstanceAllocator` trait needed to be made `async`. This includes new `#[async_trait]` methods for example. * `StoreOpaque::ensure_gc_store` is now an `async` function. This internally carries a new `unsafe` block carried over from before with the raw point passed around in `InstanceAllocationRequest`. A future PR will delete this `unsafe` block, it's just temporary. I attempted a few times to split this PR up into separate commits but everything is relatively intertwined here so this is the smallest "atomic" unit I could manage to land these changes and refactorings. * Shuffle `async-trait` dep * Fix configured build
This commit is a large-ish refactor which is made possible by the many
previous refactorings to internals w.r.t. async-in-Wasmtime. The end
goal of this change is that table and memory allocation are both
asyncfunctions. Achieving this, however, required some refactoring to enable
it to work:
Sendneither function can close overdyn VMStore.This required changing their
Option<&mut dyn VMStore>arugment toOption<&mut StoreResourceLimiter<'_>>StoreResourceLimiterneeded to be acquired from anInstanceAllocationRequest. Previously the store was stored here asan unsafe raw pointer, but I've refactored this now so
InstanceAllocationRequestdirectly stores&StoreOpaqueandOption<&mut StoreResourceLimiter>meaning it's trivial to acquirethem. This additionally means no more
unsafeaccess of the storeduring instance allocation (yay!).
InstanceAllocationRequestwere removed sincethey can be safely inferred from
&StoreOpaque. For example passingaround
&Tunablesis now all gone.InstanceAllocatortrait needed to be madeasync. This includes new#[async_trait]methods for example.StoreOpaque::ensure_gc_storeis now anasyncfunction. Thisinternally carries a new
unsafeblock carried over from before withthe raw point passed around in
InstanceAllocationRequest. A futurePR will delete this
unsafeblock, it's just temporary.I attempted a few times to split this PR up into separate commits but
everything is relatively intertwined here so this is the smallest
"atomic" unit I could manage to land these changes and refactorings.
cc #11430