github-actions[bot] commented on issue #2952:
Subscribe to Label Action
cc @peterhuene
<details>
This issue or pull request has been labeled: "cranelift", "wasmtime:c-api"Thus the following users have been cc'd because of the following labels:
- peterhuene: wasmtime:c-api
To subscribe or unsubscribe from this label, edit the <code>.github/subscribe-to-label.json</code> configuration file.
Learn more.
</details>
github-actions[bot] commented on issue #2952:
Subscribe to Label Action
cc @fitzgen, @peterhuene
<details>
This issue or pull request has been labeled: "fuzzing", "wasmtime:api"Thus the following users have been cc'd because of the following labels:
- fitzgen: fuzzing
- peterhuene: wasmtime:api
To subscribe or unsubscribe from this label, edit the <code>.github/subscribe-to-label.json</code> configuration file.
Learn more.
</details>
alexcrichton commented on issue #2952:
Locally I've got two benchmarks for changes like this:
<details>
<summary>host -> wasm overhead</summary>
fn host_to_wasm_overhead() -> anyhow::Result<()> { use wasmtime::*; let engine = Engine::default(); let module = Module::new( &engine, r#" (module (func (export "run") (param i32 i32) (result i32) local.get 0 local.get 1 i32.add ) ) "#, )?; let mut store = Store::new(&engine, ()); let instance = Instance::new(&mut store, &module, &[])?; let run = instance.get_typed_func::<(i32, i32), i32, _>(&mut store, "run")?; let now = std::time::Instant::now(); let total = 100_000_000; for _ in 0..total { run.call(&mut store, (1, 1))?; } let time = now.elapsed(); println!( "use Time: {:?}, each:{} ns/op", time, time.as_nanos() / (total as u128) ); Ok(()) }
</details>
<details>
<summary>wasm -> host overhead</summary>
fn wasm_to_host() -> anyhow::Result<()> { use wasmtime::*; let engine = Engine::default(); let module = Module::new( &engine, r#" (module (import "" "add" (func $add (param i32 i32) (result i32))) (func (export "run") (param i32) loop i32.const 1 i32.const 2 call 0 drop local.get 0 i32.const -1 i32.add local.tee 0 br_if 0 end )) "#, )?; let mut store = Store::new(&engine, ()); let func = Func::wrap(&mut store, |a: u32, b: u32| a + b); let instance = Instance::new(&mut store, &module, &[func.into()])?; let run = instance.get_typed_func::<i32, (), _>(&mut store, "run")?; let now = std::time::Instant::now(); let total = 1_000_000_000; run.call(&mut store, total)?; let time = now.elapsed(); println!( "use Time: {:?}, each:{} ns/op", time, time.as_nanos() / (total as u128) ); Ok(()) }
</details>
The numbers I got for this PR on my local macOS machine are:
before after host -> wasm 29ns 30ns wasm -> host 1ns 2ns So it looks like adding these unconditional branches has pretty negligible overhead. If it really matters in some use case we could always add a compile-time option to disable them, but otherwise I don't think there's too much impact.
One thing that's required, though, is to add
#[inline]
to a few more methods. I noticed this when profiling and gathered the numbers with some local changes to this PR. The reason is thatStoreInner
methods which previously had a generic in scope are now concrete onStoreInnermost
so they require#[inline]
to get cross-crate inlined. The ones I added inline too are:
StoreInnermost::signal_handler
StoreInnermost::vminterrupts
StoreInnermost::async_cx
StoreInnermost::default_callee
StoreInnermost::async_support
StoreInnermost::engine
StoreInnermost::data
StoreInnermost::data_mut
alexcrichton commented on issue #2952:
:+1:
Last updated: Dec 23 2024 at 12:05 UTC