Skip to content
This repository has been archived by the owner on Jul 16, 2020. It is now read-only.

Implement performance benchmarking for basic demo #18

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
1 change: 1 addition & 0 deletions wasmtime-basic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ default = ["rust"]

c = []
rust = []
benchmark = []
10 changes: 9 additions & 1 deletion wasmtime-basic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,12 @@ Rust is compiled by default. If C is desired, the appropriate feature can be inv
cargo run --no-default-features --features c
```

Or, alternatively, by changing the `default` feature in `Cargo.toml` from `["rust"]` to `["c"]`.
## Running benchmarks

`main.rs` includes performance benchmarks useful for analyzing the startup cost and runtime of functions in Wasmtime.

These benchmarks use Rust's unstable built-in benchmarking tools, and must be run on Rust nightly. Additionally, the `benchmark` feature must be enabled to run them:

```
cargo +nightly bench --features benchmark
```
82 changes: 73 additions & 9 deletions wasmtime-basic/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
//! Rust-powered JIT, to natively run programs from several different source
//! languages (Rust/C/C++) compiled to WASI-compliant WASM.

#![cfg_attr(feature = "benchmark", feature(test))]

#[cfg(test)]
extern crate test;
mbestavros marked this conversation as resolved.
Show resolved Hide resolved

use cranelift_codegen::settings;
use cranelift_native;
use std::fs::File;
use std::io::Read;
use wasmtime_jit::{ActionOutcome, Context, RuntimeValue};
use wasmtime_jit::{ActionError, ActionOutcome, Context, RuntimeValue};

// The basic WASM demo itself.
fn main() {
// Before we begin, it'll be heplful to know which source language we're
// running, so let's print it out.
Expand All @@ -18,11 +24,22 @@ fn main() {
println!("WASM binary has been compiled from Rust.");
}

println!("Loading WASM binary...");
println!("Loading and running WASM binary...");
let result = wasm_add_full();
println!("Finished. Results:");
match result.unwrap() {
ActionOutcome::Returned { values } => println!("Output: {:#?}", values),
ActionOutcome::Trapped { message } => println!("Trap from within function: {}", message),
}
println!("Done.");
}

// A function to encapsulate the full setup and execution of a single iteration of the WASM demo.
pub fn wasm_add_full() -> Result<ActionOutcome, ActionError> {
// First, we need to load the WASM binary in.
let mut binary_file = File::open(concat!(env!("OUT_DIR"), "/add.wasm")).unwrap();
let mut binary: Vec<u8> = Vec::new();
binary_file.read_to_end(&mut binary).unwrap();
println!("WASM binary loaded.");

// In order to run this binary, we need to prepare a few inputs.

Expand All @@ -40,12 +57,59 @@ fn main() {

// And, finally, invoke our function and print the results.
// For this demo, all we're doing is adding 5 and 7 together.
println!("Invoking function.");
let args = [RuntimeValue::I32(5), RuntimeValue::I32(7)];
let result = context.invoke(&mut instance, "add", &args);
match result.unwrap() {
ActionOutcome::Returned { values } => println!("Output: {:#?}", values),
ActionOutcome::Trapped { message } => println!("Trap from within function: {}", message),
context.invoke(&mut instance, "add", &args)
}

// A Rust function that does the same thing as the WASM demo, for benchmarking use.
#[cfg(test)]
pub fn native_add(a: i32, b: i32) -> i32 {
a + b
}

// Performance benchmarking for the demo.
#[cfg(test)]
mod tests {
use super::*;
use test::Bencher;

// Baseline benchmark: Simple Rust adition.
#[bench]
fn bench_native_add(b: &mut Bencher) {
b.iter(|| native_add(5, 7));
}

// Benchmark: WASM addition from start to finish, including
// loading/instantiating WASM.
#[bench]
fn bench_wasm_add_unloaded(b: &mut Bencher) {
b.iter(|| wasm_add_full());
}

// Benchmark: WASM addition once everything is set up.
#[bench]
fn bench_wasm_add_loaded(b: &mut Bencher) {
let mut binary_file = File::open(concat!(env!("OUT_DIR"), "/add.wasm")).unwrap();
let mut binary: Vec<u8> = Vec::new();
binary_file.read_to_end(&mut binary).unwrap();

// In order to run this binary, we need to prepare a few inputs.

// First, we need a Wasmtime context. To build one, we need to get an ISA
// from `cranelift_native.
let isa_builder = cranelift_native::builder().unwrap();
let flag_builder = settings::builder();
let isa = isa_builder.finish(settings::Flags::new(flag_builder));

// Then, we use the ISA to build the context.
let mut context = Context::with_isa(isa);

// Now, we instantiate the WASM module loaded into memory.
let mut instance = context.instantiate_module(None, &binary).unwrap();

// And, finally, invoke our function and print the results.
// For this demo, all we're doing is adding 5 and 7 together.
let args = [RuntimeValue::I32(5), RuntimeValue::I32(7)];
b.iter(|| context.invoke(&mut instance, "add", &args));
}
println!("Done.");
}