Stream: wasmtime

Topic: ✔ wasmtime_fiber


view this post on Zulip zeroexcuses (Nov 15 2023 at 03:58):

Apologies if this is double posting. I am new to Zulip. I tried posting this in wasmtime, but then it vanished (and I can't see it), so I'm not sure if the post went through or not.

I have a question regarding https://docs.rs/wasmtime-fiber/latest/wasmtime_fiber/struct.Suspend.html#method.suspend

  1. What problem does wasmtime_fiber solve? I see that we can create a (relatively) chap stack, but not sure where this goes from here.
  2. How does the suspend func work? If a fiber is running, it utilizes the host thread right ? Meaning the host thread can't call suspend -- so who/what is calling suspend ? Is a different thread doing so? [And if so, is this all thread safe] ?

Thanks!

view this post on Zulip Alex Crichton (Nov 15 2023 at 15:03):

FWIW the wasmtime-fiber crate is a low-level library that isn't intended necessarily to be used as a general purpose crate. It's primarily there to enable Wasmtime's async implementation.

That being said the solution it provides for Wasmtime is the ability to suspend a WebAssembly computation by capturing its native stack. The fiber itself calls suspend to return control flow to the original thread which started the fiber and then the fiber can be resumed at a later time

view this post on Zulip Notification Bot (Nov 15 2023 at 16:27):

This topic was moved here from #general > wasmtime_fiber by fitzgen (he/him).

view this post on Zulip zeroexcuses (Nov 20 2023 at 00:16):

Sorry if I am missing something very basic. Is there a way to use wasmtime-fiber as follows:

  1. create a fiber
  2. add fuel
  3. when fuel runs out, instead of aborting the wasmtime runtime, have it call suspend

I see the wasmtime-fiber crate; I see the wasmtime fuel functions. It is not obvious to me how to use the two together.

view this post on Zulip Alex Crichton (Nov 20 2023 at 03:02):

Users of the wasmtime crate don't use wasmtime-fiber at all, it's just an internal implementation detail. Everything is handled for you when using async in Wasmtime

view this post on Zulip zeroexcuses (Nov 20 2023 at 06:50):

I want to build a toy version of Beam / Lunatic, but with wasmtime as the 'lightweight' processes.

Looking at https://docs.wasmtime.dev/api/wasmtime/struct.Store.html#method.fuel_async_yield_interval this seems a bit too high level, as it auto re-marks self as "to run"

I want a system where I can

  1. have 10k wasmtime runtimes
  2. give each a different amount of fuel, tell it to run
  3. after fuel is consumed, have it notify me (instead of re-marking self for running)
  4. my logic code decides how much fuel to give to each suspended wasmtime, and tell it to run again

In particular, I want this low level control where when something runs out of fuel, it notifies "me" (my code); my code puts it on some queue, at some later point adds it more fuel, and tells it to re-run.

I want to control the logic of after "wasmtime out of fuel, suspended" to "wasmtime added fuel, rerun"

whereas the existing logic seems to just auto re-subscribe self to re-run.

view this post on Zulip zeroexcuses (Nov 20 2023 at 06:59):

In particular, neither https://docs.rs/wasmtime/latest/wasmtime/struct.Store.html#method.out_of_fuel_trap (kills wasmtime on out of fuel)
nor
https://docs.rs/wasmtime/latest/wasmtime/struct.Store.html#method.out_of_fuel_async_yield (auto refills wasmtime on out of fuel, then kills it after refills done)
does what I want

I am looking for something where I can say:

  1. run this wasmtime for X units of fuel
  2. then I move on, and afterwards, maybe I choose to run it for X1 units of fuel

the existing primitives seems to auto-refill everything and let the async runtime sort out who runs what

I want a bit more manual control

view this post on Zulip zeroexcuses (Nov 20 2023 at 07:01):

and if I use https://docs.rs/wasmtime/latest/wasmtime/struct.Store.html#method.epoch_deadline_callback it forces me then & there to decide whether to kill or refill a wasmtime

instead, I'd prefer to say: "I'm going to throw this suspended wasmtine on a queue, and at some later point, figure out whether to kill it / refill it and rerun / ..."

view this post on Zulip Lann Martin (Nov 20 2023 at 14:03):

I think you could probably get the effect you're looking for with a custom Future wrapper though it may be a little tricky depending on exactly what you're trying to accomplish. You could effectively "pause" execution by returning Poll::Pending from the wrapper's Future::poll and arranging for a wakeup based on your own logic. One hiccup is that I believe you wouldn't be able to easily control fuel/epoch refilling outside of the existing methods available as the inner Future would hold a &mut Store.

view this post on Zulip Alex Crichton (Nov 20 2023 at 14:51):

It also wouldn't be too hard to add an out-of-fuel callback similar to how epochs have a custom callback as well

view this post on Zulip zeroexcuses (Nov 20 2023 at 21:12):

Are you referring to https://docs.rs/wasmtime/latest/wasmtime/struct.Store.html#method.epoch_deadline_callback and https://docs.rs/wasmtime/latest/wasmtime/enum.UpdateDeadline.html

The problem I see there is that it demands, at the moment that it runs out of fuel, that I immediately decided what to do with it: kill, continue, or yield (which says "rerun, at the async runtime's convenience").

I'm looking for something where the callback gets something (say, like a Rc<RefCell<wasmtime-fiber>>) which it can throw onto a queue, and deal with it later.

view this post on Zulip Pat Hickey (Nov 20 2023 at 21:13):

in Rust, the value you get to manipulate with a suspended async computation is called a Future (probably a Pin<Box<dyn Future>>)

view this post on Zulip Pat Hickey (Nov 20 2023 at 21:14):

and when the epoch deadline callback returns a Yield, that means the Future currently executing wasm will return a Poll::Pending

view this post on Zulip Pat Hickey (Nov 20 2023 at 21:15):

so, execution will be suspended until you again call Future::poll on that Future.

view this post on Zulip Alex Crichton (Nov 20 2023 at 21:15):

Yes the callback would be combined with what Lann mentioned above where you might have a wrapper around Future for doing the enqueueing you're desiring

view this post on Zulip Alex Crichton (Nov 20 2023 at 21:15):

using the pending signal Pat's talking about

view this post on Zulip zeroexcuses (Nov 20 2023 at 23:17):

@Pat Hickey : I am familiar with Rust + async Rust. I am not (yet) familiar with the wasmtime api. It looks like I am misunderstanding something.

Atter an epoch deadline callback, to resume the wasmtime "lightweight process", I call a foo.await right? Where/how do I get this foo ?

view this post on Zulip Pat Hickey (Nov 20 2023 at 23:52):

go re-familiarize yourself with async rust. foo is a future, and the .await on it is a call to future::poll.

view this post on Zulip zeroexcuses (Nov 21 2023 at 00:11):

I think you misunderstood my question.

Here is the function

    pub fn epoch_deadline_callback(
        &mut self,
        callback: impl FnMut(StoreContextMut<T>) -> Result<UpdateDeadline> + Send + Sync + 'static,
    ) {
        self.inner.epoch_deadline_callback(Box::new(callback));
    }

https://docs.rs/wasmtime/latest/src/wasmtime/store.rs.html#935-940

So now my question is: for us to call foo.await, we need a foo -- but our callback gets a https://docs.rs/wasmtime/latest/wasmtime/struct.StoreContextMut.html .

Where do we get the FUTURE from ?

view this post on Zulip Pat Hickey (Nov 21 2023 at 00:33):

Function::call_async and friends return a Future. that is the future that will return Pending when the epoch causes it to yield

view this post on Zulip zeroexcuses (Nov 21 2023 at 01:07):

I think this clarifies everything up. I will test out some code. Thanks!

view this post on Zulip Notification Bot (Nov 21 2023 at 08:28):

zeroexcuses has marked this topic as resolved.


Last updated: Dec 23 2024 at 14:03 UTC