-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Implement opt-in for enabling WASI to block the current thread #8190
Implement opt-in for enabling WASI to block the current thread #8190
Conversation
Currently all of Wasmtime's implementation of WASI is built on Tokio, but some operations are currently not asynchronous such as opening a file or reading a directory. Internally these use `spawn_blocking` to satisfy the requirements of async users of WASI to avoid blocking the current thread. This use of `spawn_blocking`, however, ends up causing mostly just performance overhead in the use case of the CLI, for example, where async wasm is not used. That then leads to this commit, implementing an opt-in mechanism to be able to block the current thread. A `WasiCtx` now has a flag indicating whether it's ok to block the current thread and that's carried to various filesystem operations that use `spawn_blocking`. The call to `spawn_blocking` is now conditional and skipped if this flag is set. Additionally the invocation point in the CLI for wasm modules is wrapped in a Tokio runtime to avoid entering/exiting Tokio in the "leaves" when wasm calls the host, as happens today. This hits a better fast path in Tokio that appears to be more efficient. Semantically this should not result in any change for CLI programs except in one case: file writes. By default writes on `output-stream` in WASI are asynchronous meaning that only one write can be in flight at a time. That being said all current users are immediately blocking waiting for this write to finish anyway, so this commit won't end up changing much. It's already the case that file reads are always blocking, for example. If necessary in the future though this can be further special-cased at the preview1 layer.
crates/wasi/src/filesystem.rs
Outdated
let (r, mut buf) = if self.allow_blocking_current_thread { | ||
run(&self.file) | ||
} else { | ||
let f = Arc::clone(&self.file); | ||
spawn_blocking(move || run(&f)).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.
Might be kinda nice to wrap this dance into a helper method so that we don't have to check self.allow_blocking_current_thread
everywhere and instead call self.spawn_blocking
or something that internally either does a real spawn_blocking
or runs the thing immediately on the current thread.
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.
Sounds good yeah, I did some refactoring to thread this through File
which has a similar helper already.
Pass around `&File` instead.
This commit fixes a bug that was introduced in bytecodealliance#8190 and brought up on [Zulip]. In bytecodealliance#8190 there was a subtle change in how Tokio and the CLI are managed, namely that a Tokio runtime is installed at the start of the CLI to avoid entering/exiting the runtime on each blocking call. This had a small performance improvement relative to entering/exiting on each blocking call. This meant, though, that calls previously blocked with `Runtime::block_on` and now block with `Handle::block_on`. The [documentation of `Handle::block_on`][doc] has a clause that says that for single-threaded runtimes I/O and timers won't work. To fix this issue I've switch the fallback runtime to a multi-threaded runtime to ensure that I/O and timers continue to work. [Zulip]: https://bytecodealliance.zulipchat.com/#narrow/stream/219900-wasi/topic/Wasi-http.20requests.20hang/near/429187256 [doc]: https://docs.rs/tokio/latest/tokio/runtime/struct.Handle.html#method.block_on
This commit fixes a bug that was introduced in #8190 and brought up on [Zulip]. In #8190 there was a subtle change in how Tokio and the CLI are managed, namely that a Tokio runtime is installed at the start of the CLI to avoid entering/exiting the runtime on each blocking call. This had a small performance improvement relative to entering/exiting on each blocking call. This meant, though, that calls previously blocked with `Runtime::block_on` and now block with `Handle::block_on`. The [documentation of `Handle::block_on`][doc] has a clause that says that for single-threaded runtimes I/O and timers won't work. To fix this issue I've switch the fallback runtime to a multi-threaded runtime to ensure that I/O and timers continue to work. [Zulip]: https://bytecodealliance.zulipchat.com/#narrow/stream/219900-wasi/topic/Wasi-http.20requests.20hang/near/429187256 [doc]: https://docs.rs/tokio/latest/tokio/runtime/struct.Handle.html#method.block_on
Currently all of Wasmtime's implementation of WASI is built on Tokio, but some operations are currently not asynchronous such as opening a file or reading a directory. Internally these use
spawn_blocking
to satisfy the requirements of async users of WASI to avoid blocking the current thread. This use ofspawn_blocking
, however, ends up causing mostly just performance overhead in the use case of the CLI, for example, where async wasm is not used. That then leads to this commit, implementing an opt-in mechanism to be able to block the current thread.A
WasiCtx
now has a flag indicating whether it's ok to block the current thread and that's carried to various filesystem operations that usespawn_blocking
. The call tospawn_blocking
is now conditional and skipped if this flag is set.Additionally the invocation point in the CLI for wasm modules is wrapped in a Tokio runtime to avoid entering/exiting Tokio in the "leaves" when wasm calls the host, as happens today. This hits a better fast path in Tokio that appears to be more efficient.
Semantically this should not result in any change for CLI programs except in one case: file writes. By default writes on
output-stream
in WASI are asynchronous meaning that only one write can be in flight at a time. That being said all current users are immediately blocking waiting for this write to finish anyway, so this commit won't end up changing much. It's already the case that file reads are always blocking, for example. If necessary in the future though this can be further special-cased at the preview1 layer.