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 simple benchmarks for instantiation. #2900

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,19 @@ jobs:
env:
RUST_BACKTRACE: 1

bench:
name: Run benchmarks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: true
- run: rustup target add wasm32-wasi
- name: Install Rust
run: rustup update stable && rustup default stable
- run: cargo bench
- run: cargo bench --features uffd

# Verify that cranelift's code generation is deterministic
meta_determinist_check:
name: Meta deterministic check
Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ file-per-thread-logger = "0.1.1"
wat = "1.0.37"
libc = "0.2.60"
log = "0.4.8"
rayon = "1.2.1"
rayon = "1.5.0"
humantime = "2.0.0"
wasmparser = "0.77.0"
lazy_static = "1.4.0"
Expand All @@ -57,6 +57,8 @@ wasmtime-runtime = { path = "crates/runtime" }
tokio = { version = "1.5.0", features = ["rt", "time", "macros", "rt-multi-thread"] }
tracing-subscriber = "0.2.16"
wast = "35.0.0"
criterion = "0.3.4"
num_cpus = "1.13.0"

[build-dependencies]
anyhow = "1.0.19"
Expand Down Expand Up @@ -116,3 +118,7 @@ required-features = ["wasmtime-wasi/tokio"]

[profile.dev.package.backtrace]
debug = false # FIXME(#1813)

[[bench]]
name = "instantiation"
harness = false
1 change: 1 addition & 0 deletions benches/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
instantiation/wasi.wasm
158 changes: 158 additions & 0 deletions benches/instantiation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use anyhow::Result;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use rayon::{prelude::*, ThreadPoolBuilder};
use std::{path::PathBuf, process::Command};
use wasmtime::*;
use wasmtime_wasi::{sync::WasiCtxBuilder, Wasi};

fn instantiate(module: &Module) -> Result<Instance> {
let store = Store::new(&module.engine());

// As we don't actually invoke Wasm code in this benchmark, we still add
// the WASI context to the store as it is considered part of getting a
// module that depends on WASI "ready to run".
Wasi::set_context(&store, WasiCtxBuilder::new().build()?)
.map_err(|_| anyhow::anyhow!("wasi set_context failed"))?;

let linker = Linker::new(&store);
let instance = linker.instantiate(module)?;

Ok(instance)
}

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",
}
}

fn bench_sequential(c: &mut Criterion, modules: &[&str]) {
let mut group = c.benchmark_group("sequential");

for strategy in &[
// Skip the on-demand allocator when uffd is enabled
#[cfg(any(not(feature = "uffd"), not(target_os = "linux")))]
InstanceAllocationStrategy::OnDemand,
InstanceAllocationStrategy::pooling(),
] {
for file_name in modules {
let mut path = PathBuf::new();
path.push("benches");
path.push("instantiation");
path.push(file_name);

let mut config = Config::default();
Wasi::add_to_config(&mut config);
config.allocation_strategy(strategy.clone());

let engine = Engine::new(&config).expect("failed to create engine");
let module = Module::from_file(&engine, &path)
.expect(&format!("failed to load benchmark `{}`", path.display()));

group.bench_function(BenchmarkId::new(benchmark_name(strategy), file_name), |b| {
b.iter(|| instantiate(&module).expect("failed to instantiate module"));
});
}
}

group.finish();
}

fn bench_parallel(c: &mut Criterion) {
const PARALLEL_INSTANCES: usize = 1000;

let mut group = c.benchmark_group("parallel");

for strategy in &[
// Skip the on-demand allocator when uffd is enabled
#[cfg(any(not(feature = "uffd"), not(target_os = "linux")))]
InstanceAllocationStrategy::OnDemand,
InstanceAllocationStrategy::pooling(),
] {
let mut config = Config::default();
Wasi::add_to_config(&mut config);
config.allocation_strategy(strategy.clone());

let engine = Engine::new(&config).expect("failed to create engine");
let module = Module::from_file(&engine, "benches/instantiation/wasi.wasm")
.expect("failed to load WASI example module");

for threads in 1..=num_cpus::get_physical() {
let pool = ThreadPoolBuilder::new()
.num_threads(threads)
.build()
.unwrap();

group.bench_function(
BenchmarkId::new(
benchmark_name(strategy),
format!(
"{} instances with {} thread{}",
PARALLEL_INSTANCES,
threads,
if threads == 1 { "" } else { "s" }
),
),
|b| {
b.iter(|| {
pool.install(|| {
(0..PARALLEL_INSTANCES).into_par_iter().for_each(|_| {
instantiate(&module).expect("failed to instantiate module");
})
})
});
},
);
}
}

group.finish();
}

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");
}

fn bench_instantiation(c: &mut Criterion) {
build_wasi_example();
bench_sequential(
c,
&[
"empty.wat",
"small_memory.wat",
"data_segments.wat",
"wasi.wasm",
],
);
bench_parallel(c);
}

criterion_group!(benches, bench_instantiation);
criterion_main!(benches);
5 changes: 5 additions & 0 deletions benches/instantiation/data_segments.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(module
(memory 17)
(func (export "_start"))
(data (i32.const 0) "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789")
)
3 changes: 3 additions & 0 deletions benches/instantiation/empty.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(module
(func (export "_start"))
)
4 changes: 4 additions & 0 deletions benches/instantiation/small_memory.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(module
(memory 1)
(func (export "_start"))
)
4 changes: 2 additions & 2 deletions crates/jit/src/instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub enum SetupError {
#[error("Validation error: {0}")]
Validate(String),

/// A wasm translation error occured.
/// A wasm translation error occurred.
#[error("WebAssembly failed to compile")]
Compile(#[from] CompileError),

Expand All @@ -44,7 +44,7 @@ pub enum SetupError {
#[error("Instantiation failed during setup")]
Instantiate(#[from] InstantiationError),

/// Debug information generation error occured.
/// Debug information generation error occurred.
#[error("Debug information error")]
DebugInfo(#[from] anyhow::Error),
}
Expand Down
4 changes: 2 additions & 2 deletions crates/runtime/src/instance/allocator/pooling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1610,7 +1610,7 @@ mod test {
}

#[test]
fn test_pooling_allocator_with_memory_pages_exeeded() {
fn test_pooling_allocator_with_memory_pages_exceeded() {
assert_eq!(
PoolingInstanceAllocator::new(
PoolingAllocationStrategy::Random,
Expand All @@ -1631,7 +1631,7 @@ mod test {
}

#[test]
fn test_pooling_allocator_with_reservation_size_exeeded() {
fn test_pooling_allocator_with_reservation_size_exceeded() {
assert_eq!(
PoolingInstanceAllocator::new(
PoolingAllocationStrategy::Random,
Expand Down