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

Implement opt-in for enabling WASI to block the current thread #8190

Merged

Conversation

alexcrichton
Copy link
Member

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.

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.
@alexcrichton alexcrichton requested a review from a team as a code owner March 20, 2024 15:02
@alexcrichton alexcrichton requested review from fitzgen and removed request for a team March 20, 2024 15:02
Comment on lines 224 to 229
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
};
Copy link
Member

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.

Copy link
Member Author

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.

@github-actions github-actions bot added the wasi Issues pertaining to WASI label Mar 20, 2024
@alexcrichton alexcrichton added this pull request to the merge queue Mar 20, 2024
Merged via the queue into bytecodealliance:main with commit f4bee25 Mar 20, 2024
19 checks passed
@alexcrichton alexcrichton deleted the releive-tokio-overhead branch March 20, 2024 21:16
alexcrichton added a commit to alexcrichton/wasmtime that referenced this pull request Mar 24, 2024
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
github-merge-queue bot pushed a commit that referenced this pull request Mar 25, 2024
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wasi Issues pertaining to WASI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants