-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
226 additions
and
98 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
//! Common benchmark helpers shared by multiple benchmarks. | ||
// Not all helpers are used in all benchmarks. | ||
#![allow(dead_code)] | ||
|
||
use anyhow::Result; | ||
use std::path::PathBuf; | ||
use std::process::Command; | ||
use wasmtime::*; | ||
use wasmtime_wasi::{sync::WasiCtxBuilder, WasiCtx}; | ||
|
||
pub fn build_wasi_example() { | ||
println!("Building WASI example module..."); | ||
if !Command::new("cargo") | ||
.args(&[ | ||
"build", | ||
"--release", | ||
"-p", | ||
"example-wasi-wasm", | ||
"--target", | ||
"wasm32-wasi", | ||
]) | ||
.spawn() | ||
.expect("failed to run cargo to build WASI example") | ||
.wait() | ||
.expect("failed to wait for cargo to build") | ||
.success() | ||
{ | ||
panic!("failed to build WASI example for target `wasm32-wasi`"); | ||
} | ||
|
||
std::fs::copy( | ||
"target/wasm32-wasi/release/wasi.wasm", | ||
"benches/instantiation/wasi.wasm", | ||
) | ||
.expect("failed to copy WASI example module"); | ||
} | ||
|
||
pub fn strategies() -> Vec<InstanceAllocationStrategy> { | ||
vec![ | ||
// Skip the on-demand allocator when uffd is enabled | ||
#[cfg(any(not(feature = "uffd"), not(target_os = "linux")))] | ||
InstanceAllocationStrategy::OnDemand, | ||
InstanceAllocationStrategy::pooling(), | ||
] | ||
} | ||
|
||
pub fn modules() -> Vec<&'static str> { | ||
vec![ | ||
"empty.wat", | ||
"small_memory.wat", | ||
"data_segments.wat", | ||
"wasi.wasm", | ||
] | ||
} | ||
|
||
pub fn make_engine(strategy: &InstanceAllocationStrategy, is_async: bool) -> Result<Engine> { | ||
let mut config = Config::default(); | ||
config.allocation_strategy(strategy.clone()); | ||
config.async_support(is_async); | ||
Engine::new(&config) | ||
} | ||
|
||
pub fn load_module(engine: &Engine, module_name: &str) -> Result<(Module, Linker<WasiCtx>)> { | ||
let mut path = PathBuf::new(); | ||
path.push("benches"); | ||
path.push("instantiation"); | ||
path.push(module_name); | ||
|
||
let module = Module::from_file(&engine, &path) | ||
.unwrap_or_else(|_| panic!("failed to load benchmark `{}`", path.display())); | ||
let mut linker = Linker::new(&engine); | ||
wasmtime_wasi::add_to_linker(&mut linker, |cx| cx).unwrap(); | ||
|
||
Ok((module, linker)) | ||
} | ||
|
||
pub fn benchmark_name<'a>(strategy: &InstanceAllocationStrategy) -> &'static str { | ||
match strategy { | ||
InstanceAllocationStrategy::OnDemand => "default", | ||
#[cfg(any(not(feature = "uffd"), not(target_os = "linux")))] | ||
InstanceAllocationStrategy::Pooling { .. } => "pooling", | ||
#[cfg(all(feature = "uffd", target_os = "linux"))] | ||
InstanceAllocationStrategy::Pooling { .. } => "uffd", | ||
} | ||
} | ||
|
||
pub fn instantiate(linker: &Linker<WasiCtx>, module: &Module) -> Result<Instance> { | ||
let wasi = WasiCtxBuilder::new().build(); | ||
let mut store = Store::new(module.engine(), wasi); | ||
linker.instantiate(&mut store, module) | ||
} | ||
|
||
pub fn instantiate_pre(linker: &Linker<WasiCtx>, module: &Module) -> Result<InstancePre<WasiCtx>> { | ||
let wasi = WasiCtxBuilder::new().build(); | ||
let mut store = Store::new(module.engine(), wasi); | ||
linker.instantiate_pre(&mut store, module) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
use criterion::{criterion_group, criterion_main, Criterion}; | ||
use std::{sync::Arc, time::Instant}; | ||
use wasmtime::*; | ||
use wasmtime_wasi::{sync::WasiCtxBuilder, WasiCtx}; | ||
|
||
// Tell rustfmt to skip this module reference; otherwise it can't seem to find it (`cargo fmt` says | ||
// ".../wasmtime/benches does not exist". | ||
#[rustfmt::skip] | ||
mod common; | ||
|
||
struct Server { | ||
permits: tokio::sync::Semaphore, | ||
engine: Engine, | ||
modules: Vec<Module>, | ||
instance_pres: Vec<InstancePre<WasiCtx>>, | ||
} | ||
|
||
impl Server { | ||
async fn job(self: Arc<Self>, index: usize) { | ||
let _permit = self.permits.acquire().await.unwrap(); | ||
let ipre = &self.instance_pres[index % self.modules.len()]; | ||
let wasi = WasiCtxBuilder::new().build(); | ||
let mut store = Store::new(&self.engine, wasi); | ||
let instance = ipre.instantiate_async(&mut store).await.unwrap(); | ||
let start_func = instance.get_func(&mut store, "_start").unwrap(); | ||
start_func | ||
.call_async(&mut store, &[], &mut []) | ||
.await | ||
.unwrap(); | ||
} | ||
} | ||
|
||
fn run_server( | ||
strategy: &InstanceAllocationStrategy, | ||
filenames: &[&str], | ||
occupancy: usize, | ||
instantiations: usize, | ||
) { | ||
let engine = common::make_engine(strategy, /* async = */ true).unwrap(); | ||
let mut instance_pres = vec![]; | ||
let mut modules = vec![]; | ||
for filename in filenames { | ||
let (module, linker) = common::load_module(&engine, filename).unwrap(); | ||
let instance_pre = common::instantiate_pre(&linker, &module).unwrap(); | ||
modules.push(module); | ||
instance_pres.push(instance_pre); | ||
} | ||
|
||
let server = Arc::new(Server { | ||
permits: tokio::sync::Semaphore::new(occupancy), | ||
engine, | ||
modules, | ||
instance_pres, | ||
}); | ||
|
||
// Spawn an initial batch of jobs up to the | ||
let server_clone = server.clone(); | ||
|
||
let rt = tokio::runtime::Runtime::new().unwrap(); | ||
rt.block_on(async move { | ||
for i in 0..instantiations { | ||
let server = server_clone.clone(); | ||
tokio::spawn(server.job(i)); | ||
} | ||
}); | ||
} | ||
|
||
fn bench_server(c: &mut Criterion) { | ||
common::build_wasi_example(); | ||
|
||
let modules = vec!["wasi.wasm"]; | ||
let occupancy = 1000; | ||
|
||
for strategy in common::strategies() { | ||
c.bench_function( | ||
&format!( | ||
"strategy {}, occupancy {}, benches {:?}", | ||
common::benchmark_name(&strategy), | ||
occupancy, | ||
modules, | ||
), | ||
|b| { | ||
b.iter_custom(|iters| { | ||
let start = Instant::now(); | ||
run_server( | ||
&strategy, | ||
&modules, | ||
occupancy, | ||
/* instantiations = */ iters as usize, | ||
); | ||
start.elapsed() | ||
}); | ||
}, | ||
); | ||
} | ||
} | ||
|
||
criterion_group!(benches, bench_server); | ||
criterion_main!(benches); |