Stream: wasmtime

Topic: Can async traps subsume epoch-interruptions?


view this post on Zulip Sergei Pepyakin (Jul 04 2022 at 19:23):

During the work on slacked/async fuel metering, see #4109, we converged on an idea of checking the fuel asynchronously. TL;DR: Slacked fuel metering allows to achieve overhead close to zero in many cases while preserving determinism if the user can accept some concessions.

It works roughly like this. We reserve a register for the fuel counter. The fuel counter is incremented at each BB. The thread executing wasm will be periodically interrupted. The interrupt handler would check if the thread was interrupted in wasm based on the value of the PC register. If it was, then the handler can read the fuel register. Then, the handler can initiate a trap. Semantically, that means a wasm module can be interrupted at any wasm PC.

For macOS and Windows we would stop the thread, inspect its thread state, and if there is out-of-gas then modify the thread state, to land on a handler that would initiate unwinding.

Which made me realize: this looks equivalent to what epoch-interruption aims to achieve. Specifically, it provides an efficient way to interrupt wasm code non-deterministically (but 2-3x faster) based on some periodic signal by the embedder.

Unlike epoch-interruption, async traps do not require inline synchronous checks on each epilogue and back edges. Instead, if we don't care about pretty stack traces during such async traps, then we don't need any modifications of compiled code. Or we can follow suggestion by @Alex Crichton here. In any case, this has ≈0 overhead.

Also, I think async traps are a simpler and less-opinionated. Instead of having a single per-Engine counter that interrupts code in all stores that reached the deadline, per thread interruption is possible.

Probably I am missing something here and it might have been perhaps discussed. If so, why did the mechanism that involves synchronous checks won compared to async traps? Similar to Alex's logic in the linked issue?

cc @Chris Fallin

wasmtime right now has the fuel mechanism. It allows precise control of how many instructions are executed before suspending execution, at least at a basic block granularity. The price is a rather ...
(Builds on #3698) This PR introduces a new way of performing cooperative timeslicing that is intended to replace the "fuel" mechanism. The tradeoff is that this mechanism interrupts with less preci...
wasmtime right now has the fuel mechanism. It allows precise control of how many instructions are executed before suspending execution, at least at a basic block granularity. The price is a rather ...

view this post on Zulip Alex Crichton (Jul 05 2022 at 16:07):

I wondered the same thing myself as the async traps work unfolded. To me though the answer is not clear. Integration of epochs is quite simple where a thread simply increments a single counter. Integration of async traps seems more complicated where handles to threads-running-wasm need to be maintained and the periodic thread iterates this list. This implies at least some degree of synchronization depending on system setup.

Cost-wise given the benefits of async traps it may be worth investing in this design given how low-overhead they are!

view this post on Zulip Chris Fallin (Jul 05 2022 at 16:13):

For a little more context, at least in our embedding there was serious concern about any async thread interruption at all; partly due to historical experience and partly due to the real inherent subtleties one has to worry about (signal-safety, etc). So I guess epoch interruption fills a niche where we want pretty-fast interruptible code but no dependence on OS-specific thread interruption mechanisms

view this post on Zulip Chris Fallin (Jul 05 2022 at 16:14):

others may very well have different tradeoffs or complexity profiles though and be willing to build that out; it'd be interesting to see more options supported by wasmtime in general


Last updated: Dec 23 2024 at 13:07 UTC